用Java写一个个人笔记小应用,本质是把用户的文字内容可靠地保存到本地,并提供一个能添加、查看、修改和删除笔记的图形界面。整体技术选型可以采用JavaFX负责前端展示,SQLite作为嵌入式数据库,JDBC完成数据访问。这种组合不依赖外部服务,打包后双击即可运行,非常适合个人随手记录。

一、项目结构与依赖
新建一个普通的Java项目,推荐使用Maven管理依赖。核心只需要两个外部库:SQLite的JDBC驱动和JavaFX的运行包。前者让我们能用标准SQL操作本地文件数据库,后者提供按钮、文本框等界面组件。
在pom.xml里引入相关依赖后,项目目录可以划分为界面层、数据访问层与模型层。模型层定义Note类,数据访问层封装INSERT、SELECT等语句,界面层通过事件绑定调用数据层。分层之后逻辑清晰,后期想换成MySQL也只需改数据层实现。
<dependencies>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.45.1.0</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>21</version>
</dependency>
</dependencies>
二、数据库设计与初始化
笔记数据至少需要标题、正文和创建时间三个字段。我们用一张名为notes的表存储,id设为自增主键,方便后续按主键删除或修改。SQLite支持直接把时间存为TEXT类型,用UTC格式写入即可。
初始化时如果数据库文件不存在,驱动会自动创建。建表语句建议放在应用启动时执行一次,使用IF NOT EXISTS避免重复建表报错。下面的代码展示了如何用单例模式持有数据库连接,防止多处打开句柄造成资源浪费。
import java.sql.*;
public class DbUtil {
private static final String URL = "jdbc:sqlite:notes.db";
private static Connection conn;
public static Connection getConnection() throws SQLException {
if (conn == null || conn.isClosed()) {
conn = DriverManager.getConnection(URL);
initTable();
}
return conn;
}
private static void initTable() throws SQLException {
String sql = "CREATE TABLE IF NOT EXISTS notes (" +
"id INTEGER PRIMARY KEY AUTOINCREMENT," +
"title TEXT NOT NULL," +
"content TEXT," +
"created_at TEXT NOT NULL)";
try (Statement st = conn.createStatement()) {
st.execute(sql);
}
}
}
三、笔记模型的增删改查
数据访问对象(DAO)负责把Java对象转成SQL。添加笔记时,用PreparedStatement传入参数,可以避免标题里含有单引号导致语法错误。查询全部笔记则返回List,界面用ListView展示。
删除操作只需根据id执行DELETE语句,更新则改写title与content。注意SQLite默认在单连接下是串行写,因此把连接收口在DbUtil里更稳妥。下面给出新增与查询的示例方法。
import java.sql.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
public class NoteDao {
public void insert(String title, String content) throws SQLException {
String sql = "INSERT INTO notes(title,content,created_at) VALUES(?,?,?)";
try (Connection c = DbUtil.getConnection();
PreparedStatement ps = c.prepareStatement(sql)) {
ps.setString(1, title);
ps.setString(2, content);
ps.setString(3, LocalDateTime.now().toString());
ps.executeUpdate();
}
}
public List<String> findAllTitles() throws SQLException {
List<String> list = new ArrayList<>();
String sql = "SELECT title FROM notes ORDER BY id DESC";
try (Connection c = DbUtil.getConnection();
Statement st = c.createStatement();
ResultSet rs = st.executeQuery(sql)) {
while (rs.next()) {
list.add(rs.getString("title"));
}
}
return list;
}
}
四、JavaFX界面搭建
界面可以用FXML描述,也可以纯代码写。简单起见,我们用VBox放一个输入框组:标题TextField、正文TextArea、保存按钮,以及下方ListView显示历史笔记。点击保存就调用NoteDao插入,然后刷新列表。
由于JDBC调用可能阻塞界面线程,正式项目应放到Task里跑,但个人小应用数据量极小,直接调用也能流畅运行。下面给出启动类与基础布局,展示如何把界面和数据层连起来。
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.util.List;
public class NoteApp extends Application {
private final NoteDao dao = new NoteDao();
private final ListView<String> listView = new ListView<>();
public void start(Stage stage) {
TextField titleField = new TextField();
titleField.setPromptText("笔记标题");
TextArea contentArea = new TextArea();
contentArea.setPromptText("笔记正文");
Button saveBtn = new Button("保存");
saveBtn.setOnAction(e -> {
try {
dao.insert(titleField.getText(), contentArea.getText());
refresh();
titleField.clear();
contentArea.clear();
} catch (Exception ex) {
ex.printStackTrace();
}
});
VBox root = new VBox(8, titleField, contentArea, saveBtn, listView);
refresh();
stage.setScene(new Scene(root, 400, 500));
stage.setTitle("个人笔记");
stage.show();
}
private void refresh() {
try {
List<String> titles = dao.findAllTitles();
listView.getItems().setAll(titles);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
五、打包与后续扩展
功能跑通后,可用jpackage把JRE和应用打成一个系统安装包,这样别人不用装Java也能用。SQLite文件随应用目录走,备份时直接复制notes.db即可。
后续可以加按关键词搜索、导出Markdown、设置标签等功能。搜索只要在SQL里加LIKE,标签则新建关联表。整体架构不用大改,这也是分层设计带来的好处。只要守住数据层接口稳定,界面怎么换都行。