美文网首页
SSM框架学习日记(3)——用户模块

SSM框架学习日记(3)——用户模块

作者: 糯米团子_大芒果 | 来源:发表于2018-07-01 00:49 被阅读0次

    用户登录

    在dao层下UserMapper里新增两个方法,检查用户名和验证登录

    int checkUsername(String username);
    User selectLogin(@Param("username") String username,@Param("password") String password);
    

    然后去mappers下UserMapper.xml里写sql的实现,查询用select标签,id是在dao层下的方法名,resultType是返回值类型,parameterType是参数类型,标签里写sql语句,传入的参数用#{...}调用

      <select id="checkUsername" resultType="int" parameterType="string">
        select count(1) from mmall_user
        where username = #{username}
      </select>
    
      <select id="selectLogin" resultMap="BaseResultMap" parameterType="map">
        select
        <include refid="Base_Column_List" />
        from mmall_user
        where username = #{username}
        and password = #{password}
      </select>
    

    在service层下新建一个UserService接口类,在子包impl包写新建UserServiceImpl实现类,加上Service注解声明这个类是service,在注入的对象上加上Autowired注解,自动注入,实现login和返回响应的内容

    @Service("iUserService")
    public class UserServiceImpl implements IUserService{
    
        @Autowired
        private UserMapper userMapper;
    
        @Override
        public ServerResponse<User> login(String username, String password) {
            int resultCount = userMapper.checkUsername(username);
            if(resultCount == 0){
                return ServerResponse.createByErrorMessage("用户名不存在");
            }
    
            //todo 密码登录md5
    
            User user = userMapper.selectLogin(username,password);
            if(user == null){
                return ServerResponse.createByErrorMessage("密码错误");
            }
            user.setPassword(StringUtils.EMPTY);
            return ServerResponse.createBySuccess("登录成功",user);
        }
    }
    

    在controller层新建UserController,Controller注解声明为Controller。登录成功把用户信息放入session,登出从session删除。

    @Controller
    @RequestMapping("/user/")
    public class UserController {
    
        @Autowired
        private IUserService iUserService;
        /**
         * 用户登录
         * @param username
         * @param password
         * @param session
         * @return
         */
        @RequestMapping(value = "login.do",method = RequestMethod.POST)
        @ResponseBody
        public ServerResponse<User> login(String username, String password, HttpSession session){
            //service->mybatis->dao
            ServerResponse<User> response = iUserService.login(username,password);
            if(response.isSuccess()){
                session.setAttribute(Const.CURRENT_USER,response.getData());
            }
            return response;
        }
    
        @RequestMapping(value = "logout.do",method = RequestMethod.GET)
        @ResponseBody
        public ServerResponse<String> logout(HttpSession session){
            session.removeAttribute(Const.CURRENT_USER);
            return ServerResponse.createBySuccess();
        }
    }
    

    实现了登录和登出

    用户注册

    在UserServiceImpl里新建一个校验用户名和email是否存在的方法,传入两个参数,用type区别传入的是用户名还是email

    isNoneBlank()和isNotEmpty()的区别
    isNoneBlank(" ")返回的是false,isNotEmpty(" ")返回的是true

    public ServerResponse<String> checkValid(String str,String type){
            if(StringUtils.isNoneBlank(type)){
                if(Const.USERNAME.equals(type)){
                    int resultCount = userMapper.checkUsername(str);
                    if(resultCount > 0){
                        return ServerResponse.createByErrorMessage("用户名已存在");
                    }
                }
                if(Const.EMAIL.equals(type)){
                    int resultCount = userMapper.checkEmail(str);
                    if(resultCount > 0){
                        return ServerResponse.createByErrorMessage("email已存在");
                    }
                }
            }else{
                return ServerResponse.createByErrorMessage("参数错误");
            }
            return ServerResponse.createBySuccessMessage("校验成功");
        }
    

    在UserMapper里配置方法名在UserMapper.xml里实现sql查询

    int checkEmail(String email);
    
    <select id="checkEmail" resultType="int" parameterType="string">
        select count(1) from mmall_user
        where email = #{email}
     </select>
    

    在写一个register方法调用验证成功后MD5进行加密后插入user到数据库

    public ServerResponse<String> register(User user){
            ServerResponse validResponse = this.checkValid(user.getUsername(),Const.USERNAME);
            if(!validResponse.isSuccess()){
                return validResponse;
            }
            validResponse = this.checkValid(user.getEmail(),Const.EMAIL);
            if(!validResponse.isSuccess()){
                return validResponse;
            }
    
            user.setRole(Const.Role.ROLE_CUSTOMER);
            //MD5加密
            user.setPassword(MD5Util.MD5EncodeUtf8(user.getPassword()));
    
            int resultCount = userMapper.insert(user);
            if(resultCount==0){
                return ServerResponse.createByErrorMessage("注册失败");
            }
            return ServerResponse.createBySuccessMessage("注册成功");
        }
    

    MD5工具类
    对外有一个共有接口MD5EncodeUtf8(),传入字符串,加上properties文件里的盐值,传给私有方法MD5Encode()然后返回

    public class MD5Util {
    
        private static String byteArrayToHexString(byte b[]) {
            StringBuffer resultSb = new StringBuffer();
            for (int i = 0; i < b.length; i++)
                resultSb.append(byteToHexString(b[i]));
    
            return resultSb.toString();
        }
    
        private static String byteToHexString(byte b) {
            int n = b;
            if (n < 0)
                n += 256;
            int d1 = n / 16;
            int d2 = n % 16;
            return hexDigits[d1] + hexDigits[d2];
        }
    
        /**
         * 返回大写MD5
         *
         * @param origin
         * @param charsetname
         * @return
         */
        private static String MD5Encode(String origin, String charsetname) {
            String resultString = null;
            try {
                resultString = new String(origin);
                MessageDigest md = MessageDigest.getInstance("MD5");
                if (charsetname == null || "".equals(charsetname))
                    resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
                else
                    resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
            } catch (Exception exception) {
            }
            return resultString.toUpperCase();
        }
        public static String MD5EncodeUtf8(String origin) {
            //origin = origin + PropertiesUtil.getProperty("password.salt", "");
            return MD5Encode(origin, "utf-8");
        }
        private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5",
                "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
    
    }
    

    在之前写的login方法里也要实现一下md5

    ....
    //todo 密码登录md5
    String md5password = MD5Util.MD5EncodeUtf8(password);
    User user = userMapper.selectLogin(username,md5password);
    if(user == null){
        return ServerResponse.createByErrorMessage("密码错误");
    }
    user.setPassword(StringUtils.EMPTY);
        return ServerResponse.createBySuccess("登录成功",user);
    ...
    

    最后在controller里调用一下service的方法,注册接口就完成啦

    ....
        @RequestMapping(value = "register.do",method = RequestMethod.GET)
        @ResponseBody
        public ServerResponse<String> register(User user){
            return iUserService.register(user);
        }
    
        @RequestMapping(value = "check_valid.do",method = RequestMethod.GET)
        @ResponseBody
        public ServerResponse<String> checkValid(String str,String type){
            return iUserService.checkValid(str,type);
        }
    }
    

    密码找回

    查找验证找回密码的问题和答案
    在UserServiceImpl类里新增一个方法

    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();
                TokenCache.setKey("token_"+username,forgetToken);
                return ServerResponse.createBySuccess(forgetToken);
            }
            return ServerResponse.createByErrorMessage("问题答案错误");
        }
    

    省略dao层的查询实现,resultCount>0时,即验证通过时,随机生成一个字符串作标识,然后用GUAVA cache把标识放进本地缓存,设置有效期等配置,新建一个TokenCache类

    public class TokenCache {
        private static Logger logger = LoggerFactory.getLogger(TokenCache.class);
    
        private static LoadingCache<String,String> localCache = CacheBuilder.newBuilder()
                .initialCapacity(1000)
                .maximumSize(10000)
                .expireAfterAccess(12, TimeUnit.HOURS)
                .build(new CacheLoader<String, String>() {
                    //默认的数据加载实现,当调用get取值的时候,如果key没有值,就调用这个方法进行加载
                    @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 ex){
                logger.error("localCache get error",ex);
            }
            return null;
    
        }
    }
    

    logger是日志输出,loadingCache是Guava里的本地缓存,.newBuilder()之后.initialCapacity(1000)
    初始化它,1000就是缓存的初始化容量,.maximumSize(10000)是最大容量,超过时使用LRU算法移除缓存项,.expireAfterAccess(12, TimeUnit.HOURS)设置了有限期,即12个小时,然后build。为了避免不必要的exception,把默认返回的null,改成字符串null(因为判断时,null.equals()会报错)

    在UserServiceImpl类里新增一个方法,判断传进来的token和cache中的是否一致,不一致不可以更改密码,一致就执行dao层的update密码,

    public ServerResponse<String> forgetResetPassword(String username,String passwordNew,String forgetToken){
            if(StringUtils.isBlank(forgetToken)){
                return ServerResponse.createByErrorMessage("参数错误,token为空");
            }
            ServerResponse validResponse = this.checkValid(username,Const.USERNAME);
            if(validResponse.isSuccess()){
                //用户不存在
                return ServerResponse.createByErrorMessage("用户不存在");
            }
    
            String token = TokenCache.getKey(TokenCache.TOKEN_PREFIX+username);
            if(StringUtils.isBlank(token)){
                return ServerResponse.createByErrorMessage("token无效");
            }
            if(StringUtils.equals(forgetToken,token)){
                String md5Password = MD5Util.MD5EncodeUtf8(passwordNew);
                int rowCount = userMapper.updatePasswordByUsername(username,md5Password);
                if(rowCount>0){
                    return ServerResponse.createBySuccessMessage("密码修改成功");
                }
            }else{
                return  ServerResponse.createByErrorMessage("token错误");
            }
            return ServerResponse.createByErrorMessage("修改密码失败");
        }
    

    然后在controller调用service层

    @RequestMapping(value = "forget_reset_password.do",method = RequestMethod.GET)
        @ResponseBody
        public ServerResponse<String> forgetResetPassword(String username,String passwordNew,String forgetToken){
            return iUserService.forgetResetPassword(username, passwordNew, forgetToken);
        }
    

    相关文章

      网友评论

          本文标题:SSM框架学习日记(3)——用户模块

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