playframework 拦截器

我觉得play的拦截器有点AOP的思想,相当于struts的filter,play的拦截器使用注解方式实现的。

源码定义了这么几种注解:@before、@after、@catch、@finally 可谓是三百六十度无死角的拦截了。


标注了@Before的方法会在该类的所有方法之前执行,举例:

[java] view plaincopy在CODE上查看代码片

  1. public class Admin extends Controller {  

  2.    

  3.     @Before  

  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. }  


当请求进入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.    }  


有了这种思想,我们可以做任何自定义的拦截行为,谁也拦不住。


最后,要提醒自己,路漫漫其修远兮,吾将上下而求索。加油啊!


你可能感兴趣的:(playframework 拦截器)