1 创建IIdempotent
@Target({ElementType.PARAMETER, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface IIdempotent { }
2 创建aop
@Component @Aspect public class IdempotentAction { public final static String ERROR_REPEATSUBMIT = "Repeated submission"; //redis @Autowired protected StringRedisTemplate idempotentTemplate; //配置接入点,如果不知道怎么配置,可以百度一下规则 @Pointcut("execution(* com.kps.webAPI*.controller..*.*(..))&&@annotation(com.kps.web.aop.Idempotent.IIdempotent)") private void controllerAspect() { } //成功处理请求 @AfterReturning("controllerAspect()") public void AfterReturning(JoinPoint jp) throws Exception { IdempotentCheck(jp, ComContants.OP_RESULT[1]); } //后置异常通知 @AfterThrowing("controllerAspect()") public void AfterThrowing(JoinPoint jp) throws Exception{ IdempotentCheck(jp,ComContants.OP_RESULT[2]); } private void IdempotentCheck(JoinPoint jp, String opResult) throws Exception { String controllerName = jp.getTarget().getClass().getName(); controllerName = controllerName.substring(controllerName.lastIndexOf(".") + 1); Signature sig = jp.getSignature(); MethodSignature msig = (MethodSignature) sig; // 获得被拦截的方法 Method method = msig.getMethod(); // webUI控制器 @Controller注解 IIdempotent systemlog = method.getAnnotation(IIdempotent.class); HttpServletRequest request = WebUtil.getHttpServletRequest(); String body = NetUtil.getBodyString(request); String signMD5= MD5.md5(body); if (Boolean.parseBoolean(idempotentTemplate.opsForValue().get(signMD5))) { throw new ErrorSignException(ERROR_REPEATSUBMIT); } else { idempotentTemplate.opsForValue().set(signMD5, "true", ComContants.IDEMPOTENT_EXTIME, TimeUnit.SECONDS); } } }
测试:
//幂等apo,测试实例,30秒不可重复提交相同数据 @IIdempotent @RequestMapping(value = "test", method = RequestMethod.POST) public ApiResult<String> test(@RequestBody ApiRequest<String> requestVO) { ApiResult<String> r = new ApiResult<String>(); r.setData(requestVO.getData()); r.setCodeToSuccessed(); return r; }