拦截器

ActFramework应用程序可以使用两种方式创建拦截器:

  1. 基于注解的方式 (类似PlayFramework)
  2. 通过继承写拦截器类

基于注解的拦截器

该设计完全基于PlayFramework 1.x的方式

Before

在某方法上使用@Before注解告诉ActFramework在执行该类中的所有请求响应器之前先调用该方法

下面我们使用拦截器来创建一个安全检查:

  1. public class Admin extends Controller.Util {
  2. @Before
  3. public void checkAuthentification() {
  4. if(session.get("user") == null) {
  5. redirect("/login");
  6. }
  7. }
  8. public void index() {
  9. Iterable<User> users = userDao.findAll();
  10. render(users);
  11. }
  12. }

如果不需要拦截器拦截发送给某些响应器的请求,可以使用except参数来指定豁免清单:

  1. public class Admin extends Controller.Util {
  2. @Before(except="login")
  3. static void checkAuthentification() {
  4. if(session.get("user") == null) {
  5. redirect("/login");
  6. }
  7. }
  8. public void index() {
  9. Iterable<User> users = userDao.findAll();
  10. render(users);
  11. }
  12. }

另一方面,你也可以使用only参数来指定该拦截器唯一作用于的响应器:

  1. public class Admin extends Controller.Util {
  2. @Before(only={"login","logout"})
  3. public void doSomething() {
  4. }
  5. }

除了@Before, exceptonly参数也可以在@After, @Catch@Finally注解中使用.

@After

标注有@After的方法在执行本类中所有的响应器之后被调用.

  1. public class Admin extends Controller.Util {
  2. @After
  3. public void log() {
  4. Logger.info("Action executed ...");
  5. }
  6. public void index() {
  7. Iterable<User> users = userDao.findAll();
  8. render(users);
  9. }
  10. }

@Catch

如果某方法标注有@Catch,该方法在当前类的响应器抛出异常后被调用. 被抛出的异常作为参数传递给@Catch方法.

  1. public class Admin extends Controller.Util {
  2. @Catch(IllegalStateException.class)
  3. public void logIllegalState(Throwable throwable) {
  4. Logger.error("Illegal state %s…", throwable);
  5. }
  6. public void index() {
  7. List<User> users = userDao.findAllAsList();
  8. if (users.size() == 0) {
  9. throw new IllegalStateException("Invalid database - 0 users");
  10. }
  11. render(users);
  12. }
  13. }

和通常的Java异常处理类似,你可以在@Catch拦截器方法中申明父类异常来捕获子类异常

  1. public class Admin extends Controller.Util {
  2. @Catch(value = Throwable.class, priority = 1)
  3. public void logThrowable(Throwable throwable) {
  4. // Custom error logging…
  5. Logger.error("EXCEPTION %s", throwable);
  6. }
  7. @Catch(value = IllegalStateException.class, priority = 2)
  8. public void logIllegalState(Throwable throwable) {
  9. Logger.error("Illegal state %s…", throwable);
  10. }
  11. public void index() {
  12. List<User> users = userDao.findAllAsList();
  13. if(users.size() == 0) {
  14. throw new IllegalStateException("Invalid database - 0 users");
  15. }
  16. render(users);
  17. }
  18. }

@Finally

标注有@Finally注解的方法在当前控制器的响应方法执行完成之后被调用,即便响应方法抛出异常,该拦截器也会被调用

  1. public class Admin extends Controller.Util {
  2. @Finally
  3. static void log() {
  4. Logger.info("Response contains : " + response.out);
  5. }
  6. public static void index() {
  7. List<User> users = userDao.findAllAsList();
  8. render(users);
  9. }
  10. }

类继承对拦截器的影响

如果控制器继承了某个基类,在基类中定义的拦截器也适用于子类控制器

使用@With注解来重用拦截器定义

如果你的控制器已经继承了某个基类,而你需要重用定义在另一个类的拦截器,可以通过@With注解来实现:

某个定义了拦截器的类:

  1. public class Secure extends Controller.Util {
  2. @Before
  3. static void checkAuthenticated() {
  4. if(!session.containsKey("user")) {
  5. unAuthorized();
  6. }
  7. }
  8. }

控制器类:

  1. @With(Secure.class)
  2. public class Admin extends MyOtherBaseClass {
  3. }

实现拦截器接口

基于注解的拦截器非常轻量,不过只适用于定义或这引用了拦截器的控制器。如果需要实现全局拦截,可以通过继承XxxInterceptor来实现

  1. import act.app.ActionContext;
  2. import act.handler.builtin.controller.BeforeInterceptor;
  3. import act.plugin.Plugin;
  4. import org.osgl.http.H;
  5. import org.osgl.mvc.result.Result;
  6. import javax.inject.Singleton;
  7. @Singleton
  8. public class MockRequestContentAcceptor extends BeforeInterceptor {
  9. public MockRequestContentAcceptor() {
  10. super(1);
  11. Plugin.InfoRepo.register(this);
  12. }
  13. @Override
  14. public Result handle(ActionContext actionContext) throws Exception {
  15. String s = actionContext.paramVal("fmt");
  16. if ("json".equalsIgnoreCase(s)) {
  17. actionContext.accept(H.Format.JSON);
  18. } else if ("csv".equalsIgnoreCase(s)) {
  19. actionContext.accept(H.Format.CSV);
  20. } else if ("xml".equalsIgnoreCase(s)) {
  21. actionContext.accept(H.Format.XML);
  22. }
  23. return null;
  24. }
  25. }

上面的代码拦截所有的请求,检查是否有fmt参数,如果发现fmt参数则设置相应的Accept头。

类似的拦截器接口还有:

  1. act.handler.builtin.controller.AfterInterceptor
  2. act.handler.builtin.controller.ExceptionInterceptor
  3. act.handler.builtin.controller.FinallyInterceptor

返回目录