拦截器-防重复提交

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

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);
    }


}

 

posted @ 2021-08-04 17:39  未确定  阅读(101)  评论(0编辑  收藏  举报