create-dp-koa 1.0.1 → 1.1.0

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.
Files changed (74) hide show
  1. package/package.json +1 -1
  2. package/template/.cursor/commands/cheatsheet-backend-controller.md +2 -2
  3. package/template/.cursor/commands/implement-backend-api-controller.md +6 -4
  4. package/template/.cursor/rules/11-backend-controller-recipes.skill.md +89 -10
  5. package/template/.trae/skills/11-backend-controller-recipes.skill.md +91 -10
  6. package/template/docs/FRAMEWORK_V2_UPGRADE_GUIDE.md +134 -0
  7. package/template/package.json +2 -0
  8. package/template/scripts/sync-template.mjs +39 -1
  9. package/template/src/app.ts +21 -16
  10. package/template/src/controllers/demo/AnnotationDemoController.ts +1 -3
  11. package/template/src/controllers/example/EnterpriseExampleController.ts +2 -9
  12. package/template/src/controllers/example/ExampleController.ts +13 -4
  13. package/template/src/entity/index.ts +1 -15
  14. package/template/src/framework/decorator/processor/AnnotationProcessor.ts +5 -1
  15. package/template/src/routers/index.ts +1 -37
  16. package/template/src/utils/testDataInitializer.ts +2 -269
  17. package/template/test/controllers/example/ExampleController.test.ts +29 -31
  18. package/template/test/framework/annotation/AnnotationDecorators.test.ts +15 -15
  19. package/template/test/framework/annotation/AnnotationExecutor.test.ts +27 -32
  20. package/template/test/framework/annotation/AnnotationProcessor.test.ts +25 -24
  21. package/template/test/framework/annotation/CustomProcessors.test.ts +15 -25
  22. package/template/test/framework/annotation/NewRouter.test.ts +9 -7
  23. package/template/test/framework/annotation/ProcessorManager.test.ts +14 -27
  24. package/template/test/framework/databaseConfig.test.ts +2 -2
  25. package/template/test/integration/integration.test.ts +15 -72
  26. package/template/webpack.config.js +2 -0
  27. package/template/package-lock.json +0 -13240
  28. package/template/src/controllers/cacheManagement.controller.ts +0 -131
  29. package/template/src/controllers/captcha.controller.ts +0 -57
  30. package/template/src/controllers/example/NewAnnotationExampleController.ts +0 -159
  31. package/template/src/controllers/example/SwaggerExampleController.ts +0 -205
  32. package/template/src/controllers/example/TransactionExample.controller.ts +0 -336
  33. package/template/src/controllers/health.controller.ts +0 -235
  34. package/template/src/controllers/home/register.controller.ts +0 -58
  35. package/template/src/controllers/home/ytGoods.controller.ts +0 -92
  36. package/template/src/controllers/home/ytShop.controller.ts +0 -135
  37. package/template/src/controllers/home/ytUser.controller.ts +0 -89
  38. package/template/src/controllers/logManagement.controller.ts +0 -396
  39. package/template/src/controllers/public/emailSend.controller.ts +0 -65
  40. package/template/src/controllers/public/ytUserAuth.controller.ts +0 -174
  41. package/template/src/controllers/testData.controller.ts +0 -253
  42. package/template/src/dto/controller/example/NewAnnotationExampleController.dto.ts +0 -73
  43. package/template/src/dto/controller/home/emailSend.controller.dto.ts +0 -40
  44. package/template/src/dto/controller/home/register.controller.dto.ts +0 -45
  45. package/template/src/dto/controller/home/ytGoods.controller.dto.ts +0 -55
  46. package/template/src/dto/controller/home/ytShop.controller.dto.ts +0 -69
  47. package/template/src/dto/controller/home/ytUser.controller.dto.ts +0 -44
  48. package/template/src/dto/controller/public/ytUserAuth.controller.dto.ts +0 -63
  49. package/template/src/dto/goods.dto.ts +0 -212
  50. package/template/src/dto/service/ytService.dto.ts +0 -13
  51. package/template/src/dto/user.dto.ts +0 -177
  52. package/template/src/entity/columnTypes.ts +0 -13
  53. package/template/src/entity/goodsImagesUnlockKey.entity.ts +0 -33
  54. package/template/src/entity/goodsUnlocker.entity.ts +0 -34
  55. package/template/src/entity/shop.entity.ts +0 -52
  56. package/template/src/entity/shopUser.entity.ts +0 -41
  57. package/template/src/entity/ytGoods.entity.ts +0 -94
  58. package/template/src/entity/ytUser.entity.ts +0 -96
  59. package/template/src/examples/SwaggerProcessorExample.ts +0 -169
  60. package/template/src/examples/TransactionManagerDemo.ts +0 -377
  61. package/template/src/framework/utils/dynamicSwagger.ts +0 -410
  62. package/template/src/repository/UserRepository.ts +0 -122
  63. package/template/src/service/paramValidateTest.service.ts +0 -139
  64. package/template/src/service/ytGoods.service.ts +0 -42
  65. package/template/src/service/ytShop.service.ts +0 -90
  66. package/template/src/service/ytUser.service.ts +0 -451
  67. package/template/src/test/swaggerParameterTest.ts +0 -90
  68. package/template/test/controllers/controllers.test.ts +0 -173
  69. package/template/test/controllers/example/NewAnnotationExampleController.test.ts +0 -200
  70. package/template/test/framework/TransactionManagerDemo.test.ts +0 -363
  71. package/template/test/service/business.test.ts +0 -87
  72. package/template/test/service/paramValidateTest.service.test.ts +0 -184
  73. package/template/test/service/ytUser.service.test.ts +0 -566
  74. package/template/yarn.lock +0 -7354
