赞
踩
一、幂等校验思路:
前端:请求时先获取唯一标识,然后带着唯一标识去请求业务接口
后端:唯一标识生成接口:生成唯一标识,存储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,"错误异常");
- }
- }
-
-
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。