Java电商项目面试--用户模块

拼搏现实的明天。 2021-09-27 08:20 677阅读 0赞

面试:用户模块技术要点:
1、横向越权和纵向越权
2、MD5明文加密、guava缓存
3、高复用服务响应对象的设计思想和封装

一、用户模块功能
用户模块包含功能如下:
1、登录功能
2、用户名校验
3、注册功能
4、忘记密码
5、提交问题答案
6、重置密码
7、获取用户信息
8、更新用户信息
9、退出登录
二、高复用服务响应对象的设计思想和封装
在web开发中,现在比较流行的是从控制层往前台返回json格式的数据,而若每次的返回都设计一个类的话,不方便使用的同时也会显得很臃肿。因此可以利用泛型的设计思想设计一个高可用复用的对象,来统一返回的json格式的数据。
代码如下:

  1. //保证序列化json的时候,如果是null的对象,key也会消失
  2. /* 这里加这个的原因是: 当登陆失败的话返回的是{ status : 1 msg : 密码错误 而data是一个有key的空节点,即value = null } 这样的话data将不会出现在json之中了。 补充: 将该标记放在属性上,如果该属性为NULL则不参与序列化 如果放在类上边,那对这个类的全部属性起作用 Include.Include.ALWAYS 默认 Include.NON_DEFAULT 属性为默认值不序列化 Include.NON_EMPTY 属性为 空(“”) 或者为 NULL 都不序列化 Include.NON_NULL 属性为NULL 不序列化 。 */
  3. @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
  4. public class ServerResponse<T> implements Serializable {
  5. private int status; //状态
  6. private String msg; //信息
  7. private T data; //数据
  8. //定义4个构造方法
  9. //1
  10. private ServerResponse(int status) {
  11. this.status = status;
  12. }
  13. //2
  14. private ServerResponse(int status,T data){
  15. this.status = status;
  16. this.data = data;
  17. }
  18. //3
  19. private ServerResponse(int status,String msg,T data){
  20. this.status = status;
  21. this.msg = msg;
  22. this.data = data;
  23. }
  24. //4
  25. private ServerResponse(int status,String msg){
  26. this.status = status;
  27. this.msg = msg;
  28. }
  29. @JsonIgnore
  30. //使之不在json序列化结果当中
  31. //即json里面不会出现这个
  32. public boolean isSuccess(){
  33. //如果status == 0 则返回true
  34. //SUCCESS的枚举值为0
  35. return this.status == ResponseCode.SUCCESS.getCode();
  36. }
  37. //返回状态
  38. public int getStatus(){
  39. return status;
  40. }
  41. public T getData(){
  42. return data;
  43. }
  44. public String getMsg(){
  45. return msg;
  46. }
  47. //调用status构造器
  48. public static <T> ServerResponse<T> createBySuccess(){
  49. return new ServerResponse<T>(ResponseCode.SUCCESS.getCode());
  50. }
  51. //调用4号构造器
  52. public static <T> ServerResponse<T> createBySuccessMessage(String msg){
  53. return new ServerResponse<T>(ResponseCode.SUCCESS.getCode(),msg);
  54. }
  55. public static <T> ServerResponse<T> createBySuccess(T data){
  56. return new ServerResponse<T>(ResponseCode.SUCCESS.getCode(),data);
  57. }
  58. public static <T> ServerResponse<T> createBySuccess(String msg,T data){
  59. return new ServerResponse<T>(ResponseCode.SUCCESS.getCode(),msg,data);
  60. }
  61. public static <T> ServerResponse<T> createByError(){
  62. return new ServerResponse<T>(ResponseCode.ERROR.getCode(),ResponseCode.ERROR.getDesc());
  63. }
  64. public static <T> ServerResponse<T> createByErrorMessage(String errorMessage){
  65. return new ServerResponse<T>(ResponseCode.ERROR.getCode(),errorMessage);
  66. }
  67. public static <T> ServerResponse<T> createByErrorCodeMessage(int errorCode,String errorMessage){
  68. return new ServerResponse<T>(errorCode,errorMessage);
  69. }
  70. }

