商城项目服务端实践SSM(三)-------门户_用户接口(登录,注册,修改密码,修改个人信息等)

1、用户登录

参数:用户名username,密码password

思路:首先先校验从前端输入的用户名是否存在,如果不存在,则从后端返回一个错误信息status=1,msg=“用户名不存在”告知前端。如果校验用户名存在,则继续校验密码是否输入正确,不正确,返回一个错误信息status=1,msg=“密码错误”告知前端。否则,则登录成功,然后把用户的信息存在session中,返回用户的信息至前端。

  • controller
    @RequestMapping(value="login.do",method= RequestMethod.POST)
    @ResponseBody
    public ServerResponse login(String username, String password, HttpSession session){
        ServerResponse response=iUserService.login(username,password);
        if(response.isSuccess()){
            //把当前用户的信息加到session中
            session.setAttribute(Const.CURRENT_USER,response.getData());
        }
        return response;
    }
  • service
    //用户登录
    ServerResponse login(String username, String password);
  • serviceImp
    @Override
    public ServerResponse login(String username, String password) {
        //先检查用户名是否存在
        int resultCount=userMapper.checkUsername(username);
        if(resultCount==0){
            return ServerResponse.createByErrorMessage("用户名不存在");
        }
        //用户名存在,则判断密码是否正确,密码使用MD5加密
        String md5Password =MD5Util.MD5EncodeUtf8(password);
        User user=userMapper.selectLogin(username,md5Password);
        if(user==null){
            return ServerResponse.createByErrorMessage("密码错误");
        }
        //用户名和密码都正确,则登录成功
            user.setPassword(org.apache.commons.lang3.StringUtils.EMPTY);
            return ServerResponse.createBySuccess("登录成功",user);
    }
  • success
{
"status": 0,
"msg": "登录成功",
"data":{
"id": 22,
"username": "why",
"password": "",
"email": "[email protected]",
"phone": "15298945101",
"question": "问题",
"answer": "答案",
"role": 0,
"createTime": 1561799744000,
"updateTime": 1561910042000
    }
}
  • fail

输入密码错误

{
    "status": 1,
    "msg": "密码错误"
}

输入用户名错误 

{
"status": 1,
"msg": "用户名不存在"
}

2、用户注册

参数:User

思路:首先校验username和email是否被注册过,如果用户名被注册过,则从后端返回一个错误信息status=1,msg=“用户名已存在”告知前端。如果邮箱被注册过,则从后端返回一个status=1,msg=“邮箱已存在”告知前端。反之则注册成功。

  • controller
    //校验
    //type表示传过来的username还是email
    //str表示传过来的value值
    @RequestMapping(value = "check_valid.do",method = RequestMethod.POST)
    @ResponseBody
    public ServerResponse checkValid(String str,String type){
        return iUserService.checkValid(str,type);
    }
    //用户注册
    @RequestMapping(value = "register.do",method = RequestMethod.POST)
    @ResponseBody
    public ServerResponse register(User user){
        return iUserService.register(user);
    }
  • service
    //注册
    ServerResponse register(User user);
    //校验用户名和邮箱
    ServerResponse checkValid(String str,String type);
  • serviceImp
/*
    校验用户名和邮箱是否被注册过
    type表示传过来的是username还是email
    str表示传过来的value值
    例如:/check_valid.do?str=why&type=username
    把用户名已存在或者邮箱已存在回应至前端
    */
    public ServerResponse checkValid(String str,String type){
        //传过来的type不为空,判断type是否不为空,不为空则true
        if(org.apache.commons.lang3.StringUtils.isNotBlank(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("邮箱已存在");
                }
            }
        }else {
            return ServerResponse.createByErrorMessage("参数错误");
        }
        //否则用户名和密码不存在,说明校验成功,可以进行注册
        return ServerResponse.createBySuccessMessage("校验成功");
    }

