一个一个来,按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失败实例。