• 防止重复提交


    指定对某些请求进行重复提交校验。避免同一客户在指定时间内重复提交同样的请求(参数一样)。

    采用的方式:注解+拦截器+REDIS

    1.自定义注解

    @Inherited
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface RepeatSubmit
    {
        int intervalTime() default 3;  // 多长时间内同一客户重复提交同样的请求算重复提交 单位秒  1-9之间
    }

    2.创建拦截器

    2.1找到被注解RepeatSubmit注解的请求

    package com.ruoyi.framework.interceptor;
    
    import java.lang.reflect.Method;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import org.springframework.stereotype.Component;
    import org.springframework.web.method.HandlerMethod;
    import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
    import com.alibaba.fastjson.JSONObject;
    import com.ruoyi.common.annotation.RepeatSubmit;
    import com.ruoyi.common.core.domain.AjaxResult;
    import com.ruoyi.common.utils.ServletUtils;
    
    /**
     * 防止重复提交拦截器
     *
     * @author ruoyi
     */
    @Component
    public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter
    {
    
        /**
         * 间隔时间,单位:秒 默认3秒
         *
         * 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据
         */
        public int intervalTime = 3;
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
        {
            if (handler instanceof HandlerMethod)
            {
                HandlerMethod handlerMethod = (HandlerMethod) handler;
                Method method = handlerMethod.getMethod();
                RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);//是否被@RepeatSubmit注解
                if (annotation != null)
                {
                    int i = annotation.intervalTime();  //获取注解RepeatSubmit的参数intervalTime
                    if(i > 0 && i < 10){ //intervalTime我这里控制在0到9之间
                        intervalTime = i;
                    }
                    if(i >= 10){
                        intervalTime = 9;//intervalTime我这里控制在0到9之间
                    }
                    if (this.isRepeatSubmit(request))
                    {
                        AjaxResult ajaxResult = AjaxResult.error("不允许重复提交,请稍后再试");
                        ServletUtils.renderString(response, JSONObject.toJSONString(ajaxResult));
                        return false;
                    }
                }
                return true;
            }
            else
            {
                return super.preHandle(request, response, handler);
            }
        }
    
        /**
         * 验证是否重复提交由子类实现具体的防重复提交的规则
         *
         * @param request
         * @return
         * @throws Exception
         */
        public abstract boolean isRepeatSubmit(HttpServletRequest request);
    }

    2.2判断是否是同一请求

    package com.ruoyi.framework.interceptor.impl;
    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.concurrent.TimeUnit;
    import javax.servlet.http.HttpServletRequest;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Component;
    import com.alibaba.fastjson.JSONObject;
    import com.ruoyi.common.constant.Constants;
    import com.ruoyi.common.core.redis.RedisCache;
    import com.ruoyi.common.filter.RepeatedlyRequestWrapper;
    import com.ruoyi.common.utils.StringUtils;
    import com.ruoyi.common.utils.http.HttpHelper;
    import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;
    
    /**
     * 判断请求url和数据是否和上一次相同,
     * 如果和上次相同,则是重复提交表单。 有效时间为10秒内。
     * 
     * @author ruoyi
     */
    @Component
    public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
    {
        public final String REPEAT_PARAMS = "repeatParams";
    
        public final String REPEAT_TIME = "repeatTime";
    
        // 令牌自定义标识
        @Value("${token.header}")
        private String header;
    
        @Autowired
        private RedisCache redisCache;
    
    
        public void setIntervalTime(int intervalTime)
        {
            this.intervalTime = intervalTime;
        }
    
        @SuppressWarnings("unchecked")
        @Override
        public boolean isRepeatSubmit(HttpServletRequest request)
        {
            String nowParams = "";
            if (request instanceof RepeatedlyRequestWrapper)
            {
                RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
                nowParams = HttpHelper.getBodyString(repeatedlyRequest);
            }
    
            // body参数为空,获取Parameter的数据
            if (StringUtils.isEmpty(nowParams))
            {
                nowParams = JSONObject.toJSONString(request.getParameterMap());
            }
            Map<String, Object> nowDataMap = new HashMap<String, Object>();
            nowDataMap.put(REPEAT_PARAMS, nowParams);
            nowDataMap.put(REPEAT_TIME, System.currentTimeMillis());
    
            // 请求地址(作为存放cache的key值)
            String url = request.getRequestURI();
    
            // 唯一值(没有消息头则使用请求地址)
            String submitKey = request.getHeader(header);
            if (StringUtils.isEmpty(submitKey))
            {
                submitKey = url;
            }
    
            // 唯一标识(指定key + 消息头)
            String cache_repeat_key = Constants.REPEAT_SUBMIT_KEY + submitKey;
    
            Object sessionObj = redisCache.getCacheObject(cache_repeat_key);
            if (sessionObj != null)
            {
                Map<String, Object> sessionMap = (Map<String, Object>) sessionObj;
                if (sessionMap.containsKey(url))
                {
                    Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url);
                    if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap))
                    {
                        return true;
                    }
                }
            }
            Map<String, Object> cacheMap = new HashMap<String, Object>();
            cacheMap.put(url, nowDataMap);
            redisCache.setCacheObject(cache_repeat_key, cacheMap, intervalTime, TimeUnit.SECONDS);
            return false;
        }
    
        /**
         * 判断参数是否相同
         */
        private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap)
        {
            String nowParams = (String) nowMap.get(REPEAT_PARAMS);
            String preParams = (String) preMap.get(REPEAT_PARAMS);
            return nowParams.equals(preParams);
        }
    
        /**
         * 判断两次间隔时间
         */
        private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap)
        {
            long time1 = (Long) nowMap.get(REPEAT_TIME);
            long time2 = (Long) preMap.get(REPEAT_TIME);
            if ((time1 - time2) < (this.intervalTime * 1000))
            {
                return true;
            }
            return false;
        }
    }

    3.配置拦截器

    package com.ruoyi.framework.config;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.cors.CorsConfiguration;
    import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
    import org.springframework.web.filter.CorsFilter;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    import com.ruoyi.common.config.RuoYiConfig;
    import com.ruoyi.common.constant.Constants;
    import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;
    
    /**
     * 通用配置
     * 
     * @author ruoyi
     */
    @Configuration
    public class ResourcesConfig implements WebMvcConfigurer
    {
        @Autowired
        private RepeatSubmitInterceptor repeatSubmitInterceptor;
    
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry)
        {
            /** 本地文件上传路径 */
            registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + RuoYiConfig.getProfile() + "/");
    
            /** swagger配置 */
            registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
            registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
        }
    
        /**
         * 自定义拦截规则
         */
        @Override
        public void addInterceptors(InterceptorRegistry registry)
        {
            registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**");
        }
    
        /**
         * 跨域配置
         */
        @Bean
        public CorsFilter corsFilter()
        {
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            CorsConfiguration config = new CorsConfiguration();
            config.setAllowCredentials(true);
            // 设置访问源地址
            config.addAllowedOrigin("*");
            // 设置访问源请求头
            config.addAllowedHeader("*");
            // 设置访问源请求方法
            config.addAllowedMethod("*");
            // 对接口配置跨域设置
            source.registerCorsConfiguration("/**", config);
            return new CorsFilter(source);
        }
    }

    4.使用

        //在controller的方法上加上@RepeatSubmit注解,这个方法就会去做重复提交校验
       @PostMapping ("/addOrder") @RepeatSubmit(intervalTime = 9) public AjaxResult addOrder(@RequestBody DistinctOrderParamNew distinctOrderParamNew) throws ParseException, OutOfStockException { AjaxResult ta = ljOrderAddNewService.addOrder(distinctOrderParamNew); return ta; } }

     

  • 相关阅读:
    Hdu 4496 D-City
    Hdu 1213 How Many Tables
    T1387:搭配购买(buy)
    codevs 2597 团伙
    Hdu 1232 畅通工程
    RQNOJ PID331 家族
    提高组day4
    xjoi2018提高组训训练25
    关于upp和lower
    矩阵快速幂求fib
  • 原文地址:https://www.cnblogs.com/jthr/p/14601777.html
Copyright © 2020-2023  润新知