Spring 2.5+ 推薦註解驅動開發,核心兩大 Handler:
兩者攔截器配置方式**完全不同**,且後者**原生不支持攔截器**,需變通。
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list>
<bean class="com.example.AuthInterceptor"/>
<bean class="com.example.LoggingInterceptor"/>
</list>
</property>
</bean>
public class AuthInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// handler 為 Controller 類 (DefaultAnnotationHandlerMapping 模式)
String className = handler.getClass().getName();
if (needAuth(className) && !isLoggedIn(request)) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return false; // 阻斷請求
}
return true; // 放行
}
}
優點:標準 Spring MVC 攔截器鏈,支持 `preHandle`/`postHandle`/`afterCompletion` 完整生命週期,可訪問 Handler 類信息。
痛點:`AnnotationMethodHandlerAdapter` 無 `interceptors` 屬性。GAE 等環境禁用 `DefaultAnnotationHandlerMapping` (依賴 `BeanUtils.findEditorByConvention` → `ClassLoader.getSystemClassLoader` 被禁止) 時,被迫用此方案。
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="customArgumentResolver">
<bean class="com.example.AuthResolver"/>
</property>
</bean>
public class AuthResolver implements WebArgumentResolver {
@Override
public Object resolveArgument(MethodParameter param, NativeWebRequest request) {
// 1. 獲取 Controller 類名
String className = param.getMethod().getDeclaringClass().getName();
// 2. 從 NativeWebRequest 取原生 Request/Response
HttpServletRequest req = (HttpServletRequest) request.getNativeRequest();
HttpServletResponse resp = (HttpServletResponse) request.getNativeResponse();
// 3. 驗證邏輯
if (needAuth(className) && !isLoggedIn(req)) {
if (!resp.isCommitted()) { // 關鍵:避免重複提交錯誤
resp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
return UNRESOLVED; // 表示不處理該參數,流程終止
}
return UNRESOLVED; // 正常放行,讓後續 Resolver/默認解析器處理參數
}
}
| 缺陷 | 影響 | 規避措施 |
|---|---|---|
| 每方法參數調用一次 | 3 參數方法 → 執行 3 次驗證 | 靜態 `ThreadLocal` 緩存請求級驗證結果,首次計算後復用 |
| 非標準攔截點 | 無 `postHandle`/`afterCompletion`,無法做響應後處理 | 關鍵邏輯前置;響應後處理改用 `Filter` 或 `ResponseBodyAdvice` (Spring 4.1+) |
| 需手動判斷 `resp.isCommitted()` | 避免 `IllegalStateException: Response already committed` | 務必加守衛,見代碼 |
<mvc:annotation-driven>
<mvc:interceptors>
<bean class="com.example.AuthInterceptor"/>
</mvc:interceptors>
</mvc:annotation-driven>
Spring MVC 註解風格下,**`DefaultAnnotationHandlerMapping` 是攔截器的正統載體**;`AnnotationMethodHandlerAdapter` 的 `customArgumentResolver` 僅作受限環境下的權宜之計。現代項目 (Spring 3.1+) 請直接遷移至 `mvc:annotation-driven` + `RequestMappingHandlerMapping`,享受原生攔截器支持與更強的擴展性。理解兩代 Handler 架構差異,是排查遺留系統攔截器失效、參數解析異常的關鍵鑰匙。