美文网首页SSM搭建二手市场交易平台网站
SSM搭建二手市场交易平台(八):用户登录信息功能开发

SSM搭建二手市场交易平台(八):用户登录信息功能开发

作者: 啃饼小白 | 来源:发表于2019-01-22 08:35 被阅读37次

写在前面

本篇我们介绍用户登录获取信息,忘记密码,提示问题与答案,重置密码功能开发这四者的实现,里面的内容很多,希望大家对此有一个提前的认识。

还记得我们上一篇的UserController--->IUserService-->UserServiceImpl模式么,我们继续进行开发,把这个放在这里是让大家更清楚的知道我们的开发流程,不至于晕。

用户登录获取信息

打开UserController.java文件,写入以下代码:

    /***
     * 用户登录信息的获取
     * */
    @RequestMapping(value = "get_user_info.do",method = RequestMethod.GET)  //这里就是具体的每个方法的url链接
    @ResponseBody   //自动序列化json功能
    public ServerResponse<User> getUserInfo(HttpSession session){
        User user =(User) session.getAttribute(Const.CURRENT_USER);
        if(user != null){
            return ServerResponse.createBySuccess(user);
        }
        return ServerResponse.createByErrorMessage("用户未登录,无法获取当前用户的信息");
    }

这样我们那就完成了用户登录信息的获取操作,你可能会问后面那两个过程哪去了,这里需要说明的是,不涉及到数据库的访问操作就不需要后面两个过程,这一点你需要注意一下。

忘记密码

打开UserController.java文件,写入以下代码:(注意我这里就是直接把这个功能的完整实现代码贴这里了,没有一步一步的写,毕竟太浪费时间了,也没有必要,你们懂我的意思吧)

    /***
     * 忘记密码
     * */
    @RequestMapping(value = "forget_get_question.do",method = RequestMethod.GET)  //这里就是具体的每个方法的url链接
    @ResponseBody   //自动序列化json功能
    public ServerResponse<String> forgetGetQuestion(String username){
        return iUserService.forgetGetQuestion(username);
    }

接着打开IUserService.java文件:

 ServerResponse<String> forgetGetQuestion(String username);   //忘记密码

继续打开UserServiceImpl.java文件:

    /***
     *
     *忘记密码时的接口类
     * */
    public ServerResponse<String> forgetGetQuestion(String username){
        //判断用户名是否存在
        ServerResponse validResponse =this.checkValid(username,Const.USERNAME);
        if(validResponse.isSuccess()){  //用户名不存在
            return ServerResponse.createByErrorMessage("该用户不存在");
        }

        String question =userMapper.forgetgetQuestionByUsername(username);
        if(StringUtils.isNoneBlank(question)){
            //开始进行校验,如果找回密码的问题不为空,那么
            return ServerResponse.createBySuccess(question);
        }
        return ServerResponse.createByErrorMessage("找回密码的问题是空的");
    }
}

String question =userMapper.forgetgetQuestionByUsername(username);这行代码我需要说明一下。大家都知道我们这个UserMapper(里面的userMapper是它的实例化对象)就是DAO层,它需要提供一个接口(IUserService)和该接口的实现类(UserServiceImpl)用于访问数据库,但是我们获取数据库里面的信息是通过sql语句来实现的,于是UserMapper.xml负责sql语句的执行,UserMapper.java就负责接收查询的结果。因此就知道我们接下来要干嘛了:
打开UserMapper.java文件,里面新增代码:

String forgetgetQuestionByUsername(String username);  //这里找不到对应的实现类,所以应该去UserMapper.xml里面进行配置

然后去UserMapper.xml里面新增代码:

 <select id="forgetgetQuestionByUsername" resultType="String" parameterType="String">
     select question from store_user
     where username = #{username}
</select>

也就是说实际上我们的开发顺序与上面所说的顺序是相反的,只是为了更好的理解。接下来完成提示问题与答案这个功能。

提示问题与答案

打开UserController.java文件,写入以下代码:

   /***
     * 提示问题与答案
     * */
    @RequestMapping(value = "forget_check_answer.do",method = RequestMethod.GET)  //这里就是具体的每个方法的url链接
    @ResponseBody   //自动序列化json功能
    public ServerResponse<String> checkAnswer(String username,String question,String answer){
        return iUserService.checkAnswer(username,question,answer);
    }

