Spring Boot (32) Lock 本地锁
2024-08-30 20:27:50
平时开发中,有时会双击提交表单造成重复提交,或者网速比较慢时还没有响应又点击了按钮,我们在开发中必须防止重复提交
一般在前台进行处理,定义个变量,发送请求前判断变量值为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;
}
}
启动项目测试
第一次请求
第二次请求
最新文章
- 关于label的点击事件(原创)
- Migrating an Existing Website from SQL Membership to ASP.NET Identity
- Spring IoC源码解读——谈谈bean的几种状态
- 【C语言】C语言关键字
- AngularJS Best Practices: ngRoute
- (转)QML代码与现有Qt UI代码整合
- windows 程序设计自学:添加字符串资源
- [AHOI2013]找硬币(搜索)
- HOOK API(四)—— 进程防终止
- Win7+vs2010下安装boost_1_46_1库
- 限制EditText的输入字数
- poi合并单元格同时导出excel
- [USACO15JAN]电影移动Moovie Mooving
- HTML5 开发APP
- Map的遍历方法(java)
- 97、爬虫框架scrapy
- cache2go - cachetable源码分析
- 【Java每日一题】20170321
- 对HUAWEI-ManagedProvisioning的一次不完整分析
- Windows系统的消息机制
热门文章
- POJ 3169_Layout
- Hdoj 3697 Selecting courses 【贪心】
- 关于使用Xshell远程连接启动tomcat导致图片不显示,报错Could not initialize class sun.awt.X11GraphicsEnvironment解决方案
- java多线程之 ---- 线程死锁
- 关于hive
- hdoj--5526--欧拉回路(欧拉回路)
- 【POJ 1679】 The Unique MST
- HDU2138 素数判定
- 频繁项集------->;产生强关联规则的过程
- 28. extjs中Ext.BLANK_IMAGE_URL的作用