博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
重复提交,你是如何处理的?
阅读量:2489 次
发布时间:2019-05-11

本文共 2268 字,大约阅读时间需要 7 分钟。

 

今天早上,新来的同事小王突然问我:“周哥,什么是幂等性啊?”。然后我就跟他解释了一番,幂等性就是说无论你执行几次请求,其结果是一样的。说到了幂等就不得不说重复提交了,你连续点击提交按钮,理论上来说这是同一条数据,数据库应该只能存入一条,而实际上存放了多条,这就违反了幂等性。因此我们就需要做一些处理,来保证连续点击提交按钮后,数据库只能存入一条数据。

防止重复提交的方式很多,这里我就说一下我认为比较好用的一种。

自定义注解+Aop实现

我们通过获取用户ip及访问的接口来判断他是否重复提交,假如这个ip在一段时间内容多次访问这个接口,我们则认为是重复提交,我们将重复提交的请求直接处理即可,不让访问目标接口。

自定义注解

@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface NoRepeatSubmit {    /**     * 默认1s钟以内算重复提交     * @return     */    long timeout() default 1;}

Aop处理逻辑

我们将ip+接口地址作为key,随机生成UUID作为value,存入redis。每次请求进来,根据key查询redis,如果存在则说明是重复提交,抛出异常,如果不存在,则是正常提交,将key存入redis。

@Aspect@Componentpublic class NoRepeatSubmitAop {	@Autowired	private RedisService redisUtils;	/**	 * 	定义切入点	 */	@Pointcut("@annotation(NoRepeatSubmit)")	public void noRepeat() {}	/**	 * 	前置通知:在连接点之前执行的通知	 * @param point	 * @throws Throwable	 */	@Before("noRepeat()")	public void before(JoinPoint point) throws Exception{		// 接收到请求,记录请求内容		ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();		HttpServletRequest request = attributes.getRequest();		Assert.notNull(request, "request can not null");		// 此处可以用token或者JSessionId		String token = IpUtils.getIpAddr(request);		String path = request.getServletPath();		String key = getKey(token, path);		String clientId = getClientId();		List lGet = redisUtils.lGet(key, 0, -1);		// 获取注解		MethodSignature signature = (MethodSignature) point.getSignature();		Method method = signature.getMethod();		NoRepeatSubmit annotation = method.getAnnotation(NoRepeatSubmit.class);		long timeout = annotation.timeout();		boolean isSuccess = false;		if (lGet.size()==0 || lGet == null) {			isSuccess = redisUtils.lSet(key, clientId, timeout);		}		if (!isSuccess) {			// 获取锁失败,认为是重复提交的请求			redisUtils.lSet(key, clientId, timeout);			throw new Exception("不可以重复提交");		}	}	private String getKey(String token, String path) {		return token + path;	}	private String getClientId() {		return UUID.randomUUID().toString();	}}

提供接口用来测试

在接口上添加上我们自定义的注解@NoRepeatSubmit

@RequestMapping("/test")@NoRepeatSubmitpublic String tt(HttpServletRequest request) {    return "1";}

测试

我们在浏览器中连续请求两次接口。发现第一次接口响应正常内容:1,第二次接口响应了不可重复提交的异常信息。1s之后再点击接口,发现又响应了正常内容。

至此,这种防止重复提交的方式就介绍完了,这样我们就完美防止了接口重复提交。

转载地址:http://lflrb.baihongyu.com/

你可能感兴趣的文章
PCB设计技巧与注意事项
查看>>
linux进程之间通讯常用信号
查看>>
main函数带参数
查看>>
PCB布线技巧
查看>>
关于PCB设计中过孔能否打在焊盘上的两种观点
查看>>
PCB反推理念
查看>>
京东技术架构(一)构建亿级前端读服务
查看>>
php 解决json_encode中文UNICODE转码问题
查看>>
LNMP 安装 thinkcmf提示404not found
查看>>
PHP empty、isset、innull的区别
查看>>
apache+nginx 实现动静分离
查看>>
通过Navicat远程连接MySQL配置
查看>>
phpstorm开发工具的设置用法
查看>>
Linux 系统挂载数据盘
查看>>
Git基础(三)--常见错误及解决方案
查看>>
Git(四) - 分支管理
查看>>
PHP Curl发送数据
查看>>
HTTP协议
查看>>
HTTPS
查看>>
git add . git add -u git add -A区别
查看>>