1. 概述
在本教程中,我們將對輕量級 Java REST 框架 RESTX 進行遊覽。
2. 功能
使用 RESTX 框架構建 RESTful API 非常容易。它包含了我們從 REST 框架中期望的所有默認設置,例如服務和消費 JSON、查詢和路徑參數、路由和過濾機制、使用統計信息和監控。
RESTX 還附帶了一個直觀的管理員 Web 控制枱和命令行安裝程序,方便快速啓動。
它還獲得 Apache License 2 的許可,並由開發人員社區維護。RESTX 的最小 Java 要求是 JDK 7。
3. 配置
RESTX 附帶一個便捷的 shell/命令行應用,可快速啓動 Java 項目。
在繼續之前,我們需要先安裝該應用。詳細的安裝説明請參考 這裏。
4. 安裝核心插件
現在,是時候安裝核心插件,以便從shell本身創建應用程序。
在RESTX shell中,請運行以下命令:
shell install
它會提示我們選擇要安裝的插件。我們需要選擇指向io.restx:restx-core-shell的序號。 安裝完成後,shell會自動重啓。
5. Shell App 啓動
使用 RESTX shell,非常方便地啓動新的應用程序。它提供基於嚮導的引導。
我們首先在 shell 上執行以下命令:
app new
此命令將觸發嚮導。然後我們可以選擇使用默認選項或根據我們的要求進行更改:
由於我們選擇生成一個pom.xml,該項目可以輕鬆導入到任何標準的 Java IDE。
在某些情況下,我們可能需要調整IDE 設置。
下一步將是構建項目:
mvn clean install -DskipTests
一旦構建成功,我們就可以從 IDE 中作為 Java 應用程序運行 AppServer 類。 這將在端口 8080 上啓動服務器,帶有管理控制枱。
我們可以瀏覽到 http://127.0.0.1:8080/api/@/ui 並查看基本 UI。
以 /@/ 開頭且使用 RESTX 的路由用於管理控制枱,這是一個預留的路徑。
要登錄管理控制枱,我們可以使用默認用户名“admin“ 和我們在創建應用程序時提供的密碼。
在玩轉控制枱之前,讓我們探索代碼並瞭解嚮導生成的內容。
6. RESTX 資源
路由定義在 <em>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 還支持了許多合理的默認值,用於將方法參數映射到請求。
此外,還有 <em>@RestxResource</em> 註解,它聲明該類為 RESTX 識別的資源。
基本路徑在 <em>src/main/webapp/WEB-INF/web.xml</em> 中添加。 在我們的例子中,它是 <em>/api</em>,因此我們可以向 <em>http://localhost:8080/api/message</em> 發送 GET 請求,前提是進行了適當的身份驗證。
Message 類只是一個 Java Bean,RESTX 將其序列化為 JSON。
我們通過指定 <em>RolesAllowed</em> 註解以及 <em>HELLO_ROLE</em> (由啓動器生成的) 來控制用户訪問。
7. 模塊類
如前所述,RESTX 使用 J2EE 標準的依賴注入註解,如 @Named,並在需要時自行創建,很可能借鑑了 Dagger 框架中 @Module 和 @Provides 的用法。
它使用這些註解來創建應用程序的主模塊,該模塊中定義了管理員密碼:
@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 類
最後,AppServer 類用於在嵌入式 Jetty 服務器上以標準 Java 應用的方式運行應用程序:
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 文件(Web 存檔)以便在獨立 J2EE Web 容器中部署。
在下一部分中,我們將瞭解如何測試該應用程序。
9. 集成測試使用規範
RESTX 的強大功能之一是“規範”(specs) 的概念。一個示例 規範 看起來像這樣:
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"}
測試是用 給、當、然後 結構在 YAML 文件中編寫的,該文件基本上定義了 API 如何響應(然後)一個特定請求(當)在系統當前狀態下(給)。
HelloResourceSpecTest 類在 src/test/resources 中將觸發上述規範中的測試:
@RunWith(RestxSpecTestsRunner.class)
@FindSpecsIn("specs/hello")
public class HelloResourceSpecTest {}
RestxSpecTestsRunner 類是一個自定義 JUnit 運行器。它包含自定義 JUnit 規則,用於:
- 設置嵌入式服務器
- 準備系統狀態(根據規範中的 給 部分)
- 發出指定請求,以及
- 驗證預期響應
@FindSpecsIn 註解指向測試應運行的規範文件路徑。
規範有助於編寫集成測試並提供 API 文檔中的示例。 規範也對 模擬 HTTP 請求和記錄請求/響應對 有用。
10. 手動測試
我們還可以通過HTTP進行手動測試。首先,我們需要登錄,為此,需要在RESTX控制枱中對管理員密碼進行哈希:
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)
現在,如果我們使用會話作為/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 文檔部分列出了所有可用的路由,包括所有選項:
我們可以點擊單個路由並嘗試在控制枱中對其進行測試:
11.2. 監控
JVM 指標部分顯示了應用程序指標,包括活動會話、內存使用情況和線程 dump:
在 應用程序指標中,我們有默認監控的兩種主要類別:
- BUILD 對應於應用程序組件的實例化
- HTTP 對應於 RESTX 處理的 HTTP 請求
11.3. 統計信息
RESTX 允許用户選擇收集和共享應用程序的匿名統計信息,以便向 RESTX 社區提供信息。我們可以輕鬆通過排除 restx-stats-admin 模塊來選擇退出。
統計報告包括底層操作系統和 JVM 版本:
因為這個頁面顯示了敏感信息,請務必查看其配置選項
除此之外,管理控制枱還可以幫助我們:
- 檢查服務器日誌 (Logs)
- 查看遇到的錯誤 (Errors)
- 檢查環境變量 (Config)
12. 授權
RESTX 端點默認已啓用安全保護。這意味着對於任何端點:
@GET("/greetings/{who}")
public Message sayHello(String who) {
return new Message(who);
}
如果未進行身份驗證,則默認返回一個 401 錯誤。
要使端點公開,我們需要使用 @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);
}
通過此註解,RESTX 將驗證已身份驗證的用户是否也具有 admin 角色分配。如果未具有 admin 角色且已身份驗證的用户嘗試訪問端點,則應用程序將返回一個 403 錯誤,而不是 401 錯誤。
默認情況下,用户角色和憑據存儲在文件系統中,在單獨的文件中。
因此,包含加密密碼的用户 ID 存儲在 /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的RESTX框架。
該框架仍在開發中,可能存在一些不完善之處。請查閲 官方文檔 以獲取更多詳細信息。