对于表单提交的防止重复提交
场景:对于一些未登录的用户向系统提交表单信息时,不能拿到token来唯一标识用户,而用户恶意重复点击的情况。
方案:在表单中用自定义@Tag注解标记需要一个唯一的表单数据(比如:手机号,身份证等),使用AOP在切面中获取标记的属性值,组装放入redis并设置过期用户重复提交该条记录就不进行数据库判断,直接从redis获取数据返会重复提交,以次减少服务器和数据库压力。
代码:
注解NoRepeat :
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NoRepeat {// 默认30slong time() default 30L;
}
注解Tag :
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Tag {
}
切面:
@Aspect
@Slf4j
@Configuration
public class NoRepeatAspect {@Autowiredprivate RedisTemplate<String, String> redisTemplate;private static final String DUPLICATE_COMMIT = "DUPLICATE_COMMIT:";/*** 切点*/@Pointcut("@annotation(cn.zk.common.annatation.NoRepeat)")public void pointcut() {}@Around("pointcut()&&@annotation(nrp)")public Object around(ProceedingJoinPoint joinPoint, NoRepeat nrp) {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Object proceed = null;StringBuffer cachePrefix = null;try {// 获取需要缓存的keycachePrefix = getTagString(joinPoint);String result = redisTemplate.opsForValue().get(DUPLICATE_COMMIT+cachePrefix.toString());if (!StringUtils.isEmpty(result)) {log.info("用户重复点击!==>key:{}", cachePrefix.toString());proceed = Response.failed(BizError.SYS_TIP, "请勿重复点击!");} else {proceed = joinPoint.proceed();}} catch (Throwable throwable) {throwable.printStackTrace();log.error("重复点击切面错误==>key:{},err:[}", cachePrefix.toString(), throwable.getMessage());proceed = Response.failed(BizError.SYS_TIP, "系统错误!");} finally {if (!Objects.isNull(cachePrefix)) {redisTemplate.opsForValue().set(DUPLICATE_COMMIT+cachePrefix.toString(),sdf.format(new Date()), nrp.time(), TimeUnit.SECONDS);}}return proceed;}/*** 获取参数中有Tag注解字段 并组装成redis的key** @param joinPoint* @return* @throws IllegalAccessException*/private StringBuffer getTagString(ProceedingJoinPoint joinPoint) throws IllegalAccessException {// 获取参数Object[] params = joinPoint.getArgs();if (params.length == 0) {return null;}//获取方法,此处可将signature强转为MethodSignature// API:获取连接点处的签名(用于跟踪或记录应用程序以获取有关连接点的反射信息)MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();//参数注解,1维是参数,2维是注解StringBuffer cachePrefix = new StringBuffer();// API:返回一个 Annotations 数组,1维是参数,2维是注解Annotation[][] annotations = method.getParameterAnnotations();for (int i = 0; i < annotations.length; i++) {Object param = params[i];Class<?> clz = param.getClass();// 扫描参数中的所有字段// API:返回一个 Field 对象数组,反映由此 Class 对象表示的类或接口声明的所有字段。// 这包括公共、受保护、默认(包)访问和私有字段,但不包括继承的字段for (Field field : clz.getDeclaredFields()) {field.setAccessible(true);if (field.isAnnotationPresent(Tag.class)) {Tag tag = field.getAnnotation(Tag.class);// API:返回指定对象上此字段表示的字段的值。如果该值具有原始类型,则该值会自动包装在对象中。Object value = field.get(param);if(!Objects.isNull(value)) {cachePrefix.append(String.valueOf(value) + "-");}}}}return cachePrefix;}}
使用方式:
表单对象
接口:
验证:
第一次提交:
30秒内重复提交:
redis:
对于表单提交的防止重复提交相关推荐
- php如何防止重复提交表单,如何防止php重复提交表单方法
解读:Token一般用在两个地方--防止表单重复提交.anti csrf攻击(跨站点请求伪造). Token,就是令牌,最大的特点就是随机性,不可预测.两者在原理上都是通过session token来 ...
- 微信h5页面提交表单后返回键重复提交的问题
微信h5页面提交表单后返回键重复提交的问题 问题描述:h5表单提交保存成功之后,手机返回后原来的页面还能提交表单. 示例: mui.post('savexxxx',data,function(res) ...
- 表单令牌阻止数据重复提交
在session中存放一个特殊标志 在服务器端,生成一个唯一的标识符,将它存入session,同时将它写入表单的隐藏字段中,然后将表单页面发给浏览器,用户录入信息后点击提交,在服务器端,获取表单中隐藏 ...
- java mvc中重复提交表单,spring mvc 防止重复提交表单的两种方法,推荐第二种
第一种方法:判断session中保存的token 比较麻烦,每次在提交表单时都必须传入上次的token.而且当一个页面使用ajax时,多个表单提交就会有问题. 注解Token代码: package c ...
- ajax如何提交多表单的值_菜狗教程-03-如何解决快速提交两次重复提交表单的问题...
菜狗教程-03-如何解决快速提交两次重复提交表单的问题 如何解决快速提交两次重复提交表单的问题? 我在前端和后端分别找到了一种简单实用的方式 vue如何解决快速重复提交表单的问题? (1) 在组件中增 ...
- JQuery002: 表单验证及ajax数据提交
一.三种情况下触发验证事件 输入框失去焦点 -> $('input[!type=button]').blur(function() {}) 输入框输入中 -> $('input[!type ...
- ajax核心代码提交,ajax表单在Asp.net核心提交后的RedirectToAction
我有一个名为Index的视图和一个名为'_Addbook'的PartialView,它显示为引导模式.在partialView中使用ajax表单将数据插入到数据库中.ajax表单在Asp.net核心提 ...
- form表单按enter键自动提交的问题
废话不多说.直接上代码. 1:form表单按enter键自动提交的情况 1 <!doctype html> 2 <html lang="en"> 3 < ...
- asp.net接受表单验证格式后再提交数据_如何解析 el-form-renderer 表单渲染器1.14.0...
DEEPEXI 大前端 常人道,一入开发深似海,技术学习无止境.在新技术层出不穷的前端开发领域,有一群身怀绝技的开发,他们在钻研前沿技术的同时,也不忘分享他们的成果,回馈社区.下面,就由小水滴带大家看 ...
- ExtJs 备忘录(4)—— Form表单(四) [ 数据提交 ]
一.截图和示例共用Ext.FormPanel 1.1 截图 由于本文主要关注的是表单提交的几种方式,所以仅用了一个表单项以便于测试和减少示例代码. 1.2 示例共用Ext.FormPanel ...
最新文章
- CSS之布局(盒子模型--内边距)
- 软件架构设计学习总结(1):标准Web系统的架构分层
- KiFastCallEntry() 机制分析
- 从简历筛选看怎么写一篇有亮点的简历
- SpringBatch 配置并行启动Job详解 (八)
- mysql 生成时间轴,MYSQL 时间轴数据 获取同一天数据的前3条
- python引用numpy出错_使用numpy时出错
- linux中ssh启动报错,Linux(Ubuntu18)中启动ssh时的报错
- Java笔记-对SpringBoot中CommandLineRunner的使用笔记
- java链表对象_用Java实现链表结构对象:单向无环链表
- 解读全球热点,传递科研进展,这份AI内参要承包你的AI信息源
- ONAP如何将Open-O和ECOMP数百万行代码合并?
- 浪潮服务器怎么获取cpu信息,浪潮获取cpu、内存、硬盘等信息(redfish协议+restfull协议)...
- 分内外网,下载个东西真不方便,一肚子火
- jQuery增加删除修改tab导航特效
- 流程图软件Visio的使用笔记
- 使用用AI制作logo图标教程
- 快看这里,豆瓣9.0的Python爬虫宝藏书籍,自学爬虫必备~
- C#基础 uint,long,ulong,float,decimal 定义并初始化
- addEventListener() 事件监听
热门文章
- JAVA中的“人妖”
- 字符编码、Unicode原理、数据流压缩Zlib与Miniz的实现
- Matlab各版本对比
- STM32:外部中断的使用
- android 4.4 batteryservice 电池电量显示分析
- 什么是 “零” 拷贝?
- OpenCV视频质量检测--清晰度检测
- Linux nohup的作用
- signature=cdae83b1c2034e2244a378f624349dfb,恶意软件分析 URL链接扫描 免费在线病毒分析平台 | 魔盾安全分析...
- skmetrics输出acc、precision、recall、f1值相同的问题