防重复提交:自定义注解 + 拦截器(HandlerInterceptor)
一、思路:
1、首先自定义注解;
2、创建拦截器实现类(自定义类名称),拦截器(HandlerInterceptor);
3、创建类:配置拦截器路径(拦截URL规则);
二、代码示例:
1、首先自定义注解;
import java.lang.annotation.*;/*** @ClassName Resubmit* @Descripition 自定义注解-防重复提交* @Author * @Date 2023/8/31 10:38*/ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE, ElementType.METHOD}) public @interface Resubmit {/*** 默认过期时间* 单位:秒** @return*/int value() default 100;/*** 频繁请求提示语** @return*/String messge() default "请求过于频繁,请稍后再试!";}
2、创建拦截器实现类(自定义类名称),拦截器(HandlerInterceptor);
import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.IOException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map;/*** @ClassName ResubmitInterceptorUtil* @Descripition 防重复提拦截器工具类* @Author * @Date 2023/8/31 10:52*/ @Slf4j @Component public class ResubmitInterceptorUtil implements HandlerInterceptor {// key: 固定前缀private static final String FIXED_SESSION = "repeatData";@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {try {if (handler instanceof HandlerMethod) {HandlerMethod handlerMethod = (HandlerMethod) handler;// 请求方法Method method = handlerMethod.getMethod();// 获取自定义注解-防重复注解(@Resubmit)Resubmit annotation = method.getAnnotation(Resubmit.class);// 判断方法是否添加自定义注解(@Resubmit)if (annotation != null) {//如果重复相同数据if (repeatDataValidator(request)) {// 自定义返回结果类Result result = new Result();result.setCode(500);result.setMessage(annotation.messge());// 设置字符集编码response.setCharacterEncoding("UTF-8");// response.getWriter().write(JSON.toJSONString("请勿频繁提交请求,稍后再试."));response.getWriter().write(JSON.toJSONString(result));return false;} else {return true;}}return true;} else {return true;}} catch (IOException e) {log.error("防重复提拦截器工具类异常", e);return false;}}/*** 验证同一个url数据是否相同提交,相同返回true** @param request* @return*/private boolean repeatDataValidator(HttpServletRequest request) {// 获取POST请求体-body-入参String params = getRequestBodyParam(request);// 获取请求路径String url = request.getRequestURI();Map<String, String> map = new HashMap<>();// 组装Map key: url、 value:url+请求方法体+时间map.put(url, params);String nowUrlParams = JSON.toJSONString(map);Object preUrlParams = request.getSession().getAttribute(FIXED_SESSION);//如果上一个数据为null,表示还没有访问页面if (preUrlParams == null) {//如果上一个数据为null,表示还没有访问页面request.getSession().setAttribute(FIXED_SESSION, nowUrlParams);return false;} else {//如果上次url+数据和本次url+数据相同,则表示重复添加数据if (preUrlParams.equals(nowUrlParams)) {log.info("[请求频繁提交 repeatDataValidator URL :{}; param :{}]", url, params);return true;} else {//如果上次 url+数据 和本次url加数据不同,则不是重复提交request.getSession().setAttribute(FIXED_SESSION, nowUrlParams);return false;}}}/*** 获取请求体-body-入参** @param request* @return*/private String getRequestBodyParam(HttpServletRequest request) {BufferedReader bufferedReader = null;StringBuffer stringBuffer = new StringBuffer();try {bufferedReader = request.getReader();String str = null;while ((str = bufferedReader.readLine()) != null) {stringBuffer.append(str);}bufferedReader.close();} catch (IOException e) {log.error("解析入参异常!!!", e);} finally {if (bufferedReader != null) {try {bufferedReader.close();} catch (IOException e) {log.error("解析入参异常!!!", e);}}}return stringBuffer.toString();} }
3、创建类:配置拦截器路径(拦截URL规则);
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** @ClassName WebMvcConfig* @Descripition 配置拦截路径* @Author * @Date 2023/9/1 10:08*/ @Configuration public class WebMvcConfig implements WebMvcConfigurer {@Autowiredprivate ResubmitInterceptorUtil resubmitInterceptorUtil;@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 配置拦截类registry.addInterceptor(resubmitInterceptorUtil)// 设置拦截路径URL.addPathPatterns("/**");}}