Micro service interfaces using AOP implementation prevent secondary submission

Disclaimer: This article is a blogger original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.
This link: https://blog.csdn.net/wangchengming1/article/details/102651023

In terms of micro-services or a single program, to prevent secondary interfaces are necessary to submit solutions, now we have a mature solution, such as using the click of a button to let the gray and so on after the end of the request can click. Of course, the back end should solve this problem.

Using AOP way to prevent secondary interface to submit
  • Thinking
    • To uniquely identify as key, any value value, stored in redis (local cache may be), and set a reasonable expiration time.
    • The notes used in the add, modify, and other interfaces.
    • Each call according to key judgments, the cache exists, there is an exception is thrown or tips, there is no business logic is executed.
  • Defines a comment
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RepeatSubmitCheck {
    int keepSeconds() default 5;
}
  • To achieve this comment
@Aspect
@Component
@Slf4j
public class RepeatSubmitAspect {

    @Resource
    private RedisService redisService;
 
    @Pointcut("@annotation(com.xxx.xxx.annotation.RepeatSubmitCheck)")
    public void requestPointcut() {
    }
 
    @Around("requestPointcut()")
    public void aroundCheck(JoinPoint joinPoint, RepeatSubmitCheck repeatSubmitCheck) {
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        String paramsJsonStr = JSON.toJSONString(args);
 
        String srcStr = className + "_" + methodName + "_" + paramsJsonStr;
        String signStr = Md5Utils.md5(srcStr);
        log.info("防止重复提交的请求 Redis Key:" + signStr);
 
        //判断缓存是否存在不存在则添加缓存
        if(!redisService.exists(signStr)){
            redisService.setex(signStr, repeatSubmitCheck.keepSeconds(), "1");
        } else {//重复请求
            log.info("重复提交的请求数据:" + srcStr);
            throw new RuntimeException("重复请求");
        }
    }
}
  • RedisService part of the code

@AllArgsConstructor
public class RedisService {

	private RedisTemplate<String, Object> redisTemplate;

	public boolean exists(String key) {
        return redisTemplate.execute((RedisCallback<Boolean>) connection -> {
            return connection.exists(key.getBytes());
        });
    }
    
	public boolean setex(final String key, long expire, final String value) {
        return redisTemplate.execute((RedisCallback<Boolean>) connection -> {
            RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
            return connection.setEx(serializer.serialize(key), expire, serializer.serialize(value));
        });
    }
}
  • Instructions
@PostMapping("/repeatSubmit")
@RepeatSubmitCheck
public String testRepeatSubmit() {
    return "test RepeatSubmitCheck";
}

Guess you like

Origin blog.csdn.net/wangchengming1/article/details/102651023