Spring Boot如何防止重复提交
作者:谈胖胖 时间:2021-11-10 16:23:42
场景:同一个用户在2秒内对同一URL的提交视为重复提交。
思考逻辑:
1.从数据库方面考虑,数据设计的时候,某些数据有没有唯一性,如果有唯一性,要考虑设置唯一索引,可以避免脏数据。
2.从应用层面考虑,首先判断是单机服务还是分布式服务,则此时需要考虑一些缓存,利用缓存,来保证数据的重复提交。
假设是分布式应用,则可以将用户的信息,例如token和请求的url进行组装在一起,存储到缓存存,例如redis,并设置超时时间为2秒,如此来保证数据的唯一性。
以下是代码实现:
Application.java
package com;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author www.spring.tsh
* @功能描述 防重复提交
* @date 2018-08-26
*/
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
application.yml
spring:
redis:
host: 127.0.0.1
port: 6379
password: 123456
RedisConfig.java
package com.common;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
@Configuration
public class RedisConfig {
@Bean
@ConfigurationProperties(prefix = "spring.redis")
public JedisConnectionFactory getConnectionFactory() {
return new JedisConnectionFactory(new RedisStandaloneConfiguration(), JedisClientConfiguration.builder().build());
}
@Bean
<K, V> RedisTemplate<K, V> getRedisTemplate() {
RedisTemplate<K, V> redisTemplate = new RedisTemplate<K, V>();
redisTemplate.setConnectionFactory(getConnectionFactory());
return redisTemplate;
}
}
自定义注解NoRepeatSubmit.java
package com.common;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD) // 作用到方法上
@Retention(RetentionPolicy.RUNTIME) // 运行时有效
/**
* @功能描述 防止重复提交标记注解
* @author www.srping.tsh
* @date 2018-08-26
*/
public @interface NoRepeatSubmit {
}
aop解析注解NoRepeatSubmitAop.java
package com.common;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@Aspect
@Component
/**
* @功能描述 aop解析注解
* @author www.gaozz.club
* @date 2018-11-02
*/
public class NoRepeatSubmitAop {
private Log logger = LogFactory.getLog(getClass());
@Autowired
private RedisTemplate<String, Integer> template;
@Around("execution(* com.example..*Controller.*(..)) && @annotation(nrs)")
public Object arround(ProceedingJoinPoint pjp, NoRepeatSubmit nrs) {
ValueOperations<String, Integer> opsForValue = template.opsForValue();
try {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
String sessionId = RequestContextHolder.getRequestAttributes().getSessionId();
HttpServletRequest request = attributes.getRequest();
String key = sessionId + "-" + request.getServletPath();
if (opsForValue.get(key) == null) {// 如果缓存中有这个url视为重复提交
Object o = pjp.proceed();
opsForValue.set(key, 0, 2, TimeUnit.SECONDS);
return o;
} else {
logger.error("重复提交");
return null;
}
} catch (Throwable e) {
e.printStackTrace();
logger.error("验证重复提交时出现未知异常!");
return "{\"code\":-889,\"message\":\"验证重复提交时出现未知异常!\"}";
}
}
}
测试类:
package com.example;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.common.NoRepeatSubmit;
/**
* @功能描述 测试Controller
* @author www.spring.tsh
* @date 2018-08-26
*/
@RestController
public class TestController {
@RequestMapping("/test")
@NoRepeatSubmit
public String test() {
return ("程序逻辑返回");
}
}
来源:https://blog.csdn.net/zhuyanlin09/article/details/91626111
标签:Spring,Boot,重复提交
![](/images/zang.png)
![](/images/jiucuo.png)
猜你喜欢
Java实现发送手机短信语音验证功能代码实例
2023-04-04 19:03:31
深入探讨C#中的const、readonly关键字
2023-01-20 23:42:25
![](https://img.aspxhome.com/file/2023/5/80105_0s.png)
c#的时间日期操作示例分享(c#获取当前日期)
2021-07-09 15:44:35
面试官:Java中new Object()到底占用几个字节
2022-02-09 19:04:00
![](https://img.aspxhome.com/file/2023/9/75519_0s.png)
WPF InkCanvas基本操作方法详解
2023-07-29 06:26:59
![](https://img.aspxhome.com/file/2023/1/70441_0s.gif)
Java基础教程之static五大应用场景
2023-11-11 05:10:43
C# 定时器定时更新的简单实例
2023-01-08 12:45:50
java数据结构之希尔排序
2023-11-08 18:16:18
JAVA MyBatis入门学习过程记录
2022-04-23 13:49:24
java对ArrayList排序代码示例
2023-11-24 20:14:21
简单探索 Java 中的惰性计算
2023-11-16 20:25:28
C#中using的三种用法
2022-08-04 05:10:59
C#中方法的详细介绍
2023-08-06 12:31:21
SpringBoot的DeferredResult案例:DeferredResult的超时处理方式
2023-08-09 14:00:58
![](https://img.aspxhome.com/file/2023/6/68226_0s.jpg)
Java毕业设计实战之二手书商城系统的实现
2022-03-21 14:06:20
![](https://img.aspxhome.com/file/2023/4/72524_0s.jpg)
详解Lombok安装及Spring Boot集成Lombok
2023-11-28 23:39:55
![](https://img.aspxhome.com/file/2023/9/60369_0s.png)
JavaWeb中获取表单数据及乱码问题的解决方法
2021-11-21 11:03:53
![](https://img.aspxhome.com/file/2023/3/69673_0s.png)
C#深拷贝方法探究及性能比较(多种深拷贝)
2022-08-30 18:17:02
![](https://img.aspxhome.com/file/2023/5/77235_0s.png)
Mybatis-Plus支持GBase8s分页查询的实现示例
2021-11-21 14:33:30
![](https://img.aspxhome.com/file/2023/1/65351_0s.png)
详解C#借助.NET框架中的XmlTextReader类读取XML的方法
2023-01-18 23:31:47
![](https://img.aspxhome.com/file/2023/8/75578_0s.jpg)