@fastcar/cli 0.1.1 → 0.1.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/bin/cli.js +12 -9
- package/package.json +2 -2
- package/skills/fastcar-database/SKILL.md +360 -50
- package/skills/fastcar-framework/SKILL.md +465 -93
- package/src/reverse.js +86 -12
|
@@ -26,23 +26,36 @@ FastCar 是基于 TypeScript 的 Node.js 企业级应用开发框架,灵感来
|
|
|
26
26
|
import { FastCarApplication } from "@fastcar/core";
|
|
27
27
|
import { Application, Autowired, Component, Service } from "@fastcar/core/annotation";
|
|
28
28
|
|
|
29
|
+
// 服务层
|
|
29
30
|
@Service
|
|
30
31
|
class UserService {
|
|
31
|
-
getUsers() {
|
|
32
|
+
getUsers() {
|
|
33
|
+
return [{ id: 1, name: "Alice" }];
|
|
34
|
+
}
|
|
32
35
|
}
|
|
33
36
|
|
|
37
|
+
// 控制器层
|
|
34
38
|
@Controller
|
|
35
39
|
class UserController {
|
|
36
|
-
@Autowired
|
|
37
|
-
|
|
40
|
+
@Autowired
|
|
41
|
+
private userService!: UserService;
|
|
42
|
+
|
|
43
|
+
getUsers() {
|
|
44
|
+
return this.userService.getUsers();
|
|
45
|
+
}
|
|
38
46
|
}
|
|
39
47
|
|
|
48
|
+
// 应用入口
|
|
40
49
|
@Application
|
|
41
50
|
class App {
|
|
42
51
|
app!: FastCarApplication;
|
|
43
|
-
|
|
52
|
+
|
|
53
|
+
async start() {
|
|
54
|
+
console.log("应用启动成功!");
|
|
55
|
+
}
|
|
44
56
|
}
|
|
45
57
|
|
|
58
|
+
// 启动
|
|
46
59
|
const app = new App();
|
|
47
60
|
app.start();
|
|
48
61
|
```
|
|
@@ -51,44 +64,221 @@ app.start();
|
|
|
51
64
|
|
|
52
65
|
### Web 开发 (@fastcar/koa)
|
|
53
66
|
|
|
67
|
+
**正确的路由装饰器使用方式:**
|
|
68
|
+
|
|
54
69
|
```typescript
|
|
55
|
-
import { GET, POST, REQUEST
|
|
70
|
+
import { GET, POST, REQUEST } from "@fastcar/koa/annotation";
|
|
56
71
|
|
|
57
|
-
@Controller
|
|
72
|
+
@Controller
|
|
73
|
+
@REQUEST("/api/users")
|
|
58
74
|
class UserController {
|
|
59
|
-
|
|
60
|
-
@GET(
|
|
61
|
-
|
|
75
|
+
// GET 请求 - 无路径参数时必须有括号
|
|
76
|
+
@GET()
|
|
77
|
+
async list() {
|
|
78
|
+
return { data: [] };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// GET 请求 - 有路径参数
|
|
82
|
+
@GET("/:id")
|
|
83
|
+
async getById(id: string) {
|
|
84
|
+
return { id };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// POST 请求
|
|
88
|
+
@POST()
|
|
89
|
+
async create(body: UserDTO) {
|
|
90
|
+
return { created: true };
|
|
91
|
+
}
|
|
62
92
|
}
|
|
63
93
|
```
|
|
64
94
|
|
|
95
|
+
**⚠️ 重要:FastCar 没有 `@Body`, `@Param`, `@Query` 装饰器**
|
|
96
|
+
|
|
97
|
+
- 请求参数直接作为方法参数传入
|
|
98
|
+
- GET 请求参数通过方法参数直接获取
|
|
99
|
+
- POST 请求体通过 `body` 参数获取
|
|
100
|
+
- 路径参数通过方法参数直接获取
|
|
101
|
+
|
|
65
102
|
### 数据库 (@fastcar/mysql)
|
|
66
103
|
|
|
104
|
+
**实体定义:**
|
|
105
|
+
|
|
67
106
|
```typescript
|
|
68
|
-
import {
|
|
107
|
+
import { Table, Field, DBType, PrimaryKey, NotNull, Size } from "@fastcar/core/annotation";
|
|
69
108
|
|
|
70
109
|
@Table("users")
|
|
71
110
|
class User {
|
|
72
|
-
@
|
|
73
|
-
@
|
|
111
|
+
@Field("id")
|
|
112
|
+
@DBType("int")
|
|
113
|
+
@PrimaryKey
|
|
114
|
+
id!: number;
|
|
115
|
+
|
|
116
|
+
@Field("name")
|
|
117
|
+
@DBType("varchar")
|
|
118
|
+
@NotNull
|
|
119
|
+
@Size({ maxSize: 50 })
|
|
120
|
+
name!: string;
|
|
74
121
|
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Mapper 定义:**
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
import { Entity, Repository } from "@fastcar/core/annotation";
|
|
128
|
+
import { MysqlMapper } from "@fastcar/mysql";
|
|
75
129
|
|
|
130
|
+
@Entity(User)
|
|
76
131
|
@Repository
|
|
77
|
-
class
|
|
78
|
-
|
|
79
|
-
|
|
132
|
+
class UserMapper extends MysqlMapper<User> {}
|
|
133
|
+
|
|
134
|
+
export default UserMapper;
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Service 中使用:**
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
import { Service, Autowired } from "@fastcar/core/annotation";
|
|
141
|
+
import { OrderEnum } from "@fastcar/core/db";
|
|
142
|
+
import UserMapper from "./UserMapper";
|
|
143
|
+
|
|
144
|
+
@Service
|
|
145
|
+
class UserService {
|
|
146
|
+
@Autowired
|
|
147
|
+
private userMapper!: UserMapper;
|
|
148
|
+
|
|
149
|
+
// 查询列表
|
|
150
|
+
async getUsers() {
|
|
151
|
+
return this.userMapper.select({
|
|
152
|
+
where: { status: 1 },
|
|
153
|
+
orders: { createTime: OrderEnum.desc },
|
|
154
|
+
limit: 10
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// 查询单个
|
|
159
|
+
async getUser(id: number) {
|
|
160
|
+
return this.userMapper.selectOne({ where: { id } });
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// 根据主键查询
|
|
164
|
+
async getUserById(id: number) {
|
|
165
|
+
return this.userMapper.selectByPrimaryKey({ id } as User);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// 插入
|
|
169
|
+
async createUser(user: User) {
|
|
170
|
+
return this.userMapper.saveOne(user);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// 更新
|
|
174
|
+
async updateUser(id: number, data: Partial<User>) {
|
|
175
|
+
return this.userMapper.update({ where: { id }, row: data });
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// 根据主键更新
|
|
179
|
+
async updateById(user: User) {
|
|
180
|
+
return this.userMapper.updateByPrimaryKey(user);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// 删除
|
|
184
|
+
async deleteUser(id: number) {
|
|
185
|
+
return this.userMapper.delete({ where: { id } });
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// 统计
|
|
189
|
+
async count() {
|
|
190
|
+
return this.userMapper.count({});
|
|
191
|
+
}
|
|
80
192
|
}
|
|
81
193
|
```
|
|
82
194
|
|
|
195
|
+
### 表单验证 (@fastcar/core)
|
|
196
|
+
|
|
197
|
+
**正确的表单验证方式:**
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
import { ValidForm, NotNull, Size, Rule } from "@fastcar/core/annotation";
|
|
201
|
+
|
|
202
|
+
// DTO 类定义在单独的文件中,如 dto/UserDTO.ts
|
|
203
|
+
class UserDTO {
|
|
204
|
+
@NotNull
|
|
205
|
+
name!: string;
|
|
206
|
+
|
|
207
|
+
@Size({ minSize: 1, maxSize: 150 })
|
|
208
|
+
age!: number;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
@Controller
|
|
212
|
+
@REQUEST("/api/users")
|
|
213
|
+
class UserController {
|
|
214
|
+
|
|
215
|
+
// GET 请求 - 无需表单验证
|
|
216
|
+
@GET()
|
|
217
|
+
async list(page: number = 1, pageSize: number = 10) {
|
|
218
|
+
return { page, pageSize, data: [] };
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// POST 请求 - 使用 @ValidForm + @Rule 进行表单验证
|
|
222
|
+
@ValidForm
|
|
223
|
+
@POST()
|
|
224
|
+
async create(@Rule() body: UserDTO) {
|
|
225
|
+
// 参数会自动校验,如果校验失败会抛出异常
|
|
226
|
+
const { name, age } = body;
|
|
227
|
+
return this.userService.create({ name, age });
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**表单验证规则:**
|
|
233
|
+
|
|
234
|
+
| 装饰器 | 用途 | 示例 |
|
|
235
|
+
|--------|------|------|
|
|
236
|
+
| `@ValidForm` | 开启方法参数校验 | 放在方法上 |
|
|
237
|
+
| `@Rule()` | 标记校验对象 | 放在 DTO 参数前 |
|
|
238
|
+
| `@NotNull` | 参数不能为空 | 放在 DTO 字段上 |
|
|
239
|
+
| `@Size({min, max})` | 大小限制 | 放在 DTO 字段上 |
|
|
240
|
+
|
|
241
|
+
**⚠️ 常见错误:**
|
|
242
|
+
|
|
243
|
+
❌ **错误** - 使用不存在的装饰器:
|
|
244
|
+
```typescript
|
|
245
|
+
// 这些装饰器在 FastCar 中不存在!
|
|
246
|
+
import { Body, Param, Query } from "@fastcar/koa/annotation"; // ❌ 错误
|
|
247
|
+
|
|
248
|
+
@GET("/:id")
|
|
249
|
+
async getById(@Param("id") id: string) { ... } // ❌ 错误
|
|
250
|
+
|
|
251
|
+
@POST()
|
|
252
|
+
async create(@Body body: UserDTO) { ... } // ❌ 错误
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
✅ **正确** - 直接使用方法参数:
|
|
256
|
+
```typescript
|
|
257
|
+
@GET("/:id")
|
|
258
|
+
async getById(id: string) { ... } // ✅ 正确
|
|
259
|
+
|
|
260
|
+
@POST()
|
|
261
|
+
async create(body: UserDTO) { ... } // ✅ 正确
|
|
262
|
+
|
|
263
|
+
@GET()
|
|
264
|
+
async list(page: number = 1) { ... } // ✅ 正确
|
|
265
|
+
```
|
|
266
|
+
|
|
83
267
|
### Redis (@fastcar/redis)
|
|
84
268
|
|
|
85
269
|
```typescript
|
|
270
|
+
import { Service, Autowired } from "@fastcar/core/annotation";
|
|
86
271
|
import { RedisClient } from "@fastcar/redis/annotation";
|
|
87
272
|
|
|
88
273
|
@Service
|
|
89
274
|
class CacheService {
|
|
90
|
-
@RedisClient
|
|
91
|
-
|
|
275
|
+
@RedisClient
|
|
276
|
+
private redis!: RedisClient;
|
|
277
|
+
|
|
278
|
+
async get(key: string) {
|
|
279
|
+
return this.redis.get(key);
|
|
280
|
+
}
|
|
281
|
+
|
|
92
282
|
async set(key: string, value: string, ttl?: number) {
|
|
93
283
|
await this.redis.set(key, value, ttl);
|
|
94
284
|
}
|
|
@@ -102,8 +292,17 @@ import { Scheduled, Cron } from "@fastcar/timer/annotation";
|
|
|
102
292
|
|
|
103
293
|
@Component
|
|
104
294
|
class TaskService {
|
|
105
|
-
|
|
106
|
-
@
|
|
295
|
+
// 间隔执行(毫秒)
|
|
296
|
+
@Scheduled(60000)
|
|
297
|
+
async intervalTask() {
|
|
298
|
+
console.log("每分钟执行");
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Cron 表达式
|
|
302
|
+
@Cron("0 0 * * * *")
|
|
303
|
+
async hourlyTask() {
|
|
304
|
+
console.log("每小时执行");
|
|
305
|
+
}
|
|
107
306
|
}
|
|
108
307
|
```
|
|
109
308
|
|
|
@@ -114,9 +313,12 @@ import { WorkerPool, WorkerTask } from "@fastcar/workerpool/annotation";
|
|
|
114
313
|
|
|
115
314
|
@Component
|
|
116
315
|
class ComputeService {
|
|
117
|
-
@WorkerPool({ minWorkers: 2, maxWorkers: 4 })
|
|
316
|
+
@WorkerPool({ minWorkers: 2, maxWorkers: 4 })
|
|
317
|
+
private pool!: WorkerPool;
|
|
318
|
+
|
|
118
319
|
@WorkerTask
|
|
119
320
|
heavyComputation(data: number[]): number {
|
|
321
|
+
// 在 worker 线程中执行
|
|
120
322
|
return data.reduce((a, b) => a + b, 0);
|
|
121
323
|
}
|
|
122
324
|
}
|
|
@@ -124,6 +326,8 @@ class ComputeService {
|
|
|
124
326
|
|
|
125
327
|
## 项目模板速查
|
|
126
328
|
|
|
329
|
+
FastCar CLI 提供 5 种项目模板,分别适用于不同的业务场景。
|
|
330
|
+
|
|
127
331
|
### 模板选择指南
|
|
128
332
|
|
|
129
333
|
| 模板 | 适用场景 | 核心依赖 | 关键注解 |
|
|
@@ -136,56 +340,64 @@ class ComputeService {
|
|
|
136
340
|
|
|
137
341
|
### 各模板入口示例
|
|
138
342
|
|
|
139
|
-
|
|
343
|
+
#### Web 模板
|
|
140
344
|
```typescript
|
|
141
345
|
import { FastCarApplication } from "@fastcar/core";
|
|
142
346
|
import { Application } from "@fastcar/core/annotation";
|
|
143
347
|
import { EnableKoa, KoaMiddleware } from "@fastcar/koa/annotation";
|
|
144
348
|
import { ExceptionGlobalHandler, KoaBodyParser } from "@fastcar/koa";
|
|
145
349
|
|
|
146
|
-
@Application
|
|
350
|
+
@Application
|
|
351
|
+
@EnableKoa
|
|
147
352
|
@KoaMiddleware(ExceptionGlobalHandler)
|
|
148
353
|
@KoaMiddleware(KoaBodyParser)
|
|
149
|
-
class APP {
|
|
354
|
+
class APP {
|
|
355
|
+
app!: FastCarApplication;
|
|
356
|
+
}
|
|
150
357
|
export default new APP();
|
|
151
358
|
```
|
|
152
359
|
|
|
153
|
-
|
|
360
|
+
#### Static 模板
|
|
154
361
|
```typescript
|
|
155
362
|
import { Application } from "@fastcar/core/annotation";
|
|
156
363
|
import { EnableKoa, KoaMiddleware } from "@fastcar/koa/annotation";
|
|
157
364
|
import { ExceptionGlobalHandler, KoaStatic } from "@fastcar/koa";
|
|
158
365
|
|
|
159
|
-
@Application
|
|
366
|
+
@Application
|
|
367
|
+
@EnableKoa
|
|
160
368
|
@KoaMiddleware(ExceptionGlobalHandler)
|
|
161
369
|
@KoaMiddleware(KoaStatic)
|
|
162
|
-
class APP {
|
|
370
|
+
class APP {
|
|
371
|
+
app!: any;
|
|
372
|
+
}
|
|
163
373
|
export default new APP();
|
|
164
374
|
```
|
|
165
375
|
|
|
166
|
-
|
|
376
|
+
#### RPC 模板
|
|
167
377
|
```typescript
|
|
168
378
|
import { Application } from "@fastcar/core/annotation";
|
|
169
379
|
import { EnableRPC } from "@fastcar/rpc/annotation";
|
|
170
380
|
|
|
171
|
-
@Application
|
|
381
|
+
@Application
|
|
382
|
+
@EnableRPC
|
|
172
383
|
class APP {}
|
|
173
384
|
export default new APP();
|
|
174
385
|
```
|
|
175
386
|
|
|
176
|
-
|
|
387
|
+
#### COS 模板
|
|
177
388
|
```typescript
|
|
178
389
|
import { Application } from "@fastcar/core/annotation";
|
|
179
390
|
import { EnableKoa, KoaMiddleware } from "@fastcar/koa/annotation";
|
|
180
391
|
import { ExceptionGlobalHandler, KoaBody, KoaBodyParser, KoaCors } from "@fastcar/koa";
|
|
181
392
|
|
|
182
|
-
@
|
|
393
|
+
@EnableKoa
|
|
394
|
+
@Application
|
|
183
395
|
@KoaMiddleware(ExceptionGlobalHandler, KoaBody, KoaBodyParser, KoaCors)
|
|
184
396
|
class APP {}
|
|
185
397
|
export default new APP();
|
|
186
398
|
```
|
|
187
399
|
|
|
188
|
-
|
|
400
|
+
#### Microservices 模板
|
|
189
401
|
微服务模板采用多服务架构,包含 `app-node.ts`(子进程启动多服务)和 `app-pm2.ts`(PM2 启动入口)。服务模块分为:
|
|
190
402
|
- **center**:服务中心,提供服务注册与发现
|
|
191
403
|
- **connector**:连接器服务,处理客户端连接
|
|
@@ -202,6 +414,7 @@ export default new APP();
|
|
|
202
414
|
template/
|
|
203
415
|
├── src/
|
|
204
416
|
│ ├── controller/ # 控制器(web/cos)
|
|
417
|
+
│ ├── dto/ # DTO 类(表单验证)
|
|
205
418
|
│ ├── middleware/ # 中间件(web/cos)
|
|
206
419
|
│ ├── model/ # 数据模型
|
|
207
420
|
│ └── app.ts # 应用入口
|
|
@@ -220,10 +433,15 @@ template/
|
|
|
220
433
|
│ ├── annotation/ # 注解定义
|
|
221
434
|
│ ├── common/ # 公共代码
|
|
222
435
|
│ ├── middleware/ # 中间件
|
|
223
|
-
│ ├── servers/ #
|
|
436
|
+
│ ├── servers/ # 服务目录
|
|
437
|
+
│ │ ├── base/ # 基础服务
|
|
438
|
+
│ │ ├── center/ # 服务中心
|
|
439
|
+
│ │ ├── chat/ # 聊天服务
|
|
440
|
+
│ │ ├── connector/ # 连接器服务
|
|
441
|
+
│ │ └── web/ # Web 服务
|
|
224
442
|
│ ├── types/ # 类型定义
|
|
225
443
|
│ ├── utils/ # 工具函数
|
|
226
|
-
│ ├── app-node.ts #
|
|
444
|
+
│ ├── app-node.ts # 单节点入口(子进程启动)
|
|
227
445
|
│ └── app-pm2.ts # PM2 入口
|
|
228
446
|
├── resource/
|
|
229
447
|
│ ├── application.yml
|
|
@@ -281,14 +499,17 @@ import { Configure, Value } from "@fastcar/core/annotation";
|
|
|
281
499
|
|
|
282
500
|
@Configure
|
|
283
501
|
class AppConfig {
|
|
284
|
-
@Value("server.port")
|
|
285
|
-
|
|
502
|
+
@Value("server.port")
|
|
503
|
+
port!: number;
|
|
504
|
+
|
|
505
|
+
@Value("mysql.host")
|
|
506
|
+
dbHost!: string;
|
|
286
507
|
}
|
|
287
508
|
```
|
|
288
509
|
|
|
289
|
-
### 各模板 application.yml
|
|
510
|
+
### 各模板 application.yml 详解
|
|
290
511
|
|
|
291
|
-
#### Web / Static / COS
|
|
512
|
+
#### Web / Static / COS 通用 Koa 配置
|
|
292
513
|
|
|
293
514
|
```yaml
|
|
294
515
|
application:
|
|
@@ -298,16 +519,18 @@ settings:
|
|
|
298
519
|
koa:
|
|
299
520
|
server:
|
|
300
521
|
- { port: 8080, host: "0.0.0.0" }
|
|
301
|
-
# HTTPS
|
|
302
|
-
|
|
303
|
-
|
|
522
|
+
# HTTPS 示例:
|
|
523
|
+
# - { port: 443, host: "0.0.0.0", protocol: https, ssl: { key: "./ssl/server.key", cert: "./ssl/server.pem" } }
|
|
524
|
+
koaStatic: # 静态资源映射
|
|
525
|
+
{ "public": "public" } # 别名: 路径(相对 resource 目录或绝对路径)
|
|
526
|
+
koaBodyParser: # 请求体解析
|
|
304
527
|
enableTypes: ["json", "form", "text"]
|
|
305
528
|
extendTypes: { text: ["text/xml", "application/xml"] }
|
|
306
529
|
```
|
|
307
530
|
|
|
308
|
-
- `settings.koa.server
|
|
309
|
-
- `settings.koa.koaStatic
|
|
310
|
-
- `settings.koa.koaBodyParser
|
|
531
|
+
- `settings.koa.server`:服务器监听配置数组。支持 `http`(默认)、`http2`、`https`;启用 HTTPS 时需额外指定 `protocol: https` 和 `ssl.key / ssl.cert`。
|
|
532
|
+
- `settings.koa.koaStatic`:静态资源访问映射,格式为 `{ "别名": "路径" }`。
|
|
533
|
+
- `settings.koa.koaBodyParser`:Koa Body 解析器配置,`enableTypes` 控制允许的请求体类型,`extendTypes` 可扩展 XML 等特殊类型。
|
|
311
534
|
|
|
312
535
|
#### RPC 模板配置
|
|
313
536
|
|
|
@@ -319,53 +542,122 @@ settings:
|
|
|
319
542
|
rpc:
|
|
320
543
|
list:
|
|
321
544
|
- id: "server-1"
|
|
322
|
-
type: "ws" #
|
|
545
|
+
type: "ws" # 通信协议:ws / http / grpc / mqtt
|
|
323
546
|
server: { port: 1235 }
|
|
547
|
+
extra: {}
|
|
324
548
|
serviceType: "base" # 服务类型分类
|
|
325
|
-
secure:
|
|
549
|
+
secure:
|
|
550
|
+
username: "user"
|
|
551
|
+
password: "123456"
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
- `settings.rpc.list`:RPC 服务端点数组。
|
|
555
|
+
- `id`:节点唯一标识。
|
|
556
|
+
- `type`:通信协议,常见取值 `ws`、`http`、`grpc`、`mqtt`。
|
|
557
|
+
- `server`:监听配置,通常只写 `{ port }`。
|
|
558
|
+
- `extra`:协议扩展参数。
|
|
559
|
+
- `serviceType`:服务类型,用于服务分组或路由。
|
|
560
|
+
- `secure`:安全认证信息,包含 `username` 和 `password`。
|
|
561
|
+
|
|
562
|
+
#### COS 模板特有配置
|
|
563
|
+
|
|
564
|
+
```yaml
|
|
565
|
+
application:
|
|
566
|
+
env: "prod"
|
|
567
|
+
|
|
568
|
+
settings:
|
|
569
|
+
hotterSysConfig: true # 启用系统配置热更新监听
|
|
326
570
|
```
|
|
327
571
|
|
|
328
|
-
- `settings.
|
|
329
|
-
- `type`:通信协议;`serviceType`:服务分组;`secure`:安全认证
|
|
572
|
+
- `settings.hotterSysConfig`:设为 `true` 时,框架会监听配置变更并自动热更新。
|
|
330
573
|
|
|
331
574
|
#### Microservices 模板配置
|
|
332
575
|
|
|
333
|
-
|
|
576
|
+
主配置通常只声明环境:
|
|
577
|
+
|
|
578
|
+
```yaml
|
|
579
|
+
application:
|
|
580
|
+
env: "dev"
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
详细集群配置放在 `application-dev.yml`:
|
|
334
584
|
|
|
335
585
|
```yaml
|
|
336
586
|
settings:
|
|
337
|
-
hotterSysConfig: true
|
|
587
|
+
hotterSysConfig: true # 监听系统配置变更
|
|
588
|
+
|
|
338
589
|
microservices:
|
|
339
|
-
center:
|
|
340
|
-
token: "
|
|
590
|
+
center: # 服务中心
|
|
591
|
+
token: "nW0tT4bZ6qM7mF7wD2rT2pR9dT7gK3hZ"
|
|
341
592
|
servers:
|
|
342
593
|
- host: "localhost"
|
|
343
|
-
clusters: 1
|
|
594
|
+
clusters: 1 # 实例数,serviceId 和端口号自动递增
|
|
344
595
|
list:
|
|
345
596
|
- type: "ws"
|
|
346
597
|
server: { port: 60000 }
|
|
347
|
-
timeout: 0
|
|
598
|
+
timeout: 0 # 0 表示永不超时
|
|
348
599
|
connectionLimit: 1
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
600
|
+
disconnectInterval: 1000 # 断线重连间隔(毫秒)
|
|
601
|
+
retry:
|
|
602
|
+
retryCount: 3
|
|
603
|
+
retryInterval: 3000
|
|
604
|
+
timeout: 30000
|
|
605
|
+
maxMsgNum: 10000
|
|
606
|
+
increase: true
|
|
607
|
+
|
|
608
|
+
connector: # 连接器服务
|
|
609
|
+
token: "x3TGsWC9uloZu235LA07eAiJ61nQ1A5f"
|
|
353
610
|
servers:
|
|
354
611
|
- host: "localhost"
|
|
355
612
|
clusters: 1
|
|
356
613
|
list:
|
|
357
|
-
- front: true
|
|
614
|
+
- front: true # 标记为面向客户端的前置节点
|
|
358
615
|
type: "ws"
|
|
359
616
|
server: { port: 60100 }
|
|
360
617
|
|
|
361
|
-
chat:
|
|
362
|
-
|
|
618
|
+
chat: # 聊天服务
|
|
619
|
+
token: "go0kbkNM3wQ4e2Vgo0kbkNM3wQ4e2V"
|
|
620
|
+
servers:
|
|
621
|
+
- host: "localhost"
|
|
622
|
+
clusters: 1
|
|
623
|
+
list:
|
|
624
|
+
- type: "ws"
|
|
625
|
+
server: { port: 60200 }
|
|
626
|
+
|
|
627
|
+
web: # Web 服务
|
|
628
|
+
token: "go0kbkNM3wQ4e2Vgo0kbkNM3wQ4e2V"
|
|
629
|
+
koa:
|
|
630
|
+
koaBodyParser:
|
|
631
|
+
enableTypes: ["json", "form", "text"]
|
|
632
|
+
extendTypes: { text: ["text/xml", "application/xml"] }
|
|
633
|
+
servers:
|
|
634
|
+
- host: "localhost"
|
|
635
|
+
clusters: 1
|
|
636
|
+
list:
|
|
637
|
+
- type: "http"
|
|
638
|
+
server: { port: 8080 }
|
|
639
|
+
- type: "ws"
|
|
640
|
+
server: { port: 60300 }
|
|
363
641
|
```
|
|
364
642
|
|
|
365
|
-
- `settings.microservices
|
|
366
|
-
- `token
|
|
367
|
-
- `
|
|
368
|
-
- `
|
|
643
|
+
- `settings.microservices.<服务名>`:定义各微服务模块的集群配置。
|
|
644
|
+
- `token`:服务间通信鉴权令牌,防止非法节点接入。
|
|
645
|
+
- `servers`:服务器集群列表。
|
|
646
|
+
- `host`:主机地址。
|
|
647
|
+
- `clusters`:集群实例数量。若大于 1,框架会自动递增 `serviceId` 和端口号生成多个实例。
|
|
648
|
+
- `list`:该集群对外暴露的协议端点列表。
|
|
649
|
+
- `type`:协议类型,如 `ws`、`http`。
|
|
650
|
+
- `server`:端口配置 `{ port }`。
|
|
651
|
+
- `front: true`:仅 connector 等前置服务需要,表示该节点直接面向客户端。
|
|
652
|
+
- `timeout`:连接超时时间(毫秒),`0` 表示永不超时。
|
|
653
|
+
- `connectionLimit`:最大连接数限制。
|
|
654
|
+
- `disconnectInterval`:断线后重连间隔(毫秒)。
|
|
655
|
+
- `retry`:消息重试策略。
|
|
656
|
+
- `retryCount`:最大重试次数。
|
|
657
|
+
- `retryInterval`:重试间隔。
|
|
658
|
+
- `timeout`:重试总超时。
|
|
659
|
+
- `maxMsgNum`:消息队列最大长度。
|
|
660
|
+
- `increase`:是否递增重试间隔。
|
|
369
661
|
|
|
370
662
|
## 生命周期钩子
|
|
371
663
|
|
|
@@ -374,27 +666,22 @@ import { ApplicationStart, ApplicationStop, ApplicationInit } from "@fastcar/cor
|
|
|
374
666
|
|
|
375
667
|
@Component
|
|
376
668
|
class LifecycleService {
|
|
377
|
-
|
|
378
|
-
@
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
@
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
@Controller
|
|
394
|
-
class UserController {
|
|
395
|
-
@ValidForm
|
|
396
|
-
createUser(@Rule() @NotNull user: UserDTO) {
|
|
397
|
-
return this.userService.create(user);
|
|
669
|
+
// 应用启动时执行
|
|
670
|
+
@ApplicationStart
|
|
671
|
+
async onStart() {
|
|
672
|
+
console.log("应用启动");
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
// 应用停止前执行
|
|
676
|
+
@ApplicationStop
|
|
677
|
+
async onStop() {
|
|
678
|
+
console.log("应用停止");
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// 初始化(配合 @ApplicationRunner)
|
|
682
|
+
@ApplicationInit
|
|
683
|
+
async init() {
|
|
684
|
+
console.log("初始化完成");
|
|
398
685
|
}
|
|
399
686
|
}
|
|
400
687
|
```
|
|
@@ -446,36 +733,121 @@ TypeUtil.isClass(MyClass); // true
|
|
|
446
733
|
```bash
|
|
447
734
|
# Web 项目
|
|
448
735
|
mkdir my-web-app && cd my-web-app
|
|
449
|
-
fastcar-cli init web
|
|
736
|
+
fastcar-cli init web
|
|
737
|
+
npm install
|
|
738
|
+
npm run debug
|
|
450
739
|
|
|
451
740
|
# Static 项目
|
|
452
741
|
mkdir my-static-app && cd my-static-app
|
|
453
|
-
fastcar-cli init static
|
|
742
|
+
fastcar-cli init static
|
|
743
|
+
npm install
|
|
744
|
+
npm run debug
|
|
454
745
|
|
|
455
746
|
# RPC 项目
|
|
456
747
|
mkdir my-rpc-app && cd my-rpc-app
|
|
457
|
-
fastcar-cli init rpc
|
|
748
|
+
fastcar-cli init rpc
|
|
749
|
+
npm install
|
|
750
|
+
npm run debug
|
|
458
751
|
|
|
459
752
|
# COS 项目
|
|
460
753
|
mkdir my-cos-app && cd my-cos-app
|
|
461
|
-
fastcar-cli init cos
|
|
754
|
+
fastcar-cli init cos
|
|
755
|
+
npm install
|
|
756
|
+
npm run debug
|
|
462
757
|
|
|
463
758
|
# Microservices 项目
|
|
464
759
|
mkdir my-ms-app && cd my-ms-app
|
|
465
|
-
fastcar-cli init microservices
|
|
466
|
-
npm
|
|
467
|
-
|
|
760
|
+
fastcar-cli init microservices
|
|
761
|
+
npm install
|
|
762
|
+
npm run start-node # 单节点模式(子进程启动全部服务)
|
|
763
|
+
# 或
|
|
764
|
+
npm run start-pm2 # PM2 模式
|
|
468
765
|
```
|
|
469
766
|
|
|
470
767
|
### 手动创建项目
|
|
471
768
|
|
|
472
769
|
```bash
|
|
770
|
+
# 1. 创建项目
|
|
473
771
|
mkdir my-fastcar-app && cd my-fastcar-app
|
|
474
772
|
npm init -y
|
|
773
|
+
|
|
774
|
+
# 2. 安装依赖
|
|
475
775
|
npm i @fastcar/core @fastcar/koa @fastcar/server
|
|
476
776
|
npm i -D typescript ts-node @types/node
|
|
777
|
+
|
|
778
|
+
# 3. 初始化 TypeScript
|
|
477
779
|
npx tsc --init
|
|
478
|
-
|
|
780
|
+
|
|
781
|
+
# 4. 启用装饰器(tsconfig.json)
|
|
782
|
+
# "experimentalDecorators": true
|
|
783
|
+
# "emitDecoratorMetadata": true
|
|
784
|
+
|
|
785
|
+
# 5. 创建入口文件和配置文件,开始开发
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
## 常见错误与注意事项
|
|
789
|
+
|
|
790
|
+
### 1. 路由装饰器必须有括号
|
|
791
|
+
|
|
792
|
+
❌ **错误:**
|
|
793
|
+
```typescript
|
|
794
|
+
@GET
|
|
795
|
+
async list() { }
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
✅ **正确:**
|
|
799
|
+
```typescript
|
|
800
|
+
@GET()
|
|
801
|
+
async list() { }
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
### 2. 不要使用不存在的装饰器
|
|
805
|
+
|
|
806
|
+
❌ **错误:**
|
|
807
|
+
```typescript
|
|
808
|
+
import { Body, Param, Query } from "@fastcar/koa/annotation";
|
|
809
|
+
|
|
810
|
+
@GET("/:id")
|
|
811
|
+
async getById(@Param("id") id: string) { }
|
|
812
|
+
|
|
813
|
+
@POST()
|
|
814
|
+
async create(@Body body: UserDTO) { }
|
|
815
|
+
```
|
|
816
|
+
|
|
817
|
+
✅ **正确:**
|
|
818
|
+
```typescript
|
|
819
|
+
@GET("/:id")
|
|
820
|
+
async getById(id: string) { }
|
|
821
|
+
|
|
822
|
+
@POST()
|
|
823
|
+
async create(body: UserDTO) { }
|
|
824
|
+
```
|
|
825
|
+
|
|
826
|
+
### 3. 表单验证使用 @ValidForm + @Rule
|
|
827
|
+
|
|
828
|
+
❌ **错误:**
|
|
829
|
+
```typescript
|
|
830
|
+
@POST()
|
|
831
|
+
async create(@Body body: UserDTO) { }
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
✅ **正确:**
|
|
835
|
+
```typescript
|
|
836
|
+
@ValidForm
|
|
837
|
+
@POST()
|
|
838
|
+
async create(@Rule() body: UserDTO) { }
|
|
839
|
+
```
|
|
840
|
+
|
|
841
|
+
### 4. DTO 类放在单独文件夹
|
|
842
|
+
|
|
843
|
+
推荐项目结构:
|
|
844
|
+
```
|
|
845
|
+
src/
|
|
846
|
+
├── controller/ # 控制器
|
|
847
|
+
├── dto/ # DTO 类(表单验证)
|
|
848
|
+
├── service/ # 服务层
|
|
849
|
+
├── model/ # 数据模型
|
|
850
|
+
└── app.ts
|
|
479
851
|
```
|
|
480
852
|
|
|
481
853
|
## 参考资源
|