前言
针对于我们现在常用的RESTful API
通常我们需要对请求进行唯一标识,也就是每次都要带上一个请求号,如reqNO
。
对于入库这种操作数据库的请求我们一般要保证他的唯一性,一个请求号通常只能用一次,所以需要我们对这种请求加上校验机制。
该需求的实现思路是通过自定义
annotation
,只给需要进行校验的接口加上注解。然后通过切面使用了注解的接口将每次请求号存进Redis
,每次都进行判断是否存在这个请求号即可。
来看下加上本次插件的实际效果:
重复请求号01.jpg
重复请求号02.jpg
重复请求号03.jpg
自定义注解
首先我们要自定义一个注解:
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface CheckReqNo { String desc() default ""; }
(ps:这里并不过多的讲解注解相关的知识)。
首先使用@interface
来声明一个注解。接着利用Java
为我们提供的三个元注解来定义CheckReqNo
注解。
其中@Target
表明这个注解被用于什么地方,使用ElementType.METHOD
表明被应用到方法上,还有一些其他值可以查看java.lang.annotation.ElementType
这个枚举类型。
@Retention
注解表明我们的注解在什么范围内有效,这里配置的RetentionPolicy.RUNTIME
表明在运行时可以通过反射来获取。
@Documented
看字面意思应该也能猜到是用于生成JavaDoc
文档的。
其中定义了一个desc()
的方法其实并没有用到,但如果需要在使用注解的时候需要自定义一些filed(域)
的需求可以按照这样的方式写到这里,通过反射都可以获取到具体的值。
如:@CheckReqNo(desc = "abc")
就可以获取到"abc"
的值。
切面注解
按照之前的想法是在对所有使用了该注解的方法进行切面:
@Aspect @Component public class ReqNoDrcAspect { private static Logger logger = LoggerFactory.getLogger(ReqNoDrcAspect.class); @Value("${redis.prefixReq:reqNo}") private String prefixReq ; @Value("${redis.day:1}") private long day ; @Autowired private RedisTemplate<String, String> redisTemplate; @PostConstruct public void init() throws Exception { logger.info("SSM-REQUEST-CHECK init......"); } @Pointcut("@annotation(com.crossoverJie.request.anotation.CheckReqNo)") public void checkRepeat(){ } @Before("checkRepeat()") public void before(JoinPoint joinPoint) throws Exception { BaseRequest request; request = getBaseRequest(joinPoint); if(request != null){ final String reqNo = request.getReqNo(); if(StringUtil.isEmpty(reqNo)){ throw new RuntimeException("reqNo不能为空"); }else{ try { String tempReqNo = redisTemplate.opsForValue().get(prefixReq +reqNo); logger.debug("tempReqNo="+tempReqNo); if((StringUtil.isEmpty(tempReqNo))){ redisTemplate.opsForValue().set(prefixReq + reqNo, reqNo, day, TimeUnit.DAYS); }else{ throw new RuntimeException("请求号重复,reqNo="+reqNo); } } catch (RedisConnectionFailureException e){ logger.error("redis操作异常",e); throw new RuntimeException("need redisService") ; } } } } public static BaseRequest getBaseRequest(JoinPoint joinPoint) throws Exception { BaseRequest returnRequest = null; Object[] arguments = joinPoint.getArgs(); if(arguments != null && arguments.length > 0){ returnRequest = (BaseRequest) arguments[0]; } return returnRequest; } }