注册的register方法调用checkValid方法校验用户名和邮箱是否已存在

 //注册
    public ServerResponse register(User user) {
        //验证用户名是否被注册
        ServerResponse vaildResponse=this.checkValid(user.getUsername(),Const.USERNAME);
        if(!vaildResponse.isSuccess()){
            return vaildResponse;
        }
        //用户名不存在,则判断验证邮箱是否被注册
        vaildResponse=this.checkValid(user.getEmail(),Const.EMAIL);
        if(!vaildResponse.isSuccess()){
            return vaildResponse;
        }
        //设置用户角色
        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("注册成功");
    }
  • success
{
"status": 0,
"msg": "注册成功"
}
  • fail
{
"status": 1,
"msg": "用户名已存在"
}
{
"status": 1,
"msg": "邮箱已存在"
}

3、获取用户的登录信息

  • controller
    //获取用户登录信息
    @RequestMapping(value = "get_user_info.do",method = RequestMethod.POST)
    @ResponseBody
    public ServerResponse getUserInfo(HttpSession session){
        //从session中获取
        User user= (User) session.getAttribute(Const.CURRENT_USER);
        if(user!=null){
            return ServerResponse.createBySuccess(user);
        }
        return ServerResponse.createByErrorMessage("用户未登录,无法获取用户登录信息");
    }
  • success
{
"status": 0,
"data":{
"id": 22,
"username": "why",
"password": "",
"email": "[email protected]",
"phone": "15298945101",
"question": "问题",
"answer": "答案",
"role": 0,
"createTime": 1561799744000,
"updateTime": 1561910042000
    }
}
  • fail
{
"status": 1,
"msg": "用户未登录,无法获取用户登录信息"
}

 

4、未登录状态下忘记密码中的重置密码

(1)忘记密码问题的获取

参数:用户名username

思路:首先校验用户名是否存在,不存在则从后端返回一个错误信息status=1,msg=“用户不存在”告知前端。反之从数据库里以username为查询条件,查找出此用户忘记密码的问题返回至前端。

  • controller
    //忘记密码问题的获取
    //localhost:8080/user/forget_get_question.do?username=why
    @RequestMapping(value = "forget_get_question.do",method = RequestMethod.POST)
    @ResponseBody
    public ServerResponse forgetGetQuestion(String username){
        return iUserService.selectQuestion(username);
    }
  • service
    //忘记密码问题的获取
    ServerResponse selectQuestion(String username);
  • serviceImp
//忘记密码问题的获取
    //localhost:8080/user/forget_get_question.do?username=why
    public ServerResponse selectQuestion(String username){
        //检验用户名是否存在,再按下一步按钮,就会出现请输入密码提示答案的框
        ServerResponse validResponse=this.checkValid(username,Const.USERNAME);
       //调用注册校验的方法,如果返回值为true,则说明用户名不存在
        if(validResponse.isSuccess()){
            return ServerResponse.createByErrorMessage("用户不存在");
        }
        String question=userMapper.selectQuestionByUsername(username);
        //问题不为空
        if(org.apache.commons.lang3.StringUtils.isNotBlank(question)){
            return ServerResponse.createBySuccess(question);
        }
        return ServerResponse.createByErrorMessage("该用户未设置找回密码问题");
    }
  • success
{
"status": 0,
"data": "问题"
}
  • fail
{
    "status": 1,
    "msg": "该用户未设置找回密码问题"
}

(2)校验忘记密码中问题答案是否正确

参数:用户名username,问题question,答案answer

思路:首先以username,question,answer作为查询条件,如果查询的结果大于0,则说明从前端传来的问题的答案是正确的。此时为了防止横向越权(横向越权指的是攻击者尝试访问与他拥有相同权限的用户的资源 ),答案正确则生成一个随机的且唯一的UUID且返回至前端,以该用户名和此UUID作为一对键值对存入guava构建的本地缓存中(key为用户名,value为UUID),并且UUID存在缓存中有时间限制,超过设置的规定时间,则UUID过期变为无效。在设置新密码的时候根据此用户名取出对应的UUID。

  • guava方法
public class TokenCache {
    //声明日志
    private static Logger logger= LoggerFactory.getLogger(TokenCache.class);

    public static final String TOKEN_PREFIX="token_";

    //guava缓存
    //声明静态的内存块
    //initialCapacity为缓存的初始化容量
    // maximumSize缓存的最大容量,当超过这个容量,guava的cache就会使用LRU算法
    //缓存的有效期为12个小时
    private static LoadingCache localCache= CacheBuilder.newBuilder().initialCapacity(1000).maximumSize(10000).expireAfterAccess(12, TimeUnit.HOURS).build(new CacheLoader() {
        @Override
        //默认的数据加载实现,当调用get取值的时候,如果key没有对应的值,就调用这个方法进行加载
        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;
    }
}
  • controller
    //提交问题的答案,校验问题答案是否正确
    //localhost:8080/user/forget_check_answer.do?username=why&question=问题&answer=答案
    @RequestMapping(value = "forget_check_answer.do",method = RequestMethod.POST)
    @ResponseBody
    public  ServerResponse forgetCheckAnswer(String username,String question,String answer){
        return iUserService.checkAnswer(username,question,answer);
    }
  • service
    //校验忘记密码问题的答案是否正确
    ServerResponse checkAnswer(String username,String question,String answer);
  • serviceImp
    //利用guava缓存
    //忘记密码中重置密码的校验问题的答案是否正确
    //localhost:8080/user/forget_check_answer.do?username=why&question=答案&answer=问题
    public ServerResponse checkAnswer(String username,String question,String answer){
        int resultCount=userMapper.checkAnswer(username,question,answer);
        if(resultCount>0){

            //回答正确,则生成唯一的UUID,防止横向越权和纵向越权        
            String forgetToken= UUID.randomUUID().toString();

            //把forgetToken放到本地cache中
            //把UUID返回前端
            TokenCache.setKey(TokenCache.TOKEN_PREFIX+username,forgetToken);
            return ServerResponse.createBySuccess(forgetToken);
        }
        return ServerResponse.createByErrorMessage("问题答案错误");
    }
  • success
{
"status": 0,
"data": "27df4461-5dc3-412c-b16b-39669cf4eb6d"
}
  • fail
{
"status": 1,
"msg": "问题答案错误"
}

(3)忘记密码中设置新的密码

参数:用户名username,新密码passwordNew,UUID

思路:首先判断从前端传来的UUID是否为空,为空则从后端返回一个错误信息status=1,msg=“参数错误,token需要传递”告知前端。再判断用户名是否存在。然后根据传过来的username从缓存中取出此username的UUID,然后判断此UUID是否为空,如果为空则说明此UUID超过设置的规定时间,则被清空。如果从缓存中取出的UUID没有超过有效期,则判断此UUID与从前端传来的UUID是否一致,一致则在数据库中设置新密码,反之设置密码失败。

