使用 Javalin 创建 REST 微服务

更新于 2025-12-29

Christopher Franklin 2024-01-08

1. 简介

Javalin 是一个为 Java 和 Kotlin 编写的轻量级 Web 框架。它构建在 Jetty Web 服务器之上,因此性能非常高。Javalin 的设计灵感来源于 koa.js,从底层开始就注重简洁性和易用性。

在本教程中,我们将逐步构建一个基于该轻量框架的基本 REST 微服务。

2. 添加依赖项

要创建一个基本应用,我们只需要一个依赖项 —— Javalin 本身:

<dependency>
    <groupId>io.javalin</groupId>
    <artifactId>javalin</artifactId>
    <version>1.6.1</version>
</dependency>

最新版本可在此处查看:Javalin 官网

3. 配置 Javalin

Javalin 让搭建基本应用变得非常简单。我们首先定义主类,并设置一个简单的 “Hello World” 应用。

在项目的根包下创建一个名为 JavalinApp.java 的新文件。

在该文件中,创建一个 main 方法,并添加以下代码以启动一个基础应用:

Javalin app = Javalin.create()
  .port(7000)
  .start();
app.get("/hello", ctx -> ctx.html("Hello, Javalin!"));

这里我们创建了一个 Javalin 实例,让它监听 7000 端口并启动应用。

同时,我们还设置了第一个端点,用于响应 /hello 路径的 GET 请求。

运行此应用后,访问 http://localhost:7000/hello 即可看到效果。

4. 创建 UserController

“Hello World” 示例非常适合入门,但在实际应用中作用有限。现在我们来看一个更贴近现实的使用场景。

首先,我们需要定义所操作对象的数据模型。在项目根目录下创建一个名为 user 的包。

然后,在该包中添加一个新的 User 类:

public class User {
    public final int id;
    public final String name;

    // 构造函数
}

接下来,我们需要设置数据访问对象(DAO)。在本示例中,我们将使用内存中的对象来存储用户数据。

user 包中创建一个名为 UserDao.java 的新类:

class UserDao {

    private List<User> users = Arrays.asList(
      new User(0, "Steve Rogers"),
      new User(1, "Tony Stark"),
      new User(2, "Carol Danvers")
    );

    private static UserDao userDao = null;

    private UserDao() {
    }

    static UserDao instance() {
        if (userDao == null) {
            userDao = new UserDao();
        }
        return userDao;
    }

    Optional<User> getUserById(int id) {
        return users.stream()
          .filter(u -> u.id == id)
          .findAny();
    }

    Iterable<String> getAllUsernames() {
        return users.stream()
          .map(user -> user.name)
          .collect(Collectors.toList());
    }
}

将 DAO 实现为单例模式,便于在本示例中使用。当然,我们也可以将其声明为主类的静态成员,或使用如 Guice 这样的依赖注入库。

最后,我们创建控制器类。Javalin 在定义路由处理器方面非常灵活,以下只是其中一种方式。

user 包中创建一个名为 UserController.java 的新类:

public class UserController {
    public static Handler fetchAllUsernames = ctx -> {
        UserDao dao = UserDao.instance();
        Iterable<String> allUsers = dao.getAllUsernames();
        ctx.json(allUsers);
    };

    public static Handler fetchById = ctx -> {
        int id = Integer.parseInt(Objects.requireNonNull(ctx.param("id")));
        UserDao dao = UserDao.instance();
        Optional<User> user = dao.getUserById(id);
        if (user.isPresent()) {
            ctx.json(user);
        } else {
            ctx.html("Not Found");
        }
    };
}

通过将处理器声明为 static,我们确保控制器本身不保存任何状态。但在更复杂的应用中,如果需要在请求之间共享状态,则应移除 static 修饰符。

另外请注意,静态方法更难进行单元测试。如果需要良好的可测试性,应使用非静态方法。

5. 添加路由

我们现在已有多种方式从模型中获取数据。最后一步是通过 REST 端点暴露这些数据。我们需要在主应用中注册两个新路由。

将以下代码添加到主应用类中:

app.get("/users", UserController.fetchAllUsernames);
app.get("/users/:id", UserController.fetchById);

编译并运行应用后,即可调用这些新端点:

至此,我们已拥有一个可以检索用户数据的微服务。

6. 扩展路由

大多数微服务的核心任务之一是数据检索。

但我们也需要能够向数据存储中写入数据。Javalin 提供了构建服务所需的所有 HTTP 方法处理器。

前面我们看到了 GET 的示例,此外还支持 PATCH、POST、DELETE 和 PUT。

另外,如果我们引入 Jackson 作为依赖项,就可以自动将 JSON 请求体解析为模型类。例如:

app.post("/") { ctx ->
  User user = ctx.bodyAsClass(User.class);
}

这允许我们直接从请求体中提取 JSON 格式的用户对象,并将其转换为 User 模型实例。

7. 结论

我们可以结合上述所有技术来构建完整的微服务。

本文介绍了如何配置 Javalin 并构建一个简单应用,还讨论了如何使用不同的 HTTP 方法,使客户端能够与我们的服务进行交互。