Java秒杀实战 (二) 实现用户登录以及分布式session功能

一、两次MD5

1. 用户端: PASS = MD5( 明文 + 固定 Salt) 

2. 服务端: PASS = MD5( 用户输入 + 随机 Salt)

通过两次MD5,可以增大http明文传输过程或数据库被盗后,黑客通过彩虹表等手段反推出明文密码的难度(有一定作用,但不能保证绝对安全)。

pom文件添加依赖

		<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>

添加md5加密工具类

package com.wings.seckill.util;


import org.apache.commons.codec.digest.DigestUtils;


public class Md5Util {
	
	private static final String SALT = "1a2b3c4d";
	
	public static String md5(String src){
		return DigestUtils.md5Hex(src);
	}
	
	public static String inputPass2FormPass(String inputPass){
		String src = "" + SALT.charAt(0) + SALT.charAt(2)+ inputPass + SALT.charAt(5)+ SALT.charAt(4);
		return md5(src);
	}
	
	public static String formPass2DbPass(String formPass, String salt){
		String src = "" + salt.charAt(0) + salt.charAt(2)+ formPass + salt.charAt(5)+ salt.charAt(4);
		return md5(src);
	}
	
	public static String inputPass2DbPass(String inputPass, String salt){
		String formPass = inputPass2FormPass(inputPass);
		String dbPass = formPass2DbPass(formPass, salt);
		return dbPass;
	}
	
	public static void main(String[] args) {
		String inputPass = "13632481101";
		String salt = "mysalt";
		String formPass = inputPass2FormPass(inputPass);
		String dbPass1 = formPass2DbPass(formPass, salt);
		String dbPass2 = inputPass2DbPass(inputPass, salt);
		System.out.println(formPass);
		System.out.println(dbPass1);
		System.out.println(dbPass2);
	}
}
	
	

新增用户表seckill_user

CREATE TABLE `seckill`.`Untitled`  (
  `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(0) DEFAULT NULL COMMENT '注册时间',
  `last_login_date` datetime(0) COMMENT '上次登录时间',
  `login_count` int(11) DEFAULT 0 COMMENT '登录次数',
  PRIMARY KEY (`id`)
);

添加电话号码校验工具类

package com.wings.seckill.util;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.alibaba.druid.util.StringUtils;

public class ValidatorUtil {

	private static Pattern MOBILE_PATTERN = Pattern.compile("1\\d{10}");
	
	public static boolean isMobile(String mobile){
		if(StringUtils.isEmpty(mobile)){
			return false;
		}
		
		Matcher matcher = MOBILE_PATTERN.matcher(mobile);
		return matcher.matches();
	}
	
	public static void main(String[] args) {
		boolean result1 = isMobile("13632481101");
		boolean result2 = isMobile("1363248110");
		System.out.println(result1);
		System.out.println(result2);
	}
}

SeckillUser domain、dao、service、controller

package com.wings.seckill.domain;

import java.util.Date;

public class SeckillUser {
	private Long id;
	private String nickname;
	private String password;
	private String salt;
	private String head;
	private Date registerDate;
	private Date lastLoginDate;
	private Integer loginCount;
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getNickname() {
		return nickname;
	}
	public void setNickname(String nickname) {
		this.nickname = nickname;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getSalt() {
		return salt;
	}
	public void setSalt(String salt) {
		this.salt = salt;
	}
	public String getHead() {
		return head;
	}
	public void setHead(String head) {
		this.head = head;
	}
	public Date getRegisterDate() {
		return registerDate;
	}
	public void setRegisterDate(Date registerDate) {
		this.registerDate = registerDate;
	}
	public Date getLastLoginDate() {
		return lastLoginDate;
	}
	public void setLastLoginDate(Date lastLoginDate) {
		this.lastLoginDate = lastLoginDate;
	}
	public Integer getLoginCount() {
		return loginCount;
	}
	public void setLoginCount(Integer loginCount) {
		this.loginCount = loginCount;
	}
}
package com.wings.seckill.dao;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import com.wings.seckill.domain.SeckillUser;

@Mapper
public interface SeckillUserDao {

	@Select("select * from seckill_user where id = #{id}")
	public SeckillUser getById(long id);
}
package com.wings.seckill.service;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.wings.seckill.dao.SeckillUserDao;
import com.wings.seckill.domain.SeckillUser;
import com.wings.seckill.result.CodeMsg;
import com.wings.seckill.result.Result;
import com.wings.seckill.util.Md5Util;
import com.wings.seckill.util.ValidatorUtil;
import com.wings.seckill.vo.LoginVo;

@Service
public class SeckillUserService {

	@Autowired
	SeckillUserDao seckillUserDao;
	
	public SeckillUser getById(long id){
		return seckillUserDao.getById(id);
	}
	
	public CodeMsg login(LoginVo loginVo){
		if(loginVo == null){
			return CodeMsg.SERVER_ERROR;
		}
		String mobile = loginVo.getMobile();
		String password = loginVo.getPassword();
		
		if(StringUtils.isEmpty(mobile)){
			return CodeMsg.MOBILE_EMPTY;
		}
		if(StringUtils.isEmpty(password)){
			return CodeMsg.PASSWORD_EMPTY;
		}
		
		if(!ValidatorUtil.isMobile(mobile)){
			return CodeMsg.MOBILE_ERROR;
		}
		
		SeckillUser user = seckillUserDao.getById(Long.parseLong(loginVo.getMobile()));
		if(user == null){
			return CodeMsg.MOBILE_NOT_EXIST;
		}
		
		String salt = user.getSalt();
		String dbPass = user.getPassword();
		String md5Pass = Md5Util.formPass2DbPass(password, salt);
		if(!dbPass.equals(md5Pass)){
			return CodeMsg.PASSWORD_ERROR;
		}
		
		return CodeMsg.SUCCESS;
	}
}
package com.imooc.miaosha.controller;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.imooc.miaosha.redis.RedisService;
import com.imooc.miaosha.result.Result;
import com.imooc.miaosha.service.MiaoshaUserService;
import com.imooc.miaosha.vo.LoginVo;

@Controller
@RequestMapping("/login")
public class LoginController {

	private static Logger log = LoggerFactory.getLogger(LoginController.class);
	
	@Autowired
	MiaoshaUserService userService;
	
	@Autowired
	RedisService redisService;
	
    @RequestMapping("/to_login")
    public String toLogin() {
        return "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);
    }
}

视图层增加如下文件

登陆页面:login.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>登录</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    
    <!-- jquery -->
    <script type="text/javascript" th:src="@{/js/jquery.min.js}"></script>
    <!-- bootstrap -->
    <link rel="stylesheet" type="text/css" th:href="@{/bootstrap/css/bootstrap.min.css}" />
    <script type="text/javascript" th:src="@{/bootstrap/js/bootstrap.min.js}"></script>
    <!-- jquery-validator -->
    <script type="text/javascript" th:src="@{/jquery-validation/jquery.validate.min.js}"></script>
    <script type="text/javascript" th:src="@{/jquery-validation/localization/messages_zh.min.js}"></script>
    <!-- layer -->
    <script type="text/javascript" th:src="@{/layer/layer.js}"></script>
    <!-- md5.js -->
    <script type="text/javascript" th:src="@{/js/md5.min.js}"></script>
    <!-- common.js -->
    <script type="text/javascript" th:src="@{/js/common.js}"></script>
    
</head>
<body>

<form name="loginForm" id="loginForm" method="post"  style="width:50%; margin:0 auto">

	<h2 style="text-align:center; margin-bottom: 20px">用户登录</h2>
	
	<div class="form-group">
       	<div class="row">
	       	<label class="form-label col-md-4">请输入手机号码</label>
	        <div class="col-md-5">
	        	<input id="mobile" name = "mobile" class="form-control" type="text" placeholder="手机号码" required="true"  minlength="11" maxlength="11" />
	    	</div>
	    	<div class="col-md-1">
	    	</div>
    	</div>
    </div>
    
    <div class="form-group">
     		<div class="row">
		        <label class="form-label col-md-4">请输入密码</label>
		        <div class="col-md-5">
		        	<input id="password" name="password" class="form-control" type="password"  placeholder="密码" required="true" minlength="6" maxlength="16" />
	       		</div>
      		</div>
	</div>
	
	<div class="row">
		     	<div class="col-md-5">
	       	 		<button class="btn btn-primary btn-block" type="reset" onclick="reset()">重置</button>
	       	 	</div>
	       	 	<div class="col-md-5">
	       	 		<button class="btn btn-primary btn-block" type="submit" onclick="login()">登录</button>
	       	 	</div>
	 </div>
	 
</form>
</body>
<script>
function login(){
	$("#loginForm").validate({
        submitHandler:function(form){
             doLogin();
        }    
    });
}
function doLogin(){
	g_showLoading();
	
	var inputPass = $("#password").val();
	var salt = g_passsword_salt;
	var str = ""+salt.charAt(0)+salt.charAt(2) + inputPass +salt.charAt(5) + salt.charAt(4);
	var password = md5(str);
	
	$.ajax({
		url: "/login/do_login",
	    type: "POST",
	    data:{
	    	mobile:$("#mobile").val(),
	    	password: password
	    },
	    success:function(data){
	    	layer.closeAll();
	    	if(data.code == 0){
	    		layer.msg("成功");
	    	}else{
	    		layer.msg(data.msg);
	    	}
	    },
	    error:function(){
	    	layer.closeAll();
	    }
	});
}
</script>
</html>

全局自定义 common.js

//展示loading
function g_showLoading(){
	var idx = layer.msg('处理中...', {icon: 16,shade: [0.5, '#f5f5f5'],scrollbar: false,offset: '0px', time:100000}) ;  
	return idx;
}
//salt
var g_passsword_salt="1a2b3c4d"

 

 

(二)JSR303参数校验 + 全局异常处理器

service中的方法入参有许多参数的判断代码,为了简化,可以利用JSR303参数校验

pom文件引入依赖

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-validation</artifactId>
		</dependency>

自定义参数校验注解

package com.wings.seckill.validator;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

import org.apache.commons.lang3.StringUtils;

import com.wings.seckill.util.ValidatorUtil;

public class IsMobileValidator implements ConstraintValidator<IsMobile, String> {

	private boolean required;

	@Override
	public void initialize(IsMobile isMobile) {
		required = isMobile.required();
	}

	@Override
	public boolean isValid(String value, ConstraintValidatorContext context) {
		if(!required && StringUtils.isEmpty(value)){
			return true;
		}
		return ValidatorUtil.isMobile(value);
	}
}
package com.wings.seckill.validator;

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

@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 { };
}

使用该自定义注解:

package com.wings.seckill.vo;

import javax.validation.constraints.NotNull;

import org.hibernate.validator.constraints.Length;

import com.wings.seckill.validator.IsMobile;

public class LoginVo {
	
	@NotNull
	@IsMobile
	private String mobile;
	@NotNull
	@Length(min = 32)
	private String password;
	
	public String getMobile() {
		return mobile;
	}
	public void setMobile(String mobile) {
		this.mobile = mobile;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	@Override
	public String toString() {
		return "LoginVo [mobile=" + mobile + ", password=" + password + "]";
	}
}

在对应方法中加入@Valid 开启参数校验

	@RequestMapping("/do_login")
	@ResponseBody
	public Result<CodeMsg> doLogin(@Valid LoginVo loginVo) {
		log.info(loginVo.toString());
		seckillUserService.login(loginVo);
		return Result.success(CodeMsg.SUCCESS);
	}

service的login方法简化如下:

	public boolean login(LoginVo loginVo){
		if(loginVo == null){
			//return CodeMsg.SERVER_ERROR;
			throw new GlobalException(CodeMsg.SERVER_ERROR);
		}
		String mobile = loginVo.getMobile();
		String password = loginVo.getPassword();
		/*
		if(StringUtils.isEmpty(mobile)){
			return CodeMsg.MOBILE_EMPTY;
		}
		if(StringUtils.isEmpty(password)){
			return CodeMsg.PASSWORD_EMPTY;
		}
		
		if(!ValidatorUtil.isMobile(mobile)){
			return CodeMsg.MOBILE_ERROR;
		}
		*/
		SeckillUser user = seckillUserDao.getById(Long.parseLong(mobile));
		if(user == null){
			//return CodeMsg.MOBILE_NOT_EXIST;
			throw new GlobalException(CodeMsg.MOBILE_NOT_EXIST);
		}
		
		String salt = user.getSalt();
		String dbPass = user.getPassword();
		String md5Pass = Md5Util.formPass2DbPass(password, salt);
		if(!dbPass.equals(md5Pass)){
			//return CodeMsg.PASSWORD_ERROR;
			throw new GlobalException(CodeMsg.PASSWORD_ERROR);
		}
		
		return true;
	}

定义全局异常及异常处理器

package com.wings.seckill.exception;

import com.wings.seckill.result.CodeMsg;

public class GlobalException extends RuntimeException{
	
	private static final long serialVersionUID = 31665074385012932L;
	private CodeMsg cm;
	
	public GlobalException(CodeMsg cm){
		this.cm = cm;
	}
	public CodeMsg getCm() {
		return cm;
	}
			
}
package com.wings.seckill.exception;

import javax.servlet.http.HttpServletRequest;

import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import com.wings.seckill.result.CodeMsg;
import com.wings.seckill.result.Result;

@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {

	@ExceptionHandler(value = Exception.class)
	public Result<String> handleException(HttpServletRequest request, Exception ex){
		ex.printStackTrace();
		
		if(ex instanceof GlobalException){
			GlobalException gex = (GlobalException)ex;
			return Result.error(gex.getCm());
		} else if(ex instanceof BindException){
			BindException bex = (BindException)ex;
			String message = bex.getAllErrors().get(0).getDefaultMessage();
			return Result.error(CodeMsg.BIND_ERROR.fillMsg(message));
		} else {
			return Result.error(CodeMsg.SERVER_ERROR);
		}
	}
}

(三)分布式session

添加uuid工具类

package com.wings.seckill.util;

import java.util.UUID;

public class UUIDUtil {

	public static String uuid(){
		return UUID.randomUUID().toString().replace("-", "");
	}
}

SeckillUserService的login方法添加以下代码

                String token = UUIDUtil.uuid();
		redisService.set(SeckillUserKey.token, token, user);
		Cookie cookie = new Cookie(COOKIE_TOKEN_NAME, token);
		cookie.setMaxAge(SeckillUserKey.token.expireSeconds());
		cookie.setPath("/");
		
		response.addCookie(cookie);

SeckillUserService添加通过token获取user对象方法

	public SeckillUser getByToke(String token) {
		if(StringUtils.isEmpty(token)){
			return null;
		}
		
		return redisService.get(SeckillUserKey.token, token, SeckillUser.class);
	}

 

 

 

登录成功后跳转到商品列表,对应的Controller及页面如下

package com.wings.seckill.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.wings.seckill.domain.SeckillUser;
import com.wings.seckill.service.SeckillUserService;

@Controller
@RequestMapping("/goods")
public class GoodsController {
	
	private static Logger log = LoggerFactory.getLogger(GoodsController.class);

	@Autowired
	private SeckillUserService seckillUserService;

	@RequestMapping("/to_list")
	public String toList(Model model, 
			@CookieValue(name = SeckillUserService.COOKIE_TOKEN_NAME, required = false) String cookieToken,
			// @RequestParam 是为了兼容默写手机端会把cookie信息放入请求参数中
			@RequestParam(name = SeckillUserService.COOKIE_TOKEN_NAME, required = false) String paramToken) {
			
		if(StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)){
			return "/login/to_login";
		}
		
		String token = StringUtils.isEmpty(paramToken) ? cookieToken : paramToken;
		SeckillUser seckillUser = seckillUserService.getByToke(token);
		model.addAttribute("user", seckillUser);
		return "goods_list";
	}
	
}
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>商品列表</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="'hello:'+${user.nickname}" ></p>
</body>
</html>

(四)优化

像User这种,几乎每个Controller方法都要使用的对象,如果每个Controller的方法都通过以上方式获取,代码将相当臃肿。这时,可以使用SpringMVC中WebMvcConfigurerAdapter的addArgumentResolvers,向需要user对象的方法进行入参注入。

package com.wings.seckill.config;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class WebConfig extends WebMvcConfigurerAdapter{
	
	@Autowired
	private UserArgumentResolver userArgumentResolver; 
	
	@Override
	public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
		argumentResolvers.add(userArgumentResolver);
	}
}
package com.wings.seckill.config;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import com.wings.seckill.domain.SeckillUser;
import com.wings.seckill.service.SeckillUserService;

@Service
public class UserArgumentResolver implements HandlerMethodArgumentResolver{
	
	@Autowired
	private SeckillUserService seckillUserService;

	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		Class<?> clazz = parameter.getParameterType();
		return clazz == SeckillUser.class;
	}

	@Override
	public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
		
		HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
		HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
		
		String paramToken = request.getParameter(SeckillUserService.COOKIE_TOKEN_NAME);
		String cookieToken = getCookieValue(request, SeckillUserService.COOKIE_TOKEN_NAME);
		
		if(StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)){
			return null;
		}
		
		String token = StringUtils.isEmpty(paramToken) ? cookieToken : paramToken;
		return seckillUserService.getByToke(token, response);
	}

	private String getCookieValue(HttpServletRequest request, String cookieName) {
		Cookie[] cookies = request.getCookies();
		if(cookies != null){
			for(Cookie cookie : cookies){
				if(cookie.getName().equals(cookieName)){
					return cookie.getValue();
				}
			}
		}
		return null;
	}

}
package com.wings.seckill.service;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.wings.seckill.dao.SeckillUserDao;
import com.wings.seckill.domain.SeckillUser;
import com.wings.seckill.exception.GlobalException;
import com.wings.seckill.redis.RedisService;
import com.wings.seckill.redis.SeckillUserKey;
import com.wings.seckill.result.CodeMsg;
import com.wings.seckill.util.Md5Util;
import com.wings.seckill.util.UUIDUtil;
import com.wings.seckill.vo.LoginVo;

@Service
public class SeckillUserService {
	
	public static final String COOKIE_TOKEN_NAME = "token";

	@Autowired
	SeckillUserDao seckillUserDao;
	
	@Autowired
	RedisService redisService;
	
	public SeckillUser getById(long id){
		return seckillUserDao.getById(id);
	}
	
	public boolean login(HttpServletResponse response, LoginVo loginVo){
		if(loginVo == null){
			throw new GlobalException(CodeMsg.SERVER_ERROR);
		}
		String mobile = loginVo.getMobile();
		String password = loginVo.getPassword();

		SeckillUser user = seckillUserDao.getById(Long.parseLong(mobile));
		if(user == null){
			throw new GlobalException(CodeMsg.MOBILE_NOT_EXIST);
		}
		
		String salt = user.getSalt();
		String dbPass = user.getPassword();
		String md5Pass = Md5Util.formPass2DbPass(password, salt);
		if(!dbPass.equals(md5Pass)){
			throw new GlobalException(CodeMsg.PASSWORD_ERROR);
		}
		
		String token = UUIDUtil.uuid();
		addCookie(token, response, user);
		return true;
	}

	public SeckillUser getByToke(String token, HttpServletResponse response) {
		if(StringUtils.isEmpty(token)){
			return null;
		}
		
		// 延长有效期
		SeckillUser user = redisService.get(SeckillUserKey.token, token, SeckillUser.class);
		if(user != null){
			addCookie(token, response, user);
		}
		return user;
	}
	
	private void addCookie(String token, HttpServletResponse response, SeckillUser user){
		redisService.set(SeckillUserKey.token, token, user);
		Cookie cookie = new Cookie(COOKIE_TOKEN_NAME, token);
		cookie.setMaxAge(SeckillUserKey.token.expireSeconds());
		cookie.setPath("/");
		response.addCookie(cookie);
	}
}

这时Controller将会相当简洁

package com.wings.seckill.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.wings.seckill.domain.SeckillUser;

@Controller
@RequestMapping("/goods")
public class GoodsController {

	@RequestMapping("/to_list")
	public String toList(Model model, SeckillUser seckillUser) {
		model.addAttribute("user", seckillUser);
		return "goods_list";
	}
	
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值