Java 限制重复请求
杰拉德·皮克·谢 人气:0背景及用途
前端页面出现卡顿,用户反复点击操作按钮,导致后台接口短时间内多次提交
实现步骤
设置切面,增加注解,导致在规定时间内该接口不可重复调用
设置一个接口 NoRepeatSubmit
import java.lang.annotation.*; /** * xzj_2022_8_2 * 重复请求限制切面 */ @Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上 @Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行 @Documented //生成文档 public @interface NoRepeatSubmit { String name() default "name:"; }
实现类
import java.lang.annotation.*; /** * xzj_2022_8_2 * 重复请求限制切面 */ @Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上 @Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行 @Documented //生成文档 public @interface NoRepeatSubmit { String name() default "name:"; }
使用
@GetMapping(value = "/test") @NoRepeatSubmit public void test() { System.out.println("test"); }
补充:下面看下java防止前端重复提交
JAVA利用自定义本地锁解决重复提交的问题
1.引入jar包
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>31.1-jre</version> </dependency>
2.自定义本地锁
package com.hzt.listener; import java.lang.annotation.*; /** * 自定义-控制重复提交锁 */ @Target(ElementType.METHOD) //作用于方法 @Retention(RetentionPolicy.RUNTIME) //运行时有效 @Documented @Inherited public @interface LocalLock { String key() default ""; }
3.自定义注解切面 (aop拦截器实现)
import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Configuration; import java.util.concurrent.TimeUnit; /** * @Desc: 自定义注解拦截器 * @Author: zmk * @Date: 2022/4/2 */ @Aspect @Configuration public class LockMethodInterceptor { private final Logger log = LoggerFactory.getLogger(LockMethodInterceptor.class); private static final Cache<String, Object> CACHES = CacheBuilder.newBuilder() //最大缓存数 .maximumSize(1000) //设置过期时间 .expireAfterWrite(3, TimeUnit.SECONDS) .build(); @Around(value = "@annotation(localLock)") public Object interceptor (ProceedingJoinPoint point, LocalLock localLock) { //localLock.key() 这个是获取controller的key属性, point.getArgs()获取key的值 String key = getKey(localLock.key(), point.getArgs()); if (StringUtils.isNotBlank(key)) { if (CACHES.getIfPresent(key) != null) { throw new RuntimeException("请勿重复提交"); } //如果是第一次请求, 将key放入缓存 CACHES.put(key, key); } try { return point.proceed(); } catch (Throwable throwable) { throw new RuntimeException("服务器异常"); } finally { //标记为无效 // CACHES.invalidate(key); } } /** * * key 生成策略 * @param key key表达式 * @param args 参数 * @return 生成的key */ private String getKey(String key, Object[] args) { for (int i = 0; i < args.length; i++) { key = key.replace("arg[" + i + "]", args[i].toString()); } return key; }
4.定义controller接口
@GetMapping("/query") @LocalLock(key = "param:arg[0]") public String query (@RequestParam("abc") String abc) { return "ok"; }
第一次调用结果:
第二次调用结果:
加载全部内容