java分布式会话,Java秒杀登录模块与分布式session

一、两次MD5

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

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

pom添加依赖

commons-codec

commons-codec

1.11

org.apache.commons

commons-lang3

3.6

添加MD5工具类

package com.imooc.miaosha.util;

import org.springframework.util.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);

}

}

添加电话号码校验类

package com.imooc.miaosha.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);

}

}

resources文件下添加js/common.js,js/jquery.min.js,js/md5.min.js,templates/login.html

新增登录页面login.html

登录

用户登录

请输入手机号码

请输入密码

重置

登录

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();

}

});

}

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参数检验+全局异常处理器

pom添加依赖

org.springframework.boot

spring-boot-starter-validation

新建包package com/imooc/miaosha/validator

自定义参数注解

package com.imooc.miaosha.validator;

import javax.validation.Constraint;

import javax.validation.Payload;

import java.lang.annotation.Documented;

import java.lang.annotation.Retention;

import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

@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.imooc.miaosha.validator;

import com.imooc.miaosha.util.ValidatorUtil;

import org.apache.commons.lang3.StringUtils;

import javax.validation.ConstraintValidator;

import javax.validation.ConstraintValidatorContext;

public class IsMobileValidator implements ConstraintValidator {

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

}

}

在LoginVo中使用注解

package com.imooc.miaosha.vo;

import javax.validation.constraints.NotNull;

import com.imooc.miaosha.validator.IsMobile;

import org.hibernate.validator.constraints.Length;

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 + "]";

}

}

方法中添加参数校验

@RequestMapping("/do_login")

@ResponseBody

public Result 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/imooc/miaosha/exception

添加全局异常类GlobalException和全局异常处理器GlobalExceptionHandler

package com.imooc.miaosha.exception;

import com.imooc.miaosha.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.imooc.miaosha.exception;

import com.imooc.miaosha.result.CodeMsg;

import com.imooc.miaosha.result.Result;

import org.springframework.web.bind.annotation.ControllerAdvice;

import org.springframework.web.bind.annotation.ExceptionHandler;

import org.springframework.web.bind.annotation.ResponseBody;

import org.springframework.validation.BindException;

import javax.servlet.http.HttpServletRequest;

@ControllerAdvice

@ResponseBody

public class GlobalExceptionHandler {

@ExceptionHandler(value = Exception.class)

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

添加工具类UUIDUtil

package com.imooc.miaosha.util;

import java.util.UUID;

public class UUIDUtil {

public static String uuid(){

return UUID.randomUUID().toString().replace("-", "");

}

}

userservice的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);

userservice使用token获取user对象

public User getByToke(String token) {

if(StringUtils.isEmpty(token)){

return null;

}

return redisService.get(UserKey.token, token, User.class);

}

GoodsController

public SeckillUser getByToke(String token) {

if(StringUtils.isEmpty(token)){

return null;

}

return redisService.get(SeckillUserKey.token, token, SeckillUser.class);

}

四.优化

使用SpringMVC中WebMvcConfigurerAdapter的addArgumentResolvers,向需要user对象的方法进行入参注入。

新建包package com/imooc/miaosha/exception

新建类UserArgumentResolver和WebConfig

package com.imooc.miaosha.config;

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;

import java.util.List;

@Configuration

public class WebConfig extends WebMvcConfigurerAdapter {

@Autowired

private UserArgumentResolver userArgumentResolver;

@Override

public void addArgumentResolvers(List argumentResolvers) {

argumentResolvers.add(userArgumentResolver);

}

}

package com.imooc.miaosha.config;

import com.imooc.miaosha.domain.User;

import com.imooc.miaosha.service.UserService;

import org.apache.commons.lang3.StringUtils;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.core.MethodParameter;

import org.springframework.stereotype.Service;

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 javax.servlet.http.Cookie;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

@Service

public class UserArgumentResolver implements HandlerMethodArgumentResolver {

@Autowired

private UserService UserService;

@Override

public boolean supportsParameter(MethodParameter parameter) {

Class> clazz = parameter.getParameterType();

return clazz == User.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(UserService.COOKIE_TOKEN_NAME);

String cookieToken = getCookieValue(request, UserService.COOKIE_TOKEN_NAME);

if(StringUtils.isEmpty(cookieToken) && StringUtils.isEmpty(paramToken)){

return null;

}

String token = StringUtils.isEmpty(paramToken) ? cookieToken : paramToken;

return UserService.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;

}

}

优化后userservice类

package com.imooc.miaosha.service;

import com.imooc.miaosha.dao.UserDao;

import com.imooc.miaosha.domain.User;

import com.imooc.miaosha.exception.GlobalException;

import com.imooc.miaosha.redis.RedisService;

import com.imooc.miaosha.redis.UserKey;

import com.imooc.miaosha.result.CodeMsg;

import com.imooc.miaosha.util.Md5Util;

import com.imooc.miaosha.util.UUIDUtil;

import com.imooc.miaosha.vo.LoginVo;

import org.apache.commons.lang3.StringUtils;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import javax.servlet.http.Cookie;

import javax.servlet.http.HttpServletResponse;

@Service

public class UserService {

public static final String COOKIE_TOKEN_NAME = "token";

@Autowired

UserDao UserDao;

@Autowired

RedisService redisService;

public User getById(long id){

return UserDao.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();

User user = UserDao.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 User getByToke(String token, HttpServletResponse response) {

if(StringUtils.isEmpty(token)){

return null;

}

// 延长有效期

User user = redisService.get(UserKey.token, token, User.class);

if(user != null){

addCookie(token, response, user);

}

return user;

}

private void addCookie(String token, HttpServletResponse response, User user){

redisService.set(UserKey.token, token, user);

Cookie cookie = new Cookie(COOKIE_TOKEN_NAME, token);

cookie.setMaxAge(UserKey.token.expireSeconds());

cookie.setPath("/");

response.addCookie(cookie);

}

}

controller类

package com.imooc.miaosha.controller;

import com.imooc.miaosha.domain.User;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.RequestMapping;

@Controller

@RequestMapping("/goods")

public class GoodsController {

@RequestMapping("/to_list")

public String toList(Model model, User User) {

model.addAttribute("user", User);

return "goods_list";

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值