Javalin网站框架介绍之二 - 数据库
本文是《超简单易用的 Java Web 框架 - Javalin》的续篇。
理解了前文所述的基本原理,就能制作一个前后端分离的网站了,但前文没有涉及数据库的问题,下面以 sqlite 为例,说说如何与数据库沟通。
添加依赖
在 pom.xml 中添加以下与数据库操作有关的依赖:
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.39.2.0</version>
</dependency>
<dependency>
<groupId>org.jdbi</groupId>
<artifactId>jdbi3-core</artifactId>
<version>3.32.0</version>
</dependency>
代码结构
为了打通数据库与网站各部分的关系,可以添加 4 个文件,形成非常清晰的结构:
- Entry.java (数据模型,与 Stmt.java 里的数据表结构一一对应)
- Stmt.java (数据库的 SQL 语句)
- DB.java (数据库操作集中在这个文件里)
- Handle.java (调用 DB 的方法进行增删改查)
Entry.java
源码参考 github.com/ahui2016/monostich/.../Entry.java
public record Entry(String id, String notes, String cmd, long created) {
Map<String, Object> toMap() {
return Map.of(
"id", id,
"notes", notes,
"cmd", cmd,
"created", created
);
}
}
这里以 Entry 为例,如果数据库里还有别的数据表,则需要创建新的类。
Stmt.java
源码参考 github.com/ahui2016/monostich/.../Stmt.java
public class Stmt {
public static final String CREATE_TABLES = """
CREATE TABLE IF NOT EXISTS cmdentry
(
id TEXT PRIMARY KEY COLLATE NOCASE,
notes TEXT NOT NULL,
cmd TEXT NOT NULL,
created INT NOT NULL
);
""";
public static final String GET_ENTRY = """
SELECT * FROM cmdentry WHERE id = :id;
""";
}
- 可见,数据表与数据模型一一对应,这里 cmdentry 对应前面的 Entry 类。
- 另外有一些增删改查的 SQL 语句 (这里只列出一部分,详见源码)。
DB.java
源码参考 github.com/ahui2016/monostich/.../DB.java
package com.example.myproject;
public class DB {
private final String dbPath;
private final Jdbi jdbi;
public DB(String dbPath) {
this.path = dbPath;
this.jdbi = Jdbi.create("jdbc:sqlite:" + dbPath);
this.jdbi.useHandle(h -> h.createScript(Stmt.CREATE_TABLES).execute());
this.jdbi.registerRowMapper(ConstructorMapper.factory(Entry.class));
}
void insertEntry(Entry entry) {
jdbi.useHandle(h -> h.createUpdate(Stmt.INSERT_ENTRY)
.bindMap(entry.toMap())
.execute());
}
}
- 由于有了前面的 Entry 和 Stmt, 现在写 DB.java 就非常方便了。
- 比如
Stmt.CREATE_TABLES
和Stmt.INSERT_ENTRY
等 SQL 语句集中在一个文件里,很有条理,代码看起来也简明、清晰。 - 另外由于有了 Entry, 现在向数据库里写入数据、读取数据都很方便,看这里对 Entry 的用法就可以体会。
- 这里只展示了
insertEntry()
, 点击上面源码参考链接可以看到getEntry()
,deleteEntry()
等方法,每个方法都很简短。
Handle.java
源码参考 github.com/ahui2016/monostich/.../Handle.java
public class Handle {
static DB db = new DB("db/monostich.sqlite");
static void testDB() {
// 插入数据
for (var entry: Mock.entries) {
db.insertEntry(entry);
}
// 获取并在终端打印数据
var entries = db.getAllEntries();
for (var entry: entries) {
Print.ln(entry.toString());
}
// 删除数据
for (var entry: Mock.entries) {
db.deleteEntry(entry.id());
}
// 确认数据已删除
var emptyEntries = db.getAllEntries();
Print.ln("size: " + emptyEntries.size());
}
class Print {
public static void ln(String s) {
System.out.println(s);
}
}
}
- 在 Handle 中,主要是接收来自前端的数据,保存到数据库中,或从数据库获取数据,发送给前端。
- 这里只是为了说明与数据库的沟通方法,因此不与前端交互,专注于数据库的操作。
-
Mork.entries
只是一个简单的 Map, 详见上面源码参考链接。
总结
如上所示,数据模型 (Entry.java) 与数据表一一对应,然后在 DB.java 里通过 Jdbi 进行数据库操作,最后在 Handle.java 中调用 DB 的方法,形成非常有条理的代码结构。