1.3.0 版的新特性

#128 缓存页面

这个特性允许开发人员通过注解来打开页面缓存:

  1. @GetAction
  2. @CacheFor
  3. public void home() {
  4. }

上面的代码将主页缓存1个小时。开发人员也可以制定缓存失效期限,比如下面的代码让缓存在半小时之后失效:

  1. @GetAction
  2. @CacheFor(60 * 30)
  3. public void home() {
  4. }

注意缓存页面仅仅对 GET 请求有效. 但是某些特殊场合,比如 facebook 向应用主页(iframe 内)重定向是采用 POST 请求。这时候我们希望页面缓存对 POST 也有效,可以这样写:

  1. @GetAction
  2. @CacheFor(supportPost = true)
  3. public void home() {
  4. }

#154 支持配置多种策略处理无验证身份请求(Missing Authentication Request)

ActFramework 允许开发人员配置相应的策略来处理无验证身份请求。目前框架提供了两种策略:

  1. 将请求重定向到配置好的 URL (默认为 /login),一般用于普通的 web 应用
  2. 返回 401 Unauthorised 响应,通常用于前后端分离的单页应用,包括移动应用等

问题在于这是一个单一的全局性的配置不能处理应用在不同场合需要不同策略的情况。比如,一个应用的主体是提供 RESTful 服务来支持前端的单页应用或者移动应用,因此我们将策略配置为返回 401 响应。但后来我们需要给应添加一个采用常规编写的管理后台,对所有发送给管理后台的请求如果没有身份验证,我们希望重定向到 /admin/login 而不是统一地返回 401 响应

这个增强提供了处理这种情况的办法:使用 @HandleMissingAuthentication 注解来覆盖(Overwrite)全局配置:

  1. @HandleMissingAuthentication(value = HandleMissingAuthentication.Option.REDIRECT, custom = "/admin/login")
  2. @TemplateContext("/admin")
  3. @UrlContext("/admin")
  4. public class AdminConsole extends Controller.Base {
  5. ...
  6. }

#163 引入 @TemplateContext 注解

r1.3.0 之前, 除非开发人员在 API 里明确指定模板路径,ActFramework 通过匹配包,类和方法名字 来定位模板,例如:

  1. package com.mycom.myprj;
  2. public class MyController {
  3. @GetAction("/")
  4. public void home() {
  5. }
  6. }

这里和 home() 对应的模板应该放在:

  1. resources/rythm/com/mycom/myprj/MyController/home.html

这个规则很简单,非常容易理解和记忆,但在我们拥有一个优秀的 IDE 插件支持之前创建和寻找模板文件都是一件痛苦单调的事情。

现在因为有了 @TemplateContext 我们可以大大地缓解这种状况:

  1. package com.mycom.myprj;
  2. @TemplateContext("/my")
  3. public class MyController {
  4. @GetAction("/")
  5. public void home() {
  6. }
  7. }

根据以上代码 ActFramework 在下面的路径虚招 home() 对应的模板:

  1. resources/rythm/my/home.html

变得清爽多了,不是吗?

#164 分解 @Controller 注解到 @UrlContext@Port

我们刚刚引入了 @TemplateContext, 现在我们希望搞一个对应的: @UrlContext, 用来制定一个控制器类下所有的响应方法的 URL context。

实际上我们已经有了这个概念,不过是通过 act.controller.Controller 注解提供的, 如下例所示:

  1. @Controller("admin")
  2. public class Admin {
  3. @GetAction
  4. public String home() {
  5. }
  6. }

现在我们通过引入 @UrlContext 注解让这个概念更加清晰:

  1. @UrlContext("admin")
  2. public class Admin {
  3. @GetAction
  4. public String home() {
  5. }
  6. }

这段代码对我来讲更加清晰,因为 admin 作为 URL context 的含义被明显指定了.

@Controller 注解中还有另一个概念:命名端口,如下例所示:

  1. @Controller(port = "admin")
  2. public class Admin {
  3. @GetAction
  4. public String home() {
  5. }
  6. }

如果应用的配置文件中有下列配置:

  1. namedPorts=admin:5462

上面的代码表示 Admin 类里面的响应器只会处理发送到 5462 端口的请求。

我们不希望把命名端口指定放进 @UrlContext 注解. 因此引入了另一个注解来处理命名端口: Port:

  1. @Port("admin")
  2. public class Admin {
  3. @GetAction
  4. public String home() {
  5. }
  6. }

这段使用 @Port 的代码比上面使用 @Controller(port = "admin") 的代码更简单清楚.

#168 让所有的扫描器处理 @Env 相关注解

ActFramework 有三个和 Env(环境)相关的注解,用于在特定运行环境开关一些逻辑/特性例如:

  1. @Env.Mode(PROD)
  2. public class ModuleForProd extends Module {
  3. @Override
  4. protected void configure() {
  5. bind(HiService.class).to(HiServiceImpl.class);
  6. bind(ByeService.class).to(ByeServiceImpl.class);
  7. }
  8. }

上面的代码表示只有当应用运行在 prod 模式下依赖注入模块 ModuleForProd 才会被调用配置.

