SpringMVC攔截器的使用場景
微信公眾號:javaFramework
歡迎關注
1.SpringMVC攔截器
1.1 攔截器簡介
Spring web MVC的處理器攔截器類似於Servlet開發中的過濾器Filter,用於對處理器 進行預處理和後處理。
1.2 常見應用場景
1、日誌記錄 :記錄請求資訊的日誌
2、許可權檢查,如登入檢查
3、效能檢測:檢測方法的執行時間
1.2.1 日誌記錄
package com.yaspeed.web.interceptor;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.NamedThreadLocal;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* 日誌攔截器 <br>
* 記錄資訊:訪問時間-Controller路徑-對應方法名-請求引數資訊-請求相對路徑-請求處理時長
*
* @author Administrator
*
*/
public class LogInterceptor implements HandlerInterceptor {
public static final Logger LOGGER = LoggerFactory.getLogger(LogInterceptor.class);
private static final ThreadLocal<Long> startTimeThreadLocal = new NamedThreadLocal<Long>("ThreadLocal StartTime");
private String getParamString(Map<String, String[]> map) {
StringBuilder sb = new StringBuilder();
for (Entry<String, String[]> e : map.entrySet()) {
sb.append(e.getKey()).append("=");
String[] value = e.getValue();
if (value != null && value.length == 1) {
sb.append(value[0]).append("\t");
} else {
sb.append(Arrays.toString(value)).append("\t");
}
}
return sb.toString();
}
/**
* 將ErrorStack轉化為String.
*/
public static String getStackTraceAsString(Throwable e) {
if (e == null) {
return "";
}
StringWriter stringWriter = new StringWriter();
e.printStackTrace(new PrintWriter(stringWriter));
return stringWriter.toString();
}
@Override
/**
* 該方法將在請求處理之前進行呼叫<br>
* 多個Interceptor,然後在SpringMVC會根據宣告的前後順序一個接一個的執行,而且所有的Interceptor中的preHandle方法都會在<br>
* COntroller方法之前呼叫。SpringMVC的這種Interceptor鏈式結構也是可以中斷的,這種中斷方式時令preHandler的返回值為false<br>
* 當prehandler的返回值為false的時候整個請求就結束了。
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
long startTime = System.currentTimeMillis();
request.setAttribute("startTime", startTime);
startTimeThreadLocal.set(startTime); // 執行緒繫結變數(該資料只有當前請求的執行緒可見)
if (HandlerMethod.class.equals(handler.getClass())) {
StringBuilder sb = new StringBuilder(1000);
sb.append("-----------------------開始計時:").append(new SimpleDateFormat("hh:mm:ss.SSS").format(startTime))
.append("-------------------------------------\n");
HandlerMethod h = (HandlerMethod) handler;
sb.append("Controller: ").append(h.getBean().getClass().getName()).append("\n");
sb.append("Method : ").append(h.getMethod().getName()).append("\n");
sb.append("Params : ").append(getParamString(request.getParameterMap())).append("\n");
sb.append("URI : ").append(request.getRequestURI()).append("\n");
LOGGER.debug(sb.toString());
}
return true;
}
/**
* 在當前請求進行處理之後,也就是Controller 方法呼叫之後執行,但是它會在DispatcherServlet
* 進行檢視返回渲染之前被呼叫,所以我們可以在這個方法中對Controller 處理之後的ModelAndView 物件進行操作。
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
long startTime = (Long) request.getAttribute("startTime");
long endTime = System.currentTimeMillis();
long executeTime = endTime - startTime;
if (HandlerMethod.class.equals(handler.getClass())) {
StringBuilder sb = new StringBuilder(1000);
sb.append("CostTime : ").append(executeTime).append("ms").append("\n");
sb.append("-------------------------------------------------------------------------------");
LOGGER.debug(sb.toString());
}
}
/**
* 該方法將在整個請求結束之後,也就是在DispatcherServlet 渲染了對應的檢視之後執行。這個方法的主要作用是用於進行資源清理工作的。
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// 列印JVM資訊。
if (LOGGER.isDebugEnabled()) {
long beginTime = startTimeThreadLocal.get();// 得到執行緒繫結的區域性變數(開始時間)
long endTime = System.currentTimeMillis(); // 2、結束時間
// 如果controller報錯,則記錄異常錯誤
if (ex != null) {
LOGGER.debug("Controller異常: " + getStackTraceAsString(ex));
}
LOGGER.debug("計時結束:" + new SimpleDateFormat("hh:mm:ss.SSS").format(endTime) + " 耗時:" + (endTime - beginTime)
+ " URI:" + request.getRequestURI());
startTimeThreadLocal.remove();
}
}
}
springmvc.xml 中的配置
<!-- 配置攔截器 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.yaspeed.web.interceptor.LogInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
1.2.2 許可權檢查
/**
* 許可權檢查
*
* @author Administrator
*
*/
public class PermissionInterceptor implements HandlerInterceptor {
// 在執行handler之前來執行的
// 用於使用者認證校驗、使用者許可權校驗
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 得到請求的url
String url = request.getRequestURI();
// 判斷是否是公開 地址
// 實際開發中需要公開 地址配置在配置檔案中
// 從配置中取逆名訪問url
List<String> open_urls = ResourcesUtil.gekeyList("anonymousURL");
// 遍歷公開 地址,如果是公開 地址則放行
for (String open_url : open_urls) {
if (url.indexOf(open_url) >= 0) {
// 如果是公開 地址則放行
return true;
}
}
// 從配置檔案中獲取公共訪問地址
List<String> common_urls = ResourcesUtil.gekeyList("commonURL");
// 遍歷公用 地址,如果是公用 地址則放行
for (String common_url : common_urls) {
if (url.indexOf(common_url) >= 0) {
// 如果是公開 地址則放行
return true;
}
}
// 獲取session
HttpSession session = request.getSession();
ActiveUser activeUser = (ActiveUser) session.getAttribute("activeUser");
// 從session中取許可權範圍的url
List<SysPermission> permissions = activeUser.getPermissions();
for (SysPermission sysPermission : permissions) {
// 許可權的url
String permission_url = sysPermission.getUrl();
if (url.indexOf(permission_url) >= 0) {
// 如果是許可權的url 地址則放行
return true;
}
}
// 執行到這裡攔截,跳轉到無權訪問的提示頁面
request.getRequestDispatcher("/WEB-INF/jsp/refuse.jsp").forward(request, response);
// 如果返回false表示攔截不繼續執行handler,如果返回true表示放行
return false;
}
// 在執行handler返回modelAndView之前來執行
// 如果需要向頁面提供一些公用 的資料或配置一些檢視資訊,使用此方法實現 從modelAndView入手
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("HandlerInterceptor1...postHandle");
}
// 執行handler之後執行此方法
// 作系統 統一異常處理,進行方法執行效能監控,在preHandle中設定一個時間點,在afterCompletion設定一個時間,兩個時間點的差就是執行時長
// 實現 系統 統一日誌記錄
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("HandlerInterceptor1...afterCompletion");
}
}
1.2.3 效能檢測
/**
* 實現統計應用效能 攔截器 的實現是單例的,因此不管使用者請求多少次 都 只訪問一個攔截器例項,即執行緒不安全<br>
* 解決方案:使用ThreadLocal,它是執行緒繫結的變數,提供執行緒區域性變數 (一個執行緒一個ThreadLocal)
*
* @author Administrator
*
*/
public class TimeInterceptor implements HandlerInterceptor {
public static final Logger logger = LoggerFactory.getLogger(TimeInterceptor.class);
// 統計應用效能
private NamedThreadLocal<Long> startTimeThreadLocal = new NamedThreadLocal<>("StopWatch-StartTime");
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 1,開始時間
long startTime = System.currentTimeMillis();
// 執行緒繫結變數(該資料只有當前請求的執行緒可見)
startTimeThreadLocal.set(startTime);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// 2.結束時間
long endTime = System.currentTimeMillis();
// 得到執行緒繫結的區域性 變數(開始時間)
long beginTime = startTimeThreadLocal.get();
// 3.計算消耗時間
long consumeTime = endTime - beginTime;
logger.debug("監控==========================: "
+ String.format("%s consume %d millis", request.getRequestURI(), consumeTime));
startTimeThreadLocal.remove();
}
}
相關文章
- SpringMVC攔截器SpringMVC
- SpringMVC中的攔截器SpringMVC
- SpringMVC攔截器,設定不攔截的URLSpringMVC
- SpringMVC-攔截器SpringMVC
- 【SpringMVC】 4.3 攔截器SpringMVC
- SpringMVC中的攔截器Interceptor實現SpringMVC
- Spring MVC 中的攔截器的使用“攔截器基本配置” 和 “攔截器高階配置”SpringMVC
- SpringMVC(六) 攔截器和使用者登入校驗SpringMVC
- spring mvc 攔截器的使用SpringMVC
- 攔截器的使用問題
- axios 攔截器 的使用方法iOS
- Spring Boot中攔截器的使用Spring Boot
- SpringMvc-10.14上傳、攔截器、異常處理SpringMVC
- SpringMVC【校驗器、統一處理異常、RESTful、攔截器】SpringMVCREST
- 在springboot中使用攔截器Spring Boot
- axios 攔截器iOS
- spring攔截器Spring
- axios攔截器iOS
- sql攔截器SQL
- Mybatis 攔截器MyBatis
- MyBatis攔截器MyBatis
- grpc中的攔截器RPC
- 【SpringMVC】檔案上傳與下載、攔截器、異常處理器SpringMVC
- Springmvc mvc:exclude-mapping不攔截 無效SpringMVCAPP
- SpringMVC(五)RESTful支援,Dispatcher常見的攔截路徑SpringMVCREST
- Mybatis Interceptor 攔截器MyBatis
- spring boot 攔截器Spring Boot
- gRPC(3):攔截器RPC
- webwork的攔截器真是好用Web
- Java實現的攔截器Java
- SpringBoot攔截器中獲取註解、攔截器中注入ServiceSpring Boot
- SpringMVC 中 @ControllerAdvice 註解的三種使用場景!SpringMVCController
- Flume內建攔截器與自定義攔截器(程式碼實戰)
- Spring Boot新增攔截器Spring Boot
- SpringBoot 手寫攔截器Spring Boot
- HandlerInterceptor - 自定義攔截器
- 攔截過濾器模式過濾器模式
- mybatis註冊攔截器MyBatis