秒杀系统(二)--完成登录功能

1. 数据库设计
创建miaosha_user表:
CREATE TABLE `miaosha_user` (
    `id` bigint(20) NOT NULL COMMENT '用户id,手机号码',
    `nickname` varchar(255) NOT NULL COMMENT '用户名',
    `password` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '密码',
    `salt` varchar(10) DEFAULT NULL,
    `head` varchar(128) DEFAULT NULL COMMENT '头像,云存储得id',
    `register_date` datetime DEFAULT NULL COMMENT '注册时间',
    `last_login_date` datetime DEFAULT NULL COMMENT '上次登录时间',
    `login_count` int(11) DEFAULT NULL COMMENT '登录次数',
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2. 创建miaosha_user表对应的实体类
@Setter
@Getter
public class MiaoShaUser {
    private Long id;
    private String nickname;
    private String password;
    private String salt;
    private String head;
    private Date registerDate;
    private Date lastLoginDate;
    private Integer loginCount;
}
3. 创建dao层接口
@Mapper
public interface MiaoShaUserDao {
    @Select("select * from miaosha_user where id = #{id}")
    MiaoShaUser getById(@Param("id") long id);
}
4. 创建service层
1. 接口:

public interface IMiaoShaUserService {
    MiaoShaUser getById(long id);

    boolean login(LoginVo loginVo);
}

2. 实现类:

@Service
public class MiaoShaUserServiceImpl implements IMiaoShaUserService {

    @Autowired
    private MiaoShaUserDao miaoShaUserDao;
    @Override
    public MiaoShaUser getById(long id) {
        return miaoShaUserDao.getById(id);
    }

    @Override
    public boolean login(LoginVo loginVo) {
        if (loginVo == null){
            throw  new GlobalException(CodeMsg.SERVER_ERROR);
        }
        String mobile = loginVo.getMobile();
        String password = loginVo.getPassword();
        MiaoShaUser miaoShaUser = miaoShaUserDao.getById(Long.parseLong(mobile));
        if (miaoShaUser == null){
            throw new GlobalException(CodeMsg.MOBILE_NOT_EXIST);
        }
        //验证密码
        String dbpass = miaoShaUser.getPassword();
        String slatDB = miaoShaUser.getSalt();
        String calcPass = MD5Util.formPassToDBPass(password,slatDB);
        if (calcPass.equals(dbpass)){
            throw new GlobalException(CodeMsg.PASSWORD_ERROR);
        }
        return true;
    }
}

3. 其中异常处理类:

    在CodeMsg类中添加如下代码:        
    //登录模块 5002xx
    public static CodeMsg SESSION_ERROR = new CodeMsg(500210,"Session不存在或已失效");
    public static CodeMsg PASSWORD_EMPTY = new CodeMsg(500211,"密码不能为空");
    public static CodeMsg MOBILE_EMPTY = new CodeMsg(500212,"手机号不能为空");
    public static CodeMsg MOBILE_ERROR = new CodeMsg(500213,"手机号格式错误");
    public static CodeMsg MOBILE_NOT_EXIST = new CodeMsg(500214,"手机号不存在");
    public static CodeMsg PASSWORD_ERROR= new CodeMsg(500215,"密码错误");
    
    
    创建GlobleExceptionHandler获取异常:
    
    @ControllerAdvice
    @ResponseBody
    public class GlobleExceptionHandler {
        @ExceptionHandler(value = Exception.class)
        public Result<String> exceptionHandler(HttpServletRequest request, Exception e){

        if (e instanceof GlobalException){
            GlobalException ex = (GlobalException)e;
            return Result.error(ex.getCodeMsg());
        }
        if (e instanceof BindException){
            BindException ex = (BindException) e;
            List<ObjectError> errors = ex.getAllErrors();
            ObjectError error = errors.get(0);
            String message = error.getDefaultMessage();
            return Result.error(CodeMsg.BIND_ERROR.fillArgs(message));
        }else {
            return Result.error(CodeMsg.SERVER_ERROR);
        }
    }
}

其中GlobalException异常类:
@Setter
@Getter
public class GlobalException extends RuntimeException {
    static final long serialVersionUID = -3387516993124229948L;
    private CodeMsg codeMsg;
    public GlobalException(CodeMsg codeMsg){
        super(codeMsg.toString());
        this.codeMsg = codeMsg;
    }
}

4.使用到的工具类:
两次MD5加密类:
    
public class MD5Util {
    public static String md5(String src){
        return DigestUtils.md5Hex(src);     
    }

    private static final String salt = "1a2b3c4d";      //固定salt值
    
    /*
     * 用户输入到表单的密码,第一次MD5
     */
    public static String inputPassFormPass(String inputPass){
        String str = ""+salt.charAt(0)+salt.charAt(2)+inputPass+salt.charAt(5)+salt.charAt(4);
        return md5(str);
    }

    /*
     * 从请求到数据库中,第二次MD5
     */
    public static String formPassToDBPass(String formPass,String salt){
        String str = ""+salt.charAt(0)+salt.charAt(2)+formPass+salt.charAt(5)+salt.charAt(4);
        return md5(str);
    }
    
    //两次整合进来
    public static String inputPassToDbPass(String input,String saltDB){
        String formPass = inputPassFormPass(input);
        String dbPass = formPassToDBPass(formPass,saltDB);
        return dbPass;
    }

    //测试
    public static void main(String[] args) {
        System.out.println(inputPassFormPass("12345"));
        System.out.println(formPassToDBPass("12345","1a2b3c4d"));
        System.out.println(inputPassToDbPass("12345","1a2b3c4d"));
    }
}

5. 校验工具类:用来校验输入的手机号格式是否正确:
    
    public class ValidatorUtil {

        private static final Pattern mobile_pattern = Pattern.compile("1\\d{10}");

        public static boolean isMobile(String src){
            if (StringUtils.isEmpty(src)){
                return false;
            }
            Matcher m = mobile_pattern.matcher(src);
            return m.matches();
        }

        //测试
        public static void main(String[] args) {
            System.out.println(isMobile("18888888888"));
            System.out.println(isMobile("12313211"));
        }
    }

6. LoginVo实体类:接收用户登录请求的实体类
    @Getter
    @Setter
    public class LoginVo {
        @NotNull
        @IsMobile
        private String mobile;
        @NotNull
        @Length(min = 32)
        private String password;
    }
7. 自定义校验手机号注解
    创建IsMobileValidator类:
    public class IsMobileValidator implements ConstraintValidator<IsMobile,String> {
        private boolean required = false;

        /**
        * 判断是否可以为空
        * @param constraintAnnotation
        */
        @Override
        public void initialize(IsMobile constraintAnnotation) {
            required = constraintAnnotation.required();
        }


        @Override
        public boolean isValid(String value, ConstraintValidatorContext context) {
            if (required){
                return ValidatorUtil.isMobile(value);
            }else {
                if (StringUtils.isEmpty(value)){
                    return true;
                }else {
                    return ValidatorUtil.isMobile(value);
                }
            }
        }
    }
    
    
    创建IsMobile注解:
    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
    @Retention(RUNTIME)
    @Documented
    @Constraint(validatedBy = {IsMobileValidator.class})
    public @interface IsMobile {
        //手机号不能为空
        boolean required() default true;

        String message() default "手机号码格式错误";

        Class<?>[] groups() default { };

        Class<? extends Payload>[] payload() default { };
    }
    
8.创建LoginController
    @Controller
    @RequestMapping("/login")
    public class LoginController {

        private static Logger log = LoggerFactory.getLogger(LoginController.class);

        @Autowired
        private IMiaoShaUserService IMiaoShaUserService;


        @RequestMapping("/to_login")
        public String toLogin() {
            return "login";
        }


        @RequestMapping("/do_login")
        @ResponseBody
        public Result<Boolean> doLogin(@Valid LoginVo loginVo){
            log.info(loginVo.toString());
            //登录
            boolean cm = IMiaoShaUserService.login(loginVo);
            return Result.success(true);
        }
    }
    
9. 前端代码放在git上:https://gitee.com/ustcxu/spike_system.git
posted @ 2019-12-19 15:16  咸鱼呀咸鱼  阅读(280)  评论(0)    收藏  举报