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

用户登录

在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语句,传入的参数用#{...}调用

  

  

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

@Service("iUserService")
public class UserServiceImpl implements IUserService{

    @Autowired
    private UserMapper userMapper;

    @Override
    public ServerResponse 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 login(String username, String password, HttpSession session){
        //service->mybatis->dao
        ServerResponse 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 logout(HttpSession session){
        session.removeAttribute(Const.CURRENT_USER);
        return ServerResponse.createBySuccess();
    }
}

实现了登录和登出

用户注册

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

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

public ServerResponse 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);

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

public ServerResponse 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 register(User user){
        return iUserService.register(user);
    }

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

密码找回

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

public ServerResponse 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 localCache = CacheBuilder.newBuilder()
            .initialCapacity(1000)
            .maximumSize(10000)
            .expireAfterAccess(12, TimeUnit.HOURS)
            .build(new CacheLoader() {
                //默认的数据加载实现,当调用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 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 forgetResetPassword(String username,String passwordNew,String forgetToken){
        return iUserService.forgetResetPassword(username, passwordNew, forgetToken);
    }

你可能感兴趣的:(SSM框架学习日记(3)——用户模块)