springboot拦截器配置、消息头校验、重复请求过滤

  一个一个来,按spring boot的风格,我们不喜欢xml文件,所以使用java类来启用拦截器配置:

import com.wlf.order.prize.aop.RequestInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new RequestInterceptor()).addPathPatterns("/**").
                excludePathPatterns("/jpservice/getSign", "/jpservice/getTimeStamp");
    }
}

 

  上面我们拦截了所有的web请求,除了这两个接口:"/jpservice/getSign", "/jpservice/getTimeStamp"

  接着我们进入拦截器里,做消息头校验、重复请求校验:

 

import com.wlf.order.prize.javabean.Result;
import com.wlf.order.prize.util.BeanConvert;
import com.wlf.order.prize.util.IPUtil;
import com.wlf.order.prize.util.ThreadLocalUtil;
import com.wlf.order.prize.util.TimeStampList;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 拦截器:增加重复请求的过滤、话单记录处理
 *
 * @author wulinfeng
 * @since 2019/12/25
 */
@Slf4j
@Component
public class RequestInterceptor extends HandlerInterceptorAdapter {

    private final static SimpleDateFormat SF = new SimpleDateFormat("yyyyMMddHHmmss");

    // 话单格式:记录时间|接口名称|接口时延|调用方IP|本地IP|业务参数|结果码|序列号
    private final static String CDR_FORMAT = "{}|{}|{}|{}|{}|{}|{}|{}";

    // 时间戳缓存
    private final static TimeStampList cache = new TimeStampList(10000);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        // 请求头校验
        String timestamp = request.getHeader("timestamp");
        String sign = request.getHeader("sign");
        if (timestamp == null || timestamp.trim().equals("") || sign == null || sign.trim().equals("")) {
            Result result = new Result(1025, "请求头缺失.");
            getResponse(result, response);
            return false;
        }

        // 时间戳校验
        if (timestamp.length() != 13) {
            Result result = new Result(1026, "时间戳格式错误.");
            getResponse(result, response);
            return false;
        }

        Long requestTime = null;
        try {
            requestTime = Long.parseLong(timestamp);
        } catch (NumberFormatException e) {
            Result result = new Result(1026, "时间戳格式错误.");
            getResponse(result, response);
            return false;
        }

        // 重复请求校验
        if (cache.contains(requestTime)) {
            Result result = new Result(1027, "重复请求.");
            getResponse(result, response);
            return false;
        }

        cache.add(requestTime);

        // 获取请求和本地IP,记录话单
        String beginTime = String.valueOf(System.currentTimeMillis());
        String remoteIp = IPUtil.getRemoteIp(request);
        String localIp = IPUtil.getLocalIp();

        Map<String, String> strMap = new HashMap<>();
        strMap.put("beginTime", beginTime);
        strMap.put("remoteIp", remoteIp);
        strMap.put("localIp", localIp);
        strMap.put("sequence", timestamp);

        ThreadLocalUtil.setMap(strMap);

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           @Nullable ModelAndView modelAndView) throws Exception {

        // 计算接口时延
        Map<String, String> strMap = ThreadLocalUtil.getMap();
        long beginTime = Long.parseLong(strMap.get("beginTime"));
        long currentTime = System.currentTimeMillis();

        // 获取当前时间
        String currentDate = SF.format(new Date(currentTime));

        // 记录话单
        log.error(CDR_FORMAT, currentDate, strMap.get("apiType"), currentTime - beginTime, strMap.get("remoteIp"),
                strMap.get("localIp"), strMap.get("sequence"), strMap.get("biz"), strMap.get("resultCode"));
    }


    /**
     * 构造响应消息体
     *
     * @param result
     * @param response
     * @throws IOException
     */
    private void getResponse(Result result, HttpServletResponse response) throws IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");

        PrintWriter out = null;
        out = response.getWriter();
        out.write(BeanConvert.getResultJson(result));
        out.flush();
        out.close();
    }
}

 

  如果你的拦截器需要注入bean,而且失败了,可以参见springboot拦截器注入bean失败实例

posted on 2019-12-26 15:27  不想下火车的人  阅读(3837)  评论(0编辑  收藏  举报

导航