  • controller
    //忘记密码中的重置密码
    //localhost:8080/user/forget_reset_password.do?username=why&passwordNew=xxx&forgetToken=27df4461-5dc3-412c-b16b-39669cf4eb6d
    @RequestMapping(value = "forget_reset_password.do",method = RequestMethod.POST)
    @ResponseBody
    public ServerResponse forgetResetPassword(String username,String passwordNew,String forgetToken){
        return iUserService.forgetRestPassword(username, passwordNew, forgetToken);
    }
  • service
    //忘记密码中的重置密码
    ServerResponse forgetRestPassword(String username,String passwordNew,String forgetToken);
  • serviceImp
//忘记密码中的重置密码
    //localhost:8080/user/forget_reset_password.do?username=why&passwordNew=xxx&forgetToken=27df4461-5dc3-412c-b16b-39669cf4eb6d
    public ServerResponse forgetRestPassword(String username,String passwordNew,String forgetToken){
        //判断forgetToken是否为空,如果为空,则参数错误
        if(org.apache.commons.lang3.StringUtils.isBlank(forgetToken)){
            return ServerResponse.createByErrorMessage("参数错误,token需要传递");
        }
        ServerResponse validResponse=this.checkValid(username,Const.USERNAME);
        //调用注册校验的方法,如果返回值为true,则说明用户名不存在
        if(validResponse.isSuccess()){
            return ServerResponse.createByErrorMessage("用户不存在");
        }
        //如果用户名存在,则从缓存中取出该用户名回答问题中存的UUID
        String token=TokenCache.getKey(TokenCache.TOKEN_PREFIX+username);
        //对token进行校验,如果超过缓存规定的存放时间,则token则被清空
        if(org.apache.commons.lang3.StringUtils.isBlank(token)){
            return ServerResponse.createByErrorMessage("token过期或者无效");
        }
        if (org.apache.commons.lang3.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错误,请重新获取重置密码的token");
            }
        }
        return ServerResponse.createByErrorMessage("密码修改失败");
    }
  • success
{
    "status": 0,
    "msg": "密码修改成功"
}
  • fail
{
    "status": 1,
    "msg": "密码修改失败"
}

或者 

{
    "status": 1,
    "msg": "token过期或者无效"
}

或者 此用户的UUID(token)没失效,但是从前端传来的token与缓存中取出来的不匹配

{
"status": 1,
"msg": "token错误,请重新获取重置密码的token"
}

5、登录状态下的重置密码

参数:User,旧密码passwordOld,新密码passwordNew

思路:首先先校验是否为登录状态下,如果为登录状态下,则为了防止横向越权,则需要输入旧的密码,旧的密码正确,就设置新的密码。

  • controller
    //登录状态下的重置密码
    @RequestMapping(value = "reset_password.do",method = RequestMethod.POST)
    @ResponseBody
    public ServerResponse resetPassword(HttpSession session,String passwordOld,String passwordNew){
        User user= (User) session.getAttribute(Const.CURRENT_USER);
        if (user==null){
            return ServerResponse.createByErrorMessage("用户未登录");
        }
        return iUserService.resetPassword(passwordOld,passwordNew,user);
    }
  • service
    //登录状态下的重置密码
    ServerResponse resetPassword(String passwordOld,String passwordNew,User user);
  • serviceImp
    //登录状态下的重置密码,输入旧密码,新密码,再次确认新密码
    public ServerResponse resetPassword(String passwordOld,String passwordNew,User user){
        //防止横向越权,要校验一下这个用户的旧密码是否正确
        int resultCount=userMapper.checkPassword(MD5Util.MD5EncodeUtf8(passwordOld),user.getId());
        if (resultCount==0){
            return ServerResponse.createByErrorMessage("旧密码错误");
        }
        user.setPassword(MD5Util.MD5EncodeUtf8(passwordNew));
        int updateCount=userMapper.updateByPrimaryKeySelective(user);
        if (updateCount>0){
            return ServerResponse.createBySuccessMessage("密码更新成功");
        }
        return ServerResponse.createByErrorMessage("密码更新失败");
    }
  • success
{
    "status": 0,
    "msg": "密码更新成功"
}
  • fail
{
    "status": 1,
    "msg": "旧密码错误"
}

6、获取个人信息

参数:userId