响应对象主要包括状态、信息和数据
状态是利用枚举来实现的:

  1. public enum ResponseCode {
  2. SUCCESS(0,"SUCCESS"),
  3. ERROR(1,"ERROR"),
  4. NEED_LOGIN(10,"NEED_LOGIN"),
  5. ILLEGAL_ARGUMENT(2,"ILLEGAL_ARGUMENT");
  6. //成员变量(常量)
  7. private final int code;
  8. private final String desc;
  9. //构造方法
  10. ResponseCode(int code,String desc){
  11. this.code = code;
  12. this.desc = desc;
  13. }
  14. //普通函数
  15. public int getCode(){
  16. return code;
  17. }
  18. public String getDesc(){
  19. return desc;
  20. }
  21. public static void main(String args[]){
  22. System.out.println(ResponseCode.SUCCESS.getDesc());
  23. System.out.println(ResponseCode.SUCCESS.getCode());
  24. }
  25. }

二、登录功能
1、用户名是否存在
2、如果存在则将密码转换为MD5加密形式
3、校验用户名和密码是否正确
4、正确则将用户放入到Session中
具体实现:
Controller层:

  1. @Controller //WEB层(用于标注类本身的用途)
  2. @RequestMapping("/user/") //将请求地址的前面加上/user
  3. public class UserController {
  4. //按类型进行注入
  5. //将iUserService注入进来
  6. @Autowired
  7. private IUserService iUserService;
  8. //登陆功能
  9. //访问地址为login.do 访问方式为POST
  10. @RequestMapping(value = "login.do",method = RequestMethod.POST)
  11. @ResponseBody //自动通过SpingMvc的json插件将返回值转换成json
  12. public ServerResponse<User> login(String username, String password, HttpSession session) {
  13. ServerResponse<User> response = iUserService.login(username, password);
  14. if (response.isSuccess()) //如果登陆成功,将用户放入到Session中
  15. session.setAttribute(Const.CURRENT_USER, response.getData());
  16. return response; //将响应信息返回到前端
  17. }
  18. }

Service层:

  1. //Service表示业务层
  2. //创建iUserService对象,放入到容器中
  3. @Service("iUserService")
  4. public class UserServiceImpl implements IUserService {
  5. @Autowired //注入userMapper
  6. private UserMapper userMapper;
  7. @Override
  8. public ServerResponse<User> login(String username, String password) {
  9. int resultCount = userMapper.checkUsername(username); //先查询用户名,看用户名是否存在
  10. if (resultCount == 0) //如果查不到的话,用户不存在
  11. return ServerResponse.createByErrorMessage("用户名不存在");
  12. String md5Password = MD5Util.MD5EncodeUtf8(password); //将密码转化为MD5
  13. User user = userMapper.selectLogin(username, md5Password); //通过用户名和密码进行查询
  14. if (user == null)
  15. return ServerResponse.createByErrorMessage("密码错误");
  16. //将密码设置为空
  17. user.setPassword(org.apache.commons.lang3.StringUtils.EMPTY);
  18. return ServerResponse.createBySuccess("登录成功", user);
  19. }
  20. }

UserMapper:

  1. public interface UserMapper {
  2. int checkUsername(String username); //查询用户名,看此用户名是否存在
  3. //@Param为传入的参数起名字,这样在Dao层可以获得数据
  4. User selectLogin(@Param("username") String username, @Param("password")String password);
  5. }
  6. <select id="checkUsername" resultType="int" parameterType="string" >
  7. select count(1) from mmall_user where username = #{username}
  8. </select>
  9. <select id="selectLogin" resultMap="BaseResultMap" parameterType="map">
  10. SELECT
  11. <include refid="Base_Column_List" /> <!--只需要查询我们需要的字段-->
  12. from mmall_user
  13. where username = #{username}
  14. and password = #{password}
  15. </select>

