@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.
@@ -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() { return [{ id: 1, name: "Alice" }]; }
32
+ getUsers() {
33
+ return [{ id: 1, name: "Alice" }];
34
+ }
32
35
  }
33
36
 
37
+ // 控制器层
34
38
  @Controller
35
39
  class UserController {
36
- @Autowired private userService!: UserService;
37
- getUsers() { return this.userService.getUsers(); }
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
- async start() { console.log("应用启动成功!"); }
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, Body, Param } from "@fastcar/koa/annotation";
70
+ import { GET, POST, REQUEST } from "@fastcar/koa/annotation";
56
71
 
57
- @Controller @REQUEST("/api/users")
72
+ @Controller
73
+ @REQUEST("/api/users")
58
74
  class UserController {
59
- @GET async list() { return { data: [] }; }
60
- @GET("/:id") async getById(@Param("id") id: string) { return { id }; }
61
- @POST async create(@Body user: UserDTO) { return { created: true }; }
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 { Repository, Table, Field, PrimaryKey, SqlSession } from "@fastcar/mysql/annotation";
107
+ import { Table, Field, DBType, PrimaryKey, NotNull, Size } from "@fastcar/core/annotation";
69
108
 
70
109
  @Table("users")
71
110
  class User {
72
- @PrimaryKey @Field("id") id!: number;
73
- @Field("name") name!: string;
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 UserRepository {
78
- @SqlSession private session!: SqlSession;
79
- async findById(id: number) { return this.session.findById(User, id); }
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 private redis!: RedisClient;
91
- async get(key: string) { return this.redis.get(key); }
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
- @Scheduled(60000) async intervalTask() { console.log("每分钟执行"); }
106
- @Cron("0 0 * * * *") async hourlyTask() { console.log("每小时执行"); }
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 }) private pool!: WorkerPool;
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
- **Web 模板**
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 @EnableKoa
350
+ @Application
351
+ @EnableKoa
147
352
  @KoaMiddleware(ExceptionGlobalHandler)
148
353
  @KoaMiddleware(KoaBodyParser)
149
- class APP { app!: FastCarApplication; }
354
+ class APP {
355
+ app!: FastCarApplication;
356
+ }
150
357
  export default new APP();
151
358
  ```
152
359
 
153
- **Static 模板**
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 @EnableKoa
366
+ @Application
367
+ @EnableKoa
160
368
  @KoaMiddleware(ExceptionGlobalHandler)
161
369
  @KoaMiddleware(KoaStatic)
162
- class APP { app!: any; }
370
+ class APP {
371
+ app!: any;
372
+ }
163
373
  export default new APP();
164
374
  ```
165
375
 
166
- **RPC 模板**
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 @EnableRPC
381
+ @Application
382
+ @EnableRPC
172
383
  class APP {}
173
384
  export default new APP();
174
385
  ```
175
386
 
176
- **COS 模板**
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
- @Application @EnableKoa
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
- **Microservices 模板**
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/ # 服务目录(base/center/chat/connector/web)
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") port!: number;
285
- @Value("mysql.host") dbHost!: string;
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: { port: 443, host: "0.0.0.0", protocol: https, ssl: { key: "./ssl/server.key", cert: "./ssl/server.pem" } }
302
- koaStatic: { "public": "public" } # 静态资源映射
303
- koaBodyParser:
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`:服务器监听配置数组,支持 `http`/`https`/`http2`
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" # 协议:ws / http / grpc / mqtt
545
+ type: "ws" # 通信协议:ws / http / grpc / mqtt
323
546
  server: { port: 1235 }
547
+ extra: {}
324
548
  serviceType: "base" # 服务类型分类
325
- secure: { username: "user", password: "123456" }
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.rpc.list`:RPC 服务端点数组
329
- - `type`:通信协议;`serviceType`:服务分组;`secure`:安全认证
572
+ - `settings.hotterSysConfig`:设为 `true` 时,框架会监听配置变更并自动热更新。
330
573
 
331
574
  #### Microservices 模板配置
332
575
 
333
- 主配置声明环境,详细集群配置放在 `application-dev.yml`:
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: "xxx"
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
- retry: { retryCount: 3, retryInterval: 3000 }
350
-
351
- connector: # 连接器服务
352
- token: "xxx"
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
- web: { ... } # Web 服务(支持 http/ws 混合)
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`:服务间通信鉴权令牌;`clusters`:集群实例数(自动递增端口号)
367
- - `front: true`:标记为面向客户端的前置节点
368
- - `retry`:消息重试策略(retryCount/retryInterval/timeout/maxMsgNum/increase)
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
- @ApplicationStart async onStart() { console.log("应用启动"); }
378
- @ApplicationStop async onStop() { console.log("应用停止"); }
379
- @ApplicationInit async init() { console.log("初始化完成"); }
380
- }
381
- ```
382
-
383
- ## 表单验证
384
-
385
- ```typescript
386
- import { ValidForm, NotNull, Size, Rule } from "@fastcar/core/annotation";
387
-
388
- class UserDTO {
389
- @NotNull name!: string;
390
- @Size({ minSize: 1, maxSize: 150 }) age!: number;
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 && npm install && npm run debug
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 && npm install && npm run debug
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 && npm install && npm run debug
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 && npm install && npm run debug
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 && npm install
466
- npm run start-node # 单节点模式
467
- # 或 npm run start-pm2 # PM2 模式
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
- # 启用装饰器(tsconfig.json): experimentalDecorators, emitDecoratorMetadata
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
  ## 参考资源