美文网首页
通过Redis 实现防重复提交

通过Redis 实现防重复提交

作者: 久伴我还是酒伴我 | 来源:发表于2021-06-08 19:43 被阅读0次

    简介

    同一条数据被用户点击了多次,导致数据冗余,需要防止弱网络等环境下的重复点击,通过在指定的接口处添加注解,实现根据指定的接口参数来防重复点击,这里的重复点击是指在指定的时间段内多次点击按钮。

    自定义注解

    package com.kingxunlian.tax.utils.repeatsubmit;
    import java.lang.annotation.*;
    /**
     * 自定义注解
     */
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface RepeatSubmit
    {
    
    }
    

    防止重复提交的拦截器

    package com.kingxunlian.tax.utils.repeatsubmit;
    
    import com.alibaba.fastjson.JSON;
    import com.kingxunlian.common.XLBaseResponse;
    import org.springframework.stereotype.Component;
    import org.springframework.web.method.HandlerMethod;
    import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.lang.reflect.Method;
    
    /**
     * 防止重复提交拦截器
     */
    @Component
    public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter
    {
        @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);
                if (annotation != null)
                {
                    if (this.isRepeatSubmit(request))
                    {
                        response.setContentType("application/json");
                        response.setCharacterEncoding("utf-8");
                        response.getWriter().print(JSON.toJSONString(XLBaseResponse.setBasicError("不允许重复提交,请稍后再试")));
                        return false;
                    }
                }
                return true;
            }
            else
            {
                return super.preHandle(request, response, handler);
            }
        }
    
        /**
         * 验证是否重复提交由子类实现具体的防重复提交的规则
         * 
         * @param request
         * @return
         * @throws Exception
         */
        public abstract boolean isRepeatSubmit(HttpServletRequest request) throws Exception;
    }
    
    

    验证是否重复提交子类实现

    package com.kingxunlian.tax.utils.repeatsubmit;
    import com.alibaba.fastjson.JSON;
    import org.springframework.stereotype.Component;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * 判断请求url和数据是否和上一次相同, 
     * 如果和上次相同,则是重复提交表单。 有效时间为5秒内。
     */
    @Component
    public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
    {
        public final String REPEAT_PARAMS = "repeatParams";
    
        public final String REPEAT_TIME = "repeatTime";
    
        public final String SESSION_REPEAT_KEY = "repeatData";
    
        /**
         * 间隔时间,单位:秒 默认5秒
         * 
         * 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据
         */
        private int intervalTime = 5;
    
        public void setIntervalTime(int intervalTime)
        {
            this.intervalTime = intervalTime;
        }
    
        @SuppressWarnings("unchecked")
        @Override
        public boolean isRepeatSubmit(HttpServletRequest request) throws Exception
        {
            // 本次参数及系统时间
            String nowParams = JSON.toJSONString(request.getParameterMap());
            Map<String, Object> nowDataMap = new HashMap<String, Object>();
            nowDataMap.put(REPEAT_PARAMS, nowParams);
            nowDataMap.put(REPEAT_TIME, System.currentTimeMillis());
    
            // 请求地址(作为存放session的key值)
            String url = request.getRequestURI();
    
            HttpSession session = request.getSession();
            Object sessionObj = session.getAttribute(SESSION_REPEAT_KEY);
    
            System.out.println("nowDataMap:"+JSON.toJSONString(nowDataMap));
            System.out.println("sessionObj:"+sessionObj);
    
            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> sessionMap = new HashMap<String, Object>();
            sessionMap.put(url, nowDataMap);
            session.setAttribute(SESSION_REPEAT_KEY, sessionMap);
            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;
        }
    }
    

    配置拦截重复提交的请求

    /**
         * 配置拦截重复提交的请求
         * @param registry
         */
        @Override
        public void addInterceptors(InterceptorRegistry registry){
            registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**");
        }
    

    相关文章

      网友评论

          本文标题:通过Redis 实现防重复提交

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