三、注册功能
1、用户名是否存在
2、校验邮箱是否存在
3、将密码转化为MD5形式
4、将用户放入数据库中
具体实现:
Controller层:

  1. //注册功能
  2. @RequestMapping(value = "register.do",method = RequestMethod.POST)
  3. @ResponseBody
  4. public ServerResponse<String> register(User user){
  5. return iUserService.register(user);
  6. }
  7. //校验功能
  8. @RequestMapping(value = "check_valid.do",method = RequestMethod.POST)
  9. @ResponseBody
  10. public ServerResponse<String> checkValid(String str,String type){
  11. return iUserService.checkValid(str,type);
  12. }

Service层:

  1. //注册
  2. @Service("iUserService")
  3. public class UserServiceImpl implements IUserService {
  4. public ServerResponse<String> register(User user) {
  5. @Autowired //注入userMapper
  6. private UserMapper userMapper;
  7. ServerResponse<String> vaildResponse =
  8. this.checkValid(user.getUsername(),Const.USERNAME);
  9. if(!vaildResponse.isSuccess()) //校验用户名
  10. return vaildResponse;
  11. vaildResponse = this.checkValid(user.getEmail(),Const.EMAIL);
  12. if(!vaildResponse.isSuccess()) //校验邮箱
  13. return vaildResponse;
  14. user.setRole(Const.Role.ROLE_CUSTOMER); //设置用户角色
  15. user.setPassword(MD5Util.MD5EncodeUtf8(user.getPassword())); //MD5加密
  16. int resultCount = userMapper.insert(user); //插入用户
  17. if (resultCount == 0)
  18. return ServerResponse.createByErrorMessage("注册失败");
  19. return ServerResponse.createBySuccessMessage("注册成功");
  20. }
  21. }

校验:

  1. //校验
  2. public ServerResponse<String> checkValid(String str,String type){
  3. if(org.apache.commons.lang3.StringUtils.isNotBlank(type)){ //type不是空,才开始校验
  4. if(Const.USERNAME.equals(type)){ //判断用户名
  5. int resultCount = userMapper.checkUsername(str);
  6. if(resultCount > 0 )
  7. return ServerResponse.createByErrorMessage("用户名已存在");
  8. }
  9. if(Const.EMAIL.equals(type)){ //判断email
  10. int resultCount = userMapper.checkEmail(str);
  11. if(resultCount > 0 )
  12. return ServerResponse.createByErrorMessage("email已存在");
  13. }
  14. }else{
  15. return ServerResponse.createByErrorMessage("参数错误");
  16. }
  17. return ServerResponse.createBySuccessMessage("校验成功");
  18. }

UserMapper:

  1. public interface UserMapper {
  2. int checkEmail(String email); //查询邮箱,看此邮箱是否存在
  3. int insert(User record);
  4. }
  5. <insert id="insert" parameterType="com.mmall.pojo.User" >
  6. insert into mmall_user (id, username, password,
  7. email, phone, question,
  8. answer, role, create_time,
  9. update_time)
  10. values (#{
  11. id,jdbcType=INTEGER}, #{
  12. username,jdbcType=VARCHAR}, #{
  13. password,jdbcType=VARCHAR},
  14. #{
  15. email,jdbcType=VARCHAR}, #{
  16. phone,jdbcType=VARCHAR}, #{
  17. question,jdbcType=VARCHAR},
  18. #{
  19. answer,jdbcType=VARCHAR}, #{
  20. role,jdbcType=INTEGER}, now(),
  21. now())
  22. </insert>

四、忘记密码重置密码功能
1、用户名是否存在
2、根据用户名查询问题
3、答案正确则生成token
4、将token存入到guava cache本地缓存中,有效期为12小时(防止横向越权)
5、校验用户名是否存在
6、校验token是否正确
7、正确则重新设置密码
具体实现:
Controller层:

  1. //忘记密码的时候根据用户名查询问题
  2. @RequestMapping(value = "forget_get_question.do",method = RequestMethod.POST)
  3. @ResponseBody
  4. public ServerResponse<String> forgetGetQuestion(String username){
  5. return iUserService.selectQuestion(username); //返回提示问题
  6. }
  7. //检查用户回答的答案是否正确
  8. @RequestMapping(value = "forget_check_answer.do",method = RequestMethod.POST)
  9. @ResponseBody
  10. public ServerResponse<String> forgetCheckAnswer(String username,String question,String answer){
  11. return iUserService.checkAnswer(username,question,answer);
  12. }
  13. //忘记密码中的重置密码
  14. @RequestMapping(value = "forget_reset_password.do",method = RequestMethod.POST)
  15. @ResponseBody
  16. public ServerResponse<String> forgetRestPassword(String username,String passwordNew,String forgetToken){
  17. return iUserService.forgetResetPassword(username,passwordNew,forgetToken);
  18. }

