平时开发中,有时会双击提交表单造成重复提交,或者网速比较慢时还没有响应又点击了按钮,我们在开发中必须防止重复提交

一般在前台进行处理,定义个变量,发送请求前判断变量值为true,然后把变量设置为false,可以防止重复提交问题。如果前台没有做这个控制那就需要后端来处理

Lock 注解

  创建一个LocalLock注解,简单一个key就行了,由于暂时还未用到redis所以expire是摆设

import java.lang.annotation.*;

//作用于方法
@Target(ElementType.METHOD)
//整个运行阶段都可见
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface LocalLock {
String key() default ""; /**
* 过期时间 由于用的guava 暂时就忽略这个属性 集成redis时需要用到
*/
int expire() default 5;
}

Lock拦截器(AOP)

  首先通过CacheBuilder.newBuilder()构建出缓存对象,然后设置好过期时间,目的是为了防止因程序崩溃得不到释放。

在uti的interceptor()方法上采用的十Around(环绕增强),所有带LocalLock注解的都将被切面处理,如果想更为灵活,key的生成规则可以定义成接口形式。

package com.spring.boot.utils;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Configuration;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder; import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit; @Aspect
@Configuration
public class LockMethodInterceptor {
//本地缓存
private static final Cache<String, Object> CACHES = CacheBuilder.newBuilder()
//最大1000个
.maximumSize(1000)
//设置写缓存后5秒钟过期
.expireAfterAccess(5, TimeUnit.SECONDS)
.build(); @Around("execution(public * *(..)) && @annotation(com.spring.boot.utils.LocalLock)")
public Object interceptor(ProceedingJoinPoint pjp) {
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
LocalLock localLock = method.getAnnotation(LocalLock.class);
String key = getKey(localLock.key(), pjp.getArgs());
if (key != null || key != "") {
if (CACHES.getIfPresent(key) != null) {
throw new RuntimeException("请勿重复请求");
}
// 如果是第一次请求,就将 key 当前对象压入缓存中
CACHES.put(key, key);
}
try {
return pjp.proceed();
} catch (Throwable throwable) {
throw new RuntimeException("服务器异常");
} finally {
//CACHES.invalidate(key); 完成后移除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;
}
}

控制层

  在接口上添加@LocalLock(key = "book:arg[0]"); 意味着会将arg[0]替换成第一个参数的值,生成后的新key将被缓存起来;

package com.spring.boot.controller;

import com.spring.boot.utils.LocalLock;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; @RestController
@RequestMapping("/books")
public class BookController {
@LocalLock(key="book:arg[0]")
@GetMapping
public String query(@RequestParam String token){
return "success - " + token;
}
}

启动项目测试

第一次请求

第二次请求

最新文章

  1. 关于label的点击事件(原创)
  2. Migrating an Existing Website from SQL Membership to ASP.NET Identity
  3. Spring IoC源码解读——谈谈bean的几种状态
  4. 【C语言】C语言关键字
  5. AngularJS Best Practices: ngRoute
  6. (转)QML代码与现有Qt UI代码整合
  7. windows 程序设计自学:添加字符串资源
  8. [AHOI2013]找硬币(搜索)
  9. HOOK API(四)—— 进程防终止
  10. Win7+vs2010下安装boost_1_46_1库
  11. 限制EditText的输入字数
  12. poi合并单元格同时导出excel
  13. [USACO15JAN]电影移动Moovie Mooving
  14. HTML5 开发APP
  15. Map的遍历方法(java)
  16. 97、爬虫框架scrapy
  17. cache2go - cachetable源码分析
  18. 【Java每日一题】20170321
  19. 对HUAWEI-ManagedProvisioning的一次不完整分析
  20. Windows系统的消息机制

热门文章

  1. POJ 3169_Layout
  2. Hdoj 3697 Selecting courses 【贪心】
  3. 关于使用Xshell远程连接启动tomcat导致图片不显示,报错Could not initialize class sun.awt.X11GraphicsEnvironment解决方案
  4. java多线程之 ---- 线程死锁
  5. 关于hive
  6. hdoj--5526--欧拉回路(欧拉回路)
  7. 【POJ 1679】 The Unique MST
  8. HDU2138 素数判定
  9. 频繁项集-------&gt;产生强关联规则的过程
  10. 28. extjs中Ext.BLANK_IMAGE_URL的作用