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

一般在前台进行处理,定义个变量,发送请求前判断变量值为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;
}
}

启动项目测试

第一次请求

第二次请求

Spring Boot (32) Lock 本地锁的更多相关文章

  1. spring boot redis分布式锁

    随着现在分布式架构越来越盛行,在很多场景下需要使用到分布式锁.分布式锁的实现有很多种,比如基于数据库. zookeeper 等,本文主要介绍使用 Redis 做分布式锁的方式,并封装成spring b ...

  2. spring boot redis分布式锁 (转)

    一. Redis 分布式锁的实现以及存在的问题 锁是针对某个资源,保证其访问的互斥性,在实际使用当中,这个资源一般是一个字符串.使用 Redis 实现锁,主要是将资源放到 Redis 当中,利用其原子 ...

  3. (32)Spring Boot使用@SpringBootApplication注解,从零开始学Spring Boot

    [来也匆匆,去也匆匆,在此留下您的脚印吧,转发点赞评论] 如果看了我之前的文章,这个节你就可以忽略了,这个是针对一些刚入门的选手存在的困惑进行写的一篇文章. 很多Spring Boot开发者总是使用 ...

  4. Intellij Idea上Spring Boot编译报错:Error:(3, 32) java: 程序包org.springframework.boot不存在

    很尴尬,为了使用Spring Boot的Initializr,特意下了个Intellij Idea,刚按提示新建一个Spring Boot的Maven项目后,就出现红叉叉了.因为IDE是新的,开始是M ...

  5. spring boot集成redis缓存

    spring boot项目中使用redis作为缓存. 先创建spring boot的maven工程,在pom.xml中添加依赖 <dependency> <groupId>or ...

  6. Spring Boot Redis 实现分布式锁,真香!!

    之前看很多人手写分布式锁,其实 Spring Boot 现在已经做的足够好了,开箱即用,支持主流的 Redis.Zookeeper 中间件,另外还支持 JDBC. 本篇栈长以 Redis 为例(这也是 ...

  7. 翻译-使用Ratpack和Spring Boot打造高性能的JVM微服务应用

    这是我为InfoQ翻译的文章,原文地址:Build High Performance JVM Microservices with Ratpack & Spring Boot,InfoQ上的中 ...

  8. Spring boot 基于Spring MVC的Web应用和REST服务开发

    Spring Boot利用JavaConfig配置模式以及"约定优于配置"理念,极大简化了基于Spring MVC的Web应用和REST服务开发. Servlet: package ...

  9. Spring Boot中使用Swagger2构建强大的RESTful API文档

    由于Spring Boot能够快速开发.便捷部署等特性,相信有很大一部分Spring Boot的用户会用来构建RESTful API.而我们构建RESTful API的目的通常都是由于多终端的原因,这 ...

随机推荐

  1. zoj——3195 Design the city

    Design the city Time Limit: 1 Second      Memory Limit: 32768 KB Cerror is the mayor of city HangZho ...

  2. 何为幻读?MySQL又是如何解决幻读的?

    一.什么是幻读 在一次事务里面,多次查询之后,查询的结果集的个数不一致的情况叫做幻读.而多出来或者少的哪一行被叫做 幻行 二.为什么要解决幻读 在高并发数据库系统中,需要保证事务与事务之间的隔离性,还 ...

  3. Win7 文件加密存储操作后,如何在事后备份证书、秘钥

    这个密钥的特点是只有在此系统下用此账户才可以修改,即便是你用此账户设置加密后删除此账户再重新建一个同名的账户依然无法修改.而且此密钥无法破解.所以一旦加密后,重装系统或者更换账户就无法修改了.唯一的办 ...

  4. DELPHI异步选择模型UDP

    unit U_FrmServer; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Di ...

  5. Lua迭代器

    在Lua中我们常常使用函数来描述迭代器,每次调用该函数就返回集合的下一个元素.迭代器需要保留上一次成功调用的状态和下一次成功调用的状态,可以通过闭包提供的机制来实现这个任务(闭包中的外部局部变量可以用 ...

  6. formData 对象

    (1)创建的formData打印为空? var edition=$("#edinum").val();//版本号 var uploader=$("#upman" ...

  7. HTML5: 本地缓存

    实现前端缓存,除了自己创建js保存(參考:http://blog.csdn.net/clementad/article/details/46807641).还能够利用html5的storage方法. ...

  8. node+express+mysql小例子

    连接:https://www.cnblogs.com/humaotegong/p/5671009.html https://www.cnblogs.com/mibear/p/nodejs.html?u ...

  9. 怎样在win8系统下建立wifi热点

     2012年10月26日,微软正式推出Windows 8操作系统,不少用户也都升级到了最新的Win8.大家知道.在Win7系统下,我们非常方便的就在命令提示符下建立了WIFI热点.那么Win8上是 ...

  10. HDU3367 Pseudoforest 【并查集】+【贪心】

    Pseudoforest Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) To ...