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. 测试略过。。。

转载于:https://www.cnblogs.com/bevis-byf/p/11491547.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/482408.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Nat. Commun.速递:合群者有着相似的大脑活动

来源&#xff1a;集智俱乐部作者&#xff1a;郭瑞东 作者&#xff1a;梁金编辑&#xff1a;邓一雪摘要Convergent processing of the world may be a factor that contributes to social connectedness. We use neuroimaging and network analysis to investigate the associat…

桌面推演技术前沿及发展趋势

来源&#xff1a;蓝海长青智库作者&#xff1a;吕欣、蔡梦思、陈彬&#xff0c;国防科技大学系统工程学院摘要桌面推演通过模拟事件场景及处置过程来提高参演人员的风险感知能力、信息研判能力、指挥决策能力和协同配合能力&#xff0c;被广泛应用于军事作战、应急管理和教育培…

清华大学孙茂松:自然语言处理一瞥,知往鉴今瞻未来

来源&#xff1a;中国人工智能学会作者&#xff1a;孙茂松近日&#xff0c;清华大学人工智能研究院常务副院长孙茂松教授亲手执笔&#xff0c;对自然语言处理的贡献、当前境界与未来挑战进行了深入的探讨。AI科技评论编辑组深有同感&#xff0c;认为此文十分值得一读&#xff0…

前端基础之jQuery

jQuery jQuery的思想&#xff0c;实际上很简单&#xff0c;八个字可以概括&#xff1a;选取元素&#xff0c;对其操作。 元素选取的表达式遵循 CSS 以及 XPath 的标准。选取结果可以是一个或多个&#xff0c;后面的操作针对所有被选取的元素。多个连续的操作可以用“链式”实现…

美国自动驾驶监管里程碑:新法规允许自动驾驶汽车取消方向盘

来源&#xff1a;AI前线编译&#xff1a;刘燕NHTSA 表示&#xff0c;这一新规迈出了“历史性”的一步&#xff0c;确保为配备自动驾驶系统的车辆的乘客保持同样高水平的乘员碰撞保护。这可以视为美国自动驾驶监管的一个里程碑。InfoQ 3 月 11 日消息&#xff0c;根据路透社的报…

DataTable实现分组

有时候我们从数据库中查询出来数据之后&#xff0c;需要按照DataTable的某列进行分组&#xff0c;可以使用下面的方法实现&#xff0c;代码如下&#xff1a; using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; using…

城市大脑的定义与理论基础综述

本文发表于2022年2月下旬的《中国建设信息化》&#xff0c;作者杜青峰 刘锋 任伟阳1 前言2015以来&#xff0c;城市大脑的概念和定义首次提出后。随着城市大脑领域在理论研究和产业实践上的探索和进展,城市大脑已经成为前沿科技领域和智慧城市建设领域的新热点,到2022年&…

线程实现模型

线程实现模型 线程实现模型主要分为&#xff1a;用户级线程模型&#xff0c;内核级线程模型和两级线程模型。他们的区别在于线程与内核线程之间的对应关系。 以下我们将分析这三种线程实现模型的特点&#xff1a; 用户级线程模型 &#xff08;1&#xff09;多对一关系 用户级线…

逆生长!小鼠「逆龄疗法」登Nature子刊,有望用于人类

来源&#xff1a;机器学习研究组订阅一种新的「逆龄疗法」在小鼠身上显示出希望的曙光&#xff01;最近&#xff0c;美国索尔克生物研究所的科学家运用细胞再生疗法&#xff0c;将「山中因子」注入小鼠&#xff0c;通过多组实验证明&#xff1a;仅数个月&#xff0c;小鼠年轻多…

消息中间件那些事--RabbitMQ

消息队列已经逐渐成为企业IT系统内部通信的核心手段。它具有低耦合、可靠投递、广播、流量控制、最终一致性等一系列功能&#xff0c;成为异步RPC的主要手段之一。当今市面上有很多主流的消息中间件&#xff0c;如老牌的ActiveMQ、RabbitMQ&#xff0c;炙手可热的Kafka&#xf…

