• 第一章 ActFramework简介
    • 1. 准备工作" level="2">1. 准备工作
      • 1.1 安装JDK" level="3">1.1 安装JDK
      • 1.2 安装Maven" level="3">1.2 安装Maven
    • 2. 创建一个”Hello world”应用程序" level="2">2. 创建一个”Hello world”应用程序
      • 2.1 使用 maven archetype 生成应用框架" level="3">2.1 使用 maven archetype 生成应用框架
      • 2.2 启动应用" level="3">2.2 启动应用
      • 3. 将新建项目导入 IDE" level="3">3. 将新建项目导入 IDE
    • 4. 理解 AppEntry 类" level="2">4. 理解 AppEntry 类
      • 4.1 在 pom.xml 文件中指定应用入口类" level="4">4.1 在 pom.xml 文件中指定应用入口类
      • 4.2 主页响应方法" level="4">4.2 主页响应方法
        • 4.2.1 模板文件路径" level="5">4.2.1 模板文件路径
        • 4.2.1.1 通过代码指定模板文件路径" level="5">4.2.1.1 通过代码指定模板文件路径
      • 4.2.2 模板文件内容" level="4">4.2.2 模板文件内容
    • 4.3 加入请求处理方法" level="3"> 4.3 加入请求处理方法
  • 5. ActFramework应用项目剖析" level="2">5. ActFramework应用项目剖析
  • 6. 打包发布你的应用" level="2">6. 打包发布你的应用

    第一章 ActFramework简介

    1. 准备工作" class="reference-link">1. 准备工作

    你需要JDK和Maven来使用ActFramework创建应用程序. 因为需要Maven通过网络从中央库下载依赖包,一个良好的互联网链接也是必须的

    1. JDK (Java Development Kit), version 1.7或以上
    2. Maven (Project Management Tool), version 3.5或以上
      (目前仅支持JDK1.7,JDK1.8)

    1.1 安装JDK" class="reference-link">1.1 安装JDK

    Java官网下载JDK并安装.

    小贴士 如果是 Debian 用户,可以参考更简便的 Digitalocean 的 JDK 安装教程

    1.2 安装Maven" class="reference-link">1.2 安装Maven

    Maven官网下载Maven. 参照教程安装Maven到你的操作系统

    2. 创建一个”Hello world”应用程序" class="reference-link">2. 创建一个”Hello world”应用程序

    创建 ActFramework 应用项目最简便的方法是使用 maven archetype:

    2.1 使用 maven archetype 生成应用框架" class="reference-link">2.1 使用 maven archetype 生成应用框架

    1. mvn archetype:generate -B \
    2. -DgroupId=com.mycom.helloworld \
    3. -DartifactId=helloworld \
    4. -DappName=helloworld \
    5. -DarchetypeGroupId=org.actframework \
    6. -DarchetypeArtifactId=archetype-quickstart \
    7. -DarchetypeVersion=1.8.21.0

    注意 对于真正的项目, 你可能需要替换上面的 groupId, artifactId 以及 appName

    运行上述命令之后你的项目目录应该是下面的样子:

    1. helloworld/
    2. ├── .gitignore
    3. ├── pom.xml
    4. └── src
    5. ├── main
    6. ├── java
    7. └── com
    8. └── mycom
    9. └── helloworld
    10. └── AppEntry.java
    11. └── resources
    12. ├── com
    13. └── mycom
    14. └── helloworld
    15. └── .version
    16. ├── logback.xml
    17. └── rythm
    18. └── com
    19. └── mycom
    20. └── helloworld
    21. └── AppEntry
    22. └── home.html
    23. └── test
    24. └── java
    25. └── com
    26. └── mycom
    27. └── helloworld

    这是已经是一个完整的可以运行的应用项目了. 下面介绍如何运行新建项目.

    2.2 启动应用" class="reference-link">2.2 启动应用

    进入 helloworld 项目目录,键入 mvn compile act:run 即可启动应用,在控制台上能看到类似下面的信息:

    1. _ _ _ _ _
    2. |_| |_ | | / \ \ / / \ |_) | | \
    3. | | |_ |_ |_ \_/ \/\/ \_/ | \ |_ |_/
    4. powered by ActFramework r1.8.7-2f28
    5. version: v1.0-SNAPSHOT-180410_1739
    6. scan pkg: com.mycom.helloworld
    7. base dir: /tmp/1/helloworld
    8. pid: 3209
    9. profile: dev
    10. mode: DEV
    11. zen: Simple is better than complex.
    12. 2018-04-10 17:39:57,264 INFO a.Act@[main] - loading application(s) ...
    13. 2018-04-10 17:39:57,294 INFO a.a.App@[main] - App starting ....
    14. 2018-04-10 17:39:57,762 WARN a.h.b.ResourceGetter@[main] - URL base not exists: META-INF/resources/webjars
    15. 2018-04-10 17:39:57,794 WARN a.a.DbServiceManager@[main] - DB service not initialized: No DB plugin found
    16. 2018-04-10 17:39:59,110 WARN a.m.MailerConfig@[main] - smtp host configuration not found, will use mock smtp to send email
    17. 2018-04-10 17:40:00,046 INFO a.a.App@[main] - App[helloworld] loaded in 2751ms
    18. 2018-04-10 17:40:00,058 INFO a.a.ApiManager@[jobs-thread-3] - start compiling API book
    19. 2018-04-10 17:40:00,088 INFO o.xnio@[main] - XNIO version 3.3.8.Final
    20. 2018-04-10 17:40:00,130 INFO o.x.nio@[main] - XNIO NIO Implementation Version 3.3.8.Final
    21. 2018-04-10 17:40:00,372 INFO a.Act@[main] - network client hooked on port: 5460
    22. 2018-04-10 17:40:00,374 INFO a.Act@[main] - CLI server started on port: 5461
    23. 2018-04-10 17:40:00,377 INFO a.Act@[main] - app is ready at: http://192.168.1.5:5460
    24. 2018-04-10 17:40:00,378 INFO a.Act@[main] - it takes 4886ms to start the app

    启动浏览器并打开http://localhost:5460 能看到默认的主页:

    image

    3. 将新建项目导入 IDE" class="reference-link">3. 将新建项目导入 IDE

    基本上所有的IDE都支持maven项目. 下面使用IntelliJ IDEA做演示.

    选择File/Open... 并导航到生成的项目目录:

    image

    点击 Okay 之后打开项目:

    image

    4. 理解 AppEntry 类" class="reference-link">4. 理解 AppEntry 类

    `AppEntry` 是应用的入口类,也是这个简单应用唯一的类. 打开 AppEntry.java 文件我们看到下面两个方法:

    1. @GetAction
    2. public void home(@DefaultValue("World") @Output String who) {
    3. }
    4. public static void main(String[] args) throws Exception {
    5. Act.start();
    6. }

    非常明显 public static void main(String[[]) 方法是整个应用程序的入口函数。这个方法的实现也非常简单,就是调用 act.Act.start() 即可。具有这个方法的类,称为应用入口类。

    4.1 在 pom.xml 文件中指定应用入口类" class="reference-link">4.1 在 pom.xml 文件中指定应用入口类

    应用入口类一旦定义好,需要在 pom.xml 中指定其到 app.entry 属性:

    1. <app.entry>com.mycom.helloworld.AppEntry</app.entry>

    设置这个属性非常关键,act 的 maven 构造工具需要用到这个属性:

    1. act-maven-plugin 需要这个属性来决定运行类,否则 mvn compile act:run 无法正常工作
    2. act-starter-parent 需要这个属性来生成最后的运行文件,否则部署包解包后的 run 脚本不能正常工作

    4.2 主页响应方法" class="reference-link">4.2 主页响应方法

    home 方法上有个 @GetAction 注解, 未带有任何参数, 其含义为 @GetAction("/") , 表示任何发送到 / 的请求都将被路由到该方法. 方法有一个参数:

    1. @DefaultValue("World") @Output String who

    这个参数告诉 ActFramework 从 HTTP GET 请求中找到名为 who 的参数, 并将其注入到 String who 方法参数中. @DefaultValue("World") 的意思是如果没有 who 请求参数, 则使用 World 作为 String who 方法参数的默认值; @Output 告诉框架将 String who 放进模板输出变量中,对应的模板变量名字为 who. 如果不使用 @DefaultValue("World")@Output 注解, 整个 home 方法应该这样表达:

    1. @GetAction("/")
    2. public void home(String who) {
    3. if (null == who) who = "World";
    4. renderTemplate(who); // render template and add `who` into template argument list
    5. }

    下面是 home 方法更加冗长的表达:

    1. @GetAction("/")
    2. public Result home(ActionContext context) {
    3. String who = context.req().paramVal("who");
    4. if (null == who) who = "World";
    5. context.renderArg("who", who);
    6. return RenderTemplate.get();
    7. }

    这里可以看出 ActFramework 的一个特点:同样的功能实现可以有不同的表达方式。当然推荐用户使用更加简练的表达,表达力是 ActFramework 设计的一个专注点。

    4.2.1 模板文件路径" class="reference-link">4.2.1 模板文件路径

    home 方法中我们并没有看到指定模板文件路径的地方, ActFramework 在程序没有指定模板路径的时候按照下面的规则来寻找模板文件:

    1. /src/main/resources/rythm/com/mycom/helloworld/AppEntry/home.html
    2. -------------------
    3. 资源文件根目录
    4. rythm
    5. ------
    6. 模板
    7. 引擎
    8. id
    9. com/mycom/helloworld/AppEntry
    10. -----------------------------
    11. 控制器类的全名
    12. /home.html
    13. -----------
    14. 方法名.内容格式后缀
    4.2.1.1 通过代码指定模板文件路径" class="reference-link">4.2.1.1 通过代码指定模板文件路径

    如果模板文件放在其他地方,比如 resources/rythm/home.html 则需要使用 act.controller.Controller.Util.renderTemplate 方法来指定:

    1. @GetAction
    2. public void home(@DefaultValue("World") String who) {
    3. renderTemplate("/home.html", who);
    4. }

    上面的代码中模板路径是用字串字面量 (String literal) 来指定的,这个点非常重要,下面的方式制定模板路径是不行的:

    1. String path = "/home.html";
    2. renderTemplate(path, who);

    这里虽然使用了 path,但是 ActFramework 依旧会按照默认的方式去寻找木板,因为 path 变量不会被解释为模板路径,而是当作参数传递给模板了。

    4.2.2 模板文件内容" class="reference-link">4.2.2 模板文件内容

    ActFramework 使用 rythm 作为默认的模板引擎. Hello world 项目的主页模板内容如下:

    1. <!DOCTYPE html>
    2. <html lang="en">
    3. @args String who
    4. <head>
    5. <title>Hello World - ActFramework</title>
    6. </head>
    7. <body>
    8. <h1>Hello @who</h1>
    9. <p>
    10. Powered by ActFramework @act.Act.VERSION.getVersion()
    11. </p>
    12. </body>
    13. </html>

    其中 @args String who 声明该模板用到的模板变量, 该变量可以使用 @ 引用: @who 在模板输出变量 who 的值. @ 还可以引入任何其它变量或者方法, 比如 @act.Act.VERSION.getVersion() 在模板上输出 act.Act.VERSION 静态变量的 getVersion() 静态方法的返回值.

    小贴士 rythm 官网 有详尽的文档可供参考

    4.3 加入请求处理方法" class="reference-link"> 4.3 加入请求处理方法

    现在加入另一个请求处理方法到AppEntry.java文件中,该方法处理发送到 /bye 的请求:

    1. @GetAction("/bye")
    2. public String sayBye() {
    3. return "Bye!";
    4. }

    加完方法后, 切换到你的浏览器打开http://localhost:5460/bye, 你应该能看到如下效果:

    image

    小贴士 开发模式下, 一旦 ActFramework 项目开始运行就无需重启 (除非引入新的依赖库). 无论是添加/改变源文件, 或者配置文件, 开发人员只需刷新浏览器就能看到更改结果. 这种来源于 PlayFramework v1 的热加载特性让应用的开发变得更加容易.

    \newpage

    5. ActFramework应用项目剖析" class="reference-link">5. ActFramework应用项目剖析

    ActFramework使用标准的maven项目布局来组织文件. 下面是一种常见 Act 应用的目录结构:

    1. .
    2. ├── pom.xml
    3. ├── src
    4. ├── main
    5. ├── java -> Java 源码
    6. └── com
    7. └── mycom
    8. └── myprj
    9. ├── AppEntry.java -> 应用程序入口(提供main()方法)
    10. ├── controller -> 控制器目录
    11. ├── event -> 事件和事件响应器目录
    12. ├── mail -> 邮件发送器目录
    13. ├── model -> 域模型以及数据访问对象目录
    14. └── util -> 工具类目录
    15. └── resources -> 资源文件
    16. ├── asset -> 静态资源, 可以直接通过"/asset"访问
    17. ├── css -> CSS 文件
    18. ├── img -> 图片文件
    19. └── js -> Javascript 文件
    20. ├── conf -> 配置根目录
    21. ├── prod -> `prod` 产品环境配置
    22. ├── sit -> `sit` 系统集成测试环境配置
    23. └── uat -> "uat" 用户接受测试环境配置
    24. ├── messages.properties -> 国际化资源文件
    25. ├── routes.conf -> 路由表
    26. └── rythm -> Rythm模板根目录
    27. ├── com
    28. └── mycomp
    29. └── myprj
    30. ├── controller -> 控制器模板目录
    31. └── mail -> 邮件发送器模板目录
    32. └── __global.rythm -> 全局模板工具
    33. └── test
    34. ├── java -> 单元测试源文件
    35. └── com
    36. └── mycom
    37. └── myprj
    38. └── resources -> 单元测试资源
    39. └── target -> maven项目构建目录
    40. ├── dist -> 发布包目录
    41. └── tmp
    42. └── uploads -> 存放上传文件的临时目录

    注意 根据你的应用程序的包组织方式,你看到的有可能和以上结构有不一样的地方
    注意 asset文件夹可能不会默认被创建,你可以在有需要的时候手动创建。
    注意 asset文件夹拥有默认的路由/asset/

    1. 包组织方式完全由项目决定。你的项目中可能使用了service包而不是controller来存放所有的RESTful控制器类。 而你的业务层也许不是一个model包, 而是分布在多个不同的包里. ActFramework在项目文件组织上没有任何限制
    2. ActFramework使用common配置目录来获取缺省的配置信息。而上例所示的sitdev目录则完全由项目决定,你可以使用其他任何名字,你也可以增加另一种配置组,比如uat。如果项目不需要多个配置组,使用common即可。
    3. 如果路由都通过注解方式指定,routes文件可以不用提供. 一旦routes文件被检测到,其中的条目可以覆盖注解指定路由

    6. 打包发布你的应用" class="reference-link">6. 打包发布你的应用

    使用 maven archetype 生成的项目有完整的 ActFramework maven 工具链支持, 打包发布应用非常简单:

    1. mvn clean package

    运行上面的命令后, maven 会在 target/dist 目录下生成发布包:

    1. -rw-rw-r-- 1 luog luog 20M Apr 11 16:21 helloworld-1.0-SNAPSHOT-b180411_1621.zip

    将生成的 zip 文件通过 scp 或其他途径上传到产品服务器, 解包之后可以看到下面的文件结构:

    1. drwxr-xr-x 4 luog luog 4.0K Apr 11 16:21 classes/
    2. drwxr-xr-x 2 luog luog 4.0K Apr 11 16:21 lib/
    3. -rw-rw-r-- 1 luog luog 20M Apr 11 16:21 helloworld-1.0-SNAPSHOT-b180411_1621.zip
    4. -rwxrwxrwx 1 luog luog 2.2K Apr 11 16:21 run*
    5. -rwxrwxrwx 1 luog luog 315 Apr 11 16:21 run.bat*
    6. -rwxrwxrwx 1 luog luog 22 Apr 11 16:21 start*
    7. -rwxrwxrwx 1 luog luog 316 Apr 11 16:21 start.bat*

    执行 ./run 启动应用, 默认配置环境为 prod. 如需在其他配置环境下运行应用使用 -p 参数, 例如:

    1. ./run -p uat

    上面的命令会在 uat 配置环境下启动应用.

    小贴士 执行 ./run --help 能看到下面的帮助信息

    1. ./run start the app
    2. -d --debug enable remote debugging
    3. --debug-port <port> specify debug port (if not specified then debug port is 5005)
    4. -p --profile specify the profile to start the app
    5. -g --group specify the node group
    6. -Dprop=val specify any JVM system properties
    7. -h --help display this help message

    startrun 命令基本相同, 不同点在于 start 在后台启动应用.

    如果是在 windows 环境下, 可以是用 run.bat 或者 start.bat 命令. 当然如果是线上服务器, 还是推荐使用 Linux 系统.

    * 6.1 配置前端 http 服务器

    通常来讲, 线上服务应该配置前端 HTTP 服务器, 并反向代理到 ActFramework 应用. 这样做的优势在与:

    1. 可以帮助处理 https 请求
    2. 可以在一个 80 端口通过域名分派到多个 ActFramework 应用上

    用 nginx 为例来看看如何设置到 ActFramework 应用的反向代理. 假设应用 A 的 http 端口为 11000, 其对应的 nginx 配置文件内容大概为:

    1. # 设置 443 到应用的反向代理
    2. server {
    3. listen 443;
    4. client_max_body_size 8m;
    5. server_name www.myawesomeproduct.com myawesomeproduct.com;
    6. ssl on;
    7. ssl_certificate /home/ubuntu/cert/www_myawesomeproduct_com.crt;
    8. ssl_certificate_key /home/ubuntu/cert/www_myawesomeproduct_com.key;
    9. location / {
    10. proxy_pass http://localhost:11000;
    11. proxy_set_header X-Real-IP $remote_addr;
    12. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    13. proxy_set_header Host $http_host;
    14. }
    15. }
    16. # 设置 80 到 443 的自动跳转
    17. server {
    18. listen 80;
    19. server_name www.myawesomeproduct.com myawesomeproduct;
    20. return 301 https://$server_name$request_uri;
    21. }

    返回目录