在Spring Filter中拋出異常的一種辦法


轉自:在Spring Filter中拋出異常的一種辦法

先說辦法,如果看官覺得合適再往下看原理吧

解決辦法

步驟:

1、創建一個專門拋出Filter中異常的Controller及接口方法,例如該接口地址為:/filter/login_auth_fail

 1 @RequestMapping("/filter")
 2 @RestController
 3 public class FilterController {
 4     @RequestMapping("/login_auth_fail")
 5     public void loginAuthFail(HttpServletRequest request) {
 6       // 此處構造一個合適的異常並拋出即可
 7       String code = request.getAttribute("code");
 8       throw new CustomException(code);
 9     }
10 }

2、在Filter中,需要拋出異常的地方,將異常信息存起來(例如:可以存在HttpServletRequest中),並將請求轉發給上面創建的接口地址:

1 request.setAttribute("code", "xxx");
2 request.getRequestDispatcher("/filter/login_auth_fail").forward(request, response);

原理

可能大家嘗試過一種攔截辦法:使用@ControllerAdvice和@ExceptionHanlder組合攔截,但並沒有成功攔截Filter中的異常

1 @ControllerAdvice
2 public class ExpHanlder {
3   @ExceptionHandler(Exception.class)
4   public void handle() {
5     // do somthing...
6   }
7 }

那為什么沒有成功呢?關鍵在於@ControllerAdvice只是對Controller做了加強,而Filter在Controller之前進行,故而異常就這樣逃出了咱們的“掌心”。
本文中介紹的辦法,恰是利用了這樣的運行順序,讓異常乖乖地拋出去:既然Filter中不能拋出,那我先把錯誤信息記錄下來,把請求轉發到一個特定的接口(可認為是一個“陷阱”),然后在這個接口中利用記錄的錯誤信息復原一個異常拋出即可。

到這,解決辦法的原理已經介紹完了了,后面內容按需觀看,將和大家一起回顧Filter與Controller的業務流程。

借用Spring 梳理 - filter、interceptor、aop實現與區別 -第二篇中的順序圖:
Filter與Controller運行順序
可以看到,Spring在將請求交給Controller的接口處理前、后分別調用Filter鏈中Filter的方法對處理進行增強。當preHandle中將異常拋出時,並沒有到Controller,故而@ControllerAdvice未能攔截該異常。

筆者是在集成Shiro時,需要保留原有項目功能:在身份驗證失敗或越權時返回JSON格式錯誤信息而遇到了這個問題,因為Shiro是基於Filter做的攔截,故而需要將Filter中的錯誤信息拋出。
項目原先的登陸驗證是放在AOP做的,而AOP也在Filter之后進行,關於Filter、Interceptor、AOP及其異常拋出順序,可以看下這篇文章:Spring:過濾器filter、攔截器interceptor、和AOP的區別與聯系


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM