SoFunction
Updated on 2025-03-08

How to prevent repeated submissions of Java from java annotation @RepeatSubmit

Code explanation

@RepeatSubmit

  • is a custom annotation that is often used to prevent repeated submissions from form.
  • This annotation can be applied to the controller method to ensure that the same request will not be submitted multiple times within a certain period of time.

Here are some common parameters and usages:

  • value: The name or description of the annotation.
  • interval: The minimum interval between two requests (usually milliseconds).
  • message: The prompt message returned when a duplicate submission is detected.

Sample code

Suppose there is a @RepeatSubmit annotation defined as follows:

@Target()
@Retention()
public @interface RepeatSubmit {
    String value() default "";
    int interval() default 3000; // 3 seconds by default    String message() default "Do not repeat submission";
}

Example of usage

Use @RepeatSubmit annotation in the controller method:

@RestController
public class UserController {

    @PostMapping("/submitForm")
    @RepeatSubmit(interval = 5000, message = "Please wait 5 seconds before submitting")
    public ResponseEntity<String> submitForm(@RequestBody FormData formData) {
        // Process form submission logic        return ("Form submission successful");
    }
}

Control flow diagram

The following is the control flow diagram annotated by @RepeatSubmit, showing how it works:

flowchart TD
A[Start] --> B[Receive Request]
B --> C{Check whether to submit repeatedly}
C -->|Yes| D[Return to repeated submission prompt information]
C -->|No| E[process the request]
E --> F[Return to successful response]
F --> G[end]

illustrate

  • A: Start processing of the request.
  • B: Received the client's request.
  • C: Check whether the interval between the current request and the previous request is less than the set interval.
  • D: If a duplicate submission is detected, return the prompt message (such as "Please wait 5 seconds before submitting").
  • E: If no duplicate submission is detected, continue processing of the request.
  • F: After the request is processed successfully, a successful response is returned.
  • G: End the request processing process.

Design Patterns Used

@RepeatSubmit annotations usually combine AOP (sectional-oriented programming) and interceptor mode to prevent repeated submissions from form.

Design Pattern Analysis

AOP (System-oriented Programming):

  • Purpose: Separate cross-cutting concerns (such as logging, transaction management, security, etc.) from business logic to improve the modularity and maintainability of the code.
  • Implementation: Use Spring AOP or other AOP framework to intercept method calls through Aspects and execute additional logic (such as checking for duplicate commits).

Interceptor mode

  • Purpose: Execute specific logic before or after the request reaches the target method.
  • Implementation: In Spring, interceptors can be implemented through HandlerInterceptor or MethodInterceptor, intercept requests and perform preprocessing or postprocessing logic.

Definition annotation

   @Target()
   @Retention()
   public @interface RepeatSubmit {
       String value() default "";
       int interval() default 3000; // 3 seconds by default       String message() default "Do not repeat submission";
   }
   

Create a section

   @Aspect
   @Component
   public class RepeatSubmitAspect {

       @Around("@annotation(repeatSubmit)")
       public Object around(ProceedingJoinPoint joinPoint, RepeatSubmit repeatSubmit) throws Throwable {
           // Get the method signature           MethodSignature signature = (MethodSignature) ();
           Method method = ();

           // Get the request context           HttpServletRequest request = ((ServletRequestAttributes) ()).getRequest();

           // Get annotation parameters           int interval = ();
           String message = ();

           // Get the last requested timestamp from the session           Long lastRequestTime = (Long) ().getAttribute(());

           // Check whether to submit repeatedly           if (lastRequestTime != null && () - lastRequestTime < interval) {
               throw new RuntimeException(message);
           }

           // Record the time stamp of the current request           ().setAttribute((), ());

           // Continue to execute the target method           return ();
       }
   }
   

Use annotations in controller methods

   @RestController
   public class UserController {

       @PostMapping("/submitForm")
       @RepeatSubmit(interval = 5000, message = "Please wait 5 seconds before submitting")
       public ResponseEntity<String> submitForm(@RequestBody FormData formData) {
           // Process form submission logic           return ("Form submission successful");
       }
   }
   

What to pay attention to using @RepeatSubmit

When using the @RepeatSubmit annotation to prevent repeated submissions, you need to pay attention to the following aspects:

1. Annotation parameter configuration

  • interval: Set a reasonable interval. Too short intervals may cause users to frequently encounter prompts of repeated submissions, affecting the user experience; too long intervals may not effectively prevent rapid and continuous submissions.
  • message: Provide clear prompt information to inform the user why the request was denied, help the user understand and take the correct action.

2. Concurrent processing

  • Thread safety: In a high concurrency environment, ensure that the read and write timestamp operations are thread-safe.
  • Timestamps can be stored using thread-safe data structures such as ConcurrentHashMap or AtomicLong.
  • Distributed Environment: If the application is deployed on multiple servers, you need to consider how to share timestamp information in a distributed environment.
  • Timestamps can be stored using distributed caches such as Redis.

3. User experience

  • Front-end tips: Add anti-repeated submission mechanisms on the front-end page, such as disabling the submission button, displaying loading animations, etc., to reduce the possibility of user misoperation.
  • Error handling: Provides a friendly error handling mechanism, when a duplicate submission is detected, returns clear error information and guides the user to try again or contact support.

