场景:对于一些未登录的用户向系统提交表单信息时,不能拿到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:

对于表单提交的防止重复提交相关推荐

  1. php如何防止重复提交表单,如何防止php重复提交表单方法

    解读:Token一般用在两个地方--防止表单重复提交.anti csrf攻击(跨站点请求伪造). Token,就是令牌,最大的特点就是随机性,不可预测.两者在原理上都是通过session token来 ...

  2. 微信h5页面提交表单后返回键重复提交的问题

    微信h5页面提交表单后返回键重复提交的问题 问题描述:h5表单提交保存成功之后,手机返回后原来的页面还能提交表单. 示例: mui.post('savexxxx',data,function(res) ...

  3. 表单令牌阻止数据重复提交

    在session中存放一个特殊标志 在服务器端,生成一个唯一的标识符,将它存入session,同时将它写入表单的隐藏字段中,然后将表单页面发给浏览器,用户录入信息后点击提交,在服务器端,获取表单中隐藏 ...

  4. java mvc中重复提交表单,spring mvc 防止重复提交表单的两种方法,推荐第二种

    第一种方法:判断session中保存的token 比较麻烦,每次在提交表单时都必须传入上次的token.而且当一个页面使用ajax时,多个表单提交就会有问题. 注解Token代码: package c ...

  5. ajax如何提交多表单的值_菜狗教程-03-如何解决快速提交两次重复提交表单的问题...

    菜狗教程-03-如何解决快速提交两次重复提交表单的问题 如何解决快速提交两次重复提交表单的问题? 我在前端和后端分别找到了一种简单实用的方式 vue如何解决快速重复提交表单的问题? (1) 在组件中增 ...

  6. JQuery002: 表单验证及ajax数据提交

    一.三种情况下触发验证事件 输入框失去焦点 -> $('input[!type=button]').blur(function() {}) 输入框输入中 -> $('input[!type ...

  7. ajax核心代码提交,ajax表单在Asp.net核心提交后的RedirectToAction

    我有一个名为Index的视图和一个名为'_Addbook'的PartialView,它显示为引导模式.在partialView中使用ajax表单将数据插入到数据库中.ajax表单在Asp.net核心提 ...

  8. form表单按enter键自动提交的问题

    废话不多说.直接上代码. 1:form表单按enter键自动提交的情况 1 <!doctype html> 2 <html lang="en"> 3 < ...

  9. asp.net接受表单验证格式后再提交数据_如何解析 el-form-renderer 表单渲染器1.14.0...

    DEEPEXI 大前端 常人道,一入开发深似海,技术学习无止境.在新技术层出不穷的前端开发领域,有一群身怀绝技的开发,他们在钻研前沿技术的同时,也不忘分享他们的成果,回馈社区.下面,就由小水滴带大家看 ...

  10. ExtJs 备忘录(4)—— Form表单(四) [ 数据提交 ]

    一.截图和示例共用Ext.FormPanel 1.1 截图 由于本文主要关注的是表单提交的几种方式,所以仅用了一个表单项以便于测试和减少示例代码. 1.2 示例共用Ext.FormPanel      ...

最新文章

  1. CSS之布局(盒子模型--内边距)
  2. 软件架构设计学习总结(1):标准Web系统的架构分层
  3. KiFastCallEntry() 机制分析
  4. 从简历筛选看怎么写一篇有亮点的简历
  5. SpringBatch 配置并行启动Job详解 (八)
  6. mysql 生成时间轴,MYSQL 时间轴数据 获取同一天数据的前3条
  7. python引用numpy出错_使用numpy时出错
  8. linux中ssh启动报错,Linux(Ubuntu18)中启动ssh时的报错
  9. Java笔记-对SpringBoot中CommandLineRunner的使用笔记
  10. java链表对象_用Java实现链表结构对象:单向无环链表
  11. 解读全球热点,传递科研进展,这份AI内参要承包你的AI信息源
  12. ONAP如何将Open-O和ECOMP数百万行代码合并?
  13. 浪潮服务器怎么获取cpu信息,浪潮获取cpu、内存、硬盘等信息(redfish协议+restfull协议)...
  14. 分内外网,下载个东西真不方便,一肚子火
  15. jQuery增加删除修改tab导航特效
  16. 流程图软件Visio的使用笔记
  17. 使用用AI制作logo图标教程
  18. 快看这里,豆瓣9.0的Python爬虫宝藏书籍,自学爬虫必备~
  19. C#基础 uint,long,ulong,float,decimal 定义并初始化
  20. addEventListener() 事件监听

热门文章

  1. JAVA中的“人妖”
  2. 字符编码、Unicode原理、数据流压缩Zlib与Miniz的实现
  3. Matlab各版本对比
  4. STM32:外部中断的使用
  5. android 4.4 batteryservice 电池电量显示分析
  6. 什么是 “零” 拷贝?
  7. OpenCV视频质量检测--清晰度检测
  8. Linux nohup的作用
  9. signature=cdae83b1c2034e2244a378f624349dfb,恶意软件分析 URL链接扫描 免费在线病毒分析平台 | 魔盾安全分析...
  10. skmetrics输出acc、precision、recall、f1值相同的问题