中国联通李福昌:探索无线连接的未来

来源&#xff1a;C114通信网文&#xff1a;李福昌无线技术在当今社会中发挥着重要的作用&#xff0c;特别是5G商用以来&#xff0c;无线技术的应用从以个人为主扩展到面向生产和社会&#xff0c;逐步践行“5G改变社会”的目标。展望未来&#xff0c;面向6G&#xff0c;无线连接…

转载一个不错的LRU cache

https://github.com/paudley/lru_cache 转载于:https://www.cnblogs.com/water-bear/p/11511995.html

听完411头猪的哼哼,他们找到了理解“猪语”的算法 | Scientific Reports

图片来源&#xff1a;Pixabay来源 哥本哈根大学翻译 闭诗林编辑 魏潇我们现在可以解读猪的情绪了。一个国际研究小组利用猪从出生到死亡的生命过程中收集到的数千份录音&#xff0c;首次在其一生各个阶段的大量场景下&#xff0c;将猪的呼噜声转化为了真实的情绪。这项研究由…

弄懂goroutine调度原理

goroutine简介 golang语言作者Rob Pike说&#xff0c;“Goroutine是一个与其他goroutines 并发运行在同一地址空间的Go函数或方法。一个运行的程序由一个或更多个goroutine组成。它与线程、协程、进程等不同。它是一个goroutine“。 goroutine通过通道来通信&#xff0c;而协程…

JVM-类加载原理

写在前面 我们知道我们编写的java代码&#xff0c;会经过编译器编译成字节码文件&#xff08;class文件&#xff09;&#xff0c;再把字节码文件装载到JVM中&#xff0c;映射到各个内存区域中&#xff0c;我们的程序就可以在内存中运行了。那么字节码文件是怎样装载到JVM中的呢…

2022年斯坦福AI Index公布:中美主导跨国研究,专利、投资金额暴增

来源&#xff1a;学术头条当地时间 3 月 16 日&#xff0c;斯坦福大学以人为本人工智能研究所&#xff08;StanfordHAI&#xff09;正式发布了《2022 年人工智能指数报告》&#xff08;Artificial Intelligence Index Report 2022&#xff09;。这是该机构发布的第五份年度报告…

中国传感器规模将超7000亿元:2022最全面深入的产业分析

来源&#xff1a;前瞻经济学人整理&#xff1a;动感传感本文整理自前瞻经济学人的传感器产业报告&#xff0c;作为国内领先的咨询机构&#xff0c;前瞻经济学人的研报分析深度和数据丰富程度&#xff0c;都首屈一指。主要有如下几部分内容&#xff1a;•2022年中国传感器行业市…

强化学习教父Richard Sutton新论文探索决策智能体的通用模型:寻找跨学科共性...

来源&#xff1a;人工智能AI技术 论文虽然有些难懂&#xff0c;但或许是一个新的研究方向。强化学习和决策多学科&#xff08;Multi-Disciplinary Conference on Reinforcement Learning and Decision Making, RLDM&#xff09;的重要前提是&#xff0c;随着时间的推移&#xf…

IO模型(epoll)--详解-01

写在前面 从事服务端开发&#xff0c;少不了要接触网络编程。epoll作为linux下高性能网络服务器的必备技术至关重要&#xff0c;nginx、redis、skynet和大部分游戏服务器都使用到这一多路复用技术。 本文会从网卡接收数据的流程讲起&#xff0c;串联起CPU中断、操作系统进程调度…

一文搞懂MEMS传感器产业链(最全解析!)

来源&#xff1a;传感器专家网本文涵盖了MEMS产业链的所有与流程与知识&#xff0c;力求用最简短的内容——全文不足8000字&#xff0c;让我们知道最全面的MEMS产业链情况&#xff0c;包括如下内容&#xff1a;一、MEMS简介二、MEMS分类三、MEMS 行业发展历程四、国内传感器企业…