这个 #168 issue 让 Env 注解的含义扩充到所有的类扫描器,比如:

  1. @Env.Group("test")
  2. public class TestController {
  3. ...
  4. }
  1. @Env.Group(value = "test", unless = true)
  2. public class NoTestController {
  3. ...
  4. }

上面的代码表示当前环境是 test 组的时候 TestController 才生效,而 NoTestController 则正好相反,只有当前环境不是 test 组才生效

#169 路径中新的正则表达式变量

ActFramework 支持在路由中指定正则表达式变量,例如:

  1. @GetAction("/int/{<[0-9]+>n}")
  2. public int n(int n) {
  3. return n;
  4. }

r1.3.0 版引入了另外两种表达法:

  1. @GetAction("/int/{n<[0-9]+>}")
  2. public int n(int n) {
  3. return n;
  4. }

  1. @GetAction("/int/n:[0-9]+")
  2. public int n(int n) {
  3. return n;
  4. }

#170 更容易地定制全局模板变量

r1.3.0 之前创建全局模板变量的过程是很繁复的。首先需要建立一个新项目, 然后创建一个 ImplicitVariableProvider 插件的实现类, 编译并发布这个插件项目作为单独的 jar 库,然后才能在应用项目中使用其中定义的全局变量。

r1.3.0 版提供了一种新的机制让应用可以非常轻松自由地定于全局模板变量:

  1. @ProvidesImplicitTemplateVariable("foo")
  2. public String foo() {
  3. return "bar";
  4. }
  5. @ProvidesImplicitTemplateVariable("bar")
  6. public static int bar() {
  7. return 3;
  8. }
  9. @ProvidesImplicitTemplateVariable("reqUrl")
  10. public static String url(H.Request request) {
  11. return request.url();
  12. }

上面的代码定义了三个全局模板变量: foo, barreqUrl. 注意 reqUrl 变量的方法上有个 H.Request 类型的参数, 这个没有问题,只要参数是可以被注入的,ActFramework 都能够处理。

#171 提供一个 jQuery 增强 javascript 库

这个增强库可以通过 /asset/act/js/jquery.ext.js 引入,提供如下功能:

  1. $.put(url, [data], function)
  2. $.patch(url, [data], function)
  3. $.delete(url, [data], function)
  4. $.postJSON(url, [data], function)
  5. $.putJSON(url, [data], function)
  6. $.patchJSON(url, [data], function)
  7. $.deleteJSON(url, [data], function)

另外这个库能够处理针对 ajax 请求的 278 重定向响应. 参见 这个 SO

#174 支持 profile 特定的路由配置

除了通过注解,ActFramework 从 resources/routes.conf 文件中读取路由配置. 新版本我们提供了 profile 特定路由配置的功能,框架会从下面的文件中读取配置:

  1. resources/routes.conf
  2. resources/conf/routes.conf
  3. resources/conf/common/routes.conf
  4. resources/conf/{profile}/routes.conf

其中 {profile} 是当前运行的 profile 名字

#175 当增强类出错的时候提供更友好的错误报告

以前当发生类增强错误的时候看不到任何错误报告:

1.3.0 版的新特性 - 图1

r1.3.0 改进了这个地方,可以看到很清晰的错误报告:

1.3.0 版的新特性 - 图2

#177 当控制器响应方法或拦截器方法重名时提供友好的错误报告

ActFramework 不允许响应器/拦截器方法重名。过去关于这点没有清晰的错误报告,而开发人员会因为违反了这个规定而出现不知所措的局面. 现在的关于这种错误的报告可以非常明确的告诉程序员问题所在:

1.3.0 版的新特性 - 图3

#179 提供注解来标识需要输出到模板变量的字段或者方法参数

r1.3.0 版中引入了一个新的注解 @Output 来标明某个字段或者方法参数需要输入到模板变量列表。代码演示:

常规方法:

  1. @UrlContext("/my")
  2. public class MyController {
  3. @LoginUser
  4. private User me;
  5. @GetAction("order/{id}")
  6. public void order(@DbBind @NotNull Order order) {
  7. render(me, order); // put me and order into the render arguments
  8. }
  9. }

使用 @Output 注解的新方法:

  1. @UrlContext("/my")
  2. public class MyController {
  3. @LoginUser
  4. @Output
  5. private User me;
  6. @GetAction("order/{id}")
  7. public void order(@DbBind @NotNull @Output Order order) {}
  8. }

#181 让 redirect API 接受控制器的 URL context

r1.3.0redirect API 做了一点改变,让开发人员更容易制定重定向 URL

原来的方式:

  1. @Controller("/admin")
  2. public class AdminController {
  3. @GetAction("login")
  4. public void loginForm(){}
  5. @GetAction("logout")
  6. public void logout(H.Session session) {
  7. session.clear();
  8. redirect("/admin/login"); // 这里必须放 URL 全路径
  9. }
  10. ...
  11. }

新方式:

  1. @UrlContext("/admin")
  2. public class AdminController {
  3. @GetAction("login")
  4. public void loginForm(){}
  5. @GetAction("logout")
  6. public void logout(H.Session session) {
  7. session.clear();
  8. redirect("login"); // 只需放针对 URL context `/admin` 相对的路径
  9. }
  10. ...
  11. }