本文描述的是在springmvc中,通過注解清除(跳過)攔截器,支持在Controller類級別或者方法級別來清除,可同時清除多個攔截器。
在開發web后臺時,我們的接口一般都需要加權限控制。比如一個簡單的場景:用戶需要登錄后才能訪問,沒登錄就直接跳轉登錄界面或者返回特定的錯誤碼。通常我們會配置一個攔截器,驗證一下用戶請求攜帶的token,如果驗證通過就返回true. 這時候有這么一個需求:幾乎所有的controller都需要攔截,但某幾個Controller或者Controller里面的方法需要跳過攔截器,比如用戶登錄的接口和錯誤處理的接口,雖然這時候我們可以在配置爛機器的時候配置忽略路徑,但這樣不夠靈活。前幾天用注解實現了這一功能,這里做一個簡單描述。
首先創建一個注解,內容很簡單,value為一個包含要清除的攔截器的數組。
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Clear {
Class<? extends HandlerInterceptor>[] value() default {};
}
接下來要在你的攔截器里面來獲取當前請求對應的方法或者該方法所處的類上面是否有清除當前攔截器的注解。如果有就直接返回true。比如我有一個ApiInterceptor,主要代碼如下:
public class ApiInterceptor implements HandlerInterceptor {
//只列出主要代碼
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
HandlerMethod m= (HandlerMethod) o;
Method method=m.getMethod();
//判斷是否用注解清除
if(clearedByAnnotation(method)){
return true;
}
//其他操作,比如驗證token
httpServletResponse.sendRedirect("/api/error/401");
return false;
}
private boolean clearedByAnnotation(Method method){
Clear clear=method.getAnnotation(Clear.class);
if(clear!=null){
if(Arrays.asList(clear.value()).contains(ApiInterceptor.class)){
return true;
}
}
Class clazz=method.getDeclaringClass();
clear= (Clear) clazz.getDeclaredAnnotation(Clear.class);
if(clear!=null){
if(Arrays.asList(clear.value()).contains(ApiInterceptor.class)){
return true;
}
}
return false;
}
}
然后,在使用的時候,我們只需要在Controller或者Controller里面的方法上面加上Clear注解即可:
@RestController
@RequestMapping("/api/user")
public class UserApi {
@PostMapping("/login/{code}")
@Clear(ApiInterceptor.class)
public Res doLogin(@PathVariable String code, HttpServletRequest req){
// TODO
return Res.ok;
}
}
清除多個攔截器:
@RestController
@RequestMapping("/api/error")
@Clear({ApiInterceptor.class,AdminInterceptor.class})
public class ErrorApi {
@RequestMapping("/{code}")
public Res error(@PathVariable int code){
return Res.fail.code(code);
}
}
然后,就沒有然后了,這樣就ok了,雖然說代碼多一點,但比起配置忽略路徑要更靈活,最重要的是更能裝X。然后補充一點,如果攔截器比較多的話,每個都這么配會比較繁瑣,可以寫一個BaseInterceptor, 然后其他攔截器繼承就可以。
你說我是有多無聊,無聊到開始上班寫博客玩了……