@@ -1,410 +0,0 @@
1
- import { Provider } from "dp-ioc2";
2
- import { SwaggerExampleController } from "@src/controllers/example/SwaggerExampleController";
3
- import { logger } from "@src/framework/utils/logger";
4
- import { swaggerProcessor } from "@src/annotations/processors/SwaggerProcessor";
5
- import * as fs from 'fs';
6
- import * as path from 'path';
7
-
8
- /**
9
- * 动态检测 bindRouter 路径前缀
10
- * 通过分析路由注册信息来确定实际的前缀路径
11
- */
12
- function getBindRouterPrefix(): string {
13
- // 方法1: 从环境变量读取(推荐用于生产环境)
14
- if (process.env.SWAGGER_ROUTE_PREFIX) {
15
- const prefix = process.env.SWAGGER_ROUTE_PREFIX;
16
- logger.info(`使用环境变量中的 Swagger 路径前缀: ${prefix}`);
17
- return prefix.startsWith('/') ? prefix : `/${prefix}`;
18
- }
19
-
20
- // 方法2: 从路由文件中动态检测(开发环境和调试模式)
21
- try {
22
- const detectedPrefix = detectPrefixFromRouterFile();
23
- if (detectedPrefix) {
24
- logger.info(`从路由文件检测到 Swagger 路径前缀: ${detectedPrefix}`);
25
- return detectedPrefix;
26
- }
27
-
28
- // 方法3: 使用默认值
29
- const defaultPrefix = '/swagger/b';
30
- logger.info(`使用默认 Swagger 路径前缀: ${defaultPrefix}`);
31
- return defaultPrefix;
32
- } catch (error) {
33
- logger.warn('无法动态检测路由前缀,使用默认值');
34
- return '/swagger/b';
35
- }
36
- }
37
-
38
- /**
39
- * 从路由文件中检测 SwaggerExampleController 的路径前缀
40
- */
41
- function detectPrefixFromRouterFile(): string | null {
42
- try {
43
- // 获取路由文件路径
44
- const routerFilePath = path.join(process.cwd(), 'src/routers/index.ts');
45
-
46
- if (!fs.existsSync(routerFilePath)) {
47
- logger.warn('路由文件不存在');
48
- return null;
49
- }
50
-
51
- // 读取路由文件内容
52
- const content = fs.readFileSync(routerFilePath, 'utf8');
53
-
54
- // 查找 SwaggerExampleController 的 bindRouter 调用
55
- const regex = /bindRouter\s*\(\s*["']([^"']+)["']\s*,\s*SwaggerExampleController\s*\)/;
56
- const match = content.match(regex);
57
-
58
- if (match && match[1]) {
59
- const detectedPrefix = match[1];
60
- logger.info(`从路由文件检测到前缀: ${detectedPrefix}`);
61
- return detectedPrefix;
62
- } else {
63
- logger.warn('未找到 SwaggerExampleController 的 bindRouter 调用');
64
- return null;
65
- }
66
- } catch (error) {
67
- logger.error('检测路由文件失败:', error as Error);
68
- return null;
69
- }
70
- }
71
-
72
- /**
73
- * 动态生成 Swagger 规范
74
- * 使用新的Swagger处理器来生成更完整的API文档
75
- */
76
- export function generateDynamicSwaggerSpec() {
77
- try {
78
- logger.info('开始使用Swagger处理器生成API规范...');
79
-
80
- // 获取 SwaggerExampleController 实例
81
- const controller = Provider<any>(SwaggerExampleController);
82
-
83
- // 使用Swagger处理器生成OpenAPI规范
84
- const openAPISpec = swaggerProcessor.generateOpenAPISpec([controller]);
85
-
86
- // 动态检测 bindRouter 路径前缀
87
- const bindRouterPrefix = getBindRouterPrefix();
88
-
89
- // 更新服务器URL
90
- openAPISpec.servers = [
91
- {
92
- url: 'http://localhost:3000',
93
- description: '开发环境',
94
- },
95
- ];
96
-
97
- // 收集所有路由信息并更新路径
98
- const routes: Array<{method: string, path: string, methodName: string}> = [];
99
-
100
- // 收集 GET 方法
101
- if (controller.$_GetMethods) {
102
- const getMethods = Array.from(controller.$_GetMethods) as Array<{methodName: string, url: string}>;
103
- getMethods.forEach(({ methodName, url }) => {
104
- routes.push({ method: 'get', path: `${bindRouterPrefix}${url}`, methodName });
105
- });
106
- }
107
-
108
- // 收集 POST 方法
109
- if (controller.$_PostMethods) {
110
- const postMethods = Array.from(controller.$_PostMethods) as Array<{methodName: string, url: string}>;
111
- postMethods.forEach(({ methodName, url }) => {
112
- routes.push({ method: 'post', path: `${bindRouterPrefix}${url}`, methodName });
113
- });
114
- }
115
-
116
- // 收集 PUT 方法
117
- if (controller.$_PutMethods) {
118
- const putMethods = Array.from(controller.$_PutMethods) as Array<{methodName: string, url: string}>;
119
- putMethods.forEach(({ methodName, url }) => {
120
- routes.push({ method: 'put', path: `${bindRouterPrefix}${url}`, methodName });
121
- });
122
- }
123
-
124
- // 收集 DELETE 方法
125
- if (controller.$_DelMethods) {
126
- const delMethods = Array.from(controller.$_DelMethods) as Array<{methodName: string, url: string}>;
127
- delMethods.forEach(({ methodName, url }) => {
128
- routes.push({ method: 'delete', path: `${bindRouterPrefix}${url}`, methodName });
129
- });
130
- }
131
-
132
- // 更新OpenAPI规范中的路径
133
- routes.forEach(({ method, path, methodName }) => {
134
- const swaggerPath = path.replace(/:(\w+)/g, '{$1}');
135
-
136
- if (!openAPISpec.paths[swaggerPath]) {
137
- openAPISpec.paths[swaggerPath] = {};
138
- }
139
-
140
- // 获取方法的Swagger元数据
141
- const methodMetadata = swaggerProcessor.processMethod(controller, methodName);
142
-
143
- openAPISpec.paths[swaggerPath][method] = {
144
- operationId: methodMetadata.operationId,
145
- summary: methodMetadata.summary,
146
- description: methodMetadata.description,
147
- tags: methodMetadata.tags,
148
- parameters: methodMetadata.parameters,
149
- responses: methodMetadata.responses.reduce((acc, response) => {
150
- acc[response.status.toString()] = {
151
- description: response.description,
152
- content: response.content
153
- };
154
- return acc;
155
- }, {} as Record<string, any>)
156
- };
157
-
158
- // 添加请求体
159
- if (methodMetadata.requestBody) {
160
- openAPISpec.paths[swaggerPath][method].requestBody = methodMetadata.requestBody;
161
- }
162
- });
163
-
164
- logger.info(`使用Swagger处理器生成API规范成功,包含 ${routes.length} 个路由`);
165
- return openAPISpec;
166
-
167
- } catch (error) {
168
- logger.error('使用Swagger处理器生成API规范失败:', error as Error);
169
- return getFallbackSwaggerSpec();
170
- }
171
- }
172
-
173
- /**
174
- * 获取方法的 Swagger 元数据
175
- */
176
- function getMethodSwaggerMetadata(controller: any, methodName: string) {
177
- try {
178
- // 尝试从控制器的元数据中获取 Swagger 注解信息
179
- const metadata = Reflect.getMetadata('swagger:metadata', controller, methodName);
180
-
181
- if (metadata) {
182
- logger.info(`找到方法 ${methodName} 的 Swagger 元数据`);
183
- return metadata;
184
- }
185
-
186
- // 如果没有找到元数据,返回默认值
187
- return getDefaultMethodMetadata(methodName);
188
- } catch (error) {
189
- logger.warn(`获取方法 ${methodName} 的 Swagger 元数据失败:`, error as Error);
190
- return getDefaultMethodMetadata(methodName);
191
- }
192
- }
193
-
194
- /**
195
- * 获取默认的方法元数据
196
- */
197
- function getDefaultMethodMetadata(methodName: string) {
198
- const baseMetadata = {
199
- responses: {
200
- '200': {
201
- description: '成功',
202
- content: {
203
- 'application/json': {
204
- schema: {
205
- type: 'object',
206
- properties: {
207
- code: { type: 'number', example: 0 },
208
- data: { type: 'object' },
209
- message: { type: 'string', example: '操作成功' }
210
- }
211
- }
212
- }
213
- }
214
- }
215
- }
216
- };
217
-
218
- // 根据方法名添加特定的参数
219
- if (methodName.includes('List') || methodName.includes('list')) {
220
- return {
221
- ...baseMetadata,
222
- parameters: [
223
- {
224
- name: 'page',
225
- in: 'query',
226
- schema: { type: 'number', default: 1 },
227
- description: '页码'
228
- },
229
- {
230
- name: 'pageSize',
231
- in: 'query',
232
- schema: { type: 'number', default: 10 },
233
- description: '每页数量'
234
- },
235
- {
236
- name: 'keyword',
237
- in: 'query',
238
- schema: { type: 'string' },
239
- description: '搜索关键词'
240
- }
241
- ]
242
- };
243
- }
244
-
245
- if (methodName.includes('ById') || methodName.includes('ById')) {
246
- return {
247
- ...baseMetadata,
248
- parameters: [
249
- {
250
- name: 'id',
251
- in: 'path',
252
- required: true,
253
- schema: { type: 'number' },
254
- description: 'ID'
255
- }
256
- ]
257
- };
258
- }
259
-
260
- // DELETE 方法添加路径参数
261
- if (methodName.includes('delete') || methodName.includes('Delete')) {
262
- return {
263
- ...baseMetadata,
264
- parameters: [
265
- {
266
- name: 'id',
267
- in: 'path',
268
- required: true,
269
- schema: { type: 'number' },
270
- description: 'ID'
271
- }
272
- ]
273
- };
274
- }
275
-
276
- // POST 方法添加请求体
277
- if (methodName.includes('create') || methodName.includes('Create')) {
278
- return {
279
- ...baseMetadata,
280
- requestBody: {
281
- required: true,
282
- content: {
283
- 'application/json': {
284
- schema: {
285
- type: 'object',
286
- required: ['name', 'email'],
287
- properties: {
288
- name: {
289
- type: 'string',
290
- description: '用户名',
291
- example: '张三'
292
- },
293
- email: {
294
- type: 'string',
295
- format: 'email',
296
- description: '邮箱',
297
- example: 'zhang@example.com'
298
- },
299
- age: {
300
- type: 'number',
301
- description: '年龄',
302
- example: 25
303
- }
304
- }
305
- }
306
- }
307
- }
308
- }
309
- };
310
- }
311
-
312
- // PUT 方法添加路径参数和请求体
313
- if (methodName.includes('update') || methodName.includes('Update')) {
314
- return {
315
- ...baseMetadata,
316
- parameters: [
317
- {
318
- name: 'id',
319
- in: 'path',
320
- required: true,
321
- schema: { type: 'number' },
322
- description: 'ID'
323
- }
324
- ],
325
- requestBody: {
326
- required: true,
327
- content: {
328
- 'application/json': {
329
- schema: {
330
- type: 'object',
331
- properties: {
332
- name: { type: 'string', description: '用户名' },
333
- email: { type: 'string', format: 'email', description: '邮箱' },
334
- age: { type: 'number', description: '年龄' }
335
- }
336
- }
337
- }
338
- }
339
- }
340
- };
341
- }
342
-
343
- return baseMetadata;
344
- }
345
-
346
- /**
347
- * 获取默认摘要
348
- */
349
- function getDefaultSummary(method: string, path: string) {
350
- const methodMap: {[key: string]: string} = {
351
- 'get': '获取',
352
- 'post': '创建',
353
- 'put': '更新',
354
- 'delete': '删除'
355
- };
356
-
357
- const action = methodMap[method] || '操作';
358
- const resource = path.includes('list') ? '列表' :
359
- path.includes('{id}') ? '详情' : '资源';
360
-
361
- return `${action}${resource}`;
362
- }
363
-
364
- /**
365
- * 获取默认描述
366
- */
367
- function getDefaultDescription(method: string, path: string) {
368
- const descriptions: {[key: string]: string} = {
369
- 'get': path.includes('list') ? '获取列表数据' : '获取详细信息',
370
- 'post': '创建新资源',
371
- 'put': '更新资源信息',
372
- 'delete': '删除资源'
373
- };
374
-
375
- return descriptions[method] || 'API 操作';
376
- }
377
-
378
- /**
379
- * 备用 Swagger 规范
380
- */
381
- function getFallbackSwaggerSpec() {
382
- return {
383
- openapi: '3.0.0',
384
- info: {
385
- title: 'DP Koa Framework API',
386
- version: '1.0.0',
387
- description: '基于Koa的企业级框架API文档',
388
- },
389
- servers: [
390
- {
391
- url: 'http://localhost:3000',
392
- description: '开发环境',
393
- },
394
- ],
395
- paths: {
396
- '/swagger/user/list': {
397
- get: {
398
- tags: ['用户管理'],
399
- summary: '获取用户列表',
400
- description: '获取用户列表数据',
401
- responses: {
402
- '200': {
403
- description: '成功返回用户列表',
404
- },
405
- },
406
- },
407
- },
408
- },
409
- };
410
- }
@@ -1,122 +0,0 @@
1
- import { Repository } from 'typeorm';
2
- import { YtUserEntity } from '@src/entity/ytUser.entity';
3
- import { BaseRepository } from '@src/repository/base/BaseRepository';
4
- import { IBaseRepository } from '@src/repository/interfaces/IBaseRepository';
5
-
6
- /**
7
- * 用户Repository接口
8
- * 定义用户相关的数据访问操作
9
- */
10
- export interface IUserRepository extends IBaseRepository<YtUserEntity> {
11
- findByEmail(email: string): Promise<YtUserEntity | null>;
12
- findByTelNumber(telNumber: string): Promise<YtUserEntity | null>;
13
- findByUserType(userType: string): Promise<YtUserEntity[]>;
14
- findByStatus(status: string): Promise<YtUserEntity[]>;
15
- findActiveUsers(): Promise<YtUserEntity[]>;
16
- updateLastLoginTime(id: number): Promise<void>;
17
- updatePassword(id: number, hashedPassword: string): Promise<void>;
18
- deactivateUser(id: number): Promise<void>;
19
- activateUser(id: number): Promise<void>;
20
- }
21
-
22
- /**
23
- * 用户Repository实现
24
- */
25
- export class UserRepository extends BaseRepository<YtUserEntity> implements IUserRepository {
26
- constructor(repository: Repository<YtUserEntity>) {
27
- super(YtUserEntity, repository);
28
- }
29
-
30
- async findByEmail(email: string): Promise<YtUserEntity | null> {
31
- try {
32
- return await this.repository.findOne({
33
- where: { email }
34
- });
35
- } catch (error) {
36
- throw error;
37
- }
38
- }
39
-
40
- async findByTelNumber(telNumber: string): Promise<YtUserEntity | null> {
41
- try {
42
- return await this.repository.findOne({
43
- where: { telnumber: telNumber }
44
- });
45
- } catch (error) {
46
- throw error;
47
- }
48
- }
49
-
50
- async findByUserType(userType: string): Promise<YtUserEntity[]> {
51
- try {
52
- return await this.repository.find({
53
- where: { userType: userType as any }
54
- });
55
- } catch (error) {
56
- throw error;
57
- }
58
- }
59
-
60
- async findByStatus(status: string): Promise<YtUserEntity[]> {
61
- try {
62
- return await this.repository.find({
63
- where: { status: status as any }
64
- });
65
- } catch (error) {
66
- throw error;
67
- }
68
- }
69
-
70
- async findActiveUsers(): Promise<YtUserEntity[]> {
71
- try {
72
- return await this.repository.find({
73
- where: { status: 'normal' as any }
74
- });
75
- } catch (error) {
76
- throw error;
77
- }
78
- }
79
-
80
- async updateLastLoginTime(id: number): Promise<void> {
81
- try {
82
- await this.repository.update(id, {
83
- updateDate: new Date()
84
- } as any);
85
- } catch (error) {
86
- throw error;
87
- }
88
- }
89
-
90
- async updatePassword(id: number, hashedPassword: string): Promise<void> {
91
- try {
92
- await this.repository.update(id, {
93
- password: hashedPassword,
94
- updateDate: new Date()
95
- } as any);
96
- } catch (error) {
97
- throw error;
98
- }
99
- }
100
-
101
- async deactivateUser(id: number): Promise<void> {
102
- try {
103
- await this.repository.update(id, {
104
- status: 'forbidden' as any,
105
- updateDate: new Date()
106
- } as any);
107
- } catch (error) {
108
- throw error;
109
- }
110
- }
111
-
112
- async activateUser(id: number): Promise<void> {
113
- try {
114
- await this.repository.update(id, {
115
- status: 'normal' as any,
116
- updateDate: new Date()
117
- } as any);
118
- } catch (error) {
119
- throw error;
120
- }
121
- }
122
- }
@@ -1,139 +0,0 @@
1
- /**
2
- * 参数校验测试 Service
3
- * 用于测试 dp-ioc2 的 @ParamValidate 装饰器功能
4
- */
5
-
6
- import { Injectable, ParamValidate, IOCValidationError } from "dp-ioc2";
7
- import { IsString, IsEmail, MinLength, IsNumber, Min, Max } from "class-validator";
8
- import { BaseService } from "@src/service/base.service";
9
- import { CommonServiceResult } from "@src/framework/types/ServiceResult";
10
- import { logger } from "@src/framework/utils/logger";
11
- import Joi from "joi";
12
-
13
- /**
14
- * 测试 DTO - 创建用户
15
- */
16
- export class CreateTestUserDto {
17
- @IsString({ message: '用户名必须是字符串' })
18
- @MinLength(3, { message: '用户名长度不能少于3个字符' })
19
- name!: string;
20
-
21
- @IsEmail({}, { message: '邮箱格式不正确' })
22
- email!: string;
23
-
24
- @IsNumber({}, { message: '年龄必须是数字' })
25
- @Min(18, { message: '年龄不能小于18岁' })
26
- @Max(100, { message: '年龄不能大于100岁' })
27
- age!: number;
28
- }
29
-
30
- /**
31
- * 测试 DTO - 更新用户
32
- */
33
- export class UpdateTestUserDto {
34
- @IsString({ message: '用户名必须是字符串' })
35
- @MinLength(3, { message: '用户名长度不能少于3个字符' })
36
- name?: string;
37
-
38
- @IsEmail({}, { message: '邮箱格式不正确' })
39
- email?: string;
40
- }
41
-
42
- /**
43
- * 参数校验测试 Service
44
- */
45
- @Injectable()
46
- export class ParamValidateTestService extends BaseService {
47
-
48
- /**
49
- * 测试1:对象参数校验(使用 class-validator)
50
- */
51
- async createUser(@ParamValidate(CreateTestUserDto) dto: CreateTestUserDto): Promise<CommonServiceResult<{ id: number; name: string; email: string; age: number }>> {
52
- try {
53
- // 业务逻辑(校验已在方法调用前自动完成)
54
- const user = {
55
- id: Math.floor(Math.random() * 1000),
56
- name: dto.name,
57
- email: dto.email,
58
- age: dto.age
59
- };
60
-
61
- logger.info(`创建用户成功: ${user.name}`);
62
- return CommonServiceResult.success(user, "用户创建成功");
63
- } catch (error) {
64
- if (error instanceof IOCValidationError) {
65
- return CommonServiceResult.validationError<{ id: number; name: string; email: string; age: number }>(
66
- error.message || "参数校验失败",
67
- null
68
- );
69
- }
70
- logger.error("创建用户失败:", error as Error);
71
- return CommonServiceResult.error("创建用户失败");
72
- }
73
- }
74
-
75
- /**
76
- * 测试2:基本类型参数校验(使用 Joi)
77
- */
78
- async getUserById(@ParamValidate(undefined, Joi.number().integer().positive().required()) userId: number): Promise<CommonServiceResult<{ id: number; name: string }>> {
79
- try {
80
- // 业务逻辑
81
- const user = {
82
- id: userId,
83
- name: `用户${userId}`
84
- };
85
-
86
- return CommonServiceResult.success(user, "获取用户成功");
87
- } catch (error) {
88
- if (error instanceof IOCValidationError) {
89
- return CommonServiceResult.validationError<{ id: number; name: string }>(
90
- error.message || "参数校验失败",
91
- null
92
- );
93
- }
94
- logger.error("获取用户失败:", error as Error);
95
- return CommonServiceResult.error("获取用户失败");
96
- }
97
- }
98
-
99
- /**
100
- * 测试3:混合参数校验(基本类型 + 对象)
101
- */
102
- async updateUser(
103
- @ParamValidate(undefined, Joi.number().integer().positive().required()) userId: number,
104
- @ParamValidate(UpdateTestUserDto) dto: UpdateTestUserDto
105
- ): Promise<CommonServiceResult<{ id: number; name?: string; email?: string }>> {
106
- try {
107
- // 业务逻辑
108
- const user = {
109
- id: userId,
110
- ...dto
111
- };
112
-
113
- return CommonServiceResult.success(user, "更新用户成功");
114
- } catch (error) {
115
- if (error instanceof IOCValidationError) {
116
- return CommonServiceResult.validationError<{ id: number; name?: string; email?: string }>(
117
- error.message || "参数校验失败",
118
- null
119
- );
120
- }
121
- logger.error("更新用户失败:", error as Error);
122
- return CommonServiceResult.error("更新用户失败");
123
- }
124
- }
125
-
126
- /**
127
- * 测试4:无校验参数(用于对比)
128
- */
129
- async getUserWithoutValidation(userId: number): Promise<CommonServiceResult<{ id: number; name: string }>> {
130
- // 这个方法没有使用 @ParamValidate,用于对比测试
131
- const user = {
132
- id: userId,
133
- name: `用户${userId}`
134
- };
135
-
136
- return CommonServiceResult.success(user, "获取用户成功");
137
- }
138
- }
139
-