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