1、什么是幂等
幂等:F(F(x))=F(x) 多次运行结果相同
常见幂等
select查询天然幂等
delete删除也是幂等,删除同一个多次效果一样
update直接更新某个值的幂等
update更新累加操作的,非幂等
insert非幂等操作,每次新增一条
2、解决思路
利用拦截器统一处理请求,利用 token的唯一性和请求url 确定是否是相同请求,再放入缓存里面。
package com.medrd.interceptor;
import com.medrd.utils.InterceptorJsonUtils;
import com.medrd.utils.MD5Util;
import com.medrd.utils.RedisUtils;
import lombok.extern.log4j.Log4j2;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import static com.medrd.entity.enums.ChronicConstants.ChronicRedisPrefix.RIH_AUTH_FORM_USER;
/**
* 自定义web 拦截器 表单重复
*
* @author czq
*/
@Slf4j
@Log4j2
@Configuration
public class FormRequestInterceptor implements HandlerInterceptor {
@Autowired
private RedisUtils redisUtils;
/**
* 拦截获取jtoken 和 url验证重复提交
*
* @param request
* @param response
* @param handler
* @return
* @throws Exception
* @author czq
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String jtoken = request.getHeader("jtoken");
String key = "" + jtoken + "-" + request.getServletPath();
String method = request.getMethod();
//放开get和delete请求
if ("GET".equals(method)||"DELETE".equals(method)) {
return true;
}
log.debug("key{}", key);
if (StringUtils.isBlank(key)) {
log.debug("非法请求,key为空");
InterceptorJsonUtils.printJson(response, "400", "非法请求,key为空");
return false;
}
String keyMd5 = MD5Util.encode(key);
if (redisUtils.hasKey(RIH_AUTH_FORM_USER.getValue() + keyMd5)) {
log.debug("表单重复提交");
InterceptorJsonUtils.printJson(response, "400", "表单重复提交");
return false;
}
boolean flag = redisUtils.set(RIH_AUTH_FORM_USER.getValue() + keyMd5, key, 5);
if (flag) {
return true;
} else {
InterceptorJsonUtils.printJson(response, "400", "Redis错误");
return false;
}
}
}
返回参数类
package com.medrd.utils;
import com.medrd.entity.common.RestResult;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
/**
* 拦截器中自定返回参数
* @param
* @author
*/
@Slf4j
public class InterceptorJsonUtils {
/**
* 返回自定参数
*
* @param r HttpServletResponse
* @param code 状态码
* 2020-05-06 17:14
*/
public static void printJson(HttpServletResponse r, String code, String msg) {
r.setCharacterEncoding("UTF-8");
r.setContentType("text/html; charset=utf-8");
RestResult result = new RestResult();
PrintWriter printWriter = null;
try {
result.setCode(code);
result.setMsg(msg);
printWriter = r.getWriter();
printWriter.print(JsonHelper.serialize(result));
} catch (Exception e) {
log.info("========拦截输出失败=======");
} finally {
if (printWriter != null) {
printWriter.close();
}
}
}
public static void printJson(HttpServletResponse r, String code) {
printJson(r, code, "");
}
}