1. 簡介
本文將對 Spark 框架 進行一個快速介紹。Spark 框架靈感來源於 Ruby 的 Sinatra 框架,並基於 Java 8 Lambda 表達式的理念構建而成,使其比其他 Java 框架編寫的應用程序更簡潔。
如果您希望在 Java 中開發 Web API 或微服務時獲得與 Node.js 類似的使用體驗,那麼 Spark 是一個不錯的選擇。使用 Spark,您可以在少於十行代碼的情況下快速構建一個能夠提供 JSON 數據的 REST API。
我們將從一個“Hello World”示例開始快速上手,然後構建一個簡單的 REST API。
2. Maven 依賴
Maven 依賴是構建項目時,項目之間相互依賴的組件。 它們定義了項目需要哪些外部庫,以及如何管理這些庫的版本。 依賴關係允許開發者重用代碼,並避免重複開發。 常見的依賴類型包括:
- Compile-time dependencies: 在編譯時使用的依賴。
- Runtime dependencies: 在運行時使用的依賴。
- Test dependencies: 用於測試的依賴。
Maven 通過 pom.xml 文件來管理依賴關係。 在 pom.xml 文件中,可以使用 <dependency> 標籤來聲明依賴。
例如:
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact-manager</artifactId>
<version>3.6.3</version>
</dependency>
在這個例子中,<groupId> 標識了依賴的來源,<artifactId> 標識了依賴的名稱,<version> 標識了依賴的版本。
2.1. Spark 框架
在你的 pom.xml文件中包含以下 Maven 依賴項:
<dependency>
<groupId>com.sparkjava</groupId>
<artifactId>spark-core</artifactId>
<version>2.5.4</version>
</dependency>您可以在 Maven Central 找到 Spark 的最新版本。
2.2. Gson 庫
在示例中的多個位置,我們將使用 Gson 庫進行 JSON 操作。 要將 Gson 添加到您的項目中,請在您的 <em/>pom.xml</em/> 中包含以下依賴項:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>您可以在 Maven Central 找到 Gson 的最新版本。
3. 使用 Spark 框架入門
讓我們來了解 Spark 應用程序的基本構建塊,並演示一個簡單的 Web 服務。
3.1. 路由
Spark Java 中的 Web 服務建立在路由和它們的處理程序之上。路由是 Spark 中必不可少的組成部分。根據 官方文檔,每個路由由三個簡單元素組成——動詞、路徑 和 回調函數。
- 動詞 是與 HTTP 方法相對應的方法。動詞方法包括:get, post, put, delete, head, trace, connect, 和options
- 路徑(也稱為路由模式)確定路由應該監聽哪些 URI(s) 併為它們提供響應。
- 回調函數 是一個在給定動詞和路徑上調用以生成並返回對相應 HTTP 請求的響應的處理函數。回調函數作為參數接受一個請求對象和一個響應對象。
以下是使用 get 動詞的路由的基本結構:
get("/your-route-path/", (request, response) -> {
// your callback code
});3.2. Hello World API
讓我們創建一個簡單的 Web 服務,該服務包含兩個用於 GET 請求的路由,並在響應中返回“Hello”消息。這些路由使用 get 方法,該方法是來自類 spark.Spark 的靜態導入。
import static spark.Spark.*;
public class HelloWorldService {
public static void main(String[] args) {
get("/hello", (req, res)->"Hello, world");
get("/hello/:name", (req,res)->{
return "Hello, "+ req.params(":name");
});
}
}get 方法的第一個參數是路由的路徑。第一個路由包含一個靜態路徑,僅代表一個 URI (<“/hello”)。
第二個路由的路徑 (<“/hello/:name”) 包含一個佔位符,表示參數“name”,通過在參數前添加冒號 (”:”) 標記。該路由將在對 URI 諸如 <“/hello/Joe”> 和 <“/hello/Mary”> 的 GET 請求響應時調用。
get 方法的第二個參數是一個 lambda 表達式,為該框架增添了函數式編程的特點。
該 lambda 表達式接受 request 和 response 作為參數,並幫助返回 response。我們將 REST API 路由中的控制器邏輯放在該 lambda 表達式中,如稍後在本教程中看到的那樣。
3.3. 測試 Hello World API
運行類 HelloWorldService 作為普通的 Java 類後,您可以使用上文中通過 get 方法定義的路由,在默認端口 4567 上訪問該服務。
讓我們查看第一個路由的請求和響應:
請求:
GET http://localhost:4567/hello響應:
Hello, world讓我們測試第二條路由,通過路徑傳遞 name 參數:
請求:
GET http://localhost:4567/hello/baeldung響應:
Hello, baeldung查看文本 “baeldung” 在 URI 中的放置方式,用於匹配路由模式 “/hello/:name” – 從而觸發第二個路由的 callback 處理函數。
4. 設計一個 RESTful 服務
在本節中,我們將為以下 User 實體設計一個簡單的 RESTful Web 服務:
public class User {
private String id;
private String firstName;
private String lastName;
private String email;
// constructors, getters and setters
}4.1. 路由
以下是構成我們 API 的路由列表:
- GET /users — 獲取所有用户列表
- GET /users/:id — 獲取指定 ID 的用户
- POST /users/:id — 添加用户
- PUT /users/:id — 編輯特定用户
- OPTIONS /users/:id — 檢查是否存在指定 ID 的用户
- DELETE /users/:id — 刪除特定用户
4.2. 用户服務
以下是 UserService 接口聲明的對 User 實體 CRUD 操作:
public interface UserService {
public void addUser (User user);
public Collection<User> getUsers ();
public User getUser (String id);
public User editUser (User user)
throws UserException;
public void deleteUser (String id);
public boolean userExist (String id);
}為了演示目的,我們提供了 GitHub 代碼中對該 UserService 接口的 Map 實現,以模擬持久性。 您可以提供您自己的實現,並使用您選擇的數據庫和持久層。
4.3. JSON 響應結構
以下是我們在 REST 服務中使用的響應的 JSON 結構:
{
status: <STATUS>
message: <TEXT-MESSAGE>
data: <JSON-OBJECT>
}status 字段的值可以是 SUCCESS 或 ERROR。data 字段將包含返回數據的 JSON 表示形式,例如 User 或多個 Users 的集合。
當沒有返回數據,或者 status 為 ERROR 時,我們將填充 message 字段以傳達錯誤原因或缺少返回數據。
讓我們使用 Java 類來表示上述 JSON 結構:
public class StandardResponse {
private StatusResponse status;
private String message;
private JsonElement data;
public StandardResponse(StatusResponse status) {
// ...
}
public StandardResponse(StatusResponse status, String message) {
// ...
}
public StandardResponse(StatusResponse status, JsonElement data) {
// ...
}
// getters and setters
}其中 是一個 ,定義如下:
public enum StatusResponse {
SUCCESS ("Success"),
ERROR ("Error");
private String status;
// constructors, getters
}5. 實現 RESTful 服務
現在,讓我們實現我們的 REST API 的路由和處理程序。
5.1. 創建控制器
以下 Java 類包含我們 API 的路由,包括動詞、路徑以及每個路由的處理器的概要:
public class SparkRestExample {
public static void main(String[] args) {
post("/users", (request, response) -> {
//...
});
get("/users", (request, response) -> {
//...
});
get("/users/:id", (request, response) -> {
//...
});
put("/users/:id", (request, response) -> {
//...
});
delete("/users/:id", (request, response) -> {
//...
});
options("/users/:id", (request, response) -> {
//...
});
}
}在下面的子章節中,我們將展示每個路由處理器的完整實現。
5.2. 添加用户
以下是使用 POST 方法響應處理程序來添加 User 的示例:
post("/users", (request, response) -> {
response.type("application/json");
User user = new Gson().fromJson(request.body(), User.class);
userService.addUser(user);
return new Gson()
.toJson(new StandardResponse(StatusResponse.SUCCESS));
});注意: 在本示例中,User 對象的 JSON 表示形式作為 POST 請求的原始正文傳遞。
讓我們測試該路由:
請求:
POST http://localhost:4567/users
{
"id": "1012",
"email": "[email protected]",
"firstName": "Mac",
"lastName": "Mason1"
}響應:
{
"status":"SUCCESS"
}5.3. 獲取所有用户
以下是 get 方法響應處理程序,它從 UserService 中返回所有用户:
get("/users", (request, response) -> {
response.type("application/json");
return new Gson().toJson(
new StandardResponse(StatusResponse.SUCCESS,new Gson()
.toJsonTree(userService.getUsers())));
});現在讓我們測試一下路由:
請求:
GET http://localhost:4567/users響應:
{
"status":"SUCCESS",
"data":[
{
"id":"1014",
"firstName":"John",
"lastName":"Miller",
"email":"[email protected]"
},
{
"id":"1012",
"firstName":"Mac",
"lastName":"Mason1",
"email":"[email protected]"
}
]
}5.4. 根據ID獲取用户
以下是 方法的響應處理程序,它返回具有給定 的 :
get("/users/:id", (request, response) -> {
response.type("application/json");
return new Gson().toJson(
new StandardResponse(StatusResponse.SUCCESS,new Gson()
.toJsonTree(userService.getUser(request.params(":id")))));
});現在讓我們測試一下路由:
請求:
GET http://localhost:4567/users/1012響應:
{
"status":"SUCCESS",
"data":{
"id":"1012",
"firstName":"Mac",
"lastName":"Mason1",
"email":"[email protected]"
}
}5.5. 編輯用户
以下是 put 方法的響應處理程序,它會編輯擁有路由模式中提供的 id 的用户:
put("/users/:id", (request, response) -> {
response.type("application/json");
User toEdit = new Gson().fromJson(request.body(), User.class);
User editedUser = userService.editUser(toEdit);
if (editedUser != null) {
return new Gson().toJson(
new StandardResponse(StatusResponse.SUCCESS,new Gson()
.toJsonTree(editedUser)));
} else {
return new Gson().toJson(
new StandardResponse(StatusResponse.ERROR,new Gson()
.toJson("User not found or error in edit")));
}
});注意: 在本示例中,數據以 POST 請求的原始正文中作為 JSON 對象傳遞,其屬性名稱與要編輯的 User 對象中的字段相匹配。
讓我們測試該路由:
請求:
PUT http://localhost:4567/users/1012
{
"lastName": "Mason"
}響應:
{
"status":"SUCCESS",
"data":{
"id":"1012",
"firstName":"Mac",
"lastName":"Mason",
"email":"[email protected]"
}
}5.6. 刪除用户
以下是 delete 方法的處理程序,它將刪除具有指定 id 的 User:
delete("/users/:id", (request, response) -> {
response.type("application/json");
userService.deleteUser(request.params(":id"));
return new Gson().toJson(
new StandardResponse(StatusResponse.SUCCESS, "user deleted"));
});現在,讓我們測試一下路由:
請求:
DELETE http://localhost:4567/users/1012響應:
{
"status":"SUCCESS",
"message":"user deleted"
}5.7. 檢查用户是否存在
<em>options</em> 方法 是一種良好的條件檢查方式。下面是 <em>options</em> 方法 的響應處理程序,它將檢查是否存在具有給定 <em>id</em> 的 <em>User</em>:
options("/users/:id", (request, response) -> {
response.type("application/json");
return new Gson().toJson(
new StandardResponse(StatusResponse.SUCCESS,
(userService.userExist(
request.params(":id"))) ? "User exists" : "User does not exists" ));
});現在讓我們測試一下路由:
請求:
OPTIONS http://localhost:4567/users/1012響應:
{
"status":"SUCCESS",
"message":"User exists"
}6. 結論
在本文中,我們對 Spark 框架進行了一般性介紹,用於快速 Web 開發。
該框架主要推廣用於 Java 中生成微服務。 具備 Java 知識的 Node.js 開發者,如果希望利用基於 JVM 庫構建的庫,將在這個框架中感到賓至如歸。