858 lines
26 KiB
Plaintext
858 lines
26 KiB
Plaintext
|
|
---
|
|||
|
|
description: Java后端迁移到v1框架的系统性迁移方案和规则
|
|||
|
|
globs:
|
|||
|
|
alwaysApply: true
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# Java后端迁移到v1框架 - 系统性迁移方案
|
|||
|
|
|
|||
|
|
## 📋 迁移目标
|
|||
|
|
|
|||
|
|
**核心目标**:将Java后端完全替换为NestJS v1框架,保持数据库和前端100%不变
|
|||
|
|
|
|||
|
|
**约束条件**:
|
|||
|
|
- ✅ 数据库:完全复用Java的数据库结构(表结构、字段、索引、数据)
|
|||
|
|
- ✅ 前端:完全复用Java的前端代码(API接口、响应格式、权限逻辑)
|
|||
|
|
- ✅ 业务逻辑:100%对齐Java的业务逻辑(方法签名、参数、返回值、异常处理)
|
|||
|
|
|
|||
|
|
## 🏗️ 架构对齐方案
|
|||
|
|
|
|||
|
|
### 1. 分层架构映射
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
Java (Spring Boot) → NestJS v1 Framework
|
|||
|
|
═══════════════════════════════════════════════════════════════
|
|||
|
|
Controller层 → Controller层 (controllers/)
|
|||
|
|
├─ @RestController → @Controller
|
|||
|
|
├─ @RequestMapping → @Get/@Post/@Put/@Delete
|
|||
|
|
└─ @RequestParam/@RequestBody → @Query/@Body/@Param
|
|||
|
|
|
|||
|
|
Service层 → Service层 (services/)
|
|||
|
|
├─ @Service → @Injectable
|
|||
|
|
├─ Interface (IService) → Interface (Service)
|
|||
|
|
└─ Impl (ServiceImpl) → Impl (ServiceImpl)
|
|||
|
|
|
|||
|
|
Repository层 → Entity层 (entities/)
|
|||
|
|
├─ JpaRepository<T, ID> → @InjectRepository(Entity)
|
|||
|
|
└─ Entity → @Entity + TypeORM
|
|||
|
|
|
|||
|
|
DTO/VO/Param → DTO层 (dtos/)
|
|||
|
|
├─ VO (View Object) → VO (vo/*.dto.ts) - 保持Vo原样
|
|||
|
|
├─ DTO (Data Transfer Object) → DTO (dto/*.dto.ts) - 保持Dto原样
|
|||
|
|
└─ Param → Param (param/*.dto.ts) - 保持Param原样
|
|||
|
|
|
|||
|
|
配置层 → 配置层 (config/)
|
|||
|
|
├─ @Configuration → @Module
|
|||
|
|
├─ @Bean → providers/exports
|
|||
|
|
└─ application.yml → ConfigModule + 环境变量
|
|||
|
|
|
|||
|
|
框架能力层(v1框架提供) → 框架能力层 (@wwjBoot)
|
|||
|
|
├─ 基础设施服务
|
|||
|
|
│ ├─ RequestContextService → 请求上下文服务
|
|||
|
|
│ ├─ HttpClientService → HTTP客户端服务
|
|||
|
|
│ ├─ MetricsService → 指标服务
|
|||
|
|
│ └─ ConfigService/AppConfigService → 配置服务
|
|||
|
|
├─ 认证授权
|
|||
|
|
│ ├─ AuthService → JWT认证服务
|
|||
|
|
│ ├─ AuthGuard → 认证守卫
|
|||
|
|
│ ├─ RbacGuard → 权限守卫
|
|||
|
|
│ └─ @Public()/@Admin()/@Api() → 路由装饰器
|
|||
|
|
├─ 缓存服务
|
|||
|
|
│ ├─ CacheService → 缓存服务
|
|||
|
|
│ ├─ LockService → 分布式锁服务
|
|||
|
|
│ └─ CacheManagerService → 缓存管理服务
|
|||
|
|
├─ 队列与事件
|
|||
|
|
│ ├─ QueueService → 队列服务
|
|||
|
|
│ ├─ EventBus → 事件总线
|
|||
|
|
│ ├─ EventListenerService → 事件监听服务
|
|||
|
|
│ └─ JobSchedulerService → 任务调度服务
|
|||
|
|
├─ 工具类(vendor/utils)
|
|||
|
|
│ ├─ StringUtils → 字符串工具
|
|||
|
|
│ ├─ JsonUtils → JSON工具(含命名转换)
|
|||
|
|
│ ├─ FileUtils → 文件工具
|
|||
|
|
│ ├─ DateUtils → 日期工具
|
|||
|
|
│ ├─ CryptoUtils → 加密工具(bcrypt)
|
|||
|
|
│ ├─ ImageUtils → 图片工具(Base64转换)
|
|||
|
|
│ ├─ WwjcloudUtils → Wwjcloud API工具
|
|||
|
|
│ └─ ZipUtils → ZIP压缩工具
|
|||
|
|
├─ 线程本地存储(infra/context)
|
|||
|
|
│ └─ ThreadLocalHolder → 线程本地变量工具类(对齐Java component/base/ThreadLocalHolder)
|
|||
|
|
├─ 供应商服务(vendor)
|
|||
|
|
│ ├─ PayService → 支付服务
|
|||
|
|
│ ├─ SmsService → 短信服务
|
|||
|
|
│ ├─ NoticeService → 通知服务
|
|||
|
|
│ └─ UploadService → 上传服务
|
|||
|
|
├─ 响应包装
|
|||
|
|
│ └─ Result<T> → 统一响应格式
|
|||
|
|
├─ 中间件
|
|||
|
|
│ ├─ RequestIdMiddleware → 请求ID中间件
|
|||
|
|
│ ├─ RequestContextMiddleware → 请求上下文中间件
|
|||
|
|
│ ├─ TenantMiddleware → 租户中间件
|
|||
|
|
│ └─ IpFilterMiddleware → IP过滤中间件
|
|||
|
|
├─ 拦截器
|
|||
|
|
│ ├─ LoggingInterceptor → 日志拦截器
|
|||
|
|
│ ├─ MetricsInterceptor → 指标拦截器
|
|||
|
|
│ └─ ResponseInterceptor → 响应拦截器
|
|||
|
|
├─ 过滤器
|
|||
|
|
│ └─ HttpExceptionFilter → 异常过滤器
|
|||
|
|
├─ 守卫
|
|||
|
|
│ └─ RateLimitGuard → 限流守卫
|
|||
|
|
└─ 动态模块加载
|
|||
|
|
├─ EntityModule.register() → 动态加载实体
|
|||
|
|
├─ ServiceModule.register() → 动态加载服务
|
|||
|
|
└─ ControllerModule.register() → 动态加载控制器
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 模块组织映射
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
Java模块结构 → NestJS模块结构
|
|||
|
|
═══════════════════════════════════════════════════════════════
|
|||
|
|
com.niu.core.controller.* → controllers/adminapi/*
|
|||
|
|
com.niu.core.service.* → services/admin/*
|
|||
|
|
com.niu.core.service.impl.* → services/admin/impl/*
|
|||
|
|
com.niu.core.entity.* → entities/*
|
|||
|
|
com.niu.core.dto.* → dtos/admin/*
|
|||
|
|
com.niu.core.job.* → jobs/*
|
|||
|
|
com.niu.core.listener.* → listeners/*
|
|||
|
|
com.niu.core.common.component.base.ThreadLocalHolder → boot/infra/context/thread-local-holder.ts
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 动态模块加载机制
|
|||
|
|
|
|||
|
|
v1框架采用**动态模块加载**,自动扫描并注册所有组件:
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// EntityModule - 动态加载所有实体
|
|||
|
|
EntityModule.register()
|
|||
|
|
→ 扫描 entities/*.entity.ts
|
|||
|
|
→ 注册到 TypeOrmModule.forFeature(entities)
|
|||
|
|
|
|||
|
|
// ServiceModule - 动态加载所有服务
|
|||
|
|
ServiceModule.register()
|
|||
|
|
→ 扫描 services/**/*.service.ts
|
|||
|
|
→ 自动注册为 providers
|
|||
|
|
|
|||
|
|
// ControllerModule - 动态加载所有控制器
|
|||
|
|
ControllerModule.register()
|
|||
|
|
→ 扫描 controllers/**/*.controller.ts
|
|||
|
|
→ 自动注册为 controllers
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🔄 迁移流程(5个阶段)
|
|||
|
|
|
|||
|
|
### 阶段1:扫描与分析(Scanning)
|
|||
|
|
|
|||
|
|
**目标**:全面扫描Java项目,建立完整的元数据索引
|
|||
|
|
|
|||
|
|
**执行步骤**:
|
|||
|
|
1. **扫描Java项目结构**
|
|||
|
|
```bash
|
|||
|
|
tools/java-to-nestjs-migration/migration-coordinator.js
|
|||
|
|
```
|
|||
|
|
- 扫描所有Controller、Service、Entity、DTO文件
|
|||
|
|
- 提取方法签名、参数类型、返回值类型
|
|||
|
|
- 分析依赖关系(Service依赖、Repository依赖)
|
|||
|
|
|
|||
|
|
2. **构建中央数据仓库(CDR)**
|
|||
|
|
- Service方法签名索引(1038个方法)
|
|||
|
|
- DTO类型映射(732个类型)
|
|||
|
|
- 实体映射关系(89个实体)
|
|||
|
|
- 依赖关系图
|
|||
|
|
|
|||
|
|
3. **生成映射报告**
|
|||
|
|
- Java文件 → NestJS文件映射表
|
|||
|
|
- 方法签名对比表
|
|||
|
|
- 依赖关系分析报告
|
|||
|
|
|
|||
|
|
**输出产物**:
|
|||
|
|
- `migration-report.json` - 迁移报告
|
|||
|
|
- CDR索引数据
|
|||
|
|
- 文件映射关系表
|
|||
|
|
|
|||
|
|
### 阶段2:代码生成(Generation)
|
|||
|
|
|
|||
|
|
**目标**:使用迁移工具自动生成NestJS代码骨架
|
|||
|
|
|
|||
|
|
**执行步骤**:
|
|||
|
|
1. **生成实体(Entity)**
|
|||
|
|
- 从Java Entity生成TypeORM Entity
|
|||
|
|
- 保持表名、字段名、索引完全一致
|
|||
|
|
- 生成文件:`entities/*.entity.ts`
|
|||
|
|
|
|||
|
|
2. **生成DTO**
|
|||
|
|
- 从Java DTO/VO/Param生成NestJS DTO
|
|||
|
|
- 保持字段名、类型、验证规则一致
|
|||
|
|
- 生成文件:`dtos/admin/*/*.dto.ts`
|
|||
|
|
|
|||
|
|
3. **生成服务接口和实现**
|
|||
|
|
- 从Java Interface生成NestJS Service接口
|
|||
|
|
- 从Java ServiceImpl生成NestJS Service实现骨架
|
|||
|
|
- 生成文件:`services/admin/*/*.service.ts`
|
|||
|
|
|
|||
|
|
4. **生成控制器**
|
|||
|
|
- 从Java Controller生成NestJS Controller
|
|||
|
|
- 保持路由路径、HTTP方法、参数一致
|
|||
|
|
- 生成文件:`controllers/adminapi/*/*.controller.ts`
|
|||
|
|
|
|||
|
|
5. **生成模块文件**
|
|||
|
|
- 动态模块:`EntityModule.register()`
|
|||
|
|
- 动态模块:`ServiceModule.register()`
|
|||
|
|
- 动态模块:`ControllerModule.register()`
|
|||
|
|
|
|||
|
|
**输出产物**:
|
|||
|
|
- 所有Entity文件(89个)
|
|||
|
|
- 所有DTO文件(732个)
|
|||
|
|
- 所有Service文件(158个)
|
|||
|
|
- 所有Controller文件(110个)
|
|||
|
|
- 模块注册文件
|
|||
|
|
|
|||
|
|
### 阶段3:业务逻辑对齐(Alignment)
|
|||
|
|
|
|||
|
|
**目标**:逐个模块对齐Java的业务逻辑
|
|||
|
|
|
|||
|
|
**执行策略**:**按模块优先级逐步对齐**
|
|||
|
|
|
|||
|
|
#### 优先级排序:
|
|||
|
|
1. **核心模块(P0)**:认证、权限、用户管理
|
|||
|
|
- `services/admin/auth/*`
|
|||
|
|
- `services/admin/user/*`
|
|||
|
|
- `services/admin/rbac/*`
|
|||
|
|
|
|||
|
|
2. **基础模块(P1)**:配置、菜单、字典
|
|||
|
|
- `services/admin/sys/*`
|
|||
|
|
- `services/core/config/*`
|
|||
|
|
|
|||
|
|
3. **业务模块(P2)**:业务功能模块
|
|||
|
|
- `services/admin/member/*`
|
|||
|
|
- `services/admin/order/*`
|
|||
|
|
- `services/admin/pay/*`
|
|||
|
|
|
|||
|
|
4. **扩展模块(P3)**:插件、扩展功能
|
|||
|
|
- `services/admin/addon/*`
|
|||
|
|
|
|||
|
|
#### 对齐检查清单(每个Service方法):
|
|||
|
|
|
|||
|
|
- [ ] **方法签名对齐**
|
|||
|
|
```typescript
|
|||
|
|
// Java
|
|||
|
|
public PageResult<MemberVo> getPage(MemberSearchParam param)
|
|||
|
|
|
|||
|
|
// NestJS - 必须完全一致(保持Vo/Param原样,不添加Dto后缀)
|
|||
|
|
async getPage(param: MemberSearchParam): Promise<PageResult<MemberVo>>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
- [ ] **参数处理对齐**
|
|||
|
|
```typescript
|
|||
|
|
// Java: @RequestParam("pageNo") Integer pageNo
|
|||
|
|
// NestJS: @Query('pageNo') pageNo: number
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
- [ ] **返回值对齐**
|
|||
|
|
```typescript
|
|||
|
|
// Java: return Result.success(data)
|
|||
|
|
// NestJS: return Result.success(data)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
- [ ] **异常处理对齐**
|
|||
|
|
```typescript
|
|||
|
|
// Java: throw new BusinessException("错误信息")
|
|||
|
|
// NestJS: throw new BadRequestException("错误信息")
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
- [ ] **数据库操作对齐**
|
|||
|
|
```typescript
|
|||
|
|
// Java: repository.findByXxx()
|
|||
|
|
// NestJS: repository.find({ where: { xxx } })
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
- [ ] **事务处理对齐**
|
|||
|
|
```typescript
|
|||
|
|
// Java: @Transactional
|
|||
|
|
// NestJS: @Transaction() 或使用EntityManager
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 阶段4:框架能力集成(Integration)
|
|||
|
|
|
|||
|
|
**目标**:将业务代码集成到v1框架能力体系中
|
|||
|
|
|
|||
|
|
#### 4.1 认证授权集成
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 使用框架的AuthService
|
|||
|
|
import { AuthService } from '@wwjBoot';
|
|||
|
|
|
|||
|
|
// 生成Token
|
|||
|
|
const token = this.authService.signToken({ uid, username });
|
|||
|
|
|
|||
|
|
// 验证Token
|
|||
|
|
const claims = this.authService.verifyToken(token);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 4.2 缓存集成
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 使用框架的CacheService
|
|||
|
|
import { CacheService } from '@wwjBoot';
|
|||
|
|
|
|||
|
|
// 缓存操作
|
|||
|
|
await this.cacheService.set(key, value, ttl);
|
|||
|
|
const value = await this.cacheService.get(key);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 4.3 配置管理集成
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 使用框架的AppConfigService
|
|||
|
|
import { AppConfigService } from '@wwjBoot';
|
|||
|
|
|
|||
|
|
// 读取配置
|
|||
|
|
const config = this.appConfig.webRoot;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 4.4 工具类集成
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 使用框架的工具类
|
|||
|
|
import { JsonUtils, FileUtils, StringUtils } from '@wwjBoot';
|
|||
|
|
|
|||
|
|
// JSON操作
|
|||
|
|
const obj = JsonUtils.parseObject<Type>(jsonStr);
|
|||
|
|
const jsonStr = JsonUtils.toCamelCaseJSONString(obj);
|
|||
|
|
|
|||
|
|
// 文件操作
|
|||
|
|
const content = FileUtils.readFile(filePath);
|
|||
|
|
FileUtils.writeFile(filePath, content);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 4.5 线程本地存储集成
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 使用框架的ThreadLocalHolder(对齐Java component/base/ThreadLocalHolder)
|
|||
|
|
import { ThreadLocalHolder } from '@wwjBoot';
|
|||
|
|
|
|||
|
|
// 存储任意key-value
|
|||
|
|
ThreadLocalHolder.put('current-user', userInfo);
|
|||
|
|
ThreadLocalHolder.put('current-site-id', siteId);
|
|||
|
|
|
|||
|
|
// 获取值
|
|||
|
|
const userInfo = ThreadLocalHolder.get('current-user');
|
|||
|
|
const userInfoTyped = ThreadLocalHolder.getTyped<UserInfo>('current-user');
|
|||
|
|
|
|||
|
|
// 便捷方法
|
|||
|
|
ThreadLocalHolder.putString('key', 'value');
|
|||
|
|
const value = ThreadLocalHolder.getString('key');
|
|||
|
|
ThreadLocalHolder.putInteger('count', 10);
|
|||
|
|
const count = ThreadLocalHolder.getInteger('count');
|
|||
|
|
|
|||
|
|
// 注意:RequestContextService.runWith()会自动初始化ThreadLocalHolder上下文
|
|||
|
|
// 在请求处理过程中,ThreadLocalHolder可以直接使用
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 阶段5:测试与验证(Validation)
|
|||
|
|
|
|||
|
|
**目标**:确保迁移后的功能与Java版本100%一致
|
|||
|
|
|
|||
|
|
#### 5.1 单元测试
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 测试Service方法
|
|||
|
|
describe('LoginServiceImpl', () => {
|
|||
|
|
it('should login successfully', async () => {
|
|||
|
|
const result = await service.login({ username: 'admin', password: '123456' });
|
|||
|
|
expect(result.token).toBeDefined();
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 5.2 集成测试
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 使用Docker进行完整环境测试
|
|||
|
|
docker-compose up -d
|
|||
|
|
# 测试登录接口
|
|||
|
|
curl -X GET "http://localhost:3000/adminapi/login/admin?username=admin&password=123456"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 5.3 API兼容性测试
|
|||
|
|
|
|||
|
|
**检查点**:
|
|||
|
|
- [ ] 所有API路径与Java一致
|
|||
|
|
- [ ] 请求参数格式与Java一致
|
|||
|
|
- [ ] 响应格式与Java一致(Result包装)
|
|||
|
|
- [ ] 错误码与Java一致
|
|||
|
|
- [ ] 异常消息与Java一致
|
|||
|
|
|
|||
|
|
#### 5.4 数据库兼容性测试
|
|||
|
|
|
|||
|
|
**检查点**:
|
|||
|
|
- [ ] 表结构完全一致
|
|||
|
|
- [ ] 字段类型完全一致
|
|||
|
|
- [ ] 索引结构完全一致
|
|||
|
|
- [ ] 数据读写完全一致
|
|||
|
|
|
|||
|
|
## 🎯 关键迁移原则
|
|||
|
|
|
|||
|
|
### 原则1:优先对齐Java逻辑,再优化框架特性
|
|||
|
|
|
|||
|
|
**错误做法**:
|
|||
|
|
```typescript
|
|||
|
|
// ❌ 直接使用NestJS特性,忽略Java逻辑
|
|||
|
|
@Get(':id')
|
|||
|
|
async getById(@Param('id') id: string) {
|
|||
|
|
return await this.service.findOne(id);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**正确做法**:
|
|||
|
|
```typescript
|
|||
|
|
// ✅ 先对齐Java逻辑,再考虑优化
|
|||
|
|
@Get(':id')
|
|||
|
|
async getById(@Param('id') id: string) {
|
|||
|
|
// Java: MemberController.getById(Integer id)
|
|||
|
|
// 必须保持参数类型、返回值类型一致
|
|||
|
|
const member = await this.service.getById(Number(id));
|
|||
|
|
return Result.success(member);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 原则2:数据库100%对齐,禁止修改
|
|||
|
|
|
|||
|
|
**绝对禁止**:
|
|||
|
|
- ❌ 修改表名
|
|||
|
|
- ❌ 修改字段名
|
|||
|
|
- ❌ 修改字段类型
|
|||
|
|
- ❌ 添加或删除字段
|
|||
|
|
- ❌ 修改索引结构
|
|||
|
|
|
|||
|
|
**正确做法**:
|
|||
|
|
```typescript
|
|||
|
|
// ✅ 完全对齐Java的Entity定义
|
|||
|
|
@Entity('nc_sys_user') // 表名必须与Java一致
|
|||
|
|
export class SysUser {
|
|||
|
|
@Column({ name: 'user_name' }) // 字段名必须与Java一致
|
|||
|
|
userName: string;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 原则3:API接口100%对齐,确保前端兼容
|
|||
|
|
|
|||
|
|
**检查清单**:
|
|||
|
|
- [ ] 路由路径一致:`/adminapi/member/list`
|
|||
|
|
- [ ] HTTP方法一致:`GET`、`POST`、`PUT`、`DELETE`
|
|||
|
|
- [ ] 参数名一致:`pageNo`、`pageSize`、`keyword`
|
|||
|
|
- [ ] 响应格式一致:`Result<T>` 包装
|
|||
|
|
- [ ] 错误码一致:`error_code`、`msg_key`
|
|||
|
|
|
|||
|
|
### 原则4:业务逻辑100%对齐,禁止自创逻辑
|
|||
|
|
|
|||
|
|
**错误做法**:
|
|||
|
|
```typescript
|
|||
|
|
// ❌ 自创业务逻辑
|
|||
|
|
async login(param: LoginParam) {
|
|||
|
|
// Java中没有这个逻辑,不要添加
|
|||
|
|
if (param.username.length < 3) {
|
|||
|
|
throw new BadRequestException('用户名太短');
|
|||
|
|
}
|
|||
|
|
// ...
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**正确做法**:
|
|||
|
|
```typescript
|
|||
|
|
// ✅ 严格对齐Java逻辑(保持Param原样)
|
|||
|
|
async login(param: LoginParam) {
|
|||
|
|
// 完全按照Java的LoginServiceImpl.login()实现
|
|||
|
|
const user = await this.repository.findOne({ where: { username: param.username } });
|
|||
|
|
if (!user || !await CryptoUtils.match(param.password, user.password)) {
|
|||
|
|
// ✅ 使用NestJS的HttpException系列(不要使用BaseException)
|
|||
|
|
throw new UnauthorizedException({ msg_key: 'error.auth.invalid_credentials' });
|
|||
|
|
}
|
|||
|
|
// ...
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 原则5:异常处理使用NestJS原生特性
|
|||
|
|
|
|||
|
|
**错误做法**:
|
|||
|
|
```typescript
|
|||
|
|
// ❌ 使用机械迁移的BaseException
|
|||
|
|
import { BaseException } from '../../common/exception';
|
|||
|
|
throw new BaseException('操作失败');
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**正确做法**:
|
|||
|
|
```typescript
|
|||
|
|
// ✅ 使用NestJS的HttpException系列
|
|||
|
|
import { BadRequestException, UnauthorizedException, ForbiddenException } from '@nestjs/common';
|
|||
|
|
throw new BadRequestException({ msg_key: 'error.common.operation_failed' });
|
|||
|
|
throw new UnauthorizedException({ msg_key: 'error.auth.invalid_token' });
|
|||
|
|
throw new ForbiddenException({ msg_key: 'error.auth.insufficient_permission' });
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**配置访问使用依赖注入**:
|
|||
|
|
```typescript
|
|||
|
|
// ❌ 静态配置类(已删除)
|
|||
|
|
import { GlobalConfig } from '../../common/config';
|
|||
|
|
const prefix = GlobalConfig.tablePrefix;
|
|||
|
|
|
|||
|
|
// ✅ 使用AppConfigService(依赖注入)
|
|||
|
|
constructor(private readonly appConfig: AppConfigService) {}
|
|||
|
|
const prefix = this.appConfig.tablePrefix;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 🔧 迁移工具使用指南
|
|||
|
|
|
|||
|
|
### 1. 运行迁移工具
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
cd tools/java-to-nestjs-migration
|
|||
|
|
node migration-coordinator.js
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**输出**:
|
|||
|
|
- 扫描Java项目(1215个文件)
|
|||
|
|
- 生成NestJS代码骨架
|
|||
|
|
- 生成映射报告
|
|||
|
|
|
|||
|
|
### 2. 迁移工具生成的内容
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
wwjcloud/libs/wwjcloud-core/src/
|
|||
|
|
├── entities/ # 89个实体文件(自动生成)
|
|||
|
|
├── dtos/ # 732个DTO文件(自动生成)
|
|||
|
|
├── services/ # 158个服务文件(自动生成)
|
|||
|
|
├── controllers/ # 110个控制器文件(自动生成)
|
|||
|
|
├── entity.module.ts # 动态实体模块(自动生成)
|
|||
|
|
├── service.module.ts # 动态服务模块(自动生成)
|
|||
|
|
└── controller.module.ts # 动态控制器模块(自动生成)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 迁移工具的限制
|
|||
|
|
|
|||
|
|
**不会自动生成的内容**:
|
|||
|
|
- ❌ Service方法的业务逻辑实现(只生成方法签名)
|
|||
|
|
- ❌ Controller的参数解析逻辑(需要手动对齐)
|
|||
|
|
- ❌ 复杂的查询逻辑(需要手动实现)
|
|||
|
|
- ❌ 事务处理逻辑(需要手动添加)
|
|||
|
|
|
|||
|
|
**需要手动对齐的内容**:
|
|||
|
|
- ✅ Service方法的业务逻辑
|
|||
|
|
- ✅ Controller的参数处理
|
|||
|
|
- ✅ 异常处理逻辑
|
|||
|
|
- ✅ 数据库查询优化
|
|||
|
|
|
|||
|
|
## 📊 质量控制检查点
|
|||
|
|
|
|||
|
|
### 检查点1:编译通过
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
cd wwjcloud
|
|||
|
|
npm run build
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**要求**:
|
|||
|
|
- ✅ 无TypeScript编译错误
|
|||
|
|
- ✅ 无依赖注入错误
|
|||
|
|
- ✅ 无类型错误
|
|||
|
|
|
|||
|
|
### 检查点2:服务启动
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
docker-compose up -d
|
|||
|
|
docker logs wwjcloud-api-v1
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**要求**:
|
|||
|
|
- ✅ 服务成功启动
|
|||
|
|
- ✅ 所有模块正确加载
|
|||
|
|
- ✅ 数据库连接成功
|
|||
|
|
- ✅ Redis连接成功
|
|||
|
|
|
|||
|
|
### 检查点3:API测试
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 测试登录接口
|
|||
|
|
curl -X GET "http://localhost:3000/adminapi/login/admin?username=admin&password=123456"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**要求**:
|
|||
|
|
- ✅ 接口返回200状态码
|
|||
|
|
- ✅ 响应格式正确(Result包装)
|
|||
|
|
- ✅ Token生成正确
|
|||
|
|
- ✅ 错误处理正确
|
|||
|
|
|
|||
|
|
### 检查点4:数据库操作验证
|
|||
|
|
|
|||
|
|
```typescript
|
|||
|
|
// 验证CRUD操作
|
|||
|
|
await service.create(data); // 创建
|
|||
|
|
await service.getById(id); // 查询
|
|||
|
|
await service.update(id, data); // 更新
|
|||
|
|
await service.delete(id); // 删除
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**要求**:
|
|||
|
|
- ✅ 数据正确写入数据库
|
|||
|
|
- ✅ 数据正确从数据库读取
|
|||
|
|
- ✅ 字段映射正确
|
|||
|
|
- ✅ 类型转换正确
|
|||
|
|
|
|||
|
|
## 🚨 常见问题与解决方案
|
|||
|
|
|
|||
|
|
### 问题1:Repository无法注入
|
|||
|
|
|
|||
|
|
**症状**:
|
|||
|
|
```
|
|||
|
|
UnknownDependenciesException: Nest can't resolve dependencies of the XxxServiceImpl (?, ?).
|
|||
|
|
Please make sure that the argument "XxxRepository" at index [1] is available.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**原因**:
|
|||
|
|
- EntityModule没有正确注册
|
|||
|
|
- Entity没有正确导出
|
|||
|
|
- ServiceModule没有导入EntityModule
|
|||
|
|
|
|||
|
|
**解决方案**:
|
|||
|
|
```typescript
|
|||
|
|
// 1. 确保EntityModule正确注册
|
|||
|
|
EntityModule.register()
|
|||
|
|
|
|||
|
|
// 2. 确保Entity正确导出
|
|||
|
|
@Entity('nc_sys_user')
|
|||
|
|
export class SysUser { ... }
|
|||
|
|
|
|||
|
|
// 3. 确保ServiceModule导入EntityModule
|
|||
|
|
ServiceModule.register()
|
|||
|
|
→ imports: [EntityModule.register()]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 问题2:DTO类型不匹配
|
|||
|
|
|
|||
|
|
**症状**:
|
|||
|
|
```
|
|||
|
|
TS2345: Argument of type 'Record<string, any>' is not assignable to parameter of type 'XxxDto'.
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**原因**:
|
|||
|
|
- Controller参数类型错误
|
|||
|
|
- DTO定义不完整
|
|||
|
|
|
|||
|
|
**解决方案**:
|
|||
|
|
```typescript
|
|||
|
|
// ✅ 正确使用DTO(保持Param原样,不添加Dto后缀)
|
|||
|
|
@Get(':id')
|
|||
|
|
async getById(@Param('id') id: string, @Query() query: XxxSearchParam) {
|
|||
|
|
// query已经是XxxSearchParam类型,不需要转换
|
|||
|
|
return await this.service.getPage(query);
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 问题3:业务逻辑不一致
|
|||
|
|
|
|||
|
|
**症状**:
|
|||
|
|
- 功能行为与Java版本不一致
|
|||
|
|
- 数据计算结果不同
|
|||
|
|
|
|||
|
|
**原因**:
|
|||
|
|
- 业务逻辑实现有偏差
|
|||
|
|
- 工具类使用不当
|
|||
|
|
|
|||
|
|
**解决方案**:
|
|||
|
|
1. 对比Java源码,逐行对齐
|
|||
|
|
2. 使用框架提供的工具类(JsonUtils、FileUtils等)
|
|||
|
|
3. 确保异常处理逻辑一致
|
|||
|
|
4. 使用NestJS的HttpException系列,不要使用已删除的BaseException
|
|||
|
|
|
|||
|
|
### 问题4:使用了已删除的机械Java迁移内容
|
|||
|
|
|
|||
|
|
**症状**:
|
|||
|
|
- 编译错误:Cannot find module './exception/base-exception'
|
|||
|
|
- 编译错误:Cannot find module './config/global-config'
|
|||
|
|
- 编译错误:Cannot find module './annotation/sa-not-check-login'
|
|||
|
|
|
|||
|
|
**原因**:
|
|||
|
|
- 使用了已删除的机械Java迁移内容
|
|||
|
|
|
|||
|
|
**解决方案**:
|
|||
|
|
```typescript
|
|||
|
|
// ❌ 已删除:BaseException
|
|||
|
|
import { BaseException } from '../../common/exception';
|
|||
|
|
throw new BaseException('错误');
|
|||
|
|
|
|||
|
|
// ✅ 替换为:HttpException系列
|
|||
|
|
import { BadRequestException } from '@nestjs/common';
|
|||
|
|
throw new BadRequestException({ msg_key: 'error.common.operation_failed' });
|
|||
|
|
|
|||
|
|
// ❌ 已删除:GlobalConfig
|
|||
|
|
import { GlobalConfig } from '../../common/config';
|
|||
|
|
const prefix = GlobalConfig.tablePrefix;
|
|||
|
|
|
|||
|
|
// ✅ 替换为:AppConfigService
|
|||
|
|
constructor(private readonly appConfig: AppConfigService) {}
|
|||
|
|
const prefix = this.appConfig.tablePrefix;
|
|||
|
|
|
|||
|
|
// ❌ 已删除:SaNotCheckLogin
|
|||
|
|
import { SaNotCheckLogin } from '../../common/annotation';
|
|||
|
|
@SaNotCheckLogin()
|
|||
|
|
async publicMethod() {}
|
|||
|
|
|
|||
|
|
// ✅ 替换为:@Public
|
|||
|
|
import { Public } from '@wwjBoot';
|
|||
|
|
@Public()
|
|||
|
|
async publicMethod() {}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 📈 迁移进度跟踪
|
|||
|
|
|
|||
|
|
### 模块迁移状态
|
|||
|
|
|
|||
|
|
| 模块 | 实体 | DTO | Service | Controller | 状态 |
|
|||
|
|
|------|------|-----|---------|------------|------|
|
|||
|
|
| Auth | ✅ | ✅ | ✅ | ✅ | ✅ 完成 |
|
|||
|
|
| User | ✅ | ✅ | ⚠️ | ⚠️ | 🔄 进行中 |
|
|||
|
|
| Member | ✅ | ✅ | ⚠️ | ⚠️ | 🔄 进行中 |
|
|||
|
|
| Order | ✅ | ✅ | ❌ | ❌ | 📋 待开始 |
|
|||
|
|
| Pay | ✅ | ✅ | ❌ | ❌ | 📋 待开始 |
|
|||
|
|
| Addon | ✅ | ✅ | ⚠️ | ⚠️ | 🔄 进行中 |
|
|||
|
|
|
|||
|
|
**图例**:
|
|||
|
|
- ✅ 完成:已对齐Java逻辑,测试通过
|
|||
|
|
- ⚠️ 进行中:代码已生成,业务逻辑对齐中
|
|||
|
|
- ❌ 待开始:代码已生成,未开始业务逻辑对齐
|
|||
|
|
|
|||
|
|
### 统计数据
|
|||
|
|
|
|||
|
|
- **实体文件**:89/89 (100%)
|
|||
|
|
- **DTO文件**:732/732 (100%)
|
|||
|
|
- **Service文件**:158/158 (100%) - 骨架完成,业务逻辑对齐中
|
|||
|
|
- **Controller文件**:110/110 (100%) - 骨架完成,业务逻辑对齐中
|
|||
|
|
|
|||
|
|
## 🎓 最佳实践
|
|||
|
|
|
|||
|
|
### 1. 一次对齐一个模块
|
|||
|
|
|
|||
|
|
**不要**:同时修改多个模块
|
|||
|
|
**要**:按模块优先级,逐个完整对齐
|
|||
|
|
|
|||
|
|
### 2. 先对齐核心流程,再对齐边界情况
|
|||
|
|
|
|||
|
|
**优先级**:
|
|||
|
|
1. 正常流程(happy path)
|
|||
|
|
2. 异常处理
|
|||
|
|
3. 边界情况
|
|||
|
|
4. 性能优化
|
|||
|
|
|
|||
|
|
### 3. 保持Java代码对照
|
|||
|
|
|
|||
|
|
**方法**:
|
|||
|
|
- 左侧打开Java源码
|
|||
|
|
- 右侧编写NestJS代码
|
|||
|
|
- 逐行对比,确保一致
|
|||
|
|
|
|||
|
|
### 4. 使用框架能力,不要重复造轮子
|
|||
|
|
|
|||
|
|
**使用框架提供的**:
|
|||
|
|
- ✅ AuthService(认证)
|
|||
|
|
- ✅ CacheService(缓存)
|
|||
|
|
- ✅ AppConfigService(配置,替代GlobalConfig)
|
|||
|
|
- ✅ JsonUtils、FileUtils(工具类)
|
|||
|
|
- ✅ HttpException系列(异常处理,替代BaseException)
|
|||
|
|
- ✅ @Public装饰器(替代SaNotCheckLogin)
|
|||
|
|
- ✅ ConfigService(配置服务,替代静态配置类)
|
|||
|
|
|
|||
|
|
**不要自创**:
|
|||
|
|
- ❌ 自定义认证逻辑(使用框架的AuthService)
|
|||
|
|
- ❌ 自定义缓存逻辑(使用框架的CacheService)
|
|||
|
|
- ❌ 自定义工具类(使用框架的工具类)
|
|||
|
|
- ❌ 自定义异常类(使用NestJS的HttpException系列)
|
|||
|
|
- ❌ 静态配置类(使用AppConfigService/ConfigService)
|
|||
|
|
- ❌ Java反射加载(使用NestJS动态模块)
|
|||
|
|
|
|||
|
|
**已删除的机械Java迁移内容**:
|
|||
|
|
- ❌ BaseException系列 → ✅ 使用HttpException/BadRequestException/UnauthorizedException等
|
|||
|
|
- ❌ GlobalConfig静态配置 → ✅ 使用AppConfigService(依赖注入)
|
|||
|
|
- ❌ SaNotCheckLogin装饰器 → ✅ 使用@Public装饰器
|
|||
|
|
- ❌ SystemLoader动态加载 → ✅ 使用NestJS动态模块(DynamicModule)
|
|||
|
|
- ❌ EnumUtils工具类 → ✅ 直接使用TypeScript枚举
|
|||
|
|
- ❌ ServletUtils工具类 → ✅ 使用@Query/@Body/@Param装饰器
|
|||
|
|
|
|||
|
|
## 📝 迁移成功标准
|
|||
|
|
|
|||
|
|
1. ✅ **编译通过**:无TypeScript编译错误
|
|||
|
|
2. ✅ **服务启动**:所有模块正确加载
|
|||
|
|
3. ✅ **API兼容**:所有接口与Java版本100%一致
|
|||
|
|
4. ✅ **数据兼容**:数据库操作100%正确
|
|||
|
|
5. ✅ **功能一致**:业务逻辑100%对齐
|
|||
|
|
|
|||
|
|
### 迁移完成标志
|
|||
|
|
|
|||
|
|
- [ ] 所有模块编译通过
|
|||
|
|
- [ ] 所有服务启动成功
|
|||
|
|
- [ ] 所有API测试通过
|
|||
|
|
- [ ] 所有数据库操作验证通过
|
|||
|
|
- [ ] 与Java版本功能100%一致
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**最后更新**:2025-01-11
|
|||
|
|
**版本**:v1.0
|
|||
|
|
**维护者**:AI Migration Team
|
|||
|
|
|
|||
|
|
### 3. 保持Java代码对照
|
|||
|
|
|
|||
|
|
**方法**:
|
|||
|
|
- 左侧打开Java源码
|
|||
|
|
- 右侧编写NestJS代码
|
|||
|
|
- 逐行对比,确保一致
|
|||
|
|
|
|||
|
|
### 4. 使用框架能力,不要重复造轮子
|
|||
|
|
|
|||
|
|
**使用框架提供的**:
|
|||
|
|
- ✅ AuthService(认证)
|
|||
|
|
- ✅ CacheService(缓存)
|
|||
|
|
- ✅ AppConfigService(配置,替代GlobalConfig)
|
|||
|
|
- ✅ JsonUtils、FileUtils(工具类)
|
|||
|
|
- ✅ HttpException系列(异常处理,替代BaseException)
|
|||
|
|
- ✅ @Public装饰器(替代SaNotCheckLogin)
|
|||
|
|
- ✅ ConfigService(配置服务,替代静态配置类)
|
|||
|
|
|
|||
|
|
**不要自创**:
|
|||
|
|
- ❌ 自定义认证逻辑(使用框架的AuthService)
|
|||
|
|
- ❌ 自定义缓存逻辑(使用框架的CacheService)
|
|||
|
|
- ❌ 自定义工具类(使用框架的工具类)
|
|||
|
|
- ❌ 自定义异常类(使用NestJS的HttpException系列)
|
|||
|
|
- ❌ 静态配置类(使用AppConfigService/ConfigService)
|
|||
|
|
- ❌ Java反射加载(使用NestJS动态模块)
|
|||
|
|
|
|||
|
|
**已删除的机械Java迁移内容**:
|
|||
|
|
- ❌ BaseException系列 → ✅ 使用HttpException/BadRequestException/UnauthorizedException等
|
|||
|
|
- ❌ GlobalConfig静态配置 → ✅ 使用AppConfigService(依赖注入)
|
|||
|
|
- ❌ SaNotCheckLogin装饰器 → ✅ 使用@Public装饰器
|
|||
|
|
- ❌ SystemLoader动态加载 → ✅ 使用NestJS动态模块(DynamicModule)
|
|||
|
|
- ❌ EnumUtils工具类 → ✅ 直接使用TypeScript枚举
|
|||
|
|
- ❌ ServletUtils工具类 → ✅ 使用@Query/@Body/@Param装饰器
|
|||
|
|
|
|||
|
|
## 📝 迁移成功标准
|
|||
|
|
|
|||
|
|
1. ✅ **编译通过**:无TypeScript编译错误
|
|||
|
|
2. ✅ **服务启动**:所有模块正确加载
|
|||
|
|
3. ✅ **API兼容**:所有接口与Java版本100%一致
|
|||
|
|
4. ✅ **数据兼容**:数据库操作100%正确
|
|||
|
|
5. ✅ **功能一致**:业务逻辑100%对齐
|
|||
|
|
|
|||
|
|
### 迁移完成标志
|
|||
|
|
|
|||
|
|
- [ ] 所有模块编译通过
|
|||
|
|
- [ ] 所有服务启动成功
|
|||
|
|
- [ ] 所有API测试通过
|
|||
|
|
- [ ] 所有数据库操作验证通过
|
|||
|
|
- [ ] 与Java版本功能100%一致
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**最后更新**:2025-01-11
|
|||
|
|
**版本**:v1.0
|
|||
|
|
**维护者**:AI Migration Team
|
|||
|
|
|