美文网首页
限制重复提交

限制重复提交

作者: 王小杰at2019 | 来源:发表于2019-04-18 17:58 被阅读0次

    [toc]

    使用说明

    1. 强依赖 redisTemplate ,但 spring-boot-starter-redis scope 为 provided 项目在使用时候需要手动引入改依赖
    2. 需要配置 redis 连接
    spring.redis.host=localhost
    spring.redis.port=6379
    
    1. 启用 @EnableResubmitCheck 注解
    2. 该校验非强制校验,需要在校验的目标方法上给启用 @ResubmitCheck
    3. 校验可选参数项
     /**
         * md5 是否包含header中的认证信息 ,默认为true
         *
         * @return
         */
        boolean includeAuthorization() default true;
    
        /**
         * 重复数据提交间隔时间,默认30s
         *
         * @return
         */
        int expireTime() default 30;
    
    

    核心代码

    package com.runstyle.common.resubmit;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.serializer.PropertyFilter;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.codec.digest.DigestUtils;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestAttributes;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.Closeable;
    import java.io.PrintWriter;
    import java.lang.reflect.Method;
    import java.util.List;
    import java.util.concurrent.TimeUnit;
    import java.util.stream.Collectors;
    import java.util.stream.Stream;
    
    @Aspect
    @Component
    @Slf4j
    public class ResubmitAspect {
    
        @Autowired
        RedisTemplate<String, String> redisTemplate;
    
        /**
         * 调用方法前输出日志
         *
         * @param joinPoint
         */
        @Around(value = "@annotation( com.runstyle.common.resubmit.ResubmitCheck)")
        public Object methodBefore(ProceedingJoinPoint joinPoint) throws Throwable {
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            Method method = methodSignature.getMethod();
            ResubmitCheck annotation = method.getAnnotation(ResubmitCheck.class);
            String data = getRequestData(joinPoint);
            HttpServletRequest request = (HttpServletRequest) RequestContextHolder.currentRequestAttributes().resolveReference(RequestAttributes.REFERENCE_REQUEST);
            if (annotation.includeAuthorization()) {
                String authorization = request.getHeader("Authorization");
                data += ":" + authorization;
            }
            data += ":" + request.getRequestURI();
            String key = "resubmit:" + DigestUtils.md5Hex(data);
            boolean s1 = redisTemplate.opsForValue().setIfAbsent(key, "");
            if (!s1) {
                //不通过
                HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getResponse();
                response.setStatus(403);
                PrintWriter writer = response.getWriter();
                data += ":left" + redisTemplate.getExpire(key, TimeUnit.SECONDS);
                String fullName = methodSignature.getDeclaringTypeName() + "." + methodSignature.getName();
                log.warn("重复提交 method:{},data:{}", fullName, data);
                writer.write("resubmit:" + data);
                return null;
            }
            redisTemplate.expire(key, annotation.expireTime(), TimeUnit.SECONDS);
            Object proceed = joinPoint.proceed();
            return proceed;
        }
    
        /**
         * 获取请求参数
         *
         * @param joinPoint
         * @return
         */
        private String getRequestData(ProceedingJoinPoint joinPoint) {
            //排除序列化字段
            Object[] args = joinPoint.getArgs();
            List<Object> collect = Stream.of(args).filter(o -> !(o instanceof Closeable || o instanceof ServletRequest || o instanceof ServletResponse)).collect(Collectors.toList());
            PropertyFilter propertyFilter = (object, name, value) -> {
                if (object instanceof Closeable || object instanceof ServletRequest || object instanceof ServletResponse ||
                        value instanceof Closeable || value instanceof ServletRequest || value instanceof ServletResponse) {
                    //  过滤掉
                    return false;
                }
                return true;
            };
            return JSON.toJSONString(collect, propertyFilter);
        }
    }
    
    

    demo

    启动类

    @SpringBootApplication
    @EnableResubmitCheck
    public class DemoApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    
    }
    
    

    controller

    
    @RestController
    @Slf4j
    public class TestController {
        @RequestMapping("/test")
        @ResubmitCheck
        public String test(@RequestBody(required = false) String body, String param1, HttpServletRequest request, HttpServletResponse response) {
            log.info("body:{}", body);
            log.info("param1:{}", param1);
            return "ok";
        }
    }
    
    

    执行效果

    浏览器

    resubmit:["dddd2","3"]:null:/test:left29
    

    控制台

    2019-04-18 17:43:48.389  INFO 10572 --- [nio-8080-exec-4] com.example.demo.TestController          : body:dddd2
    2019-04-18 17:43:48.390  INFO 10572 --- [nio-8080-exec-4] com.example.demo.TestController          : param1:3
    2019-04-18 17:43:56.651  WARN 10572 --- [nio-8080-exec-5] c.r.common.resubmit.ResubmitAspect       : 重复提交 method:com.example.demo.TestController.test,data:["dddd2","3"]:null:/test:left21
    2019-04-18 17:45:18.621  INFO 10572 --- [nio-8080-exec-7] com.example.demo.TestController          : body:dddd2
    2019-04-18 17:45:18.621  INFO 10572 --- [nio-8080-exec-7] com.example.demo.TestController          : param1:3
    2019-04-18 17:45:19.489  WARN 10572 --- [nio-8080-exec-8] c.r.common.resubmit.ResubmitAspect       : 重复提交 method:com.example.demo.TestController.test,data:["dddd2","3"]:null:/test:left29
    

    相关文章

      网友评论

          本文标题:限制重复提交

          本文链接:https://www.haomeiwen.com/subject/xiotgqtx.html