chanjs 2.7.7 → 2.7.10
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/README.md +261 -363
- package/config/index.js +4 -2
- package/core/App.js +35 -0
- package/core/Container.js +56 -29
- package/core/Database.js +58 -8
- package/core/EventBus.js +88 -0
- package/core/Lang.js +56 -0
- package/core/Repository.js +34 -2
- package/core/Task.js +87 -0
- package/core/errors.js +0 -5
- package/doc/00-README.md +208 -0
- package/doc/01-/346/240/270/345/277/203/347/261/273Controller-Service-Repository.md +432 -0
- package/doc/02-/345/223/215/345/272/224/344/270/216/351/224/231/350/257/257.md +255 -0
- package/doc/03-/345/256/211/345/205/250/346/250/241/345/235/227.md +264 -0
- package/doc/04-/345/255/230/345/202/250/344/270/216/347/274/223/345/255/230.md +157 -0
- package/doc/05-/345/267/245/345/205/267/344/270/216/346/240/241/351/252/214.md +309 -0
- package/doc/06-/345/272/224/347/224/250/347/224/237/345/221/275/345/221/250/346/234/237.md +207 -0
- package/doc/07-/344/272/213/344/273/266/347/263/273/347/273/237EventBus.md +324 -0
- package/doc/08-/345/256/232/346/227/266/344/273/273/345/212/241Task.md +262 -0
- package/doc/09-/345/233/275/351/231/205/345/214/226Lang.md +220 -0
- package/index.js +31 -2
- package/middleware/log.js +48 -31
- package/middleware/waf.js +4 -8
- package/package.json +21 -3
- package/response/code.js +0 -12
- package/response/response.js +8 -2
- package/security/keywords.js +2 -3
- package/utils/logger.js +60 -91
- package/utils/signal.js +21 -2
- package/USAGE.md +0 -533
- package/doc/Cache.md +0 -333
- package/doc/Common.md +0 -638
- package/doc/Controller.md +0 -223
- package/doc/Help.md +0 -390
- package/doc/QuickStart.md +0 -116
- package/doc/Repository.md +0 -560
- package/doc/Service.md +0 -240
- package/publish.bat +0 -4
- package/todo.md +0 -1
package/doc/Service.md
DELETED
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
# Service 服务基类
|
|
2
|
-
|
|
3
|
-
## 概述
|
|
4
|
-
|
|
5
|
-
`Service` 是纯业务逻辑层基类,继承自 `Container` 容器类。**不包含任何数据库 CRUD 方法**,仅作为业务逻辑的载体。
|
|
6
|
-
|
|
7
|
-
业务子类可注入多个 `Repository` 实例,进行跨表事务编排。
|
|
8
|
-
|
|
9
|
-
## 继承关系
|
|
10
|
-
|
|
11
|
-
```
|
|
12
|
-
Container <── Service
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## 构造函数
|
|
16
|
-
|
|
17
|
-
```javascript
|
|
18
|
-
constructor()
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
调用父类 `Container` 构造函数,指定组件类型为 `'service'`。
|
|
22
|
-
|
|
23
|
-
## 设计原则
|
|
24
|
-
|
|
25
|
-
1. **无表绑定**:Service 不直接操作数据库表
|
|
26
|
-
2. **无 CRUD 方法**:所有数据操作委托给 Repository
|
|
27
|
-
3. **业务编排**:负责组合多个 Repository 完成复杂业务逻辑
|
|
28
|
-
4. **事务管理**:可跨 Repository 进行事务编排
|
|
29
|
-
|
|
30
|
-
## 使用示例
|
|
31
|
-
|
|
32
|
-
### 基础示例
|
|
33
|
-
|
|
34
|
-
```javascript
|
|
35
|
-
import { Service } from 'chanjs';
|
|
36
|
-
import UserRepo from '../repository/UserRepo.js';
|
|
37
|
-
import OrderRepo from '../repository/OrderRepo.js';
|
|
38
|
-
|
|
39
|
-
export default class UserService extends Service {
|
|
40
|
-
constructor() {
|
|
41
|
-
super();
|
|
42
|
-
this.userRepo = new UserRepo();
|
|
43
|
-
this.orderRepo = new OrderRepo();
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// 查询用户及其订单
|
|
47
|
-
async getUserWithOrders(userId) {
|
|
48
|
-
const user = await this.userRepo.findById(userId);
|
|
49
|
-
if (!user.success) {
|
|
50
|
-
return user;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const orders = await this.orderRepo.all({
|
|
54
|
-
query: { userId }
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
return this.success({
|
|
58
|
-
data: {
|
|
59
|
-
user: user.data,
|
|
60
|
-
orders: orders.data
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### 跨表事务示例
|
|
68
|
-
|
|
69
|
-
```javascript
|
|
70
|
-
import { Service } from 'chanjs';
|
|
71
|
-
import UserRepo from '../repository/UserRepo.js';
|
|
72
|
-
import WalletRepo from '../repository/WalletRepo.js';
|
|
73
|
-
|
|
74
|
-
export default class PaymentService extends Service {
|
|
75
|
-
constructor() {
|
|
76
|
-
super();
|
|
77
|
-
this.userRepo = new UserRepo();
|
|
78
|
-
this.walletRepo = new WalletRepo();
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// 用户充值(跨表事务)
|
|
82
|
-
async recharge(userId, amount) {
|
|
83
|
-
const trx = await this.db.transaction();
|
|
84
|
-
|
|
85
|
-
try {
|
|
86
|
-
// 更新用户余额
|
|
87
|
-
await this.userRepo.updateById(userId, {
|
|
88
|
-
balance: this.db.raw(`balance + ${amount}`)
|
|
89
|
-
}, trx);
|
|
90
|
-
|
|
91
|
-
// 记录充值流水
|
|
92
|
-
await this.walletRepo.insert({
|
|
93
|
-
userId,
|
|
94
|
-
amount,
|
|
95
|
-
type: 'recharge',
|
|
96
|
-
createdAt: new Date()
|
|
97
|
-
}, trx);
|
|
98
|
-
|
|
99
|
-
await trx.commit();
|
|
100
|
-
return this.success({ msg: '充值成功' });
|
|
101
|
-
} catch (err) {
|
|
102
|
-
await trx.rollback();
|
|
103
|
-
return this.fail({
|
|
104
|
-
msg: '充值失败',
|
|
105
|
-
code: 500
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### 复杂业务逻辑示例
|
|
113
|
-
|
|
114
|
-
```javascript
|
|
115
|
-
import { Service } from 'chanjs';
|
|
116
|
-
import UserRepo from '../repository/UserRepo.js';
|
|
117
|
-
import OrderRepo from '../repository/OrderRepo.js';
|
|
118
|
-
import ProductRepo from '../repository/ProductRepo.js';
|
|
119
|
-
|
|
120
|
-
export default class OrderService extends Service {
|
|
121
|
-
constructor() {
|
|
122
|
-
super();
|
|
123
|
-
this.userRepo = new UserRepo();
|
|
124
|
-
this.orderRepo = new OrderRepo();
|
|
125
|
-
this.productRepo = new ProductRepo();
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// 创建订单
|
|
129
|
-
async createOrder(userId, products) {
|
|
130
|
-
// 1. 校验用户
|
|
131
|
-
const user = await this.userRepo.findById(userId);
|
|
132
|
-
if (!user.success) {
|
|
133
|
-
return this.fail({ msg: '用户不存在' });
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// 2. 校验商品库存
|
|
137
|
-
for (const item of products) {
|
|
138
|
-
const product = await this.productRepo.findById(item.productId);
|
|
139
|
-
if (!product.success || product.data.stock < item.quantity) {
|
|
140
|
-
return this.fail({
|
|
141
|
-
msg: `商品 ${product.data.name} 库存不足`
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// 3. 计算订单金额
|
|
147
|
-
const totalAmount = await this.calculateTotal(products);
|
|
148
|
-
|
|
149
|
-
// 4. 创建订单
|
|
150
|
-
const order = await this.orderRepo.insert({
|
|
151
|
-
userId,
|
|
152
|
-
totalAmount,
|
|
153
|
-
status: 'pending',
|
|
154
|
-
createdAt: new Date()
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
// 5. 扣减库存
|
|
158
|
-
await this.deductStock(products);
|
|
159
|
-
|
|
160
|
-
return this.success({
|
|
161
|
-
data: { orderId: order.data.insertId },
|
|
162
|
-
msg: '订单创建成功'
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// 计算订单总额
|
|
167
|
-
async calculateTotal(products) {
|
|
168
|
-
let total = 0;
|
|
169
|
-
for (const item of products) {
|
|
170
|
-
const product = await this.productRepo.findById(item.productId);
|
|
171
|
-
total += product.data.price * item.quantity;
|
|
172
|
-
}
|
|
173
|
-
return total;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// 扣减库存
|
|
177
|
-
async deductStock(products) {
|
|
178
|
-
for (const item of products) {
|
|
179
|
-
await this.productRepo.updateById(item.productId, {
|
|
180
|
-
stock: this.db.raw(`stock - ${item.quantity}`)
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
## 访问全局资源
|
|
188
|
-
|
|
189
|
-
Service 继承自 Container,可访问以下全局资源:
|
|
190
|
-
|
|
191
|
-
| 属性 | 说明 |
|
|
192
|
-
|------|------|
|
|
193
|
-
| `this.app` | 全局应用实例 |
|
|
194
|
-
| `this.config` | 全局配置对象 |
|
|
195
|
-
| `this.db` | 默认数据库连接 |
|
|
196
|
-
| `this.paths` | 路径工具对象 |
|
|
197
|
-
|
|
198
|
-
### 示例
|
|
199
|
-
|
|
200
|
-
```javascript
|
|
201
|
-
export default class ConfigService extends Service {
|
|
202
|
-
async getAppName() {
|
|
203
|
-
// 访问全局配置
|
|
204
|
-
const appName = this.config.APP_NAME;
|
|
205
|
-
return this.success({ data: appName });
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
async getDbVersion() {
|
|
209
|
-
// 访问数据库连接
|
|
210
|
-
const [result] = await this.db.raw('SELECT VERSION() as version');
|
|
211
|
-
return this.success({ data: result[0].version });
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
## 动态加载组件
|
|
217
|
-
|
|
218
|
-
Service 可使用 `get` 方法动态加载其他 Service 或 Repository:
|
|
219
|
-
|
|
220
|
-
```javascript
|
|
221
|
-
export default class OrderService extends Service {
|
|
222
|
-
async processOrder(orderId) {
|
|
223
|
-
// 动态加载 UserService
|
|
224
|
-
const userService = await this.get('user', 'UserService');
|
|
225
|
-
|
|
226
|
-
// 调用 UserService 方法
|
|
227
|
-
const user = await userService.getUserById(1);
|
|
228
|
-
|
|
229
|
-
// 业务逻辑...
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
## 注意事项
|
|
235
|
-
|
|
236
|
-
1. Service 不包含 CRUD 方法,数据操作请使用 Repository
|
|
237
|
-
2. 建议在 Service 中注入所需的 Repository 实例
|
|
238
|
-
3. 跨表事务需在 Service 层统一管理
|
|
239
|
-
4. Service 文件应放在 `app/modules/{moduleName}/service/` 目录下
|
|
240
|
-
5. 导出时使用 `export default` 导出实例或类
|
package/publish.bat
DELETED
package/todo.md
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
Express + HMVC + DI + AOP + Knex (多库) + Redis + 微服务
|