这篇文章主要介绍Spring Boot如何防止重复提交,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!
场景:同一个用户在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 ("程序逻辑返回");
}
}
以上是“Spring Boot如何防止重复提交”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注亿速云行业资讯频道!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。