Duplicate submissions, how do you handle them?

This morning, a new colleague, Xiao Wang, suddenly asked me, "What is idempotency, Zhou Ge?"Then I explained t...
Custom Annotation+Aop Implementation

This morning, a new colleague, Xiao Wang, suddenly asked me, "What is idempotency, Zhou Ge?"Then I explained to him that idempotency means that no matter how many requests you make, the result will be the same.When it comes to idempotency, you have to repeat the submission button. In theory, this is the same data. The database should only store one, but actually there are many, which violates idempotency.So we need to do something to make sure that the database can only store one piece of data when we click the Submit button continuously.

There are many ways to prevent duplicate submissions, so let me just say one that I think works better.

Custom Annotation+Aop Implementation

We determine whether a user submits a duplicate request by acquiring the user's ip and the interface he accesses. If the ip accesses this interface multiple times over a period of time, we consider it a duplicate submission. We will process the duplicate submission request directly and do not allow access to the target interface.

Custom Notes

@Target() @Retention(RetentionPolicy.RUNTIME) @Documented public @interface NoRepeatSubmit { /** * Duplicate submissions within default 1s minutes * @return */ long timeout() default 1; }

Aop Processing Logic

We use the ip+interface address as the key, randomly generate a UUID as the value, and store it in redis.Each request comes in, queries redis according to the key, and if it exists it means a duplicate submission, throws an exception, if it does not exist it is a normal submission, and stores the key in redis.

@Aspect @Component public class NoRepeatSubmitAop { @Autowired private RedisService redisUtils; /** * Define entry points */ @Pointcut("@annotation(NoRepeatSubmit)") public void noRepeat() {} /** * Pre-notification: Notification performed before the connection point * @param point * @throws Throwable */ @Before("noRepeat()") public void before(JoinPoint point) throws Exception{ // Receive request, record request content ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); Assert.notNull(request, "request can not null"); // You can use token or JSessionId here 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); // Get annotations 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) { // Failed to acquire lock, considered a duplicate request redisUtils.lSet(key, clientId, timeout); throw new Exception("No duplicate submissions are allowed"); } } private String getKey(String token, String path) { return token + path; } private String getClientId() { return UUID.randomUUID().toString(); } }

Provide interfaces for testing

Add our custom comment @NoRepeatSubmit to the interface

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

test

We request interfaces in the browser twice in a row.The first interface responded to normal content: 1. The second interface responded to exceptional information that could not be submitted repeatedly.1s and then click on the interface, found that it responded to normal content.

So far, this way of preventing duplicate submissions has been described, and we have perfectly prevented interface duplicate submissions.

23 June 2020, 21:12 | Views: 3495

Add new comment

For adding a comment, please log in
or create account

0 comments