重复提交,你是如何处理的?

栏目: IT技术 · 发布时间: 6年前

内容简介:今天早上,新来的同事小王突然问我:“周哥,什么是幂等性啊?”。然后我就跟他解释了一番,幂等性就是说无论你执行几次请求,其结果是一样的。说到了幂等就不得不说重复提交了,你连续点击提交按钮,理论上来说这是同一条数据,数据库应该只能存入一条,而实际上存放了多条,这就违反了幂等性。因此我们就需要做一些处理,来保证连续点击提交按钮后,数据库只能存入一条数据。防止重复提交的方式很多,这里我就说一下我认为比较好用的一种。我们通过获取用户ip及访问的接口来判断他是否重复提交,假如这个ip在一段时间内容多次访问这个接口,我们

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

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

自定义注解+Aop实现

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

自定义注解

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NoRepeatSubmit {

    /**
     * 默认1s钟以内算重复提交
     * @return
     */
    long timeout() default 1;
}

Aop处理逻辑

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

@Aspect
@Component
public 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<Object> 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")
@NoRepeatSubmit
public String tt(HttpServletRequest request) {

    return "1";
}

测试

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

重复提交,你是如何处理的?

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


以上所述就是小编给大家介绍的《重复提交,你是如何处理的?》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。

大话存储

大话存储

张冬 / 清华大学出版社 / 2008-11 / 58.00元

网络存储,是近二十年来的新兴行业。从纸带到硬盘再到大型磁盘阵列,存储系统经历了从简单到复杂,从单块硬盘到存储区域网络(SAN)。网络存储行业目前已经是一个步入正轨的IT行业了。. 网络存储是一个涉及计算机硬件以及网络协议/技术、操作系统以及专业软件等各方面综合知识的领域。目前国内阐述网络存储的书籍少之又少,大部分是国外作品,对存储系统底层细节的描述不够深入,加之术语太多,初学者很难真正理解网......一起来看看 《大话存储》 这本书的介绍吧!

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

html转js在线工具
html转js在线工具

html转js在线工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换