create-pixle-koa-template 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +7 -3
- package/template/.env +3 -3
- package/template/app.js +1 -0
- package/template/config/index.js +1 -1
- package/template/middleware/auth.js +1 -0
- package/template/middleware/notFound.js +74 -64
- package/template/middleware/upload.js +27 -27
- package/template/models/BaseDAO.js +1 -1
- package/template/package-lock.json +3427 -3427
- package/template/package.json +1 -1
- package/template/public/images/1.png +0 -0
- package/template/routes/upload.js +28 -28
- package/template/routes/user.js +1 -1
- package/template/services/DownloadService.js +0 -1
- package/template/services/EmailService.js +2 -2
- package/template/services/JwtTokenService.js +1 -0
- package/template/storage/uploads/image/2025/12/25/image_1766623635715_mg7xr2125j.png +0 -0
- package/template/storage/uploads/image/2025/12/25/image_1766624354283_gwy09ck78ek.png +0 -0
- package/template/storage/uploads/image/2025/12/28/image_1766933215147_8v1ghholjdc.jpg +0 -0
- package/template//344/275/277/347/224/250/346/225/231/347/250/213.md +112 -107
package/template/package.json
CHANGED
|
Binary file
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
const Router = require("@koa/router");
|
|
2
|
-
const router = new Router({prefix: '/upload'});
|
|
3
|
-
const UploadController = require("../controllers/UploadController.js");
|
|
4
|
-
const uploadMiddleware = require('../middleware/upload');//上传中间件
|
|
5
|
-
const upload = uploadMiddleware(
|
|
6
|
-
//可选配置项
|
|
7
|
-
// {
|
|
8
|
-
// limits:{
|
|
9
|
-
// fileSize: 20 * 1024 * 1024, // 单个文件最大20MB
|
|
10
|
-
// files: 5, //一次最多5个文件
|
|
11
|
-
// },
|
|
12
|
-
// allowedMimes:["image/jpeg", "image/png"],//允许上传文件格式
|
|
13
|
-
// //自定义过滤函数
|
|
14
|
-
// fileFilter:(req, file, cb)=>{
|
|
15
|
-
|
|
16
|
-
// }
|
|
17
|
-
// }
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
//上传路由(单文件)
|
|
21
|
-
router.post("/single", upload.single(), UploadController.single);
|
|
22
|
-
|
|
23
|
-
//上传路由(多文件)
|
|
24
|
-
router.post("/multiple", upload.array(), UploadController.multiple);
|
|
25
|
-
|
|
26
|
-
module.exports = router;
|
|
27
|
-
|
|
28
|
-
|
|
1
|
+
const Router = require("@koa/router");
|
|
2
|
+
const router = new Router({prefix: '/upload'});
|
|
3
|
+
const UploadController = require("../controllers/UploadController.js");
|
|
4
|
+
const uploadMiddleware = require('../middleware/upload');//上传中间件
|
|
5
|
+
const upload = uploadMiddleware(
|
|
6
|
+
//可选配置项
|
|
7
|
+
// {
|
|
8
|
+
// limits:{
|
|
9
|
+
// fileSize: 20 * 1024 * 1024, // 单个文件最大20MB
|
|
10
|
+
// files: 5, //一次最多5个文件
|
|
11
|
+
// },
|
|
12
|
+
// allowedMimes:["image/jpeg", "image/png"],//允许上传文件格式
|
|
13
|
+
// //自定义过滤函数
|
|
14
|
+
// fileFilter:(req, file, cb)=>{
|
|
15
|
+
|
|
16
|
+
// }
|
|
17
|
+
// }
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
//上传路由(单文件)
|
|
21
|
+
router.post("/single", upload.single(), UploadController.single);
|
|
22
|
+
|
|
23
|
+
//上传路由(多文件)
|
|
24
|
+
router.post("/multiple", upload.array(), UploadController.multiple);
|
|
25
|
+
|
|
26
|
+
module.exports = router;
|
|
27
|
+
|
|
28
|
+
|
package/template/routes/user.js
CHANGED
|
@@ -10,12 +10,12 @@ const QQ_EMAIL_CONFIG = require("../config/email");
|
|
|
10
10
|
const transporter = nodemailer.createTransport(QQ_EMAIL_CONFIG);
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* 生成
|
|
13
|
+
* 生成6位验证码
|
|
14
14
|
* @returns 验证码
|
|
15
15
|
*/
|
|
16
16
|
const generateVerificationCode = () => {
|
|
17
17
|
let code = "";
|
|
18
|
-
for (let i = 0; i <
|
|
18
|
+
for (let i = 0; i < 6; i++) {
|
|
19
19
|
code += Math.floor(Math.random() * 10); // 0-9
|
|
20
20
|
}
|
|
21
21
|
return code;
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## 1. 项目概述
|
|
4
4
|
|
|
5
|
-
本项目是一个基于 Koa.js
|
|
5
|
+
本项目是一个基于 Koa.js 框架构建的后端服务开箱即用的脚手架项目,它提供了完整的 MVC 架构、用户认证、文件上传、数据访问层等核心功能,采用模块化设计,各组件职责清晰,便于扩展与维护。
|
|
6
6
|
|
|
7
7
|
### 主要特性:
|
|
8
8
|
- 完整的用户认证系统(登录、注册、密码重置)
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
- Redis 集成(用于验证码、Token 存储)
|
|
14
14
|
- 文件上传下载功能
|
|
15
15
|
- 详细的请求日志记录
|
|
16
|
+
- 支持热更新与环境变量配置
|
|
17
|
+
- 保持Koa的简洁本质,不添加过度抽象
|
|
18
|
+
- 符合前端人员开发习惯的使用设计
|
|
16
19
|
|
|
17
20
|
## 2. 环境要求
|
|
18
21
|
|
|
@@ -65,7 +68,7 @@ const pool = mysql.createPool({
|
|
|
65
68
|
host: "localhost", // 数据库服务器地址
|
|
66
69
|
port: 3306, // 数据库端口
|
|
67
70
|
user: "root", // 数据库用户名
|
|
68
|
-
password: "
|
|
71
|
+
password: "1234qwer", // 数据库密码
|
|
69
72
|
database: "demo", // 数据库名称
|
|
70
73
|
// 连接池配置
|
|
71
74
|
waitForConnections: true,
|
|
@@ -213,103 +216,103 @@ const validateParams = (schema) => {
|
|
|
213
216
|
module.exports = validateParams;
|
|
214
217
|
```
|
|
215
218
|
|
|
216
|
-
### 5.3 验证码系统
|
|
217
|
-
|
|
218
|
-
验证码系统用于用户注册、密码重置等场景,确保操作的安全性和防止恶意攻击。本系统通过邮箱发送验证码,并使用Redis进行验证码存储和频率限制管理。
|
|
219
|
-
|
|
220
|
-
#### 验证码使用场景
|
|
221
|
-
|
|
222
|
-
- **用户注册**:新用户注册时需要验证邮箱的真实性
|
|
223
|
-
- **密码重置**:用户忘记密码时通过邮箱验证码进行身份验证
|
|
224
|
-
|
|
225
|
-
#### 验证码类型
|
|
226
|
-
|
|
227
|
-
- `register`:用于用户注册场景
|
|
228
|
-
- `resetPassword`:用于密码重置场景
|
|
229
|
-
|
|
230
|
-
#### 如何使用验证码系统
|
|
231
|
-
|
|
232
|
-
##### 1. 发送验证码
|
|
233
|
-
|
|
234
|
-
**步骤说明**:
|
|
235
|
-
|
|
236
|
-
1. 调用发送验证码接口 `/api/auth/verify-code`
|
|
237
|
-
2. 系统会自动执行以下操作:
|
|
238
|
-
- 验证邮箱格式是否正确
|
|
239
|
-
- 检查邮箱是否已注册(注册场景)
|
|
240
|
-
- 验证发送频率限制(60秒内只能发送一次)
|
|
241
|
-
- 验证每日发送次数限制(每邮箱每日最多10次)
|
|
242
|
-
- 生成
|
|
243
|
-
- 发送验证码邮件
|
|
244
|
-
- 存储验证码到Redis(有效期5分钟)
|
|
245
|
-
|
|
246
|
-
**使用示例**:
|
|
247
|
-
|
|
248
|
-
```javascript
|
|
249
|
-
// 前端调用示例
|
|
250
|
-
const response = await fetch('/api/auth/verify-code', {
|
|
251
|
-
method: 'POST',
|
|
252
|
-
headers: {
|
|
253
|
-
'Content-Type': 'application/json'
|
|
254
|
-
},
|
|
255
|
-
body: JSON.stringify({
|
|
256
|
-
email: 'user@example.com',
|
|
257
|
-
type: 'register' // 或 'resetPassword'
|
|
258
|
-
})
|
|
259
|
-
});
|
|
260
|
-
const result = await response.json();
|
|
261
|
-
// {"code": 200, "message": "验证码发送成功", "data": true}
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
##### 2. 验证验证码
|
|
265
|
-
|
|
266
|
-
**步骤说明**:
|
|
267
|
-
|
|
268
|
-
1. 在用户注册或重置密码接口中传递验证码
|
|
269
|
-
2. 系统会自动执行以下操作:
|
|
270
|
-
- 从Redis获取存储的验证码
|
|
271
|
-
- 验证验证码是否有效且未过期
|
|
272
|
-
- 验证用户输入的验证码是否匹配
|
|
273
|
-
- 验证成功后自动清除验证码(防止重复使用)
|
|
274
|
-
|
|
275
|
-
**使用示例**:
|
|
276
|
-
|
|
277
|
-
```javascript
|
|
278
|
-
// 注册时验证验证码
|
|
279
|
-
const registerResponse = await fetch('/api/auth/register', {
|
|
280
|
-
method: 'POST',
|
|
281
|
-
headers: {
|
|
282
|
-
'Content-Type': 'application/json'
|
|
283
|
-
},
|
|
284
|
-
body: JSON.stringify({
|
|
285
|
-
account: 'newuser',
|
|
286
|
-
password: 'StrongPass123',
|
|
287
|
-
email: 'user@example.com',
|
|
288
|
-
code: '
|
|
289
|
-
})
|
|
290
|
-
});
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
#### 验证码系统的安全特性
|
|
294
|
-
|
|
295
|
-
1. **有效期限制**:验证码默认有效期为5分钟,通过环境变量 `VERIFICATION_CODE_EXPIRE` 配置
|
|
296
|
-
2. **发送频率限制**:60秒内每个邮箱只能发送一次验证码,通过环境变量 `VERIFICATION_SEND_LIMIT_EXPIRE` 配置
|
|
297
|
-
3. **每日次数限制**:每个邮箱每日最多发送10次验证码,通过环境变量 `MAX_ATTEMPTS_PER_DAY` 配置
|
|
298
|
-
4. **邮箱格式验证**:系统自动验证邮箱格式的合法性
|
|
299
|
-
5. **验证码一次性使用**:验证成功后自动删除验证码,防止重复使用
|
|
300
|
-
6. **安全的Redis存储**:验证码以特定格式存储在Redis中,使用合理的键名前缀
|
|
301
|
-
|
|
302
|
-
#### 常见错误处理
|
|
303
|
-
|
|
304
|
-
使用验证码系统时,可能遇到的常见错误:
|
|
305
|
-
|
|
306
|
-
- 邮箱格式不正确
|
|
307
|
-
- 邮箱已被注册(注册场景)
|
|
308
|
-
- 60秒内已发送验证码
|
|
309
|
-
- 今日发送验证码已达上限
|
|
310
|
-
- 验证码无效或已过期
|
|
311
|
-
- 验证码错误
|
|
312
|
-
|
|
219
|
+
### 5.3 验证码系统
|
|
220
|
+
|
|
221
|
+
验证码系统用于用户注册、密码重置等场景,确保操作的安全性和防止恶意攻击。本系统通过邮箱发送验证码,并使用Redis进行验证码存储和频率限制管理。
|
|
222
|
+
|
|
223
|
+
#### 验证码使用场景
|
|
224
|
+
|
|
225
|
+
- **用户注册**:新用户注册时需要验证邮箱的真实性
|
|
226
|
+
- **密码重置**:用户忘记密码时通过邮箱验证码进行身份验证
|
|
227
|
+
|
|
228
|
+
#### 验证码类型
|
|
229
|
+
|
|
230
|
+
- `register`:用于用户注册场景
|
|
231
|
+
- `resetPassword`:用于密码重置场景
|
|
232
|
+
|
|
233
|
+
#### 如何使用验证码系统
|
|
234
|
+
|
|
235
|
+
##### 1. 发送验证码
|
|
236
|
+
|
|
237
|
+
**步骤说明**:
|
|
238
|
+
|
|
239
|
+
1. 调用发送验证码接口 `/api/auth/verify-code`
|
|
240
|
+
2. 系统会自动执行以下操作:
|
|
241
|
+
- 验证邮箱格式是否正确
|
|
242
|
+
- 检查邮箱是否已注册(注册场景)
|
|
243
|
+
- 验证发送频率限制(60秒内只能发送一次)
|
|
244
|
+
- 验证每日发送次数限制(每邮箱每日最多10次)
|
|
245
|
+
- 生成6位数字验证码
|
|
246
|
+
- 发送验证码邮件
|
|
247
|
+
- 存储验证码到Redis(有效期5分钟)
|
|
248
|
+
|
|
249
|
+
**使用示例**:
|
|
250
|
+
|
|
251
|
+
```javascript
|
|
252
|
+
// 前端调用示例
|
|
253
|
+
const response = await fetch('/api/auth/verify-code', {
|
|
254
|
+
method: 'POST',
|
|
255
|
+
headers: {
|
|
256
|
+
'Content-Type': 'application/json'
|
|
257
|
+
},
|
|
258
|
+
body: JSON.stringify({
|
|
259
|
+
email: 'user@example.com',
|
|
260
|
+
type: 'register' // 或 'resetPassword'
|
|
261
|
+
})
|
|
262
|
+
});
|
|
263
|
+
const result = await response.json();
|
|
264
|
+
// {"code": 200, "message": "验证码发送成功", "data": true}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
##### 2. 验证验证码
|
|
268
|
+
|
|
269
|
+
**步骤说明**:
|
|
270
|
+
|
|
271
|
+
1. 在用户注册或重置密码接口中传递验证码
|
|
272
|
+
2. 系统会自动执行以下操作:
|
|
273
|
+
- 从Redis获取存储的验证码
|
|
274
|
+
- 验证验证码是否有效且未过期
|
|
275
|
+
- 验证用户输入的验证码是否匹配
|
|
276
|
+
- 验证成功后自动清除验证码(防止重复使用)
|
|
277
|
+
|
|
278
|
+
**使用示例**:
|
|
279
|
+
|
|
280
|
+
```javascript
|
|
281
|
+
// 注册时验证验证码
|
|
282
|
+
const registerResponse = await fetch('/api/auth/register', {
|
|
283
|
+
method: 'POST',
|
|
284
|
+
headers: {
|
|
285
|
+
'Content-Type': 'application/json'
|
|
286
|
+
},
|
|
287
|
+
body: JSON.stringify({
|
|
288
|
+
account: 'newuser',
|
|
289
|
+
password: 'StrongPass123',
|
|
290
|
+
email: 'user@example.com',
|
|
291
|
+
code: '123456' // 用户收到的验证码
|
|
292
|
+
})
|
|
293
|
+
});
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
#### 验证码系统的安全特性
|
|
297
|
+
|
|
298
|
+
1. **有效期限制**:验证码默认有效期为5分钟,通过环境变量 `VERIFICATION_CODE_EXPIRE` 配置
|
|
299
|
+
2. **发送频率限制**:60秒内每个邮箱只能发送一次验证码,通过环境变量 `VERIFICATION_SEND_LIMIT_EXPIRE` 配置
|
|
300
|
+
3. **每日次数限制**:每个邮箱每日最多发送10次验证码,通过环境变量 `MAX_ATTEMPTS_PER_DAY` 配置
|
|
301
|
+
4. **邮箱格式验证**:系统自动验证邮箱格式的合法性
|
|
302
|
+
5. **验证码一次性使用**:验证成功后自动删除验证码,防止重复使用
|
|
303
|
+
6. **安全的Redis存储**:验证码以特定格式存储在Redis中,使用合理的键名前缀
|
|
304
|
+
|
|
305
|
+
#### 常见错误处理
|
|
306
|
+
|
|
307
|
+
使用验证码系统时,可能遇到的常见错误:
|
|
308
|
+
|
|
309
|
+
- 邮箱格式不正确
|
|
310
|
+
- 邮箱已被注册(注册场景)
|
|
311
|
+
- 60秒内已发送验证码
|
|
312
|
+
- 今日发送验证码已达上限
|
|
313
|
+
- 验证码无效或已过期
|
|
314
|
+
- 验证码错误
|
|
315
|
+
|
|
313
316
|
系统会返回相应的错误信息,前端可以根据返回的错误信息给用户友好的提示。
|
|
314
317
|
### 5.4 数据访问层
|
|
315
318
|
|
|
@@ -693,7 +696,7 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
|
|
693
696
|
|
|
694
697
|
**请求**:
|
|
695
698
|
```
|
|
696
|
-
GET /api/
|
|
699
|
+
GET /api/users/current
|
|
697
700
|
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
|
698
701
|
```
|
|
699
702
|
|
|
@@ -786,12 +789,12 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
|
|
786
789
|
|
|
787
790
|
| 接口路径 | 方法 | 描述 | 请求参数 | 成功响应 (200 OK) |
|
|
788
791
|
|---------|------|------|---------|-------------------|
|
|
789
|
-
| `/api/
|
|
790
|
-
| `/api/
|
|
791
|
-
| `/api/
|
|
792
|
-
| `/api/
|
|
793
|
-
| `/api/
|
|
794
|
-
| `/api/
|
|
792
|
+
| `/api/users/current` | `GET` | 获取当前用户信息 | 无(需要JWT认证) | `{"code": 200, "message": "获取成功", "data": {"id": 1, "account": "用户名", "email": "邮箱", "created_at": "2023-07-01 00:00:00", "updated_at": "2023-07-01 00:00:00"}}` |
|
|
793
|
+
| `/api/users/list` | `GET` | 获取用户列表 | 查询参数:`email`(邮箱), `startTime`(开始时间), `endTime`(结束时间), `page`(页码), `pageSize`(每页数量), `all`(是否获取全部列表,默认为false) | 当all=true时:`{"code": 200, "message": "success", "data": [{"id": 15, "account": "admin", "updated_at": "2025-12-15 16:28:58", "email": "xxx@qq.com", "created_at": "2025-12-15 15:38:12"}]}`<br>当all=false时:`{"code": 200, "message": "success", "data": {"list": [{"id": 15, "account": "admin", "updated_at": "2025-12-15 16:28:58", "email": "xxx@qq.com", "created_at": "2025-12-15 15:38:12"}], "pagination": {"page": 2, "pageSize": 1, "total": 4, "totalPages": 4, "hasNext": true, "hasPrev": true}}}` |
|
|
794
|
+
| `/api/users` | `POST` | 创建新用户 | `{"account": "用户名", "password": "密码", "email": "邮箱"}` | `{"code": 200, "message": "创建成功", "data": {"id": 1, "account": "用户名", "email": "邮箱", "created_at": "2023-07-01 00:00:00", "updated_at": "2023-07-01 00:00:00"}}` |
|
|
795
|
+
| `/api/users/:id` | `PUT` | 更新用户信息 | `{"account": "用户名", "email": "邮箱"}` | `{"code": 200, "message": "success", "data": true}` |
|
|
796
|
+
| `/api/users/:id` | `DELETE` | 删除用户 | 无(路径参数id) | `{"code": 200, "message": "删除成功"}` |
|
|
797
|
+
| `/api/users/:id` | `GET` | 获取指定用户信息 | 无(路径参数id) | `{"code": 200, "message": "获取成功", "data": {"id": 1, "account": "用户名", "email": "邮箱", "created_at": "2023-07-01 00:00:00", "updated_at": "2023-07-01 00:00:00"}}` |
|
|
795
798
|
|
|
796
799
|
#### 文件上传相关接口
|
|
797
800
|
|
|
@@ -858,8 +861,10 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
|
|
858
861
|
在 DAO 层可以通过获取连接并手动控制事务:
|
|
859
862
|
|
|
860
863
|
```javascript
|
|
864
|
+
const pool = require("../config/db");
|
|
865
|
+
|
|
861
866
|
async transactionExample() {
|
|
862
|
-
const connection = await
|
|
867
|
+
const connection = await pool.getConnection();
|
|
863
868
|
try {
|
|
864
869
|
await connection.beginTransaction();
|
|
865
870
|
// 执行多个操作
|