java 使用注解+Aop+redis实现防止重复提交

防止重复提交的方式有很多

  可以用数据库的唯一索引,保证数据完整性

  在业务层用select....for update,依然是使用数据库的事务来做的

  使用注解+拦截器 HandlerIntercetper+redis

  我这里使用注解+aop+redis。

1、注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Resubmit {
    int interval() default 5; // s 单位为秒,x秒内防止重复提交
}

 

2、切面实现,

@Aspect
@Component
public class ResubmitAspect {
    private final static String CACHE_KEY = "resubmit:";

    @Resource
    private CacheComponent cacheComponent;

    @Around(value = "@annotation(resubmit)")
    public Object around(ProceedingJoinPoint point, Resubmit resubmit) throws Throwable {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        Object loginUser = ThreadLocalConst.getLoginUser();
        String username = null;
        if(Objects.nonNull(loginUser)){
            username = ThreadLocalConst.getUserId().toString();
        }else {
            username = ThreadLocalConst.getRequestIp();
        }
    // 这里用于redis缓存的key用的是,已经登录的userId + 请求方法 + 请求路径。没登录就用ip地址。
    // 可以用getSignature() 是方法的全限定名称 String cacheKey
= CACHE_KEY + username + request.getMethod() + request.getRequestURI(); String shortString = point.getSignature().toShortString(); Boolean success = cacheComponent.setNx(cacheKey, shortString, resubmit.interval(), TimeUnit.SECONDS); // redis的setNx 命令,保证原子性 if(success){ Object result = point.proceed(); return result; }else { throw new BizException("请勿重复提交"); } } }

 

3、使用

    @PutMapping
    @Resubmit
    public JsonResult<Boolean> save(@Validated @RequestBody EnterpriseRecheckEditRequest request){
        return JsonResult.success(enterpriseRecheckService.add(request));
    }

 

对比是否是同一数据重复提交,判断方式还可以加入请求参数

posted @ 2022-11-15 14:16  小小小小青石  阅读(707)  评论(0)    收藏  举报