目录
1.背景
2.思路
3.实现
创建自定义注解
编写拦截器
4.使用
5.验证
6.总结
1.背景
在进行添加操作时,防止恶意点击,后端进行请求接口的防重复提交
2.思路
通过拦截器搭配自定义注解的方式进行实现,拦截器拦截请求,使用注解的方式可以提高复用性和灵活性。
3.实现
创建自定义注解
package com.zsp.quartz.Interceptor;
import java.lang.annotation.*;/*** 自定义注解防止表单重复提交*/
@Inherited //可以被继承
@Target(ElementType.METHOD) // 使用范围
@Retention(RetentionPolicy.RUNTIME)
// RetentionPolicy.RUNTIME表示注解在编译时和运行时都保留
// 可以通过反射机制在运行时访问和处理注解
@Documented
public @interface RepeatSubmit {}
重要:@Retention,因为要在拦截器那里通过反射机制对添加了该注解的方法进行处理。
编写拦截器
package com.zsp.quartz.Interceptor;//怎么拦截import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zsp.quartz.util.jwtUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;public class MyInterceptor implements HandlerInterceptor {private final Map<String, String> lastRequestMap = new HashMap<>();@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {Map<String,Object> map=new HashMap<>();// 防重复提交if (handler instanceof HandlerMethod) {HandlerMethod handlerMethod = (HandlerMethod) handler;Method method = handlerMethod.getMethod();// method.getAnnotation:获取指定方法上的指定注解 annotationClass.它返回一个注解对象,如果该方法上不存在指定的注解,则返回 null。RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);if (annotation != null) {String key = request.getRequestURI();String lastRequestKey = lastRequestMap.get(handlerMethod.getMethod().getName());if (lastRequestKey != null && lastRequestKey.equals(key)) {map.put("state",false);//设置状态map.put("code",201);map.put("msg","请勿重复提交表单!");String json = new ObjectMapper().writeValueAsString(map);response.setContentType("application/json;charset=UTF-8");response.getWriter().println(json);return false;}lastRequestMap.put(handlerMethod.getMethod().getName(), key);}return true;//放行请求}return false;}
}
4.使用
直接在方法上加自定义注解
@RepeatSubmit@PostMapping("/test")public String login() {return "你好啊,doPost方法";}
5.验证
第一次点击
第二次点击
6.总结
在这里只做实现思路,用了Map<key,value> 来判断。
在实际开发中通过存入redis,并设置过期时间来判断是否重复提交。
以下是简单举例。
String nowParams = "前端传的value";String url = request.getRequestURI();String cacheKey = String.format("自己的key,可以是随机数", url);String preParams = redisTemplate.opsForValue().get(cacheKey).toString();if (preParams == null || "".equals(preParams)){//用户提交参数缓存10秒redisTemplate.opsForValue().set(cacheKey, nowParams, 10, TimeUnit.SECONDS);return false;}if (compareParams(nowParams, preParams)) {return true;}//用户提交参数缓存10秒redisTemplate.opsForValue().set(cacheKey, nowParams, 10, TimeUnit.SECONDS);return false;/*** 判断参数是否相同*/private boolean compareParams(String nowParams, String preParams) {return nowParams.equals(preParams);}