1. 简介
Javalin 是一个轻量级的 Web 框架,专为 Java 和 Kotlin 设计。它底层基于 Jetty 构建,性能表现非常出色。Javalin 的设计灵感源自 koa.js,从零开始就追求简洁易懂,API 设计直观,上手成本极低。
本文将带你一步步使用 Javalin 构建一个基础的 REST 风格微服务。适合想快速搭建轻量后端接口的同学,踩坑少、开发快,简单粗暴有效。
2. 添加依赖
要启动一个基本的 Javalin 应用,你只需要引入一个核心依赖:
<dependency>
<groupId>io.javalin</groupId>
<artifactId>javalin</artifactId>
<version>1.6.1</version>
</dependency>
✅ 建议使用最新稳定版,可在 Maven Central 查询当前版本。
⚠️ 注意:虽然版本号看起来不高,但 Javalin 社区活跃,API 稳定,无需担心“老版本”问题。
3. 初始化 Javalin 应用
Javalin 的初始化非常简洁,几行代码就能跑起来。
创建主类 JavalinApp.java
,写入以下内容:
Javalin app = Javalin.create()
.port(7000)
.start();
app.get("/hello", ctx -> ctx.html("Hello, Javalin!"));
解释一下关键点:
Javalin.create()
:创建应用实例.port(7000)
:监听 7000 端口.start()
:启动内嵌的 Jetty 服务器app.get(...)
:注册一个 GET 类型的接口
启动后访问 http://localhost:7000/hello,就能看到返回内容。
✅ 这是最小可运行单元,适合做原型验证或内部工具。
4. 实现 UserController
“Hello World” 只是热身,接下来我们搞点实际的:用户管理。
4.1 定义 User 模型
在 user
包下创建 User
类:
public class User {
public final int id;
public final String name;
public User(int id, String name) {
this.id = id;
this.name = name;
}
}
⚠️ 注意:这里使用 public final
字段是为了配合 Jackson 自动序列化,省去 getter。生产环境建议用 private + getter,但 demo 中简化处理。
4.2 实现 UserDao(数据访问层)
我们用内存存储模拟数据库,实际项目可替换为 JPA、MyBatis 等。
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());
}
}
✅ 使用单例模式简化示例,避免依赖注入复杂化。
❌ 但注意:静态单例不利于单元测试和扩展,真实项目建议用 Spring 或 Guice 管理生命周期。
4.3 创建 UserController
这是接口逻辑的核心。我们将 Handler 定义为静态方法,保持无状态:
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.get());
} else {
ctx.status(404).html("Not Found");
}
};
}
关键点说明:
ctx.param("id")
:获取路径参数/users/:id
中的id
ctx.json(...)
:自动序列化对象为 JSON 响应ctx.status(404)
:设置状态码,更符合 REST 规范
5. 注册接口(Routes)
现在把 Controller 中的 Handler 挂载到路由上:
app.get("/users", UserController.fetchAllUsernames);
app.get("/users/:id", UserController.fetchById);
启动服务后测试:
✅
GET http://localhost:7000/users
返回:["Steve Rogers", "Tony Stark", "Carol Danvers"]
✅
GET http://localhost:7000/users/1
返回:{"id":1,"name":"Tony Stark"}
❌
GET http://localhost:7000/users/999
返回 404 和 "Not Found" 文本
至此,一个支持查询的 REST 微服务已成型。
6. 扩展接口功能
光有读取不够,我们还需要支持增删改。
Javalin 支持所有标准 HTTP 方法:
app.get()
→ 查询app.post()
→ 创建app.put()
→ 全量更新app.patch()
→ 部分更新app.delete()
→ 删除
6.1 自动解析 JSON 请求体
添加 Jackson 依赖(Javalin 默认已包含,无需额外引入):
app.post("/users", ctx -> {
User user = ctx.bodyAsClass(User.class);
// 保存逻辑...
ctx.status(201).json(user);
});
✅ bodyAsClass
会自动将请求体反序列化为指定类,前提是字段名匹配且有构造函数。
6.2 示例:添加用户
private static AtomicInteger idCounter = new AtomicInteger(3);
app.post("/users", ctx -> {
User newUser = ctx.bodyAsClass(User.class);
int newId = idCounter.getAndIncrement();
User savedUser = new User(newId, newUser.name);
// 实际应加入 users 列表
ctx.status(201).json(savedUser);
});
📌 提示:内存存储不支持持久化,仅用于演示。真实场景需对接数据库。
7. 总结
通过本文,你应该掌握了:
- ✅ 如何快速初始化 Javalin 应用
- ✅ 使用静态 Handler 组织 Controller 逻辑
- ✅ 路由注册与参数解析
- ✅ JSON 自动序列化/反序列化
- ✅ 构建完整的 RESTful 接口集
Javalin 的优势在于轻量、无侵入、低学习成本,特别适合:
- 内部工具系统
- 快速原型开发
- 学习 REST 设计
- 替代 Spring Boot 做极简服务
📌 官方文档非常完善:https://javalin.io/documentation
📌 示例代码已托管 GitHub:https://github.com/example/javalin-demo
如果你厌倦了 Spring 的臃肿配置,不妨试试 Javalin,说不定就成了你新的“生产力神器”。