接着打开IUserService.java文件:

ServerResponse<String> checkAnswer(String username,String question,String answer);   //提示问题与答案

继续打开UserServiceImpl.java文件:

    /***
     *
     *提示问题与答案时的接口类
     * */
    public ServerResponse<String> checkAnswer(String username,String question,String answer){
        int resultCount = userMapper.checkAnswer(username,question,answer);  //根据用户名来检查用户设置的问题与答案是否存在
        if(resultCount >0){
            //说明提示问题及问题答案是这个用户的,并且是正确的
            String forgetToken = UUID.randomUUID().toString();
            TockenCache.setKey("token_"+username,forgetToken);
            return ServerResponse.createBySuccess(forgetToken);
        }
        return ServerResponse.createByErrorMessage("问题的答案错误!");
    }

同样checkAnswer这个方法需要定义,打开UserMapper.java文件,里面新增代码:

  //这里找不到对应的实现类,所以应该去UserMapper.xml里面进行配置
    int checkAnswer(@Param("username")String username,@Param("question")String question,@Param("answer")String answer);   //注意mybatis传递多个参数时,需要使用param注解

然后去UserMapper.xml里面新增代码:

<select id="checkAnswer" resultType="int" parameterType="map">  <!--注意使用多个参数是是需要使用map的-->
     select count(1) from store_user
     where username = #{username}
      and question = #{question}
      and answer = #{answer}
</select>

还有因为我们这个提示问题与答案是需要写入cache的,因此我们需要在common包下面新建一个类,里面写入如下代码:

package top.store.common;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;

public class TockenCache {
    private static Logger logger = LoggerFactory.getLogger(TockenCache.class);

    //本地缓存
    //这里采用了LRU算法,初始值是1000,最大值是10000,如果超过最大值就会使用LRU算法进行消除,其实就是删除使用频率低的值,它的有效时间为12个小时
    private static LoadingCache<String,String> localCache = CacheBuilder.newBuilder().initialCapacity(1000).maximumSize(10000).expireAfterAccess(12, TimeUnit.HOURS).build(new CacheLoader<String, String>(){
        @Override
        public String load(String s) throws Exception {
            return "null";
        }
    });


    public static void setKey(String key,String value){
        localCache.put(key,value);
    }

    public static String getKey(String key){
        String value = null;
        try{
            value = localCache.get(key);
            if("null".equals(value)){
                return null;
            }
            return value;
        }catch (Exception e){
            logger.error("localCache get error",e);
        }
        return null;
    }
}

接下来便是忘记密码中的重置密码的开发了,我们知道这个必须在忘记密码实现以后才能开始。

重置密码

打开UserController.java文件,写入以下代码:

    /***
     *
     * 忘记密码中的重置密码
     */
    @RequestMapping(value = "forget_reset_password.do",method = RequestMethod.GET)  //这里就是具体的每个方法的url链接
    @ResponseBody   //自动序列化json功能
    public ServerResponse<String>  forgetResetPassword(String username,String passwordNew, String forgetToken){
        return iUserService.forgetResetPassword(username,passwordNew,forgetToken);
    }

接着打开IUserService.java文件:

ServerResponse<String>  forgetResetPassword(String username,String passwordNew, String forgetToken);  //忘记密码中的重置密码

继续打开UserServiceImpl.java文件:

