1. 引言
本文将快速介绍 Spark 框架。这是一个受 Ruby 的 Sinatra 框架启发的快速开发 Web 框架,其核心设计围绕 Java 8 Lambda 表达式理念,相比其他 Java 框架更加简洁。
如果你想在 Java 中开发 Web API 或微服务时获得类似 Node.js 的体验,Spark 是个不错的选择。用 Spark,十行代码就能搭建一个返回 JSON 的 REST API。
我们先通过"Hello World"示例快速上手,然后构建一个简单的 REST API。
2. Maven 依赖
2.1. Spark 框架
在 pom.xml 中添加以下依赖:
<dependency>
<groupId>com.sparkjava</groupId>
<artifactId>spark-core</artifactId>
<version>2.5.4</version>
</dependency>
最新版本可在 Maven Central 查找。
2.2. Gson 库
示例中多处使用 Gson 处理 JSON。添加依赖:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
最新版本可在 Maven Central 查找。
3. Spark 框架快速上手
3.1. 路由
Spark Java 的 Web 服务基于路由及其处理器构建。路由是核心要素,根据文档,每个路由包含三部分:动词、路径和回调。
- 动词:对应 HTTP 方法,包括 get, post, put, delete, head, trace, connect, options
- 路径(路由模式):决定路由监听的 URI
- 回调:处理函数,针对特定动词和路径生成响应。回调接收请求和响应对象作为参数
使用 get 动词的路由基本结构:
get("/your-route-path/", (request, response) -> {
// 回调代码
});
3.2. Hello World API
创建一个简单的 Web 服务,包含两个 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 参数占位符(以冒号开头)。该路由会响应如 "/hello/Joe" 和 "/hello/Mary" 的请求。
第二个参数是 Lambda 表达式,赋予框架函数式编程风格。Lambda 接收请求和响应参数,我们将在后续教程的 REST API 路由中把控制器逻辑放在这里。
3.3. 测试 Hello World API
运行 HelloWorldService 后,可通过默认端口 4567 访问服务。
测试第一个路由:
请求:
GET http://localhost:4567/hello
响应:
Hello, world
测试第二个路由(路径传递 name 参数):
请求:
GET http://localhost:4567/hello/baeldung
响应:
Hello, baeldung
注意 URI 中的 "baeldung" 如何匹配路由模式 *"/hello/:name"*,触发第二个路由的回调函数。
4. 设计 RESTful 服务
4.1. 路由设计
为 User 实体设计 REST API 路由:
public class User {
private String id;
private String firstName;
private String lastName;
private String email;
// 构造方法、getter/setter
}
✅ 路由清单:
- GET /users — 获取所有用户列表
- GET /users/:id — 获取指定 ID 的用户
- POST /users/:id — 添加用户
- PUT /users/:id — 编辑指定用户
- OPTIONS /users/:id — 检查用户是否存在
- DELETE /users/:id — 删除指定用户
4.2. 用户服务
UserService 接口声明 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);
}
⚠️ 示例代码中提供了基于 Map 的实现模拟持久化。实际项目中可替换为数据库实现。
4.3. JSON 响应结构
REST 服务使用统一 JSON 结构:
{
status: <STATUS>
message: <TEXT-MESSAGE>
data: <JSON-OBJECT>
}
- status:SUCCESS 或 ERROR
- data:返回数据的 JSON 表示(如 User 或用户集合)
- message:错误原因或无数据时的说明
用 Java 类表示:
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) {
// ...
}
// getter/setter
}
StatusResponse 枚举:
public enum StatusResponse {
SUCCESS ("Success"),
ERROR ("Error");
private String status;
// 构造方法、getter
}
5. 实现 RESTful 服务
5.1. 创建控制器
包含所有路由的控制器类:
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 方法处理器添加用户:
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": "john.doe@example.com",
"firstName": "Mac",
"lastName": "Mason1"
}
响应:
{
"status":"SUCCESS"
}
5.3. 获取所有用户
get 方法处理器返回所有用户:
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":"jane.smith@example.com"
},
{
"id":"1012",
"firstName":"Mac",
"lastName":"Mason1",
"email":"john.doe@example.com"
}
]
}
5.4. 根据 ID 获取用户
get 方法处理器返回指定用户:
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":"john.doe@example.com"
}
}
5.5. 编辑用户
put 方法处理器编辑用户:
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")));
}
});
⚠️ 注意:编辑数据作为 JSON 对象在请求体中传递,属性名需匹配 User 字段。
测试路由:
请求:
PUT http://localhost:4567/users/1012
{
"lastName": "Mason"
}
响应:
{
"status":"SUCCESS",
"data":{
"id":"1012",
"firstName":"Mac",
"lastName":"Mason",
"email":"john.doe@example.com"
}
}
5.6. 删除用户
delete 方法处理器删除用户:
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. 检查用户是否存在
options 方法适合条件检查:
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 微服务,Node.js 开发者若具备 Java 知识并想利用 JVM 库,使用此框架会倍感亲切。
完整代码示例见 GitHub 项目。