zoukankan      html  css  js  c++  java
  • 防止重复提交

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

    采用的方式:注解+拦截器+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; } }

     

  • 相关阅读:
    DataTable 只保留想要的几列
    如何用多个字符串来切分字符串
    用.net 发送邮件
    sqlserver 行列转换
    sql面试题一 学生成绩
    将DataReader转换为DataTable
    C# 如何用多个字符串来切分字符串并去除空格
    SqlServer按时间自动生成生成单据编号
    实验一 Java开发环境的熟悉
    Java学习笔记心得——初识Java
  • 原文地址:https://www.cnblogs.com/jthr/p/14601777.html
Copyright © 2011-2022 走看看