/***
     *
     * 忘记密码中的重置密码的接口类
     */
    public ServerResponse<String>  forgetResetPassword(String username,String passwordNew, String forgetToken){
        //首先进行token的校验
        if(StringUtils.isBlank(forgetToken)){  //如果token是空的话
            return ServerResponse.createByErrorMessage("参数错误,token还没有被传递呢");
        }

        //这里我们需要校验username,因为forgetToken是通过token_与username进行拼接的,上面是验证了forgetToken不为空,但这并不代表username就不为空
        ServerResponse validResponse =this.checkValid(username,Const.USERNAME);
        if(validResponse.isSuccess()){  //用户名不存在
            return ServerResponse.createByErrorMessage("该用户不存在");
        }

        String token = TockenCache.getKey(TockenCache.TOKEN_PREFIX+username); //可以参看第146行代码
        //对caChe里的token进行校验
        if(StringUtils.isBlank(token)){
            return ServerResponse.createByErrorMessage("token无效或者过期");
        }

        /***
        String a = null;
        if("abc".equals(a)){}   //总是错误
        if(a.equals("abc")){}   //引发空指针异常
         */
        //这里使用.equals方法,可以避免出现Null值在前的空指针,在后总是错误的问题
        if(StringUtils.equals(forgetToken,token)){
            //修改密码成功,我们需要更新旧的密码了
            String md5Password = MD5Util.MD5EncodeUtf8(passwordNew);
            int rowCount = userMapper.updatePasswordByUsername(username,md5Password);
            if(rowCount>0){
                return ServerResponse.createBySuccessMassage("密码修改成功!");
            }

        }else{
            return ServerResponse.createByErrorMessage("token错误,请重新获取重置密码的token");
        }
        return ServerResponse.createByErrorMessage("密码修改失败!");
    }

这里面有几个注意的事项:
1、"token_"这个之前在写提示问题与答案时的接口类时,没有将其设定为一个常量,实际上它是一个常量,为了以后便于调用它,我们将其设定为一个常量:
打开TockenCache.java文件,我们新增一行代码:

public static final String TOKEN_PREFIX = "token_"; //这里把token_作为一个常量。因为需要多次使用

然后你将checkAnswer方法里面的这行代码:

ockenCache.setKey("token_"+username,forgetToken);  //这里没有把token_当做一个全局的常量进行引用

替换为:

TockenCache.setKey(TockenCache.TOKEN_PREFIX+username,forgetToken);   // 这里把token_当做一个全局的常量进行引用(在TockenCache.TOKEN_PREFIX里面)

2、StringUtils.equals(forgetToken,token)注意这里我们使用了StringUtils.equals方法,它最大的好处就是可以避免null值在前在后的问题:

 public static boolean equals(CharSequence cs1, CharSequence cs2) {
        if (cs1 == cs2) {
            return true;
        } else if (cs1 != null && cs2 != null) {
            if (cs1.length() != cs2.length()) {
                return false;
            } else {
                return cs1 instanceof String && cs2 instanceof String ? cs1.equals(cs2) : CharSequenceUtils.regionMatches(cs1, false, 0, cs2, 0, cs1.length());
            }
        } else {
            return false;
        }
    }

那么什么是null值在前在后的问题呢?很简单我举个例子你就知道了:

String a = null;
if("abc".equals(a)){}   //总是错误
if(a.equals("abc")){}   //引发空指针异常

所以这个问题我们就可以不用考虑了。
3、int rowCount = userMapper.updatePasswordByUsername(username,md5Password);这行代码中的updatePasswordByUsername方法,老规矩还是需要定义这个方法,打开UserMapper.java文件,里面新增代码:

 //这里找不到对应的实现类,所以应该去UserMapper.xml里面进行配置
 int updatePasswordByUsername(@Param("username")String username,@Param("passwordNew")String passwordNew);   //注意mybatis传递多个参数时,需要使用param注解

然后去UserMapper.xml里面新增代码:

<update id="updatePasswordByUsername"  parameterType="map">  <!--注意使用多个参数是是需要使用map的,而且这里因为是更新操作,因此需要使用update-->
        update store_user
        set password =#{passwordNew},update_time =now()
        where username = #{username}
</update>

这段代码因为是执行更新操作的,因此需要使用update,而且别忘记使用update_time =now()这个时间戳,否则你不知道具体什么时候修改了密码。

4、至于为什么我们每次判断的时候总是看它大于0或者等于0,那是因为我们使用的方法最后我们都是让它返回修改的行数(其实就是受影响的行数),如果为0就说明没有修改,否则就进行了修改,这个应该很好理解的吧。

这样,我们本篇关于用户登录获取信息,忘记密码,提示问题与答案,重置密码功能开发这四者的介绍就到此为止了,感谢你的赏阅!

相关文章

网友评论

    本文标题:SSM搭建二手市场交易平台(八):用户登录信息功能开发

    本文链接:https://www.haomeiwen.com/subject/rfewcqtx.html