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

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 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 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 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  咸鱼呀咸鱼  阅读(283)  评论(0)    收藏  举报