思路:判断用户是否登录,如果登录了,就以该用户的id为查询条件,查询出该用户的个人信息并返回至前端。

  • controller
    //获取用户的详细信息,前台上展示用户的个人信息以便用户修改
    @RequestMapping(value = "get_information.do",method = RequestMethod.POST)
    @ResponseBody
    public ServerResponse get_information(HttpSession session){
        User currentUser= (User) session.getAttribute(Const.CURRENT_USER);
        if(currentUser==null){
            return ServerResponse.createByErrorCodeMessage(ResponseCode.NEED_LOGIN.getCode(),"用户未登录,无法获取当前用户信息,status=10,强制登录");
        }
        return iUserService.getInformation(currentUser.getId());
    }
  • service
    //获取用户个人信息
    ServerResponse getInformation(Integer userId);
  • serviceImp
    //获取用户个人信息
    public ServerResponse getInformation(Integer userId){
        User user=userMapper.selectByPrimaryKey(userId);
        if(user==null){
            return ServerResponse.createByErrorMessage("找不到当前用户");
        }
        user.setPassword(org.apache.commons.lang3.StringUtils.EMPTY);
        return ServerResponse.createBySuccess(user);
    }
  • success
{
"status": 0,
"data":{
"id": 22,
"username": "why",
"password": "",
"email": "[email protected]",
"phone": "15298945101",
"question": "问题",
"answer": "答案",
"role": 0,
"createTime": 1561799744000,
"updateTime": 1561910042000
    }
}
  • fail
{
    "status": 10,
    "msg": "用户未登录,无法获取当前用户信息,status=10,强制登录"
}

7、修改个人信息

参数:User

思路:判断用户是否登录,用户名不能被更改,修改邮箱要判断邮箱是否被注册过,修改成功则要更新session里的数据。

  • controller
   //更新个人用户信息
    @RequestMapping(value = "update_information.do",method = RequestMethod.POST)
    @ResponseBody
    public ServerResponse update_information(HttpSession session,User user){
        //判断是否为登录状态
        User currentUser= (User) session.getAttribute(Const.CURRENT_USER);
        if(currentUser==null){
            return ServerResponse.createByErrorMessage("用户未登录");
        }
        user.setId(currentUser.getId());
        user.setUsername(currentUser.getUsername());
        ServerResponse response= iUserService.updateInformation(user);
        if (response.isSuccess()){
            //如果更新成功,则重新更改session中的个人信息
            session.setAttribute(Const.CURRENT_USER,response.getData());
        }
        return response;
    }
  • service
    //更新个人用户信息
    ServerResponse updateInformation(User user);
  • serviceImp
    //修改个人信息
    public ServerResponse updateInformation(User user){
        //username是不能被更新的
        //email也要被校验,检验新的email是否已经存在
        int resultCount=userMapper.checkEmailByUserId(user.getEmail(),user.getId());
        if(resultCount>0){
            return ServerResponse.createByErrorMessage("email已经存在,请更换email再尝试更新");
        }
        User updateUser=new User();
        updateUser.setId(user.getId());
        updateUser.setUsername(user.getUsername());
        updateUser.setEmail(user.getEmail());
        updateUser.setPhone(user.getPhone());
        updateUser.setQuestion(user.getQuestion());
        updateUser.setAnswer(user.getAnswer());

        int updateCount=userMapper.updateByPrimaryKeySelective(updateUser);
        if (updateCount>0){
            return ServerResponse.createBySuccess("更新个人信息成功",updateUser);
        }
        return ServerResponse.createByErrorMessage("更新个人信息失败");
    }
  • success
{
    "status": 0,
    "msg": "更新个人信息成功"
}
  • fail
{
    "status": 1,
    "msg": "更新个人信息失败"
}

8、退出登录

  • controller
    //退出登录
    @RequestMapping(value="logout.do",method = RequestMethod.POST)
    @ResponseBody
    public ServerResponse logout(HttpSession session){
        //把当前用户的信息移出session
        session.removeAttribute(Const.CURRENT_USER);
        return ServerResponse.createBySuccessMessage("退出登录成功");
    }
  • success
{
"status": 0,
"msg": "退出登录成功"
}

Mapper.java

public interface UserMapper {
    int deleteByPrimaryKey(Integer id);

    int insert(User record);

