一個一個來,按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失敗實例。