1.写一个标注
2,在需要幂等的方法上加上这个标注
3.用拦截器,拦截每一个请求,从请求中获取参数,如果带有标注则进行幂等检查,如果没有则不作
4.具体幂等检查(根据请求中的token和url来作为key,检查redis中是否存在
然后设置该key在redis中有效期,比如2秒)
代码如下
标注:
@Inherited
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SameUrlData {
}
@Component
public class SameUrlDataInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
SameUrlData annotation = method.getAnnotation(SameUrlData.class);
if (annotation != null) {
if (repeatDataValidator(request)) {
// 请求数据相同
JSONObject result = new JSONObject();
result.put("statusCode", "500");
result.put("message", "Do not submit repeatedly");
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
response.getWriter().write(result.toString());
response.getWriter().close();
return false;
}
}
}
return true;
}
/**
* 验证同一个url数据是否相同提交,相同返回true
*
* @param httpServletRequest
* @return
*/
public boolean repeatDataValidator(HttpServletRequest httpServletRequest) {
// 获取请求参数map
Map<String, String[]> parameterMap = httpServletRequest.getParameterMap();
Iterator<Map.Entry<String, String[]>> it = parameterMap.entrySet().iterator();
Map<String, String[]> parameterMapNew = new HashMap<>();
while (it.hasNext()) {
Map.Entry<String, String[]> entry = it.next();
parameterMapNew.put(entry.getKey(), entry.getValue());
}
String token = httpServletRequest.getHeader("Auth-token");
if (StringUtil.isBlank(token)) {
// 如果没有token,直接放行
return false;
}
// 过滤过后的请求内容
String params = JSONObject.toJSONString(parameterMapNew);
System.out.println("params===========" + params);
String url = httpServletRequest.getRequestURI();
Map<String, String> map = new HashMap<>();
// key为接口,value为参数
map.put(url, params);
String nowUrlParams = map.toString();
StringRedisTemplate smsRedisTemplate = SpringContextHolder.getBean(StringRedisTemplate.class);
String redisKey = token + url;
String preUrlParams = smsRedisTemplate.opsForValue().get(redisKey);
if (preUrlParams == null) {// 如果上一个数据为null,表示还没有访问页面
// 存放并且设置有效期,2秒
smsRedisTemplate.opsForValue().set(redisKey, nowUrlParams, 2, TimeUnit.SECONDS);
return false;
} else {// 否则,已经访问过页面
if (preUrlParams.equals(nowUrlParams)) {
// 如果上次url+数据和本次url+数据相同,则表示重复添加数据
return true;
} else {// 如果上次 url+数据 和本次url加数据不同,则不是重复提交
smsRedisTemplate.opsForValue().set(redisKey, nowUrlParams, 1, TimeUnit.SECONDS);
return false;
}
}
}