在现代Web开发中,TODO列表应用是一个经典的示例,用于展示如何使用前端和后端技术构建一个简单的任务管理工具。本文将详细介绍如何使用Express.js框架和SQLite3数据库来构建一个TODO列表应用,并解释代码的各个部分,帮助读者理解其工作原理。
前端UI请参考,使用React和Material-UI构建TODO应用的前端UI
在开始之前,请确保你已经安装了以下工具和库:
安装所需的依赖:
npm install express cors sqlite3
让我们逐步分析代码,理解每个部分的功能。
import express from 'express';
import cors from 'cors';
import sqlite3 from 'sqlite3';
import path from 'path';
const app = express();
这行代码创建了一个Express应用实例,后续的所有中间件和路由都将注册到这个实例上。
const db = new sqlite3.Database(path.join(__dirname, '../database/db.sqlite'));
这里创建了一个SQLite3数据库连接,数据库文件位于../database/db.sqlite
。path.join
用于确保路径在不同操作系统下都能正确解析。
db.serialize(() => {
db.run(`
CREATE TABLE IF NOT EXISTS todos
(
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
description TEXT,
completed BOOLEAN DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
});
这段代码在数据库中创建了一个名为todos
的表,如果该表不存在的话。表结构如下:
0
(即false
)。app.use(cors());
app.use(express.json());
req.body
可以访问到客户端发送的数据。interface Todo {
id?: number;
title: string;
description?: string;
completed?: boolean;
created_at?: string;
}
这是一个TypeScript接口,定义了TODO项的结构。id
、description
、completed
和created_at
是可选的,而title
是必填的。
app.get('/api/todos', (req: express.Request, res: express.Response) => {
const search = (req.query.q as string) || '';
db.all<Todo>(
`SELECT *
FROM todos
WHERE title ILIKE ?
OR description ILIKE ?
ORDER BY created_at DESC`,
[`%${search}%`, `%${search}%`],
(err, rows) => {
if (err) return res.status(500).json({ error: err.message });
res.json(rows);
}
);
});
q
参数进行模糊搜索。q
用于模糊搜索标题或描述。ILIKE
进行不区分大小写的匹配,按创建时间降序排列。app.post('/api/todos', (req: express.Request, res: express.Response) => {
const { title, description } = req.body as Todo;
if (!title) {
return res.status(400).json({ error: 'Title is required' });
}
db.run(
'INSERT INTO todos (title, description) VALUES (?, ?)',
[title, description],
function (err) {
if (err) return res.status(500).json({ error: err.message });
db.get<Todo>(
'SELECT * FROM todos WHERE id = ?',
[this.lastID],
(err, row) => {
if (err) return res.status(500).json({ error: err.message });
res.status(201).json(row);
}
);
}
);
});
title
,description
可选。title
是否为空,返回400错误;数据库操作失败返回500错误。app.put('/api/todos/:id', (req: express.Request, res: express.Response) => {
const { id } = req.params;
const { title, description, completed } = req.body as Todo;
db.run(
`UPDATE todos
SET title = ?,
description = ?,
completed = ?
WHERE id = ?`,
[title, description, completed ? 1 : 0, id],
function (err) {
if (err) return res.status(500).json({ error: err.message });
if (this.changes === 0) {
return res.status(404).json({ error: 'Todo not found' });
}
db.get<Todo>(
'SELECT * FROM todos WHERE id = ?',
[id],
(err, row) => {
if (err) return res.status(500).json({ error: err.message });
res.json(row);
}
);
}
);
});
title
、description
和completed
。completed
字段转换为1
或0
。app.delete('/api/todos/:id', (req: express.Request, res: express.Response) => {
const { id } = req.params;
db.run(
'DELETE FROM todos WHERE id = ?',
[id],
function (err) {
if (err) return res.status(500).json({ error: err.message });
if (this.changes === 0) {
return res.status(404).json({ error: 'Todo not found' });
}
res.status(204).send();
}
);
});
const PORT = 3002;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
服务器监听在3002端口,启动后在控制台输出提示信息。
尽管这段代码已经可以正常工作,但为了提升应用的性能和可维护性,可以考虑以下优化:
express-validator
对请求体进行验证,确保数据的合法性和完整性。Sequelize
或Knex.js
,简化数据库操作,提高代码的可读性和可维护性。winston
或morgan
记录请求和错误信息,便于调试和监控。通过本文,我们详细解析了一个使用Express.js和SQLite3构建的TODO列表应用。从数据库的初始化、路由的定义到错误处理,每个部分都进行了详细的解释。希望这篇文章能够帮助读者理解如何使用这些技术构建一个简单的Web应用,并为进一步的学习和开发打下基础。