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 服务基于路由及其处理器构建。路由是核心要素,根据文档,每个路由包含三部分:动词路径回调

  1. 动词:对应 HTTP 方法,包括 get, post, put, delete, head, trace, connect, options
  2. 路径(路由模式):决定路由监听的 URI
  3. 回调:处理函数,针对特定动词和路径生成响应。回调接收请求和响应对象作为参数

使用 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 项目


原始标题:Intro to Spark Java Framework | Baeldung