Service层:

  1. //忘记密码,查询问题
  2. public ServerResponse selectQuestion(String username){
  3. ServerResponse validResponse = this.checkValid(username,Const.USERNAME); //先看下用户是否存在
  4. if(validResponse.isSuccess())
  5. return ServerResponse.createByErrorMessage("用户不存在");
  6. String question = userMapper.selectQuestionByUsername(username); //存在的话根据用户名查询问题
  7. if(org.apache.commons.lang3.StringUtils.isNotBlank(question)) //当问题不为空的时候返回
  8. return ServerResponse.createBySuccess(question);
  9. return ServerResponse.createByErrorMessage("找回密码的问题是空的");
  10. }
  11. //检查用户回答的答案是否正确
  12. public ServerResponse<String> checkAnswer(String username,String question,String answer){
  13. int resultCount = userMapper.checkAnswer(username,question,answer);
  14. if(resultCount > 0){ //说明问题及问题答案是这个用户的,并且是正确的
  15. String forgetToken = UUID.randomUUID().toString(); //声明一个token
  16. TokenCache.setKey(TokenCache.TOKEN_PREFIX + username,forgetToken);
  17. return ServerResponse.createBySuccess(forgetToken);
  18. }
  19. return ServerResponse.createByErrorMessage("问题的答案错误");
  20. }
  21. //忘记密码中的重置密码
  22. public ServerResponse<String> forgetResetPassword(String username,String passwordNew,String forgetToken) {
  23. if (org.apache.commons.lang3.StringUtils.isBlank(forgetToken)) //先判断是否携带了token
  24. return ServerResponse.createByErrorMessage("参数错误,token需要传递");
  25. ServerResponse validResponse = this.checkValid(username, Const.USERNAME);
  26. if (validResponse.isSuccess()) //校验一下用户名
  27. return ServerResponse.createByErrorMessage("用户不存在");
  28. String token = TokenCache.getKey(TokenCache.TOKEN_PREFIX + username); //从缓存中获取用户的token
  29. if (org.apache.commons.lang3.StringUtils.isBlank(token)) //获取到看token是否为空
  30. return ServerResponse.createByErrorMessage("token无效或者过期");
  31. if (org.apache.commons.lang3.StringUtils.equals(forgetToken, token)) { //比较token是否相等
  32. String md5Password = MD5Util.MD5EncodeUtf8(passwordNew);
  33. int rowCount = userMapper.updatePasswordByUsername(username, md5Password); //更新密码
  34. if (rowCount > 0) //如果个数大于1,则更新密码成功
  35. return ServerResponse.createBySuccessMessage("修改密码成功");
  36. }else {
  37. return ServerResponse.createByErrorMessage("token错误,请重新获取重置密码的token");
  38. }
  39. return ServerResponse.createByErrorMessage("修改密码失败");
  40. }

五、登录状态下重置密码功能
1、从session中取出用户
2、校验旧密码是否正确(防止横向越权)
3、正确则修改密码
具体实现:
Controller层:

  1. //登陆状态下的重置密码
  2. @RequestMapping(value = "reset_password.do",method = RequestMethod.POST)
  3. @ResponseBody
  4. public ServerResponse<String> resetPassword(HttpSession session,String passwordOld,String passwordNew){
  5. User user = (User)session.getAttribute(Const.CURRENT_USER);
  6. if(user == null)
  7. return ServerResponse.createByErrorMessage("用户未登录");
  8. return iUserService.resetPassword(passwordOld,passwordNew,user); //重置密码
  9. }

