Part1.AOP切面
@Aspect
@Component
@Log
public class NoRepeatSubmitAspect {
@Value("${submitCode.header}")
private String submitCodeHeader;
@Autowired
private RedisService redisService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
private HttpServletRequest request;
@Pointcut("execution(* com..*.controller.*(..))")
public void noRepeatSubmitPointcut() {
}
@Before("noRepeatSubmitPointcut()")
public void submitBefore(JoinPoint point) {
//用户身份的唯一标识,也可以用session来做到这个
String token = jwtTokenUtil.getToken(request);
String method = request.getMethod();
/*防止重复提交请求前提是用户属于登录状况,且不是Get和DELETE类型的方法*/
if (token != null&&!"GET".equals(method)&&!"DELETE".equals(method)) {
/*构建查询重复提交的key值*/
String servletPath = request.getServletPath();
final String submitCode = submitCodeHeader+"-"+token + "-" + servletPath;
/*
//不处理参数不重复的情况,在限定时间内重复发送该请求都判定为重复提交
boolean exist = redisService.isExist(submitCode);
if (!exist) {
redisService.saveSubmitStatus(submitCode);
}else{
throw new RepeatSubmitException(servletPath);
}*/
/*处理并发*/
synchronized(this){
/*获取所有传入参数*/
String submitParam = JSON.toJSONString(point.getArgs());
/*获取存储的参数*/
Optional<String> storeSubmitParamOpt = redisService.getSubmitParams(submitCode);
if (storeSubmitParamOpt.isPresent()) {
if (submitParam.equals(storeSubmitParamOpt.get())) {
/*传入参数与之前请求携带的参数一致判定为相同请求*/
throw new RepeatSubmitException(servletPath);
}else{
/*参数不一致判定为不同请求*/
redisService.saveSubmitStatus(submitCode,submitParam);
}
}else{
/*新请求*/
redisService.saveSubmitStatus(submitCode,submitParam);
}
}
}
}
}
Part2.redis存储请求参数
@Value("${submitCode.expiration}")
private Long submitExpiration;
@Override
public void saveSubmitStatus(String submitCode, String submitParam) {
redisTemplate.opsForValue().set(submitCode,submitParam,submitExpiration,TimeUnit.SECONDS);
}
@Override
public Optional<String> getSubmitParams(String submitCode) {
return Optional.ofNullable((String) redisTemplate.opsForValue().get(submitCode));
}
Part3.在application.yml配置
submitCode.header
submitCode.expiration
Part4.RepeatSubmitException为自定义异常,最后可用@ExceptionHandler做一个全局的处理
原创文章,转载请注明出处:https://www.jianshu.com/p/ab486fb5be47
网友评论