• 拦截器-防重复提交


    为了保证接口幂等性,需要前后端都要做处理。

    1 前端-提交按钮置灰,不再请求接口。

    2 后盾-防重复提交。

    package com.jiutong.zqp.manage.interceptor;
    
    import groovy.util.logging.Slf4j;
    import org.apache.commons.lang.StringUtils;
    import org.apache.shiro.SecurityUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.core.ValueOperations;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.util.Objects;
    import java.util.concurrent.TimeUnit;
    
    /**
     * bi 防重复提交
     * @author zhouq
     */
    @Slf4j
    public class RedisResubmitInterceptor implements HandlerInterceptor {
    
        private static final String RESUBMIT_TOKEN;
    
        static {
            RESUBMIT_TOKEN = "bi_resubmit_token_";
        }
    
        protected Logger logger = LoggerFactory.getLogger(getClass());
    
        @Autowired
        private RedisTemplate redisTemplate;
    
        private String[] NOT_INTERCEPT_URL = {"newOrders/orderStatusCount", "newOrders/getBuyerOrders","/views","/resources"};
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            Object shrioUser = null;
            try {
                //获取登入用户ID
                shrioUser = SecurityUtils.getSubject().getSession().getAttribute("adminUid");
            } catch (Exception e) {
            }
            if (shrioUser == null) {
                return true;
            }
            Integer userId = (Integer)shrioUser;
            if (userId == null || Objects.equals(userId, 0)) {
                return true;
            }
            //获取请求路径
            String methodFullName = request.getRequestURI() + "_" + userId;
    
            //其他请求不做防重复提交
            for (String url:  NOT_INTERCEPT_URL) {
                if (StringUtils.indexOf(methodFullName, url) > 0) {
                    return true;
                }
            }
            //路径加密
            String resubmitTokenKey = RESUBMIT_TOKEN + MD5.MD5Encode(methodFullName);
            logger.debug("resubmitTokenKey lock key: " + resubmitTokenKey);
            //redis模版k-v 键值操作
            ValueOperations<String, String> valueOps = redisTemplate.opsForValue();
            //redis 如果resubmitTokenKey相同,自增
            long count = valueOps.increment(resubmitTokenKey, 1);
            // 如果等于1,说明是第一个请求,如果该KEY的数值大于1,说明是第一次请求处理未完成,重复提交的请求,不做处理
            if (count == 1) {
                // 设置有效期
                redisTemplate.expire(resubmitTokenKey, 30, TimeUnit.SECONDS);
                logger.debug("resubmitTokenKey get lock, key: " + resubmitTokenKey + " , expire in 20 seconds.");
                return true;
            } else {
                //判断日志级别
                if (logger.isDebugEnabled()) {
                    String desc = String.valueOf(valueOps.get(resubmitTokenKey));
                    logger.debug("resubmitTokenKey key: " + resubmitTokenKey + " locked by another business:" + desc);
                }
                return false;
            }
    
        }
    
        @Override
        public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            Object shrioUser = null;
            try {
                shrioUser = SecurityUtils.getSubject().getSession().getAttribute("adminUid");
            } catch (Exception e) {
            }
            if (shrioUser == null) {
                return ;
            }
            Integer userId = (Integer)shrioUser;
            String methodFullName = request.getRequestURI() + "_" + userId;
            String resubmitTokenKey = RESUBMIT_TOKEN + MD5.MD5Encode(methodFullName);
            //响应成功,删除缓存
            redisTemplate.delete(resubmitTokenKey);
        }
    
    
    }
  • 相关阅读:
    Effective C++ -----条款29:为“异常安全”而努力是值得的
    Effective C++ -----条款28:避免返回handles指向对象内部成分
    Effective C++ -----条款27:尽量少做转型动作
    Effective C++ -----条款26:尽可能延后变量定义式的出现时间
    Effective C++ -----条款25:考虑写出一个不抛异常的swap函数
    Effective C++ -----条款24:若所有参数皆需类型转换,请为此采用non-member函数
    HGE 第一个程序
    Help him http://acm.hdu.edu.cn/showproblem.php?pid=5059
    C 语言实例
    C 语言实例
  • 原文地址:https://www.cnblogs.com/zq1003/p/15100034.html
Copyright © 2020-2023  润新知