resubmit

resubmit is a progressive anti-duplicate submission framework designed for java.

Recommended reading:

Interviewer: How did you prevent duplicate submissions in your project?

Introduction to resubmit Progressive Anti-Duplicate Submission Framework

creative purpose

Sometimes it is very troublesome to manually add to prevent repeated submissions, and manual writing every time is not conducive to reuse.

So I hope to realize a tool from simple to complex, which is convenient for daily use.

characteristic

  • Progressive implementation, can be used independently of spring
  • Based on annotation + bytecode, flexible configuration
  • Support for programmatic calls
  • Support annotation, perfect integration of spring
  • Support integration of spring-boot
Changelog

在这里插入图片描述

quick start

maven import

 <dependency>
    <group>com.github.houbb</group>
    <artifact>resubmit-core</artifact>
    <version>1.0.0</version>
</dependency>

coding

  • UserService.java

@Resubmit The corresponding attributes are as follows:

Attributes illustrate Defaults
value() How long to suppress duplicate submissions, in milliseconds. 60000
 @Resubmit(5000)
public void queryInfo(final String id) {
    System.out.println("query info: " + id);
}
  • test code

If the request is repeated within the specified time difference, an exception ResubmitException will be thrown

 @Test(expected = ResubmitException.class)
public void errorTest() {
    UserService service = ResubmitProxy.getProxy(new UserService());
    service.queryInfo("1");
    service.queryInfo("1");
}

If the same parameter is submitted twice directly, an error will be reported.

  • Test Scenario 2

If the wait exceeds the specified 5s, no error will be reported.

 @Test
public void untilTtlTest() {
    UserService service = ResubmitProxy.getProxy(new UserService());
    service.queryInfo("1");
    DateUtil.sleep(TimeUnit.SECONDS, 6);
    service.queryInfo("1");
}

customize

ResubmitProxy.getProxy(new UserService()); You can get the proxy corresponding to UserService.

Equivalent to:

 ResubmitBs resubmitBs = ResubmitBs.newInstance()
                .cache(new CommonCacheServiceMap())
                .keyGenerator(new KeyGenerator())
                .tokenGenerator(new HttpServletRequestTokenGenerator());

UserService service = ResubmitProxy.getProxy(new UserService(), resubmitBs);

Among them, ResubmitBs is used as a guide class, and the corresponding policies support customization.

Attributes illustrate Defaults
cache() Cache Implementation Strategy The default is a memory-based cache implementation based on the ConcurrentHashMap implementation
keyGenerator() The key implementation strategy is used to uniquely identify a method + parameters to determine whether it is the same submission md5 strategy
tokenGenerator() The token implementation strategy is used to uniquely identify a user. Obtained from the header attribute in HttpServletRequest resubmit_token

Spring integration

maven import

 <dependency>
    <group>com.github.houbb</group>
    <artifact>resubmit-spring</artifact>
    <version>1.0.0</version>
</dependency>

code writing

  • UserService.java
 @Service
public class UserService {

    @Resubmit(5000)
    public void queryInfo(final String id) {
        System.out.println("query info: " + id);
    }

}
  • SpringConfig.java
 @ComponentScan("com.github.houbb.resubmit.test.service")
@EnableResubmit
@Configuration
public class SpringConfig {
}

@EnableResubmit annotation description

@EnableResubmit , the user can specify the corresponding implementation strategy, which is convenient to adapt to the business scenario more flexibly.

One-to-one correspondence with the attributes that support custom in ResubmitBs .

Attributes illustrate Defaults
cache() Cache Implementation Strategy The default is a memory-based cache implementation based on the ConcurrentHashMap implementation
keyGenerator() The key implementation strategy is used to uniquely identify a method + parameters to determine whether it is the same submission md5 strategy
tokenGenerator() The token implementation strategy is used to uniquely identify a user. Obtained from the header attribute in HttpServletRequest resubmit_token

test code

 @ContextConfiguration(classes = SpringConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class ResubmitSpringTest {

    @Autowired
    private UserService service;

    @Test(expected = ResubmitException.class)
    public void queryTest() {
        service.queryInfo("1");
        service.queryInfo("1");
    }

}

Integrate spring-boot

maven import

 <dependency>
    <groupId>com.github.houbb</groupId>
    <artifactId>resubmit-springboot-starter</artifactId>
    <version>1.0.0</version>
</dependency>

Code

  • UserService.java

The implementation of this method is the same as before.

 @Service
public class UserService {

    @Resubmit(5000)
    public void queryInfo(final String id) {
        System.out.println("query info: " + id);
    }

}
  • Application.java

boot entry

 @SpringBootApplication
public class ResubmitApplication {

    public static void main(String[] args) {
        SpringApplication.run(ResubmitApplication.class, args);
    }

}

test code

 @ContextConfiguration(classes = ResubmitApplication.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class ResubmitSpringBootStarterTest {

    @Autowired
    private UserService service;

    @Test(expected = ResubmitException.class)
    public void queryTest() {
        service.queryInfo("1");
        service.queryInfo("1");
    }

}

custom strategy

The policies mentioned above in @EnableResubmit support customization.

Here we only take cache as an example. For simplicity, the default is a cache implementation based on local memory.

If you are not a single point application, then a redis-based cache is more suitable

custom cache

Implement caching

You only need to implement the ICommonCacheService interface.

 public class MyDefineCache extends CommonCacheServiceMap {

    // 这里只是作为演示,实际生产建议使用 redis 作为统一缓存
    @Override
    public synchronized void set(String key, String value, long expireMills) {
        System.out.println("------------- 自定义的设置实现");

        super.set(key, value, expireMills);
    }

}

specified in core

In non-spring projects, we can specify the cache we define in the bootstrap class.

 ResubmitBs resubmitBs = ResubmitBs.newInstance()
                .cache(new MyDefineCache());

UserService service = ResubmitProxy.getProxy(new UserService(), resubmitBs);

Other usage remains unchanged.

specified in spring

In the spring project, we need to adjust the configuration, other things remain unchanged.

 @ComponentScan("com.github.houbb.resubmit.test.service")
@Configuration
@EnableResubmit(cache = "myDefineCache")
public class SpringDefineConfig {

    @Bean("myDefineCache")
    public ICommonCacheService myDefineCache() {
        return new MyDefineCache();
    }

}

@EnableResubmit(cache = "myDefineCache") Specify our custom cache policy name.

Redis' built-in caching strategy

In order to facilitate reuse, the cache strategy based on redis has been implemented, and there is time to explain it later.

Redis-Config

open source address

In order to facilitate everyone's learning and use, the current anti-duplicate submission framework has been open sourced.

Welcome to fork+star, encourage the old horse~

https://github.com/houbb/resubmit

老马啸西风
191 声望34 粉丝