赞
踩
本功能是在切面执行链基础上实现的功能,如果不知道切面执行链的同学,请看一下我之前专门介绍切面执行链的文章。
在SpringBoot项目中实现切面执行链功能-CSDN博客
1.定义防重复提交handler
- /**
- * 重复提交handler
- *
- */
- @AspectHandlerOrder
- public class ResubmitAspectHandler implements AspectHandler {
-
- private StringRedisTemplate stringRedisTemplate;
-
- public void setStringRedisTemplate(StringRedisTemplate stringRedisTemplate) {
- this.stringRedisTemplate = stringRedisTemplate;
- }
-
- @Override
- public boolean execute(ProceedingJoinPoint pjp) throws Exception {
- Method method = getMethod(pjp);
- if (!method.isAnnotationPresent(Resubmit.class)) {
- return true;
- }
- Resubmit annotation = method.getAnnotation(Resubmit.class);
- long ttl = annotation.ttl();
- String key = getKey();
- String value = "1";
- if (lock(key, value, ttl)) {
- return true;
- }
- throw new BaseRuntimeException(ExceptionEnums.ERROR_10012.getCode(), "操作频率过高,请稍后再试!");
- }
-
- @Override
- public void afterCompletion(ProceedingJoinPoint pjp, Object response, Exception exception) {
- Method method = getMethod(pjp);
- if (method.isAnnotationPresent(Resubmit.class)) {
- unlock(getKey());
- }
- }
-
- /**
- * redis原子操作:如果key不存在就设置key:value
- *
- * @param key
- * @param value
- * @return true:设置成功拿到锁,false:设置失败未拿到锁
- */
- private boolean lock(final String key, final String value, final long ttl) {
- Boolean result = stringRedisTemplate.boundValueOps(key).setIfAbsent(value, Duration.ofSeconds(ttl));
- return result != null ? result : false;
- }
-
- /**
- * 解锁:删除key
- *
- * @param key
- */
- private void unlock(String key) {
- if (StringUtils.isNotBlank(key)) {
- stringRedisTemplate.delete(key);
- }
- }
-
- /**
- * 获取方法
- *
- * @param pjp
- * @return
- */
- private Method getMethod(ProceedingJoinPoint pjp) {
- MethodSignature signature = (MethodSignature) pjp.getSignature();
- Method method = signature.getMethod();
- return method;
- }
-
- /**
- * 获取key
- *
- * @return
- */
- private String getKey() {
- ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
- HttpServletRequest request = requestAttributes.getRequest();
- String url = request.getRequestURI();
- String httpMethod = request.getMethod();
-
- HttpHeader httpHeader = WebContext.getHttpHeader();
- String deviceId = httpHeader.getDevice_id();
-
- String key = RedisConstants.REDIS_RESUBMIT_KEY + httpMethod + url + ":" + deviceId;
- return key;
- }
- }
-
2.定义防重复提交注解
- /**
- * 防止重复提交
- */
- @Retention(RetentionPolicy.RUNTIME)
- @Target(ElementType.METHOD)
- public @interface Resubmit {
-
- /**
- * 存活时间(秒),当意外情况(例如锁定之后重启服务)
- * 未能执行解锁功能,redis将在${ttl}秒之后自动删除锁标志
- * 默认 10秒
- * @return
- */
- long ttl() default 10;
-
- }
3.在配置类中注入防重复提交切面类
- @Bean
- public List<AspectHandler> apiAspectHandlers() {
- ResubmitAspectHandler resubmitAspectHandler = new ResubmitAspectHandler();
- resubmitAspectHandler.setStringRedisTemplate(stringRedisTemplate);
-
- return Arrays.asList(resubmitAspectHandler);
- }
4.controller中应用防重复提交注解
- @PostMapping("/release")
- @Resubmit
- public ApiResponse<?> insert(@RequestBody @Valid InsertAppRequestDTO req) {
- // 处理业务逻辑
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。