playframework 攔截器

我以爲play的攔截器有點AOP的思想,至關於struts的filter,play的攔截器使用註解方式實現的。java

源碼定義了這麼幾種註解:@before、@after、@catch、@finally 可謂是三百六十度無死角的攔截了。session


標註了@Before的方法會在該類的全部方法以前執行,舉例:less

[java] view plaincopy在CODE上查看代碼片派生到個人代碼片socket

  1. public class Admin extends Controller {  源碼分析

  2.    

  3.     @Before  spa

  4.     static void checkAuthentification() {  .net

  5.         if(session.get("user") == null) login();  日誌

  6.     }  code

  7.    

  8.     public static void index() {  orm

  9.         List<User> users = User.findAll();  

  10.         render(users);  

  11.     }  

  12.     …  

  13. }  


當請求進入Admin時會先檢查這個類中是否有@before註解,有就優先執行。

固然還有高級點的特性,若是您不想攔截某些方法,您能夠使用unless代表,這樣若是用戶發來login的請求就不會執行@Before了,以下:

[java] view plaincopy在CODE上查看代碼片派生到個人代碼片

  1. public class Admin extends Controller {  

  2.    

  3.     @Before(unless="login")  

  4.     static void checkAuthentification() {  

  5.         if(session.get("user") == null) login();  

  6.     }  

  7.    

  8.     public static void index() {  

  9.         List<User> users = User.findAll();  

  10.         render(users);  

  11.     }  

  12.    

  13.     …  

  14. }  

一樣,您也能夠使用only屬性,指定須要攔截的請求:

[java] view plaincopy在CODE上查看代碼片派生到個人代碼片

  1. public class Admin extends Controller {  

  2.    

  3.     @Before(only={"login","logout"})  

  4.     static void doSomething() {    

  5.         …    

  6.     }  

  7.     …  

  8. }  



@After註解的道理是同樣的,不過是執行了請求方法以後執行

[java] view plaincopy在CODE上查看代碼片派生到個人代碼片

  1. public class Admin extends Controller {  

  2.    

  3.     @After  

  4.     static void log() {  

  5.         Logger.info("Action executed ...");  

  6.     }  

  7.    

  8.     public static void index() {  

  9.         List<User> users = User.findAll();  

  10.         render(users);  

  11.     }  

  12.    

  13.     …  

  14. }  


下面說說@Catch註解,這個很好用,當程序拋出異常時候能夠被標註了@Catch的方法抓住,咱們能夠在裏面作一些必要的操做,好比rollback等。

[java] view plaincopy在CODE上查看代碼片派生到個人代碼片

  1. public class Admin extends Controller {  

  2.       

  3.     @Catch(IllegalStateException.class)  

  4.     public static void logIllegalState(Throwable throwable) {  

  5.         Logger.error("Illegal state %s…", throwable);  

  6.     }  

  7.       

  8.     public static void index() {  

  9.         List<User> users = User.findAll();  

  10.         if (users.size() == 0) {  

  11.             throw new IllegalStateException("Invalid database - 0 users");  

  12.         }  

  13.         render(users);  

  14.     }  

  15. }  


對了,其中的prioroty屬性能夠設置執行順序的優先級,priority=1是最早執行的。

[java] view plaincopy在CODE上查看代碼片派生到個人代碼片

  1. public class Admin extends Controller {  

  2.    

  3.     @Catch(value = Throwable.class, priority = 1)  

  4.     public static void logThrowable(Throwable throwable) {  

  5.         // Custom error logging…  

  6.         Logger.error("EXCEPTION %s", throwable);  

  7.     }  

  8.    

  9.     @Catch(value = IllegalStateException.class, priority = 2)  

  10.     public static void logIllegalState(Throwable throwable) {  

  11.         Logger.error("Illegal state %s…", throwable);  

  12.     }  

  13.    

  14.     public static void index() {  

  15.         List<User> users = User.findAll();  

  16.         if(users.size() == 0) {  

  17.             throw new IllegalStateException("Invalid database - 0 users");  

  18.         }  

  19.         render(users);  

  20.     }  

  21. }  


@Finally註解的方法和java的finally同樣,無論有沒有執行成功都會進入該方法,咱們能夠在裏面打印日誌:

[java] view plaincopy在CODE上查看代碼片派生到個人代碼片

  1. public class Admin extends Controller {  

  2.    

  3.     @Finally  

  4.     static void log(Throwable e) {  

  5.         if( e == null ){  

  6.             Logger.info("action call was successful");  

  7.         } else{  

  8.             Logger.info("action call failed", e);  

  9.         }  

  10.     }  

  11.    

  12.     public static void index() {  

  13.         List<User> users = User.findAll();  

  14.         render(users);  

  15.     }  

  16.     …  

  17. }  


上述全部的註解做用域都是類級別的,若是您想對另外的類也起做用,請用@With標籤:

[java] view plaincopy在CODE上查看代碼片派生到個人代碼片

  1. public class Secure extends Controller {  

  2.       

  3.     @Before  

  4.     static void checkAuthenticated() {  

  5.         if(!session.containsKey("user")) {  

  6.             unAuthorized();  

  7.         }  

  8.     }  

  9. }      

  10.   

  11. @With(Secure.class)  

  12. public class Admin extends Controller {  

  13.       

  14.     …  

  15. }  


實現的原理應該是這樣:socket請求發過來的時候,play 的路由會去匹配進入哪一個Controller,而後看這個Controller裏面有哪些系統標籤,而後按規定好的執行順序依次執行,這就是所謂的攔截了。(有時間把源碼分析也一塊兒發出來)

知道原理,咱們就能夠寫本身的攔截器了,好比權限管理:在每一個須要權限的方法上加上自定義的權限註解如:@MyAnatation(priority=1),用戶發起請求——@Before攔截——從登陸token拿到用戶信息——查看該用戶全部權限ID——對比自定義註解的priority——priority在權限ID中則容許訪問,不包含返回無此權限信息。


[java] view plaincopy在CODE上查看代碼片派生到個人代碼片

  1.  @Before(priority = 1)  

  2.     public static void doAuth(){  

  3.         Annotation annotation =  request.invokedMethod.getAnnotation(MyAnotation.class);  

  4.         if(annotation !=null){  

  5.             //鑑權開始  

  6.             QicFunction function =  (QicFunction)annotation;  

  7.             //todo  

  8.        }  

  9.   

  10.    }  


有了這種思想,咱們能夠作任何自定義的攔截行爲,誰也攔不住。


最後,要提醒本身,路漫漫其修遠兮,吾將上下而求索。加油啊!

相關文章
相關標籤/搜索