1.建立数据库
miaosha_user
2.两次MD5
(1)添加依赖
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.6</version>
</dependency>
(2)MD5Util
用户端:PASS=MD5(明文+固定Salt),防止用户的明文密码在网络上传输,被别人抓包获取到密码
public static String inputPassToFormPass(String inputPass) {
String str = ""+salt.charAt(0)+salt.charAt(2) + inputPass +salt.charAt(5) + salt.charAt(4);
System.out.println(str);
return md5(str);
}
服务端:PASS=MD5(用户输入+随机Salt),salt写入数据库,防止在数据库被盗后密码反向破解,保证密码不会泄露
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 inputPass, String saltDB) {
String formPass = inputPassToFormPass(inputPass);
String dbPass = formPassToDBPass(formPass, saltDB);
return dbPass;
}
3.LoginController
to_login通过thymeleat模板返回到login.html
@RequestMapping("/to_login")
public String toLogin() {
return "login";
}
do_login对提交的数据进行参数比较
@RequestMapping("/do_login")
@ResponseBody
public Result<Boolean> doLogin(HttpServletResponse response, @Valid LoginVo loginVo) {
log.info(loginVo.toString());
//登录
userService.login(response, loginVo);
return Result.success(true);
}
}
4.ValidatorUtil
验证手机格式
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();
}
}
5.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 { };
}
6.IsMobileValidator
public class IsMobileValidator implements ConstraintValidator<IsMobile, String> {
private boolean required = false;
//初始化方法
public void initialize(IsMobile constraintAnnotation) {
required = constraintAnnotation.required();
}
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);
}
}
}
}
7.LoginVo
验证不为空、验证长度和手机号格式
@NotNull
@IsMobile
private String mobile;
@NotNull
@Length(min=32)
private String password;
8.GlobalExceptionHandler
将异常信息显示在页面,添加exceptionHandler方法,通过@ExceptionHandler拦截所有的异常,方法体内先拦截绑定异常,返回具体错误,调用fillArgs方法,其他异常返回系统错误。
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
@ExceptionHandler(value=Exception.class)
public Result<String> exceptionHandler(HttpServletRequest request, Exception e){
e.printStackTrace();
if(e instanceof GlobalException) {
GlobalException ex = (GlobalException)e;
return Result.error(ex.getCm());
}else if(e instanceof BindException) {
BindException ex = (BindException)e;
List<ObjectError> errors = ex.getAllErrors();
ObjectError error = errors.get(0);
String msg = error.getDefaultMessage();
return Result.error(CodeMsg.BIND_ERROR.fillArgs(msg));
}else {
return Result.error(CodeMsg.SERVER_ERROR);
}
}
}
9.GlobalException
在GlobalException类中封装CondeMsg类型变量,供抛出时实例化使用
public class GlobalException extends RuntimeException{
private static final long serialVersionUID = 1L;
private CodeMsg cm;
public GlobalException(CodeMsg cm) {
super(cm.toString());
this.cm = cm;
}
public CodeMsg getCm() {
return cm;
}
}
10.分布式Session
分布式Session:将Session单独放到一个缓存中,通过redis来管理。
登陆成功后,通过UUIDUtil为用户生成token标识用户,写到cookie中,传递给客户端,客户端上传token,服务器端根据token获取到用户信息。
UUIDUtil
public class UUIDUtil {
public static String uuid() {
return UUID.randomUUID().toString().replace("-", "");
}
}
MiaoshaUserService
private void addCookie(HttpServletResponse response, String token, MiaoshaUser user) {
redisService.set(MiaoshaUserKey.token, token, user);
Cookie cookie = new Cookie(COOKI_NAME_TOKEN, token);
cookie.setMaxAge(MiaoshaUserKey.token.expireSecconds());
cookie.setPath("/");
response.addCookie(cookie);
生成cookie
String token = UUIDUtil.uuid();
addCookie(response, token, user);
return true;
getByToke()获取user对象
addCookie()延长有效期
public MiaoshaUser getByToken(HttpServletResponse response, String token) {
if(StringUtils.isEmpty(token)) {
return null;
}
MiaoshaUser user = redisService.get(MiaoshaUserKey.token, token, MiaoshaUser.class);
//延长有效期
if(user != null) {
addCookie(response, token, user);
}
return user;
}
11.GoodsController
登录成功后跳转到商品列表
@Controller
@RequestMapping("/goods")
public class GoodsController {
private static Logger log = LoggerFactory.getLogger(GoodsController.class);
@Autowired
private MiaoshaUserService miaoshaUserService;
@Autowired
RedisService redisService;
@RequestMapping("/to_list")
public String toLogin(Model model,MiaoshaUser user){
model.addAttribute("user", user);
return "goods_list";
}
}