Service层:

  1. //登陆状态下的重置密码
  2. public ServerResponse<String> resetPassword(String passwordOld, String passwordNew,User user) {
  3. //防止横向越权,要校验一下这个用户的旧密码,一定要指定是这个用户.因为我们会查询一个count(1),如果不指定id,那么结果就是true啦count>0;
  4. int resultCount = userMapper.checkPassword(MD5Util.MD5EncodeUtf8(passwordOld),user.getId());
  5. if(resultCount == 0)
  6. return ServerResponse.createByErrorMessage("旧密码错误");
  7. user.setPassword(MD5Util.MD5EncodeUtf8(passwordNew));
  8. int updateCount = userMapper.updateByPrimaryKeySelective(user); //选择性的更新,没变化的就不动,变化了的就更新
  9. if(updateCount > 0) //更新成功
  10. return ServerResponse.createBySuccessMessage("密码更新成功");
  11. return ServerResponse.createByErrorMessage("密码更新失败");
  12. }

六、更新用户信息
1、判断用户是否登录
2、取出用户的id和username
3、判断邮箱是否重复
3、不重复则更新用户信息并将其放入到session中
具体实现:
Controller层:

  1. //更新用户信息
  2. @RequestMapping(value = "update_information.do",method = RequestMethod.POST)
  3. @ResponseBody
  4. public ServerResponse<User> update_information(HttpSession session,User user){
  5. User currentUser = (User)session.getAttribute(Const.CURRENT_USER); //取出当前用户
  6. if(currentUser == null)
  7. return ServerResponse.createByErrorMessage("用户未登录");
  8. user.setId(currentUser.getId());
  9. user.setUsername(currentUser.getUsername()); //取出id和username
  10. ServerResponse<User> response = iUserService.updateInformation(user);
  11. if(response.isSuccess()){ //如果更新成功
  12. response.getData().setUsername(currentUser.getUsername());
  13. session.setAttribute(Const.CURRENT_USER,response.getData()); //将其放入到session中
  14. }
  15. return response;
  16. }

Service层:

  1. //更新用户信息,更新完用户信息之后,将其放入到session中
  2. public ServerResponse<User> updateInformation(User user){
  3. //username是不能被更新的
  4. //email也要进行一个校验,校验新的email是不是已经存在,并且存在的email如果相同的话,不能是我们当前的这个用户的.
  5. int resultCount = userMapper.checkEmailByUserId(user.getEmail(),user.getId());
  6. if(resultCount > 0)
  7. return ServerResponse.createByErrorMessage("email已存在,请更换email再尝试更新");
  8. User updateUser = new User();
  9. updateUser.setId(user.getId());
  10. updateUser.setEmail(user.getEmail());
  11. updateUser.setPhone(user.getPhone());
  12. updateUser.setQuestion(user.getQuestion());
  13. updateUser.setAnswer(user.getAnswer());
  14. int updateCount = userMapper.updateByPrimaryKeySelective(updateUser);
  15. if(updateCount > 0)
  16. return ServerResponse.createBySuccess("更新个人信息成功",updateUser);
  17. return ServerResponse.createByErrorMessage("更新个人信息失败");
  18. }

七、获取用户信息和退出登录
获取用户信息:
1、判断用户是否登录
2、登录则将用户信息取出来
退出登录:
1、将用户从session中移除
八、项目要点分析
Java电商项目面试–横向越权和纵向越权
Java电商项目面试–Token
Java电商项目面试–缓存(Guava Cache)
Java面试–String和byte[]之间的转化(MD5加密)


Java面试的完整博客目录如下:Java笔试面试目录

转载请标明出处,原文地址:https://blog.csdn.net/weixin_41835916 如果觉得本文对您有帮助,请点击顶支持一下,您的支持是我写作最大的动力,谢谢。
这里写图片描述

发表评论

表情:
评论列表 (有 0 条评论,677人围观)

还没有评论,来说两句吧...

相关阅读