4. Performance considerations

  • Performance overhead: Anti-repeated submission checks will increase certain performance overhead, especially in high concurrency scenarios. Make sure these checks do not become a bottleneck in system performance.
  • Caching policy: Use cache to store timestamp information, reduce frequent access to databases or sessions, and improve performance.

5. Security

  • Session Management: Ensure the security of session management and prevent attacks such as session hijacking.
  • Timestamp Verification: Verify the validity and legality of timestamps to prevent malicious users from tampering with timestamps.

6. Logging

  • Logging: Records the timestamp and processing results of each request, which facilitates subsequent audits and problem investigations.

Sample code

The following is a more complete @RepeatSubmit annotation and sectional implementation, taking into account the above precautions:

Definition annotation

@Target()
@Retention()
public @interface RepeatSubmit {
    String value() default "";
    int interval() default 3000; // 3 seconds by default    String message() default "Do not repeat submission";
}
// Create facets@Aspect
@Component
public class RepeatSubmitAspect {

    @Autowired
    private RedisTemplate<String, Long> redisTemplate;

    @Around("@annotation(repeatSubmit)")
    public Object around(ProceedingJoinPoint joinPoint, RepeatSubmit repeatSubmit) throws Throwable {
        // Get the method signature        MethodSignature signature = (MethodSignature) ();
        Method method = ();

        // Get the request context        HttpServletRequest request = ((ServletRequestAttributes) ()).getRequest();

        // Get annotation parameters        int interval = ();
        String message = ();

        // Generate a unique request identifier        String key = () + ":" + ();

        // Get the last requested timestamp from Redis        Long lastRequestTime = ().get(key);

        // Check whether to submit repeatedly        if (lastRequestTime != null && () - lastRequestTime < interval) {
            throw new RuntimeException(message);
        }

        // Record the time stamp of the current request        ().set(key, (), interval, );

        // Continue to execute the target method        return ();
    }
}
// Use annotations in the controller method@RestController
public class UserController {

    @PostMapping("/submitForm")
    @RepeatSubmit(interval = 5000, message = "Please wait 5 seconds before submitting")
    public ResponseEntity<String> submitForm(@RequestBody FormData formData) {
        // Process form submission logic        return ("Form submission successful");
    }
}

Control flow diagram

The following is the control flow diagram annotated by @RepeatSubmit, showing how it works:

flowchart TD
    A[start] --> B[Receive request]
    B --> C[Generate a unique request identifier]
    C --> D[from Redis Get the last requested timestamp]
    D -->|Exist and not expired| E[Return to repeated submission prompt information]
    D -->|Does not exist or has expired| F[Record the current request time stamp]
    F --> G[Continue to execute the target method]
    G --> H[Return a successful response]
    H --> I[Finish]

illustrate

  • A: Start processing of the request.
  • B: Received the client's request.
  • C: Generate a unique request identifier, usually including the method name and client IP address.
  • D: Get the last requested timestamp from Redis.
  • E: If it exists and has not expired, return the repeated submission prompt message.
  • F: If it does not exist or has expired, record the timestamp of the current request.
  • G: Continue to execute the target method.
  • H: After the request is processed successfully, a successful response is returned.
  • I: End the request processing process.

Will using @RepeatSubmit fail?

When using the @RepeatSubmit annotation to prevent repeated submissions, you may indeed encounter problems that fail in some cases.

Here are some common causes and solutions for failure:

1. Fast continuous clicks on the front end

  • Reason: Users quickly click the submit button in a short period of time, resulting in the backend being unable to respond and process in a timely manner.
  • Solution: Front-end disable button:
  • After the user clicks the Submit button, immediately disable the button to prevent multiple clicks. Front-end display loading animation: Display loading animation to inform the user that the request is being processed.

2. Network delay

  • Cause: Network delay may cause the user to think the request failed and thus submit again.
  • Solution: Front-end timeout prompt: Set a reasonable request timeout time and prompt the user after the timeout.
  • Backend retry mechanism: Implement the retry mechanism on the backend, but be handled with caution to avoid unlimited retry.

3. Session failure

  • Cause: If you use a session to store a timestamp, the session may fail due to timeout or server restart.
  • Solution: Use distributed caches: Use distributed caches such as Redis to store timestamps to ensure that they work properly in multi-server environments.

4. Concurrent requests

  • Cause: In a high concurrency environment, multiple requests may arrive at the same time, resulting in the timestamp check invalidation.
  • Solution: Thread-safe: Use thread-safe data structures such as ConcurrentHashMap or AtomicLong to store timestamps.
  • Distributed lock: In a distributed environment, distributed locks (such as Redis distributed locks) are used to ensure that the read and write timestamp operations are atomic.

5. Timestamp accuracy issue

  • Cause: The accuracy of the timestamp may not be high enough, resulting in multiple requests being considered the same request within a short period of time.
  • Solution: Improve timestamp accuracy: Use higher precision timestamps (such as nanoseconds) to reduce conflicts.

6. Code logic error

  • Cause: Logical errors in the facet or interceptor may cause the @RepeatSubmit annotation to be invalid.
  • Solution: Code Review: Carefully review the code of the section or interceptor to ensure the logic is correct.
  • Unit Testing: Write unit tests that cover various boundary situations and make sure the @RepeatSubmit annotation works as expected.

Summarize

The above is personal experience. I hope you can give you a reference and I hope you can support me more.