CREATE TABLE miaosha_user (
`id` bigint(20) NOT NULL COMMENT '用户ID,手机号码',
`nickname` varchar(255) NOT NULL,
`password` varchar(32) DEFAULT NULL COMMENT 'MD5(MD5(pass明文+固定salt) + salt)',
`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 '0' COMMENT '登录次数',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
引入MD5工具类,添加MD5Util
http是明文登录的,不安全
<dependency>
<groupId>commons-codecgroupId>
<artifactId>commons-codecartifactId>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-lang3artifactId>
<version>3.6version>
dependency>
(代码可见github)
(文件见github)
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;
}
引入spring-boot-starter-validation
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-validationartifactId>
dependency>
自己定义:
validator:
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = IsMobileValidator.class)//会去找ismobilexxx
public @interface IsMobile {
String message() default "手机号码格式有误";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
boolean required() default true; //允许为空
}
public class IsMobileValidator implements ConstraintValidator<IsMobile, String>{
}
IsMobileValidator
public class IsMobileValidator extends ConstraintValidator<>(){
private boolean required = false;
public void initialize(IsMobile constraintAnnotation){
required =
}
public boolean isValid(){
if(required){
return ValidatorUtil.isMobile
}
else{
if(StringUtils.isEmpty(value)){
return true;
}
else {
return ValidatorUtil.isMobile(value);
}
}
}
}
public boolean login(HttpServletResponse response,LoginVo loginVo) {
if(loginVo == null) {
throw new GlobalException(CodeMsg.SERVER_ERROR);
}
String mobile = loginVo.getMobile();
String formpass = loginVo.getPassword();
MiaoshaUser user = getById(Long.parseLong(mobile));//获取数据库中的人
if(user == null) {
throw new GlobalException(CodeMsg.MOBILE_NOT_EXIST);
}
//验证密码
String dbPass = user.getPassword();//获取数据库中人的密码
String saltDB = user.getSalt();//获取数据库中人的salt
String calcPass = MD5Util.formPass2DBPass(formpass, saltDB);//通过salt把输入的密码变成calc密码
if(!calcPass.equals(dbPass)) {//再比较这两个密码
throw new GlobalException(CodeMsg.PASSWORD_ERROR);
}
}
@ControllerAdvice
@ResponseBody
@ExceptionHandler(value=Excption.class)
public Result<String> excptionHandler(HttpServletRequest request ,Exeption e){
if(e instanceof BindException){
BindException ex = (BindException)e;
List<ObjectError> errors = ex.getAllErrors();
return Result.error(CodeMsg.BIND_EORROR.fillArgs());
}
}
@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
@ExceptionHandler(value=Exception.class)
public Result<String> allExceptionHandler(HttpServletRequest request, Exception exception) throws Exception{
}
}
实际实现中,不会只有一台服务器,如果第一次请求到达第一个服务器,第二个请求到了第二个服务器,第一次的session信息就丢失了,所以就把session信息存放在redis当中
登录之后,跳转到to_list页面
跳转的时候要把参数带上,用的就是cookie(或者还有request的参数)
然后我们在to_list当中,就要把cookie中的参数取出来
通过参数从redis中获取到user
展示这个user的货物界面
将用户信息存放在redis中时需要用token唯一标识
(登录成功之后啊,给这个用户生成一个类似于sessionID,标示这个用户,然后写到cookie当中传递给客户端,客户端在随后的访问都在cookie中传token,服务端拿到这个token之后,就用这个token来取到用户对应的session信息)
//设置对象
//参数:前缀+key+value
public <T> boolean set(KeyPrefix prefix, String key, T value) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
String str = beanToString(value);
if(str == null || str.length() <= 0) {
return false;
}
//生成真正的key
String realKey = prefix.getPrefix() + key;
int seconds = prefix.expireSeconds();
if(seconds <= 0) {
jedis.set(realKey, str);
}else {
jedis.setex(realKey, seconds, str);
}
return true;
}finally {
returnToPool(jedis);
}
}
要写到cookie里面:token => cookie
但是要标示一下这个token对应着哪一个用户,所以就把这个用户信息写到redis当中(第三方缓存),这样只用知道token就可以得到用户信息
//添加cookie到response中,redis中存储
private void addCookie(HttpServletResponse response, String token, MiaoshaUser user) {
//1. redis中存储
//用到了上面的set方法 参数:前缀+key+value
//MiaoshaUserKey.token是一个前缀字符串,需要在MiaoshaUserKey中实现
redisService.set(MiaoshaUserKey.token, token, user);
//2.添加cookie到response中
Cookie cookie = new Cookie(COOKIE_NAME_TOKEN, token);
//再设置一下有效期和网站根目录
cookie.setMaxAge(MiaoshaUserKey.token.expireSeconds());
cookie.setPath("/");
response.addCookie(cookie);
}
就是上面的login加上最后的addCookie部分
public boolean login(HttpServletResponse response,LoginVo loginVo) {
if(loginVo == null) {
throw new GlobalException(CodeMsg.SERVER_ERROR);
}
String mobile = loginVo.getMobile();
String formpass = loginVo.getPassword();
MiaoshaUser user = getById(Long.parseLong(mobile));//获取数据库中的人
if(user == null) {
throw new GlobalException(CodeMsg.MOBILE_NOT_EXIST);
}
//验证密码
String dbPass = user.getPassword();//获取数据库中人的密码
String saltDB = user.getSalt();//获取数据库中人的salt
String calcPass = MD5Util.formPass2DBPass(formpass, saltDB);//通过salt把输入的密码变成calc密码
if(!calcPass.equals(dbPass)) {//再比较这两个密码
throw new GlobalException(CodeMsg.PASSWORD_ERROR);
}
//生成一个token(随机的immutable universally unique identifier )
String token = UUIDUtil.uuid();
addCookie(response, token, user);
return true;
}