    int insertSelective(User record);

    User selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(User record);

    int updateByPrimaryKey(User record);

    //检测用户名是否存在
    int checkUsername(String username);

    //验证登录,登录成功则返回用户的信息
    //将请求中参数username的值赋值给变量username
    User selectLogin(@Param("username") String username,@Param("password") String password);

    //检查邮箱是否被注册
    int checkEmail(String email);

    //忘记密码问题的获取
    String selectQuestionByUsername(String uername);

    //校验忘记密码问题的答案
    int checkAnswer(@Param("username") String username,@Param("question") String question,@Param("answer")String answer);

    //忘记密码中的重置密码
    int updatePasswordByUsername(@Param("username") String username,@Param("passwordNew") String passwordNew);

    //登录状态下的重置密码
    int checkPassword(@Param("password") String password,@Param("userId") Integer userId);

    //根据ID查询email是否被使用注册
    int checkEmailByUserId(@Param("email")String eamil,@Param("userId")Integer userId);
}

Mapper.xml




  
    
      
      
      
      
      
      
      
      
      
      
    
  
  
    id, username, password, email, phone, question, answer, role, create_time, update_time
  
  
  
    delete from mmall_user
    where id = #{id,jdbcType=INTEGER}
  
  
    insert into mmall_user (id, username, password, 
      email, phone, question, 
      answer, role, create_time, 
      update_time)
    values (#{id,jdbcType=INTEGER}, #{username,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR}, 
      #{email,jdbcType=VARCHAR}, #{phone,jdbcType=VARCHAR}, #{question,jdbcType=VARCHAR}, 
      #{answer,jdbcType=VARCHAR}, #{role,jdbcType=INTEGER}, now(),
     now())
  
  
    insert into mmall_user
    
      
        id,
      
      
        username,
      
      
        password,
      
      
        email,
      
      
        phone,
      
      
        question,
      
      
        answer,
      
      
        role,
      
      
        create_time,
      
      
        update_time,
      
    
    
      
        #{id,jdbcType=INTEGER},
      
      
        #{username,jdbcType=VARCHAR},
      
      
        #{password,jdbcType=VARCHAR},
      
      
        #{email,jdbcType=VARCHAR},
      
      
        #{phone,jdbcType=VARCHAR},
      
      
        #{question,jdbcType=VARCHAR},
      
      
        #{answer,jdbcType=VARCHAR},
      
      
        #{role,jdbcType=INTEGER},
      
      
        now(),
      
      
        now(),
      
    
  
  
    update mmall_user
    
      
        username = #{username,jdbcType=VARCHAR},
      
      
        password = #{password,jdbcType=VARCHAR},
      
      
        email = #{email,jdbcType=VARCHAR},
      
      
        phone = #{phone,jdbcType=VARCHAR},
      
      
        question = #{question,jdbcType=VARCHAR},
      
      
        answer = #{answer,jdbcType=VARCHAR},
      
      
        role = #{role,jdbcType=INTEGER},
      
      
        create_time = #{createTime,jdbcType=TIMESTAMP},
      
      
        update_time =now(),
      
    
    where id = #{id,jdbcType=INTEGER}
  
  
    update mmall_user
    set username = #{username,jdbcType=VARCHAR},
      password = #{password,jdbcType=VARCHAR},
      email = #{email,jdbcType=VARCHAR},
      phone = #{phone,jdbcType=VARCHAR},
      question = #{question,jdbcType=VARCHAR},
      answer = #{answer,jdbcType=VARCHAR},
      role = #{role,jdbcType=INTEGER},
      create_time = #{createTime,jdbcType=TIMESTAMP},
      update_time = now()
    where id = #{id,jdbcType=INTEGER}
  

  

  

  

  

  

  
    update mmall_user
    set password=#{passwordNew},update_time=now()
    where username=#{username}
  

  

  

 

你可能感兴趣的:(商城项目实践)