您的位置:首页 > 其它

play框架使用起来(8)

2016-11-03 16:27 357 查看
1、拦截器

  控制器中可以定义拦截方法(也可称之为拦截器),为控制器及其子类的所有Action提供服务。当所有的Action都需要进行通用的处理时,该功能就显得非常有用:比
如验证用户的合法性,加载请求范围内的信息等。

        读者在使用时需要注意的是,这些拦截器方法不能定义为public,但必须是static,并通过有效的拦截标记进行注解。


1.1 @Before#

      使用@Before注解的方法会在每个Action调用之前执行。如创建具有用户合法性检查的拦截器:

public class Admin extends Application {
 
    @Before
    static void checkAuthentification() {
        if(session.get("user") == null) login();
    }
 
    public static void index() {
        List<User> users = User.findAll();
        render(users);
    }
 
    ...
 
}


 如果不希望@Before注解拦截所有的Action方法,那么可以使用unless参数列出需要排除的方法:

public class Admin extends Application {
 
    @Before(unless="login")
    static void checkAuthentification() {
        if(session.get("user") == null) login();
    }
 
    public static void index() {
        List<User> users = User.findAll();
        render(users);
    }
 
    ...
 
}


      或者直接使用only参数把需要拦截的方法列举出来:

public class Admin extends Application {
 
    @Before(only={"login","logout"})
    static void doSomething() {  
        ...
    }
    ...
}


      unless和only参数对@After,@Before以及@Finally注解都适用。


1.2 @After#

      使用@After注解的方法会在每个Action调用之后执行:

public class Admin extends Application {
 
    @After
    static void log() {
        Logger.info("Action executed ...");
    }
 
    public static void index() {
        List<User> users = User.findAll();
        render(users);
    }
 
    ...
 
}



1.3 @Catch#

      如果有Action方法抛出了异常,那么使用@Catch注解的方法就会执行,且抛出的异常会以参数的形式传递到@Catch注解的方法中。具体实现如下:

public class Admin extends Application {
       
    @Catch(IllegalStateException.class)
    public static void logIllegalState(Throwable throwable) {
        Logger.error("Illegal state %s…", throwable);
    }
   
    public static void index() {
        List<User> users = User.findAll();
        if (users.size() == 0) {
            throw new IllegalStateException("Invalid database - 0 users");
        }
        render(users);
    }
}


      使用@Catch注解和普通的Java异常处理程序一样,捕获父类往往可以获得更多的异常类型。如果拥有多个需要捕获的方法,可以通过指定优先级来确定他们的执行顺序。具体实现如下:

public class Admin extends Application {
 
    @Catch(value = Throwable.class, priority = 1)
    public static void logThrowable(Throwable throwable) {
        // Custom error logging…
        Logger.error("EXCEPTION %s", throwable);
    }
 
    @Catch(value = IllegalStateException.class, priority = 2)
    public static void logIllegalState(Throwable throwable) {
        Logger.error("Illegal state %s…", throwable);
    }
 
    public static void index() {
        List<User> users = User.findAll();
        if(users.size() == 0) {
            throw new IllegalStateException("Invalid database - 0 users");
        }
        render(users);
    }
}



1.4 @Finally#

      @Finally注解的方法总是在每个Action调用之后执行(无论Action是否成功执行):

public class Admin extends Application {
 
    @Finally
    static void log() {
        Logger.info("Response contains : " + response.out);
    }
 
    public static void index() {
        List<User> users = User.findAll();
        render(users);
    }
 
    ...
 
}


      如果@Finally注解的方法中包含的参数是可抛出的异常,其方法中的内容还是可以继续执行的,具体如下:

public class Admin extends Application {
 
    @Finally
    static void log(Throwable e) {
        if( e == null ){
            Logger.info("action call was successful");
        } else{
            Logger.info("action call failed", e);
        }
    }
 
    public static void index() {
        List<User> users = User.findAll();
        render(users);
    }



1.5 使用@with注解增加更多拦截器#

      如果某个控制器是其他一些类的父类,那么该控制器中定义的所有拦截器会影响到所有子类。由于Java不允许多重继承,对单纯通过继承来使用拦截器造成了一定的局限性。Play可以通过@With注解,调用其他控制器中已经定义好的拦截方法,从而突破这一局限。比如创建Secure控制器,定义checkAuthenticated()拦截方法验证用户合法性:

public class Secure extends Controller {
   
    @Before
    static void checkAuthenticated() {
        if(!session.containsKey("user")) {
            unAuthorized();
        }
    }
}    


      在其他的控制器中,可以通过@With(Secure.class)注解将其包含进来:

@With(Secure.class)
public class Admin extends Application {
   
    ...
}


1.6 Session和Flash作用域

      在Play开发中,如果需要在HTTP请求之间保存数据,可以将数据保存在Session或者Flash内。保存在Session中的数据在整个用户会话中都是有效的,而保存在Flash的数据只对下一次请求有效。

      特别需要注意的是,Session和Flash作用域中的数据都是采用Cookie机制添加到随后的HTTP响应中的(并没有存储在服务器上的),所以数据大小非常有限(不能超过4K),而且只能存储字符串类型的数据。

      由于Cookie是使用密钥签名过的,所以客户端不能轻易修改Cookie的数据(否则会失效)。不要将Play的Session当作缓存来使用,如果需要在特定的会话中缓存一些数据,那么可以使用Play内置的缓存机制,并将session.getId()作为缓存的key进行储存。

public static void index() {
    List messages = Cache.get(session.getId() + "-messages", List.class);
    if(messages == null) {    
        // 处理缓存失效
        messages = Message.findByUser(session.get("user"));
        Cache.set(session.getId() + "-messages", messages, "30mn");
    }
    render(messages);
}


      Session在用户关闭浏览器后就会失效,除非修改配置文件中的application.session.maxAge属性。设置方法如下:

application.session.maxAge=7d  # Remember for one week.


      使用Play内置的Cache缓存时需要注意,Cache与传统Servlet的HTTP Session对象是不同的。框架无法保证这些缓存对象会一直存在,所以在业务代码中必须处理缓存失效的问题,以便保持应用完全无状态化。

控制层基本的工作流程为:接收HTTP请求的参数,通过对域模型的操作来实现业务逻辑,最终调用视图进行渲染。有时候控制器所做的仅仅是简单的查询操作,有时候需要改变域模型的状态(更新数据),或者通过Action链将处理转发至其他控制器方法。值得注意的是,Play将Session数据以Cookie的机制存放在客户端,而服务器端则用Cache的方式进行数据缓存。

拦截器
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: