1. 概述

在这篇教程中,我们将带你快速了解一个轻量级的 Java REST 框架 —— RESTX

2. 特性一览

使用 RESTX 构建 RESTful API 相当简单。它提供了我们对现代 REST 框架的所有基本预期功能:

✅ JSON 的请求与响应处理
✅ 支持查询参数和路径参数
✅ 路由机制和过滤器机制
✅ 使用统计和监控支持

此外,RESTX 还内置了一个直观的管理后台 Web UI 和命令行工具,用于快速初始化项目。

项目采用 Apache License 2 开源协议,并由社区维护。最低 JDK 要求为 JDK 7。

3. 环境配置

RESTX 提供了一个命令行工具(shell app),可以快速帮你搭建一个 Java 项目。

不过在使用之前,需要先安装这个工具。详细的安装说明可以参考官方文档

4. 安装核心插件

安装完 shell 工具后,下一步是安装核心插件,这样我们就可以在 shell 中直接创建应用了。

在 RESTX shell 中执行以下命令:

shell install

系统会提示你选择要安装的插件。我们需要选择 io.restx:restx-core-shell 这一项。✅ 安装完成后 shell 会自动重启。

5. 使用 Shell 初始化项目

使用 RESTX shell 初始化项目非常方便,它提供了一个向导式的流程。

在 shell 中执行以下命令开始:

app new

这个命令会启动向导流程,你可以使用默认配置,也可以根据需要自定义:

shell app bootstrap

如果你选择了生成 pom.xml 文件,项目就可以轻松导入到任意标准 Java IDE 中。

有些时候你可能需要调整 IDE 的配置

接下来我们构建项目:

mvn clean install -DskipTests

✅ 构建成功后,你可以在 IDE 中直接运行 AppServer 类,它会启动一个嵌入式 Jetty 服务器,管理后台默认监听 8080 端口。

访问地址:http://127.0.0.1:8080/api/@/ui 即可看到基本界面。

⚠️ 注意:所有以 /@/ 开头的路由是管理后台专用路径,属于保留路径。

登录管理后台的默认用户名是 admin,密码是你在创建项目时设置的。

在进一步探索之前,我们先来看看向导生成的代码结构。

6. 一个 RESTX 资源类

路由定义在 <main_package>.rest.HelloResource 类中:

@Component
@RestxResource
public class HelloResource {
    @GET("/message")
    @RolesAllowed(Roles.HELLO_ROLE)
    public Message sayHello() {
        return new Message().setMessage(String.format("hello %s, it's %s", 
          RestxSession.current().getPrincipal().get().getName(),
          DateTime.now().toString("HH:mm:ss")));
    }
}

从代码可以看出,RESTX 使用了标准 J2EE 的注解来处理安全和 REST 绑定,同时也自定义了一些注解来处理依赖注入。

RESTX 对方法参数的映射也支持很多合理的默认行为。比如自动将请求参数映射到方法参数。

⚠️ @RestxResource 是 RESTX 的核心注解,用于标识这是一个 REST 资源类。

基础路径配置在 src/main/webapp/WEB-INF/web.xml 中,默认是 /api,因此你可以发送 GET 请求到:

http://localhost:8080/api/message

前提是已经完成身份认证。

Message 类只是一个普通的 Java Bean,RESTX 会自动将其序列化为 JSON。

通过 @RolesAllowed 注解,我们可以控制访问权限。示例中使用了向导自动生成的 HELLO_ROLE 权限。

7. 模块类(Module Class)

如前所述,RESTX 使用标准的 J2EE 依赖注入注解,比如 @Named,同时也在必要时自定义了 @Module@Provides,灵感可能来源于 Dagger。

这些注解用于定义应用的主模块,其中也包括管理后台的密码配置:

@Module
public class AppModule {
    
    @Provides
    public SignatureKey signatureKey() {
        return new SignatureKey("restx-demo -44749418370 restx-demo 801f-4116-48f2-906b"
            .getBytes(Charsets.UTF_8));
    }

    @Provides
    @Named("restx.admin.password")
    public String restxAdminPassword() {
        return "1234";
    }

    @Provides
    public ConfigSupplier appConfigSupplier(ConfigLoader configLoader) {
        return configLoader.fromResource("restx/demo/settings");
    } 
   
    // 其他组件创建方法
}
  • @Module:声明一个模块类,类似于 Dagger 中的 @Module,或 Spring 中的 @Configuration
  • @Provides:用于声明一个组件的创建方法,类似 Dagger 的 @Provides 或 Spring 的 @Bean
  • @Named:标识组件名称

AppModule 还提供了一个 SignatureKey,用来对客户端内容进行签名。例如,创建会话时会设置一个签名 Cookie:

HTTP/1.1 200 OK
...
Set-Cookie: RestxSessionSignature-restx-demo="ySfv8FejvizMMvruGlK3K2hwdb8="; RestxSession-restx-demo="..."
...

更多依赖注入内容可参考 RESTX 组件工厂文档

8. 启动类(Launcher Class)

最后是 AppServer 类,用于在嵌入式 Jetty 服务器中运行应用:

public class AppServer {
    public static final String WEB_INF_LOCATION = "src/main/webapp/WEB-INF/web.xml";
    public static final String WEB_APP_LOCATION = "src/main/webapp";

    public static void main(String[] args) throws Exception {
        int port = Integer.valueOf(Optional.fromNullable(System.getenv("PORT")).or("8080"));
        WebServer server = 
            new Jetty8WebServer(WEB_INF_LOCATION, WEB_APP_LOCATION, port, "0.0.0.0");
        System.setProperty("restx.mode", System.getProperty("restx.mode", "dev"));
        System.setProperty("restx.app.package", "restx.demo");
        server.startAndAwait();
    }
}

这里使用了 dev 模式来启用开发阶段的功能,比如自动编译,缩短开发反馈周期。

✅ 你可以将项目打包为 war 文件部署到标准 J2EE 容器中。

9. 使用 Specs 进行集成测试

RESTX 的一大亮点是它的“specs”机制。一个典型的 spec 看起来是这样的:

title: should admin say hello
given:
  - time: 2013-08-28T01:18:00.822+02:00
wts:
  - when: |
      GET hello?who=xavier
    then: |
      {"message":"hello xavier, it's 01:18:00"}

测试采用 Given-When-Then 结构,写在 YAML 文件中,描述了在给定条件下,某个请求应返回什么样的响应。

HelloResourceSpecTest 类会触发这些测试:

@RunWith(RestxSpecTestsRunner.class)
@FindSpecsIn("specs/hello")
public class HelloResourceSpecTest {}

RestxSpecTestsRunner 是一个自定义的 JUnit Runner,它会:

✅ 启动嵌入式服务器
✅ 设置系统状态(given)
✅ 发送请求(when)
✅ 验证响应(then)

@FindSpecsIn 注解用于指定 spec 文件的位置。

✅ Specs 不仅用于集成测试,还能作为 API 文档中的示例。此外,它还能 模拟 HTTP 请求并记录请求/响应对

10. 手动测试

你也可以通过 HTTP 手动测试接口。首先需要登录,先在 shell 中对密码进行 MD5 加密:

hash md5 <clear-text-password>

然后调用 /sessions 接口登录:

curl -b u1 -c u1 -X POST -H "Content-Type: application/json" 
  -d '{"principal":{"name":"admin","passwordHash":"1d528266b85cf052803a57288"}}'
  http://localhost:8080/api/sessions

⚠️ Windows 用户需要先 下载 curl。

登录后,带上 Cookie 调用 /message 接口:

curl -b u1 "http://localhost:8080/api/message?who=restx"

会得到类似这样的响应:

{"message" : "hello admin, it's 09:56:51"}

11. 管理后台功能概览

访问地址:http://127.0.0.1:8080/admin/@/ui

11.1. API 文档

API Docs 页面列出了所有可用的接口路由,并支持直接在页面中调用测试:

admin api docs

admin api docs 2

11.2. 监控

JVM Metrics 页面展示了应用运行时指标,包括:

✅ 活跃会话数
✅ 内存使用情况
✅ 线程堆栈信息

admin monitoring

Application Metrics 默认监控两类指标:

  • BUILD:组件初始化相关
  • HTTP:HTTP 请求处理相关

11.3. 统计信息

RESTX 支持收集匿名使用统计信息,帮助社区了解使用情况。你可以通过排除 restx-stats-admin 模块来关闭该功能。

统计信息包括操作系统、JVM 版本等:

admin stats

⚠️ 该页面包含敏感信息,请务必检查其 配置选项

此外,管理后台还可以:

✅ 查看日志(Logs)
✅ 查看错误(Errors)
✅ 查看配置项(Config)

12. 权限控制

RESTX 默认对所有接口进行权限控制。 例如下面这个接口:

@GET("/greetings/{who}")
public Message sayHello(String who) {
    return new Message(who);
}

如果未认证访问,会返回 401 Unauthorized

要让接口公开访问,需要使用 @PermitAll 注解:

@PermitAll 
@GET("/greetings/{who}")
public Message sayHello(String who) {
    return new Message(who);
}

⚠️ 如果加在类上,整个类的所有接口都会公开。

你也可以通过 @RolesAllowed 指定用户角色:

@RolesAllowed("admin")
@GET("/greetings/{who}")
public Message sayHello(String who) {
    return new Message(who);
}

此时,如果用户没有 admin 角色,会返回 403 Forbidden 而不是 401

默认情况下,用户信息和角色分别存储在两个文件中:

用户密码文件:/data/credentials.json

{
    "user1": "$2a$10$iZluUbCseDOvKnoe",
    "user2": "$2a$10$oym3Swr7pScdiCXu"
}

用户角色文件:/data/users.json

[
    {"name":"user1", "roles": ["hello"]},
    {"name":"user2", "roles": []}
]

这些文件在 AppModule 中通过 FileBasedUserRepository 加载:

new FileBasedUserRepository<>(StdUser.class, mapper, 
  new StdUser("admin", ImmutableSet.<String> of("*")), 
  Paths.get("data/users.json"), Paths.get("data/credentials.json"), true)

StdUser 是默认的用户类,你也可以自定义自己的用户类,只要能序列化为 JSON 即可。

当然,你也可以使用自定义的 UserRepository 实现,比如连接数据库的版本。

13. 总结

这篇教程带你快速了解了基于 Java 的轻量级 REST 框架 RESTX。

虽然框架仍在发展中,可能存在一些不完善的地方,但它已经具备了构建 RESTful API 所需的核心功能。

更多内容请参考 官方文档

示例项目代码已上传至 GitHub 仓库


原始标题:Introduction to RESTX