@fastcar/cli 0.1.1 → 0.1.3
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 +21 -9
- package/package.json +2 -2
- package/skills/fastcar-database/SKILL.md +380 -147
- package/skills/fastcar-framework/SKILL.md +278 -186
- package/skills/fastcar-rpc-microservices/SKILL.md +19 -69
- package/skills/fastcar-serverless/SKILL.md +48 -48
- package/skills/fastcar-toolkit/SKILL.md +22 -31
- package/skills/typescript-coding-style/SKILL.md +144 -0
- package/src/pack.js +7 -7
- package/src/reverse.js +86 -12
- package/src/update.js +301 -0
- package/src/utils.js +2 -2
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: fastcar-framework
|
|
3
|
-
description: FastCar 是一个基于 TypeScript 的 Node.js 企业级应用开发框架,采用 IoC
|
|
3
|
+
description: FastCar 是一个基于 TypeScript 的 Node.js 企业级应用开发框架,采用 IoC(控制反转)设计思想。Use when working with FastCar framework for: (1) Creating IoC-based Node.js applications, (2) Using dependency injection with decorators (@Component, @Service, @Autowired), (3) Building web APIs with @fastcar/koa, (4) Database operations with MySQL/MongoDB/Redis, (5) Setting up scheduled tasks or worker pools, (6) Managing application lifecycle and configuration.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# FastCar Framework
|
|
7
7
|
|
|
8
|
-
FastCar 是基于 TypeScript 的 Node.js
|
|
8
|
+
FastCar 是基于 TypeScript 的 Node.js 企业级应用开发框架,采用 IoC(控制反转)设计思想。
|
|
9
9
|
|
|
10
10
|
## 核心概念
|
|
11
11
|
|
|
@@ -15,32 +15,41 @@ FastCar 是基于 TypeScript 的 Node.js 企业级应用开发框架,灵感来
|
|
|
15
15
|
|--------|------|------|
|
|
16
16
|
| `@Application` | 入口应用类 | `@Application class App {}` |
|
|
17
17
|
| `@Component` | 通用组件 | `@Component class UtilService {}` |
|
|
18
|
-
| `@Service` | 服务层 | `@Service class
|
|
19
|
-
| `@Controller` | 控制器层 | `@Controller class
|
|
20
|
-
| `@Repository` | 数据访问层 | `@Repository class
|
|
21
|
-
| `@Autowired` | 依赖注入 | `@Autowired private
|
|
18
|
+
| `@Service` | 服务层 | `@Service class BizService {}` |
|
|
19
|
+
| `@Controller` | 控制器层 | `@Controller class ApiController {}` |
|
|
20
|
+
| `@Repository` | 数据访问层 | `@Repository class DataRepository {}` |
|
|
21
|
+
| `@Autowired` | 依赖注入 | `@Autowired private service!: BizService;` |
|
|
22
22
|
|
|
23
23
|
### 基础应用结构
|
|
24
24
|
|
|
25
25
|
```typescript
|
|
26
26
|
import { FastCarApplication } from "@fastcar/core";
|
|
27
|
-
import { Application, Autowired, Component, Service } from "@fastcar/core/annotation";
|
|
27
|
+
import { Application, Autowired, Component, Service, Controller } from "@fastcar/core/annotation";
|
|
28
28
|
|
|
29
29
|
@Service
|
|
30
|
-
class
|
|
31
|
-
|
|
30
|
+
class BizService {
|
|
31
|
+
getData() {
|
|
32
|
+
return [{ id: 1, name: "示例" }];
|
|
33
|
+
}
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
@Controller
|
|
35
|
-
class
|
|
36
|
-
@Autowired
|
|
37
|
-
|
|
37
|
+
class ApiController {
|
|
38
|
+
@Autowired
|
|
39
|
+
private service!: BizService;
|
|
40
|
+
|
|
41
|
+
getData() {
|
|
42
|
+
return this.service.getData();
|
|
43
|
+
}
|
|
38
44
|
}
|
|
39
45
|
|
|
40
46
|
@Application
|
|
41
47
|
class App {
|
|
42
48
|
app!: FastCarApplication;
|
|
43
|
-
|
|
49
|
+
|
|
50
|
+
async start() {
|
|
51
|
+
console.log("应用启动成功!");
|
|
52
|
+
}
|
|
44
53
|
}
|
|
45
54
|
|
|
46
55
|
const app = new App();
|
|
@@ -51,44 +60,167 @@ app.start();
|
|
|
51
60
|
|
|
52
61
|
### Web 开发 (@fastcar/koa)
|
|
53
62
|
|
|
63
|
+
**路由装饰器使用方式:**
|
|
64
|
+
|
|
54
65
|
```typescript
|
|
55
|
-
import { GET, POST, REQUEST
|
|
66
|
+
import { GET, POST, REQUEST } from "@fastcar/koa/annotation";
|
|
56
67
|
|
|
57
|
-
@Controller
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
@
|
|
68
|
+
@Controller
|
|
69
|
+
@REQUEST("/api/items")
|
|
70
|
+
class ItemController {
|
|
71
|
+
// GET 请求 - 无路径参数时必须有括号
|
|
72
|
+
@GET()
|
|
73
|
+
async list() {
|
|
74
|
+
return { data: [] };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// GET 请求 - 有路径参数
|
|
78
|
+
@GET("/:id")
|
|
79
|
+
async getById(id: string) {
|
|
80
|
+
return { id };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// POST 请求
|
|
84
|
+
@POST()
|
|
85
|
+
async create(body: ItemDTO) {
|
|
86
|
+
return { created: true };
|
|
87
|
+
}
|
|
62
88
|
}
|
|
63
89
|
```
|
|
64
90
|
|
|
91
|
+
**⚠️ 重要:FastCar 没有 `@Body`, `@Param`, `@Query` 装饰器**
|
|
92
|
+
|
|
93
|
+
- 请求参数直接作为方法参数传入
|
|
94
|
+
- GET 请求参数通过方法参数直接获取
|
|
95
|
+
- POST 请求体通过 `body` 参数获取
|
|
96
|
+
- 路径参数通过方法参数直接获取
|
|
97
|
+
|
|
65
98
|
### 数据库 (@fastcar/mysql)
|
|
66
99
|
|
|
67
|
-
|
|
68
|
-
import { Repository, Table, Field, PrimaryKey, SqlSession } from "@fastcar/mysql/annotation";
|
|
100
|
+
**实体定义:**
|
|
69
101
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
102
|
+
```typescript
|
|
103
|
+
import { Table, Field, DBType, PrimaryKey, NotNull, Size } from "@fastcar/core/annotation";
|
|
104
|
+
|
|
105
|
+
@Table("entities")
|
|
106
|
+
class Entity {
|
|
107
|
+
@Field("id")
|
|
108
|
+
@DBType("int")
|
|
109
|
+
@PrimaryKey
|
|
110
|
+
id!: number;
|
|
111
|
+
|
|
112
|
+
@Field("name")
|
|
113
|
+
@DBType("varchar")
|
|
114
|
+
@NotNull
|
|
115
|
+
@Size({ maxSize: 50 })
|
|
116
|
+
name!: string;
|
|
74
117
|
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Mapper 定义:**
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
import { Entity, Repository } from "@fastcar/core/annotation";
|
|
124
|
+
import { MysqlMapper } from "@fastcar/mysql";
|
|
75
125
|
|
|
126
|
+
@Entity(Entity)
|
|
76
127
|
@Repository
|
|
77
|
-
class
|
|
78
|
-
|
|
79
|
-
|
|
128
|
+
class EntityMapper extends MysqlMapper<Entity> {}
|
|
129
|
+
export default EntityMapper;
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**Service 中使用:**
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
import { Service, Autowired } from "@fastcar/core/annotation";
|
|
136
|
+
import { OrderEnum } from "@fastcar/core/db";
|
|
137
|
+
import EntityMapper from "./EntityMapper";
|
|
138
|
+
|
|
139
|
+
@Service
|
|
140
|
+
class EntityService {
|
|
141
|
+
@Autowired
|
|
142
|
+
private mapper!: EntityMapper;
|
|
143
|
+
|
|
144
|
+
async getList() {
|
|
145
|
+
return this.mapper.select({
|
|
146
|
+
where: { status: 1 },
|
|
147
|
+
orders: { createTime: OrderEnum.desc },
|
|
148
|
+
limit: 10
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async getOne(id: number) {
|
|
153
|
+
return this.mapper.selectOne({ where: { id } });
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async create(data: Entity) {
|
|
157
|
+
return this.mapper.saveOne(data);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async update(id: number, data: Partial<Entity>) {
|
|
161
|
+
return this.mapper.update({ where: { id }, row: data });
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async delete(id: number) {
|
|
165
|
+
return this.mapper.delete({ where: { id } });
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### 表单验证 (@fastcar/core)
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
import { ValidForm, NotNull, Size, Rule } from "@fastcar/core/annotation";
|
|
174
|
+
|
|
175
|
+
class ItemDTO {
|
|
176
|
+
@NotNull
|
|
177
|
+
name!: string;
|
|
178
|
+
|
|
179
|
+
@Size({ minSize: 1, maxSize: 150 })
|
|
180
|
+
value!: number;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
@Controller
|
|
184
|
+
@REQUEST("/api/items")
|
|
185
|
+
class ItemController {
|
|
186
|
+
@GET()
|
|
187
|
+
async list(page: number = 1, pageSize: number = 10) {
|
|
188
|
+
return { page, pageSize, data: [] };
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
@ValidForm
|
|
192
|
+
@POST()
|
|
193
|
+
async create(@Rule() body: ItemDTO) {
|
|
194
|
+
const { name, value } = body;
|
|
195
|
+
return this.service.create({ name, value });
|
|
196
|
+
}
|
|
80
197
|
}
|
|
81
198
|
```
|
|
82
199
|
|
|
200
|
+
**表单验证规则:**
|
|
201
|
+
|
|
202
|
+
| 装饰器 | 用途 | 示例 |
|
|
203
|
+
|--------|------|------|
|
|
204
|
+
| `@ValidForm` | 开启方法参数校验 | 放在方法上 |
|
|
205
|
+
| `@Rule()` | 标记校验对象 | 放在 DTO 参数前 |
|
|
206
|
+
| `@NotNull` | 参数不能为空 | 放在 DTO 字段上 |
|
|
207
|
+
| `@Size({min, max})` | 大小限制 | 放在 DTO 字段上 |
|
|
208
|
+
|
|
83
209
|
### Redis (@fastcar/redis)
|
|
84
210
|
|
|
85
211
|
```typescript
|
|
212
|
+
import { Service, Autowired } from "@fastcar/core/annotation";
|
|
86
213
|
import { RedisClient } from "@fastcar/redis/annotation";
|
|
87
214
|
|
|
88
215
|
@Service
|
|
89
216
|
class CacheService {
|
|
90
|
-
@RedisClient
|
|
91
|
-
|
|
217
|
+
@RedisClient
|
|
218
|
+
private redis!: RedisClient;
|
|
219
|
+
|
|
220
|
+
async get(key: string) {
|
|
221
|
+
return this.redis.get(key);
|
|
222
|
+
}
|
|
223
|
+
|
|
92
224
|
async set(key: string, value: string, ttl?: number) {
|
|
93
225
|
await this.redis.set(key, value, ttl);
|
|
94
226
|
}
|
|
@@ -97,13 +229,24 @@ class CacheService {
|
|
|
97
229
|
|
|
98
230
|
### 定时任务 (@fastcar/timer)
|
|
99
231
|
|
|
232
|
+
> **推荐使用 `@fastcar/timer/scheduling2` 模块**
|
|
233
|
+
|
|
100
234
|
```typescript
|
|
101
|
-
import {
|
|
235
|
+
import { ScheduledInterval, ScheduledCron } from "@fastcar/timer/scheduling2";
|
|
102
236
|
|
|
103
237
|
@Component
|
|
104
238
|
class TaskService {
|
|
105
|
-
|
|
106
|
-
@
|
|
239
|
+
// 间隔执行(毫秒)
|
|
240
|
+
@ScheduledInterval({ fixedRate: 60000 })
|
|
241
|
+
async intervalTask() {
|
|
242
|
+
console.log("每分钟执行");
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Cron 表达式
|
|
246
|
+
@ScheduledCron("0 0 * * * *")
|
|
247
|
+
async hourlyTask() {
|
|
248
|
+
console.log("每小时执行");
|
|
249
|
+
}
|
|
107
250
|
}
|
|
108
251
|
```
|
|
109
252
|
|
|
@@ -114,7 +257,9 @@ import { WorkerPool, WorkerTask } from "@fastcar/workerpool/annotation";
|
|
|
114
257
|
|
|
115
258
|
@Component
|
|
116
259
|
class ComputeService {
|
|
117
|
-
@WorkerPool({ minWorkers: 2, maxWorkers: 4 })
|
|
260
|
+
@WorkerPool({ minWorkers: 2, maxWorkers: 4 })
|
|
261
|
+
private pool!: WorkerPool;
|
|
262
|
+
|
|
118
263
|
@WorkerTask
|
|
119
264
|
heavyComputation(data: number[]): number {
|
|
120
265
|
return data.reduce((a, b) => a + b, 0);
|
|
@@ -124,42 +269,31 @@ class ComputeService {
|
|
|
124
269
|
|
|
125
270
|
## 项目模板速查
|
|
126
271
|
|
|
127
|
-
|
|
272
|
+
FastCar CLI 提供 5 种项目模板:
|
|
128
273
|
|
|
129
274
|
| 模板 | 适用场景 | 核心依赖 | 关键注解 |
|
|
130
275
|
|------|---------|---------|---------|
|
|
131
276
|
| web | RESTful API 服务 | @fastcar/koa, @fastcar/server | @EnableKoa |
|
|
132
277
|
| static | 静态资源服务器 | @fastcar/koa, @fastcar/server | @EnableKoa + KoaStatic |
|
|
133
278
|
| rpc | RPC 微服务通信 | @fastcar/rpc, @fastcar/server | @EnableRPC |
|
|
134
|
-
| cos |
|
|
135
|
-
| microservices | 分布式多服务架构 | @fastcar/koa, @fastcar/rpc, @fastcar/server, @fastcar/timer | @EnableKoa / @EnableRPC
|
|
279
|
+
| cos | 对象存储/文件上传 | @fastcar/koa, @fastcar/cossdk, @fastcar/server | @EnableKoa |
|
|
280
|
+
| microservices | 分布式多服务架构 | @fastcar/koa, @fastcar/rpc, @fastcar/server, @fastcar/timer | @EnableKoa / @EnableRPC |
|
|
136
281
|
|
|
137
282
|
### 各模板入口示例
|
|
138
283
|
|
|
139
284
|
**Web 模板**
|
|
140
285
|
```typescript
|
|
141
|
-
import { FastCarApplication } from "@fastcar/core";
|
|
142
286
|
import { Application } from "@fastcar/core/annotation";
|
|
143
287
|
import { EnableKoa, KoaMiddleware } from "@fastcar/koa/annotation";
|
|
144
288
|
import { ExceptionGlobalHandler, KoaBodyParser } from "@fastcar/koa";
|
|
145
289
|
|
|
146
|
-
@Application
|
|
290
|
+
@Application
|
|
291
|
+
@EnableKoa
|
|
147
292
|
@KoaMiddleware(ExceptionGlobalHandler)
|
|
148
293
|
@KoaMiddleware(KoaBodyParser)
|
|
149
|
-
class APP {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
**Static 模板**
|
|
154
|
-
```typescript
|
|
155
|
-
import { Application } from "@fastcar/core/annotation";
|
|
156
|
-
import { EnableKoa, KoaMiddleware } from "@fastcar/koa/annotation";
|
|
157
|
-
import { ExceptionGlobalHandler, KoaStatic } from "@fastcar/koa";
|
|
158
|
-
|
|
159
|
-
@Application @EnableKoa
|
|
160
|
-
@KoaMiddleware(ExceptionGlobalHandler)
|
|
161
|
-
@KoaMiddleware(KoaStatic)
|
|
162
|
-
class APP { app!: any; }
|
|
294
|
+
class APP {
|
|
295
|
+
app!: FastCarApplication;
|
|
296
|
+
}
|
|
163
297
|
export default new APP();
|
|
164
298
|
```
|
|
165
299
|
|
|
@@ -168,68 +302,27 @@ export default new APP();
|
|
|
168
302
|
import { Application } from "@fastcar/core/annotation";
|
|
169
303
|
import { EnableRPC } from "@fastcar/rpc/annotation";
|
|
170
304
|
|
|
171
|
-
@Application
|
|
172
|
-
|
|
173
|
-
export default new APP();
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
**COS 模板**
|
|
177
|
-
```typescript
|
|
178
|
-
import { Application } from "@fastcar/core/annotation";
|
|
179
|
-
import { EnableKoa, KoaMiddleware } from "@fastcar/koa/annotation";
|
|
180
|
-
import { ExceptionGlobalHandler, KoaBody, KoaBodyParser, KoaCors } from "@fastcar/koa";
|
|
181
|
-
|
|
182
|
-
@Application @EnableKoa
|
|
183
|
-
@KoaMiddleware(ExceptionGlobalHandler, KoaBody, KoaBodyParser, KoaCors)
|
|
305
|
+
@Application
|
|
306
|
+
@EnableRPC
|
|
184
307
|
class APP {}
|
|
185
308
|
export default new APP();
|
|
186
309
|
```
|
|
187
310
|
|
|
188
311
|
**Microservices 模板**
|
|
189
|
-
|
|
190
|
-
- **center**:服务中心,提供服务注册与发现
|
|
191
|
-
- **connector**:连接器服务,处理客户端连接
|
|
192
|
-
- **chat**:聊天服务,处理实时消息
|
|
193
|
-
- **web**:Web 服务,提供 HTTP 接口
|
|
194
|
-
- **base**:基础服务,提供公共功能
|
|
195
|
-
|
|
196
|
-
各服务模块内部根据职责使用 `@EnableKoa` 或 `@EnableRPC`。
|
|
312
|
+
微服务模板包含多服务架构:center(服务中心)、connector(连接器)、message(消息服务)、web(Web服务)、base(基础服务)。
|
|
197
313
|
|
|
198
314
|
### 项目结构示例
|
|
199
315
|
|
|
200
|
-
**Web / Static / RPC / COS 模板**
|
|
201
316
|
```
|
|
202
317
|
template/
|
|
203
318
|
├── src/
|
|
204
319
|
│ ├── controller/ # 控制器(web/cos)
|
|
205
|
-
│ ├──
|
|
320
|
+
│ ├── dto/ # DTO 类(表单验证)
|
|
321
|
+
│ ├── service/ # 服务层
|
|
206
322
|
│ ├── model/ # 数据模型
|
|
207
323
|
│ └── app.ts # 应用入口
|
|
208
324
|
├── resource/
|
|
209
325
|
│ └── application.yml # 配置文件
|
|
210
|
-
├── target/ # 编译输出
|
|
211
|
-
├── package.json
|
|
212
|
-
├── tsconfig.json
|
|
213
|
-
└── ecosystem.config.yml
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
**Microservices 模板**
|
|
217
|
-
```
|
|
218
|
-
template/
|
|
219
|
-
├── src/
|
|
220
|
-
│ ├── annotation/ # 注解定义
|
|
221
|
-
│ ├── common/ # 公共代码
|
|
222
|
-
│ ├── middleware/ # 中间件
|
|
223
|
-
│ ├── servers/ # 服务目录(base/center/chat/connector/web)
|
|
224
|
-
│ ├── types/ # 类型定义
|
|
225
|
-
│ ├── utils/ # 工具函数
|
|
226
|
-
│ ├── app-node.ts # 单节点入口
|
|
227
|
-
│ └── app-pm2.ts # PM2 入口
|
|
228
|
-
├── resource/
|
|
229
|
-
│ ├── application.yml
|
|
230
|
-
│ ├── application-dev.yml
|
|
231
|
-
│ └── ecosystem.config.yml
|
|
232
|
-
├── test/
|
|
233
326
|
├── package.json
|
|
234
327
|
└── tsconfig.json
|
|
235
328
|
```
|
|
@@ -252,7 +345,7 @@ npm i @fastcar/core @fastcar/koa @fastcar/rpc @fastcar/server @fastcar/timer
|
|
|
252
345
|
|
|
253
346
|
## 配置管理
|
|
254
347
|
|
|
255
|
-
配置文件放在 `resource/application.yml
|
|
348
|
+
配置文件放在 `resource/application.yml`。支持按 `env` 加载多文件,例如 `application-dev.yml` 会与主配置合并。
|
|
256
349
|
|
|
257
350
|
### 基础配置示例
|
|
258
351
|
|
|
@@ -281,14 +374,15 @@ import { Configure, Value } from "@fastcar/core/annotation";
|
|
|
281
374
|
|
|
282
375
|
@Configure
|
|
283
376
|
class AppConfig {
|
|
284
|
-
@Value("server.port")
|
|
285
|
-
|
|
377
|
+
@Value("server.port")
|
|
378
|
+
port!: number;
|
|
379
|
+
|
|
380
|
+
@Value("mysql.host")
|
|
381
|
+
dbHost!: string;
|
|
286
382
|
}
|
|
287
383
|
```
|
|
288
384
|
|
|
289
|
-
###
|
|
290
|
-
|
|
291
|
-
#### Web / Static / COS 通用配置
|
|
385
|
+
### Web 模板 application.yml
|
|
292
386
|
|
|
293
387
|
```yaml
|
|
294
388
|
application:
|
|
@@ -298,18 +392,13 @@ settings:
|
|
|
298
392
|
koa:
|
|
299
393
|
server:
|
|
300
394
|
- { port: 8080, host: "0.0.0.0" }
|
|
301
|
-
|
|
302
|
-
|
|
395
|
+
koaStatic:
|
|
396
|
+
{ "public": "public" }
|
|
303
397
|
koaBodyParser:
|
|
304
398
|
enableTypes: ["json", "form", "text"]
|
|
305
|
-
extendTypes: { text: ["text/xml", "application/xml"] }
|
|
306
399
|
```
|
|
307
400
|
|
|
308
|
-
|
|
309
|
-
- `settings.koa.koaStatic`:静态资源访问映射,格式 `{ "别名": "路径" }`
|
|
310
|
-
- `settings.koa.koaBodyParser`:请求体解析配置
|
|
311
|
-
|
|
312
|
-
#### RPC 模板配置
|
|
401
|
+
### RPC 模板配置
|
|
313
402
|
|
|
314
403
|
```yaml
|
|
315
404
|
application:
|
|
@@ -319,54 +408,38 @@ settings:
|
|
|
319
408
|
rpc:
|
|
320
409
|
list:
|
|
321
410
|
- id: "server-1"
|
|
322
|
-
type: "ws"
|
|
411
|
+
type: "ws"
|
|
323
412
|
server: { port: 1235 }
|
|
324
|
-
serviceType: "base"
|
|
325
|
-
secure:
|
|
413
|
+
serviceType: "base"
|
|
414
|
+
secure:
|
|
415
|
+
username: "user"
|
|
416
|
+
password: "password"
|
|
326
417
|
```
|
|
327
418
|
|
|
328
|
-
|
|
329
|
-
- `type`:通信协议;`serviceType`:服务分组;`secure`:安全认证
|
|
330
|
-
|
|
331
|
-
#### Microservices 模板配置
|
|
332
|
-
|
|
333
|
-
主配置声明环境,详细集群配置放在 `application-dev.yml`:
|
|
419
|
+
### Microservices 模板配置
|
|
334
420
|
|
|
335
421
|
```yaml
|
|
336
422
|
settings:
|
|
337
|
-
hotterSysConfig: true # 监听配置变更
|
|
338
423
|
microservices:
|
|
339
|
-
center:
|
|
340
|
-
token: "
|
|
424
|
+
center:
|
|
425
|
+
token: "your-token-here"
|
|
341
426
|
servers:
|
|
342
427
|
- host: "localhost"
|
|
343
|
-
clusters: 1
|
|
428
|
+
clusters: 1
|
|
344
429
|
list:
|
|
345
430
|
- type: "ws"
|
|
346
431
|
server: { port: 60000 }
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
retry: { retryCount: 3, retryInterval: 3000 }
|
|
350
|
-
|
|
351
|
-
connector: # 连接器服务
|
|
352
|
-
token: "xxx"
|
|
432
|
+
connector:
|
|
433
|
+
token: "your-token-here"
|
|
353
434
|
servers:
|
|
354
435
|
- host: "localhost"
|
|
355
436
|
clusters: 1
|
|
356
437
|
list:
|
|
357
|
-
- front: true
|
|
438
|
+
- front: true
|
|
358
439
|
type: "ws"
|
|
359
440
|
server: { port: 60100 }
|
|
360
|
-
|
|
361
|
-
chat: { ... } # 聊天服务
|
|
362
|
-
web: { ... } # Web 服务(支持 http/ws 混合)
|
|
363
441
|
```
|
|
364
442
|
|
|
365
|
-
- `settings.microservices.<服务名>`:各微服务模块配置
|
|
366
|
-
- `token`:服务间通信鉴权令牌;`clusters`:集群实例数(自动递增端口号)
|
|
367
|
-
- `front: true`:标记为面向客户端的前置节点
|
|
368
|
-
- `retry`:消息重试策略(retryCount/retryInterval/timeout/maxMsgNum/increase)
|
|
369
|
-
|
|
370
443
|
## 生命周期钩子
|
|
371
444
|
|
|
372
445
|
```typescript
|
|
@@ -374,27 +447,19 @@ import { ApplicationStart, ApplicationStop, ApplicationInit } from "@fastcar/cor
|
|
|
374
447
|
|
|
375
448
|
@Component
|
|
376
449
|
class LifecycleService {
|
|
377
|
-
@ApplicationStart
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
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);
|
|
450
|
+
@ApplicationStart
|
|
451
|
+
async onStart() {
|
|
452
|
+
console.log("应用启动");
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
@ApplicationStop
|
|
456
|
+
async onStop() {
|
|
457
|
+
console.log("应用停止");
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
@ApplicationInit
|
|
461
|
+
async init() {
|
|
462
|
+
console.log("初始化完成");
|
|
398
463
|
}
|
|
399
464
|
}
|
|
400
465
|
```
|
|
@@ -446,39 +511,66 @@ TypeUtil.isClass(MyClass); // true
|
|
|
446
511
|
```bash
|
|
447
512
|
# Web 项目
|
|
448
513
|
mkdir my-web-app && cd my-web-app
|
|
449
|
-
fastcar-cli init web
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
mkdir my-static-app && cd my-static-app
|
|
453
|
-
fastcar-cli init static && npm install && npm run debug
|
|
514
|
+
fastcar-cli init web
|
|
515
|
+
npm install
|
|
516
|
+
npm run debug
|
|
454
517
|
|
|
455
518
|
# RPC 项目
|
|
456
519
|
mkdir my-rpc-app && cd my-rpc-app
|
|
457
|
-
fastcar-cli init rpc
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
mkdir my-cos-app && cd my-cos-app
|
|
461
|
-
fastcar-cli init cos && npm install && npm run debug
|
|
520
|
+
fastcar-cli init rpc
|
|
521
|
+
npm install
|
|
522
|
+
npm run debug
|
|
462
523
|
|
|
463
524
|
# Microservices 项目
|
|
464
525
|
mkdir my-ms-app && cd my-ms-app
|
|
465
|
-
fastcar-cli init microservices
|
|
466
|
-
npm
|
|
467
|
-
|
|
526
|
+
fastcar-cli init microservices
|
|
527
|
+
npm install
|
|
528
|
+
npm run start-node
|
|
468
529
|
```
|
|
469
530
|
|
|
470
|
-
|
|
531
|
+
## 常见错误与注意事项
|
|
471
532
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
# 启用装饰器(tsconfig.json): experimentalDecorators, emitDecoratorMetadata
|
|
533
|
+
### 1. 路由装饰器必须有括号
|
|
534
|
+
|
|
535
|
+
❌ **错误:**
|
|
536
|
+
```typescript
|
|
537
|
+
@GET
|
|
538
|
+
async list() { }
|
|
479
539
|
```
|
|
480
540
|
|
|
481
|
-
|
|
541
|
+
✅ **正确:**
|
|
542
|
+
```typescript
|
|
543
|
+
@GET()
|
|
544
|
+
async list() { }
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
### 2. 不要使用不存在的装饰器
|
|
548
|
+
|
|
549
|
+
❌ **错误:**
|
|
550
|
+
```typescript
|
|
551
|
+
import { Body, Param, Query } from "@fastcar/koa/annotation";
|
|
482
552
|
|
|
483
|
-
|
|
484
|
-
|
|
553
|
+
@GET("/:id")
|
|
554
|
+
async getById(@Param("id") id: string) { }
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
✅ **正确:**
|
|
558
|
+
```typescript
|
|
559
|
+
@GET("/:id")
|
|
560
|
+
async getById(id: string) { }
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
### 3. 表单验证使用 @ValidForm + @Rule
|
|
564
|
+
|
|
565
|
+
❌ **错误:**
|
|
566
|
+
```typescript
|
|
567
|
+
@POST()
|
|
568
|
+
async create(@Body body: ItemDTO) { }
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
✅ **正确:**
|
|
572
|
+
```typescript
|
|
573
|
+
@ValidForm
|
|
574
|
+
@POST()
|
|
575
|
+
async create(@Rule() body: ItemDTO) { }
|
|
576
|
+
```
|