springboot+拦截器实现接口幂等

项目中引入redis

定义注解类

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
​
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Idempotent {
​
    /**
     * 用于拼接幂等性判断的key的入参字段
     *
     * @return
     */
    String[] fields();
    /**
     * 用于接口幂等性校验的Redis中Key的过期时间,单位秒
     * @return
     */
    long timeout() default 10l;
}
​

定义拦截器实现接口幂等功能

@Data
public class IdempotentInterceptor implements HandlerInterceptor {
​
​
    @Autowired
    private RedisCache redisCache;
​
    private final int BUFFER_SIZE = 1024 * 8;
​
    /**
     * read string.
     *
     * @param reader Reader instance.
     * @return String.
     * @throws IOException
     */
    public  String read(Reader reader) throws IOException {
        try (StringWriter writer = new StringWriter()) {
            write(reader, writer);
            return writer.getBuffer().toString();
        }
    }
​
    /**
     * write.
     *
     * @param reader Reader.
     * @param writer Writer.
     * @return count.
     * @throws IOException
     */
    public  long write(Reader reader, Writer writer) throws IOException {
        return write(reader, writer, BUFFER_SIZE);
    }
​
    /**
     * write.
     *
     * @param reader     Reader.
     * @param writer     Writer.
     * @param bufferSize buffer size.
     * @return count.
     * @throws IOException
     */
    public long write(Reader reader, Writer writer, int bufferSize) throws IOException {
​
        int read;
        long total = 0;
        char[] buf = new char[bufferSize];
        while ((read = reader.read(buf)) != -1) {
​
            writer.write(buf, 0, read);
            total += read;
        }
        return total;
    }
​
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Idempotent idempotent = ((HandlerMethod)handler).getMethodAnnotation(Idempotent.class);
        if(idempotent == null){
            return true;
        }
        String idempotentKey = this.idempotentKey(idempotent,request);
        if(!redisCache.setIfAbsent(idempotentKey,idempotentKey, idempotent.timeout())){
            throw Problem.valueOf(Status.BAD_REQUEST, "重复提交");
        }
        return true;
    }
​
    private String idempotentKey(Idempotent idempotent,HttpServletRequest request) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
        String read = this.read(reader);
        String md5 = MD5.create().digestHex(JsonUtils.objToString(read));
        return md5;
    }
​
    /**
     * 接口渲染
     * @param response
     * @throws Exception
     */
    private void render(HttpServletResponse response,String message)throws Exception {
        response.setContentType("application/json;charset=UTF-8");
        OutputStream out = response.getOutputStream();
        out.write(message.getBytes("UTF-8"));
        out.flush();
        out.close();
    }
​
}

把拦截器注入到WebMvcConfigurer 使拦截器生效

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
​
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(getLoginHandlerInterceptor());
    }
​
    @Bean
    public IdempotentInterceptor getLoginHandlerInterceptor(){
        return new IdempotentInterceptor();
    }
​
}

在controller 的方法中使用@Idempotent注解

@ApiOperation("保单录入提交接口")
@PostMapping("/submit")
@Idempotent(fields = {"info"},timeout = 10)
public OrderInfoResDTO submit(@Valid @RequestBody OrderInfoDTO info) {
  throw Problem.valueOf(Status.BAD_REQUEST, "正常结束流程");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值