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失敗實例


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM