SpringBoot防止重复请求,重复表单提交超级简单的注解实现
1. 注解接口
/**
* @description 防止表单重复提交注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface DuplicateSubmitToken {
//保存重复提交标记 默认为需要保存
boolean save() default true;
}
2. 定义异常类
/**
* 重复提交异常
*/
public class DuplicateSubmitException extends RuntimeException {
public DuplicateSubmitException(String msg) {
super(msg);
}
public DuplicateSubmitException(String msg, Throwable cause){
super(msg,cause);
}
}
3. 拦截器
/**
* @description 防止表单重复提交拦截器
*/
@Aspect
@Component
@Slf4j
public class DuplicateSubmitAspect {
public static final String DUPLICATE_TOKEN_KEY="duplicate_token_key";
@Pointcut("execution(public * cn.test.core.controller..*(..))")
public void webLog() {
}
@Before("webLog() && @annotation(token)")
public void before(final JoinPoint joinPoint, DuplicateSubmitToken token){
if (token!=null){
Object[]args=joinPoint.getArgs();
HttpServletRequest request=null;
HttpServletResponse response=null;
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof HttpServletRequest){
request= (HttpServletRequest) args[i];
}
if (args[i] instanceof HttpServletResponse){
response= (HttpServletResponse) args[i];
}
}
boolean isSaveSession=token.save();
if (isSaveSession){
String key = getDuplicateTokenKey(joinPoint);
Object t = request.getSession().getAttribute(key);
if (null==t){
String uuid= UUID.randomUUID().toString();
request.getSession().setAttribute(key.toString(),uuid);
log.info("token-key="+key);
log.info("token-value="+uuid.toString());
}else {
throw new DuplicateSubmitException(TextConstants.REQUEST_REPEAT);
}
}
}
}
/**
* 获取重复提交key-->duplicate_token_key+','+请求方法名
* @param joinPoint
* @return
*/
public String getDuplicateTokenKey(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
StringBuilder key=new StringBuilder(DUPLICATE_TOKEN_KEY);
key.append(",").append(methodName);
return key.toString();
}
@AfterReturning("webLog() && @annotation(token)")
public void doAfterReturning(JoinPoint joinPoint,DuplicateSubmitToken token) {
// 处理完请求,返回内容
log.info("出来方法:");
if (token!=null){
Object[]args=joinPoint.getArgs();
HttpServletRequest request=null;
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof HttpServletRequest){
request= (HttpServletRequest) args[i];
}
}
boolean isSaveSession=token.save();
if (isSaveSession){
String key = getDuplicateTokenKey(joinPoint);
Object t = request.getSession().getAttribute(key);
if (null!=t){
//方法执行完毕移除请求重复标记
request.getSession(false).removeAttribute(key);
log.info("方法执行完毕移除请求重复标记!");
}
}
}
}
/**
* 异常
* @param joinPoint
* @param e
*/
@AfterThrowing(pointcut = "webLog()&& @annotation(token)", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Throwable e, DuplicateSubmitToken token) {
if (null!=token
&& e instanceof DuplicateSubmitException==false){
//处理处理重复提交本身之外的异常
Object[]args=joinPoint.getArgs();
HttpServletRequest request=null;
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof HttpServletRequest){
request= (HttpServletRequest) args[i];
}
}
boolean isSaveSession=token.save();
//获得方法名称
if (isSaveSession){
String key=getDuplicateTokenKey(joinPoint);
Object t = request.getSession().getAttribute(key);
if (null!=t){
//方法执行完毕移除请求重复标记
request.getSession(false).removeAttribute(key);
log.info("异常情况--移除请求重复标记!");
}
}
}
}
}
4. 控制器 使用方法:在你想要避免重复提交的控制器方法添加注解@DuplicateSubmitToken即可
/**
* @description
*/
@RestController
public class TestController {
@RequestMapping(value = "/test", method = RequestMethod.GET)
public Map<String, Object> firstResp (HttpServletRequest request){
Map<String, Object> map = new HashMap<>();
request.getSession().setAttribute("request Url", request.getRequestURL());
map.put("request Url", request.getRequestURL());
return map;
}
@DuplicateSubmitToken
@RequestMapping(value = "/test/d", method = RequestMethod.GET)
public Map<String, Object> test (HttpServletRequest request){
Random r=new Random();
int i = r.nextInt(3);
if (i==2){
throw new CustomException("有异常");
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Map<String, Object> map = new HashMap<>();
request.getSession().setAttribute("request Url", request.getRequestURL());
map.put("request Url", request.getRequestURL());
return map;
}
}
5. 测试略过。。。
SpringBoot防止重复请求,重复表单提交超级简单的注解实现的更多相关文章
- java post请求的表单提交和json提交简单小结
在java实现http请求时有分为多种参数的传递方式,以下给出通过form表单提交和json提交的参数传递方式: public String POST_FORM(String url, Map< ...
- node07---post请求、表单提交、文件上传
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- VUE中关于表单提交的简单实现
main.js import Vue from "../vue.js"; import App from "./App.js"; //启动 new Vue({ ...
- HTML 表单提交 的简单代码
<form action="check.php" method="post"> 用户名:<input type="text" ...
- layui表单提交
关于layui表单提交 只是简单用一个文本框记录一下提交过程 其他的如下拉框选择框样式可以参考官网 下面直接开始.首 一:前台页面 <!DOCTYPE html><html& ...
- php+mysql 除了设置主键防止表单提交内容重复外的另一种方法
感觉好久没有更新博客了,一直在做网站及后台,也没有遇到让我觉得可以整理的内容,之前做的一个系统,已经完成了,后来客户又要求加一个功能,大概就是表单提交的时候,约束有一项不能和以前的内容重复,如图 比如 ...
- JavaWeb -- Struts2,对比, 简单表单提交,校验,防重复提交, 文件上传
Struts2核心流程图 1. Struts2 和 Struts1 对比 struts1:基于Servlet(ActionServlet),actionForm众多(类的爆炸),action单例(数据 ...
- Jquery 实现表单提交按钮变灰,防止多次点击提交重复数据
表单提交时候我们应该控制提交按钮,不能点击多次进行数据的重复提交.要不然就会有冗余的重复的数据在系统中,造成系统出现数据垃圾.jQuery很简单的就可以实现对表单提交按钮控制,下面就是相关的例子和代码 ...
- <input type="image">表单提交2次 重复插入数据问题
写一个表单提交用到图片:两种代码. <input type="image" src="xxx.gif"onclick="return dosub ...
随机推荐
- Java类初始化顺序,大神3个示例带你躺坑。。
最近发现微信群里面有些群友在讨论类的初始化顺序,如类的静态变量.成员变量.静态代码块.非静态代码块.构造器,及继承父类时,它们的初始化顺序都是怎样的,下面我通过例子来说明这个情况,以免被人误导. 示例 ...
- vt-is-UTF8 - check whether current VT is in UTF8- or byte-mode. 检查当前VT是否处于VTF8模式或是字节模式.
总览 vt-is-UTF8 [-h|--help] [-V|--version] [-q|--quiet] 描述 vt-is-UTF8 checks whether the current VT is ...
- Windows的ODBC配置指南: MySQL, PostgreSQL, DB2, Oracle
MySQL- 官网: https://dev.mysql.com/downloads/connector/odbc/- 安装: * msi格式, 直接安装即可 * zip格式, 解压缩, 命令行(管理 ...
- c 语言函数分析
第一个参数为指向线程标识符的指针. 第二个参数用来设置线程属性. 第三个参数是线程运行函数的起始地址. 最后一个参数是运行函数的参数. result = pthread_create(&tid ...
- thinkphp模块设计
3.2发布版本自带了一个应用目录结构,并且带了一个默认的应用入口文件,方便部署和测试,默认的应用目录是Application(实际部署过程中可以随意设置). 通常情况下3.2无需使用多应用模式,因为大 ...
- 数位dp——牛客多校H
/* x[1,A] y[1,B] x^y<C 或 x&y>C 把ABC拆成二进制后按位进行数位dp dp[pos][s1][s2][f1][f2] 表示从高到低第pos位,条件一状 ...
- Delphi2007中正确调用SetWindowLong隐藏程序任务栏图标
http://terony.blog.sohu.com/71347192.html Delphi2007中正确调用SetWindowLong隐藏程序任务栏图标 标签: Delphi2007 SetW ...
- JS对象的可枚举属性和不可枚举属性
昨天在写文章(转载)的时候发现了有些对象的方法是分可枚举性和不可枚举性的.简单的查了一下资料,今天来捋一捋啥是对象的可枚举啥是不可枚举. 可枚举性: 对象的每一个属性都有一个描述对象,用来描述和控制该 ...
- hdu4126_hdu4756_求最小生成树的最佳替换边_Kruskal and Prim
目录 Catalog Solution: (有任何问题欢迎留言或私聊 && 欢迎交流讨论哦 Catalog Problem: Portal: hdu4126 hdu4756 原题目 ...
- 在WinDBG中查看内存的命令
当我们在调试器中分析问题时, 经常需要查看不同内存块的内容以分析产生的原因, 并且在随后验证所做出的假设是否正确. 由于各个对象的状态都是保存在内存中的, 因此内存的内容也就相当于对象的状态. d命令 ...