redis防表单重复提交
参考链接:
防表单重复提交的四种方法:https://www.cnblogs.com/huanghuizhou/p/9153837.html
补充几点个人想法:
1. 对于前后端传递token验证的方式,每次都需要页面加载才能在后端存放token,这样会导致用户在第一次提交表单失败后就无法提交成功,需要刷新页面。
2. 利用session去给前后端的token存放获取,这对于APP来说不协调,适合用redis。
使用哪种方法要根据自己项目去考虑,比如单纯做网页的用session也不错。
我这里后台是提供给微信端和APP端,所以使用了第四种方法:使用Redis和AOP自定义切入实现
好处是校验只在后端完成,不需要前端传递token之类的,这里直接从链接中拿出来(进行少许改动,防丢,哈哈)
注意:这个方法需要自己指定防重复提交的间隔时间,在这个时间内都不能提交第二次,过了这个时间就能提交,所以时间需要把控好,可以算优点也能是缺点
实现原理:
- 自定义防止重复提交标记(@AvoidRepeatableCommit)。
- 对需要防止重复提交的Congtroller里的mapping方法加上该注解。
- 新增Aspect切入点,为@AvoidRepeatableCommit加入切入点。
- 每次提交表单时,Aspect都会保存当前key到reids(须设置过期时间)。
- 重复提交时Aspect会判断当前redis是否有该key,若有则拦截。
自定义标签
import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/*** 避免重复提交* @author hhz* @version* @since*/@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface AvoidRepeatableCommit {/*** 指定时间内不可重复提交,单位秒* @return*/long timeout() default 5 ;}
自定义切入点Aspect
package com.xx.web;import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;import javax.servlet.http.HttpServletRequest;import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;import com.alibaba.fastjson.JSON;
import com.xx.web.util.DynamicRedisUtil;
import com.xx.web.util.IPUtil;/*** 重复提交aop* * @author * @date */
@Aspect
@Component
@EnableAspectJAutoProxy(exposeProxy=true)
public class AvoidRepeatableCommitAspect {@Autowired HttpServletRequest request; //这里可以获取到request/*** @param point*/@Around("@annotation(com.xx.web.AvoidRepeatableCommit)")public Object around(ProceedingJoinPoint point) throws Throwable {String ip = IPUtil.getIpAddr(request);//获取注解MethodSignature signature = (MethodSignature) point.getSignature();Method method = signature.getMethod();//目标类、方法String className = method.getDeclaringClass().getName();String name = method.getName();String ipKey = String.format("%s#%s",className,name);int hashCode = Math.abs(ipKey.hashCode());String key = String.format("%s_%d",ip,hashCode);
// log.info("ipKey={},hashCode={},key={}",ipKey,hashCode,key);AvoidRepeatableCommit avoidRepeatableCommit = method.getAnnotation(AvoidRepeatableCommit.class);int timeout = avoidRepeatableCommit.timeout();if (timeout < 0){timeout = 5;}//用多参数set方法保证对redis操作原子性Integer isSuccess = DynamicRedisUtil.setnxAndExpire(key, UUID.randomUUID().toString(), timeout*1000, DynamicRedisUtil.AVOID_REPEATABLE_COMMIT_DB);if (isSuccess == 0) {resultMap.put("errCode", 10001);resultMap.put("errMsg", "请勿重复提交");return JSON.toJSONString(resultMap);}//执行方法Object object = point.proceed();return object;}}/*** redis工具类方法* 比setnx多了个保存失效时间* @author wangdy* @date 2018年8月13日 下午2:38:07* @param key* @param value* @param seconds 失效时间,单位秒* @param db* @return 当key不存在,保存成功并返回1,当key已存在不保存并返回0*/public static Integer setnxAndExpire(final String key, String value, long milliseconds, int db) {JedisPool pool = getPool();Jedis jds = null;boolean broken = false;int setnx = 0;try {jds = pool.getResource();jds.select(db);String result = jds.set(key, value, "NX", "PX", milliseconds);if ("OK".equals(result)) {setnx = 1;}return setnx;} catch (Exception e) {broken = true;logger.error("setString:" + e.getMessage());} finally {if (broken) {pool.returnBrokenResource(jds);} else if (jds != null) {pool.returnResource(jds);}}return setnx;}
Rest方法:
//重复提交测试@RequestMapping(value = "testCommit",method = {RequestMethod.GET,RequestMethod.POST})@ResponseBody@AvoidRepeatableCommit(timeout = 3)public String testCommit(HttpServletRequest request){Map<String,Object> resultMap = new HashMap<String,Object>();try{ resultMap.put("success", true);}catch (Exception e) {e.printStackTrace();resultMap.put("success", false);}return JSON.toJSONString(resultMap);}
redis防表单重复提交相关推荐
- JavaWeb -- Struts1 使用示例: 表单校验 防表单重复提交 表单数据封装到实体
1. struts 工作流程图 超链接 2. 入门案例 struts入门案例:1.写一个注册页面,把请求交给 struts处理<form action="${pageContext.r ...
- SpringMVC中实现的token,防表单重复提交
一:首先创建一个token处理类 ,这里的类名叫 TokenHandler private static Logger logger = Logger.getLogger(TokenHandler. ...
- Spring Boot中防表单重复提交以及拦截器登录检测
目录 理论 演示 源码 理论 在用户登录后,如果按F5刷新会出现表单重复提交的问题,解决这个问题后,如果没有拦截器登录检测,就会造成,任意用户可以登录后台界面,所以要有拦截器登录检测. 相关的逻辑步骤 ...
- 基于拦截器实现防表单重复提交
1.定义自定义注解 2.定义防重复提交拦截器 /*** 防止重复提交拦截器** */ @Component public abstract class RepeatSubmitInterceptor ...
- redis防止表单重复提交
1. 对于前后端传递token验证的方式,每次都需要页面加载才能在后端存放token,这样会导致用户在第一次提交表单失败后就无法提交成功,需要刷新页面. 2. 利用session去给前后端的toke ...
- 简单介绍redis分布式锁解决表单重复提交的问题
在系统中,有些接口如果重复提交,可能会造成脏数据或者其他的严重的问题,所以我们一般会对与数据库有交互的接口进行重复处理.本文就详细的介绍一下redis分布式锁解决表单重复提交,感兴趣的可以了解一下 假 ...
- 表单重复提交(前端未做单击防重复点击策略)
表单重复提交导致重复添加,用token解决:提交前的请求会给前端一token,后端将这token存在缓存中,表单提交时要带上这token,后端校验token通过执行业务逻辑,后端 并删除缓存中的tok ...
- springboot 订单重复提交_防止表单重复提交(springboot,redis)
我们在web项目中经常需要在后台对用户提交的表单进行校验防止重复提交.下面通过springboot的aop.redis来解决表单重复提交的问题. 通过在controller加上CheckSubmitF ...
- java后端 防重复提交_后台防止表单重复提交
具体的做法: 1.获取用户填写用户名和密码的页面时向后台发送一次请求,这时后台会生成唯一的随机标识号,专业术语称为Token(令牌). 2.将Token发送到客户端的Form表单中,在Form表单中使 ...
最新文章
- redis 中 set 和 hset 有什么不同,什么时候使用 hset 什么时候使用set?
- Mac OS 上安装 PostgreSQL
- [sh]top添加到crontab不生效问题解决
- Lesson 14.3 Batch Normalization综合调参实战
- Vue报错Module not found: Error: Can‘t resolve ‘less-loader‘
- 电机控制pid_微电机控制如此简单,揭秘微电机调速的控制,PID控制之双环调速...
- server精简版代理意外终止 sql_来自阿里巴巴内部JAVA面试宝典意外流出
- 设计模式(17) 访问者模式(VISITOR) C++实现
- 厚积薄发!华为云7篇论文被AAAI收录,2021年AI行业技术风向标看这里!
- 计算机系统层次中 从上层,在计算机系统层次结构中下层是上层的上层是下层的一个.ppt...
- 小程序切换账户拉取仓库文件的appid提示
- keyshot分辨率多少合适_分辨率单位及换算详解
- 固态硬盘用软件测试掉速严重,固态硬盘为什么会“掉速”?
- 学习路线、站点推荐、工具软件、资源下载
- 336亿的生意——你所不了解的Dapp这一年(下)
- PADS输出BOM表和位号图(装配图)
- 湖北民院OJ 计算球体体积
- 2019第五届中国诗歌春晚致敬先贤
- Axon Framework官方文档(五)
- 奔腾cpu可以安装黑苹果吗_【2020】macOS黑苹果硬件主板CPU和显卡的支持列表和选购指南...