koa后端项目基本架构
# koa项目基本架构
# 1.前期简单安装一些依赖(根据需要再添加)
npm init -y
npm install koa
npm install nodemon -D–开发依赖
npm install dotenv,可加载根目录下的.env文件,将里面的直接加载到环境变量里面process.env
npm install koa-router路由库
npm install koa-bodyparser:中间件,解析json数据
npm install mysql2连接数据库
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 2.文件目录拆分
src
app:主体部分 constants:放一些常量 controller:控制器,写一些逻辑操作,比如,获取我们输入的信息,再调用service中操作数据库的方法 middleware:中间件,比如验证授权、验证输入的账号密码是否正确/存在、验证token是否已过期等 router:路由层,在这个文件夹中写路由 service:service层,就是操作数据库的一些方法 utils:放一些可以用到的方法,比如读取文件的方法 main.js:程序的入口,这个入口,越简单越好 .env:一些不能写死的环境变量,比如,服务端口port,数据库的一些信息,抽离到这个文件中
# 3.写接口的步骤
习惯性依次的创建xxx.router.js、xxx.middleware.js、xxx.controller.js、xxx.service.js这几个文件,当然xxx.middleware.js这个可根据需求决定是否需要创建,或者引用已经创建好的中间件文件
事例如下:
(1)在router文件夹中创建文件,如:department.router.js
// 请求路径 中间件处理的 映射
const Router = require('koa-router');
// 中间件
// 具体的处理逻辑 增删改查
const {
list,
create,
update,
remove
} = require('../controller/department.controller');
// 前缀:
const deportmentRouter = new Router({
prefix: '/api/department'
});
deportmentRouter.post('/', create);
deportmentRouter.get('/list', list);
deportmentRouter.patch('/:departmentId', update);
deportmentRouter.delete('/:departmentId', remove);
// 导出
module.exports = deportmentRouter;
(2)在middleware文件夹下创建auth.middleware.js文件
未进行鉴权
(3)在controller文件夹中创建文件,如:department.controller.js
const departmentService = require('../service/department.service')
class DepartmentController {
async list(ctx, next) {
// 1.获取数据(offset/size)
const {
offset,
size
} = ctx.query;
// 2.查询列表
const {
result,
count
} = await departmentService.getDepartmentList(offset, size);
ctx.body = {
code: 200,
data: result,
totalCount: count[0].total
};
}
async create(ctx, next) {
// 获取用户请求传递的参数
const department = ctx.request.body;
// 查询数据库 -> 抽离到service
const result = await departmentService.create(department);
// 返回结果
ctx.body = {
code: 200,
data: result
};
}
async update(ctx, next) {
const {
departmentId
} = ctx.params;
const {
departmentName,
principal,
adviser,
departmentTotal
} = ctx.request.body;
const result = await departmentService.update(departmentName, principal, adviser, departmentTotal, departmentId);
ctx.body = {
code: 200,
data: result
};
}
async remove(ctx, next) {
// 1.
const {
departmentId
} = ctx.params;
// 2.删除内容
const result = await departmentService.remove(departmentId);
ctx.body = {
code: 200,
data: result
};
}
}
module.exports = new DepartmentController();
(4)在service文件夹下创建department.service.js文件
const connection = require('../app/database');
class DeportmentService {
async getDepartmentList(offset, size) {
const statement = `
SELECT
d.id id, d.department_name departmentName, d.principal principal, d.adviser adviser, d.department_total departmentTotal, d.createAt createAt, d.updateAt updateAt
FROM department d
LIMIT ?, ?;
`;
const state = `SELECT COUNT(*) total FROM department`;
const [result] = await connection.execute(statement, [offset, size]);
const [count] = await connection.execute(state);
return {
result,
count
};
}
async create(deportment) {
const {
departmentName,
principal,
adviser,
departmentTotal
} = deportment;
// 使用sql语句将user存储到数据库中
const statement = `INSERT INTO department (department_name, principal, adviser, department_total) VALUES (?, ?, ?, ?);`;
const result = await connection.execute(statement, [departmentName, principal, adviser, departmentTotal]);
return result[0];
}
async update(departmentName, principal, adviser, departmentTotal, deportmentId) {
const statement = `UPDATE department SET department_name = ?, principal = ?, adviser = ?, department_total = ? WHERE id = ?;`;
const [result] = await connection.execute(statement, [departmentName, principal, adviser, departmentTotal, deportmentId]);
return result;
}
async remove(deportmentId) {
const statement = `DELETE FROM department WHERE id = ?;`;
const [result] = await connection.execute(statement, [deportmentId]);
return result;
}
}
module.exports = new DeportmentService();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# 4.app文件夹中的一些内容
(1)index.js
const Koa = require('koa');
// 导入bodyParser中间件,解析json
const bodyParser = require('koa-bodyparser')
// 导入错误信息处置方法
const errorHandler = require('./error-handle');
// 导入路由 升级版 动态加载路由
const useRoutes = require('../router');
const app = new Koa();
app.use(bodyParser());
useRoutes(app);
app.on('error', errorHandler);
module.exports = app;
(2)database.js
const mysql = require('mysql2');
const config = require('./config');
// 创建连接池,与数据库进行连接
const connections = mysql.createPool({
host: config.MYSQL_HOST,
port: config.MYSQL_PORT,
database: config.MYSQL_DATABASE,
user: config.MYSQL_USER,
password: config.MYSQL_PASSWORD
});
// 测试
connections.getConnection((err, conn) => {
// err为空即为成功
conn.connect((err) => {
if (err) {
console.log("数据库连接失败", err)
} else {
console.log("数据库连接成功")
}
})
});
// 通过promise操作数据库
module.exports = connections.promise();
(3)config.js
// 可加载根目录下的.env文件,将里面的直接加载到环境变量里面
const dotenv = require('dotenv');
const fs = require('fs');
const path = require('path');
dotenv.config();
module.exports = {
APP_HOST,
APP_PORT,
MYSQL_HOST,
MYSQL_PORT,
MYSQL_DATABASE,
MYSQL_USER,
MYSQL_PASSWORD,
} = process.env;
(4)error-handle.js
const errorType = require('../constants/error-types');
const errorHandler = (error, ctx) => {
let status, message;
switch (error.message) {
case errorType.NAME_OR_PASSWORD_IS_REQUIRED:
status = 400; // Bad Request
message = "用户名或者密码不能为空!";
break;
case errorType.USER_ALREADY_EXISTS:
status = 409; // Conflict 冲突
message = "用户名已存在!";
break;
case errorType.USER_DOES_NOT_EXISTS:
status = 400; // 参数错误
message = "用户名不存在!";
break;
case errorType.PASSWORD_IS_INCORRENT:
status = 400; // 参数错误
message = "密码错误!";
break;
case errorType.UNAUTHORIZATION:
status = 401; // 参数错误
message = "无效的token!";
break;
case errorType.UNPERMISSION:
status = 401; // 参数错误
message = "你不具备操作权限!";
break;
default:
status = 404;
message = "NOT FOUND";
}
ctx.status = status;
ctx.body = message;
}
module.exports = errorHandler;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# 5. .env文件中的内容
APP_HOST = http://localhost
APP_PORT = 9999
MYSQL_HOST = localhost
MYSQL_PORT = 3306
MYSQL_DATABASE = kylinKoa
MYSQL_USER = root
MYSQL_PASSWORD = root
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 6.读取文件的方法
// 读取文件的工具方法
const fs = require('fs')
module.exports.getFileJsonData = (filePath) => {
// 根据文件的路径, 读取文件的内容
return new Promise((resolve, reject) => {
fs.readFile(filePath, 'utf-8', (error, data) => {
if(error) {
// 读取文件失败
reject(error)
} else {
// 读取文件成功
resolve(data)
}
})
})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
上次更新: 2022/05/12 14:57:53