幂等性校验

一、幂等校验思路:

前端:请求时先获取唯一标识,然后带着唯一标识去请求业务接口

后端:唯一标识生成接口:生成唯一标识,存储redis,返回前端。

            业务处理接口:在业务接口上添加自定义幂等校验注解,前端请求时,拦截器进行拦截判断该请求的方法上是否添加了幂等校验注解,如有进行校验,无放行。校验逻辑:判断redis是否存在,存在则删除该幂等标识(删除是为了防止并发问题)并放行,不存在说明是重复请求。

二、代码样例:

        1、幂等校验注解

/*
 * 在需要保证 接口幂等性 的Controller的方法上使用此注解
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Idempotent {
}

        2、拦截器

@Component
//幂等性拦截,方法上是否添加幂等性校验注解
public class IdempotenceInterceptor implements HandlerInterceptor {


    @Autowired
    private IdempotentImpl idempotentImpl;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //判断是否是方法请求
        if (!(handler instanceof HandlerMethod)){
                return true;
        }
        HandlerMethod handlerMethod= (HandlerMethod)handler;

        Method method = handlerMethod.getMethod();
        Idempotent idempotent= method.getAnnotation(Idempotent.class);
        if (null !=idempotent){
          String idem=  request.getHeader("idempotent");
          if (StringUtils.isEmpty(idem)){
              throw new GlobalException(ResponseCode.FAILUER_1.getCode(),"未携带幂等标识");
          }
            //幂等校验
            idempotentImpl.checkToken(idem);
        }
        return true;
    }
}


/*
 * @Description
 */
@Configuration
public class WebConfigurer implements WebMvcConfigurer {
 
    @Autowired
    private IdempotenceInterceptor idempotenceInterceptor;
 
    /*
    * 幂等性拦截器
    * */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(idempotenceInterceptor);
    }
 
}

        3、幂等标识生成校验

@Component
public class IdempotentImpl {

    private static final String IDEMPOTENT = "idempotent";
    @Resource
    private RedisSessionTemplate redisSessionTemplate;

    //创建一个唯一idempotent标识
    public String createToken() {
        String uuid = UUID.randomUUID().toString();
        //存储redis,保留固定时间,超过失效
        redisSessionTemplate.set(uuid, uuid, 60 * 30);
        return uuid;
    }


    public void checkToken(String idempotent) {

        //如果redis中不存在,说明该标识已请求处理
        if (!redisSessionTemplate.exists(idempotent)) {
            throw new GlobalException(ResponseCode.FAILUER_1.getCode(), "重复请求");
        }
        //防止并发问题,要判断删除是否成功,不成功说明已请求处理
        Long del = redisSessionTemplate.del(idempotent);
        if (del <= 0) {
            throw new GlobalException(ResponseCode.FAILUER_1.getCode(), "重复请求");
        }
    }
}

        4、业务请求接口加幂等注解

@RestController
@RequestMapping("/test")
public class TestController {
    @Autowired
    private TestService testService;

    @GetMapping("/selectTest")
    @Idempotent()
    public String selectTest(){
        try {
            return  testService.SelectTest();
        }catch (Exception ex){
            throw new GlobalException(1001,"错误异常");
        }
    }


}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值