11 KiB
逐层手写迁移指南
🎯 核心思路
清理机械Java迁移 → 优先使用NestJS特性 → 逐层手写对齐 → 完成迁移
通过逐层手写,确保每个文件都与Java版本100%对齐,同时充分利用NestJS v11框架特性。
📊 当前状态
控制器层(Controllers)
- 总数:109个文件
- 待对齐:63个文件包含TODO(199个TODO标记)
- 已完成:约46个文件基本完成
服务层(Services)
- 总数:161个文件
- 待对齐:107个文件包含TODO(690个TODO标记)
- 已完成:约54个文件基本完成
🔄 迁移策略
策略选择:先Service后Controller
原因:
- Service层是业务逻辑核心,Controller只负责调用
- Service对齐后,Controller只需要调整参数传递和返回值包装
- 避免在Controller层反复修改Service调用
执行顺序
阶段1: 清理基础层 ✅(已完成)
├─ common/enums ✅
├─ common/exception ❌(已删除,改用HttpException)
├─ common/annotation ❌(已删除,改用@Public等)
├─ common/utils ✅
├─ common/config ❌(已删除,改用AppConfigService)
└─ common/domain ✅
阶段2: Service层对齐(进行中)
├─ 优先级1:核心服务(auth、user、site)
├─ 优先级2:基础服务(sys、config、dict)
├─ 优先级3:业务服务(member、order、pay)
└─ 优先级4:扩展服务(addon、upgrade)
阶段3: Controller层对齐(待开始)
├─ 优先级1:认证相关(login、auth)
├─ 优先级2:核心功能(user、member、sys)
├─ 优先级3:业务功能(order、pay、wechat)
└─ 优先级4:扩展功能(addon、plugin)
📝 Service层对齐步骤(逐文件)
步骤1:准备工作
-
打开Java源码
左侧:Java ServiceImpl源码 右侧:NestJS ServiceImpl文件 -
确认依赖注入
// 检查需要的依赖是否已注入 constructor( @InjectRepository(Entity) private readonly repository: Repository<Entity>, private readonly appConfig: AppConfigService, // ... 其他依赖 ) {} -
确认工具类使用
// 使用框架提供的工具类,不要自己写 import { JsonUtils, FileUtils, StringUtils } from '@wwjBoot';
步骤2:逐方法对齐
2.1 对齐方法签名
// Java源码
public PageResult<MemberVo> getPage(MemberSearchParam param) {
// ...
}
// NestJS - 完全对齐
async getPage(param: MemberSearchParam): Promise<PageResult<MemberVo>> {
// 业务逻辑
}
2.2 对齐参数处理
// Java: 参数验证
if (param.pageNo == null || param.pageNo < 1) {
throw new CommonException("pageNo必须大于0");
}
// NestJS - 对齐验证逻辑,使用HttpException
if (!param.pageNo || param.pageNo < 1) {
throw new BadRequestException({ msg_key: 'error.param.page_no_invalid' });
}
2.3 对齐数据库查询
// Java: MyBatis QueryWrapper
QueryWrapper<Member> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("site_id", siteId);
queryWrapper.like("nickname", param.keyword);
// NestJS - TypeORM
const queryBuilder = this.repository.createQueryBuilder('member');
queryBuilder.where('member.siteId = :siteId', { siteId });
if (param.keyword) {
queryBuilder.andWhere('member.nickname LIKE :keyword', { keyword: `%${param.keyword}%` });
}
2.4 对齐异常处理
// Java: throw new CommonException("错误信息")
// NestJS: throw new BadRequestException({ msg_key: 'error.xxx' })
// Java: throw new AuthException("未授权")
// NestJS: throw new UnauthorizedException({ msg_key: 'error.auth.xxx' })
2.5 对齐返回值
// Java: return Result.success(data)
// NestJS: return Result.success(data)
// Java: return PageResult.build(list, total)
// NestJS: return PageResult.build(list, total)
步骤3:使用框架能力
3.1 配置访问
// ❌ 不要使用已删除的GlobalConfig
// import { GlobalConfig } from '../../common/config';
// ✅ 使用AppConfigService(依赖注入)
constructor(private readonly appConfig: AppConfigService) {}
const prefix = this.appConfig.tablePrefix;
3.2 异常处理
// ❌ 不要使用已删除的BaseException
// import { BaseException } from '../../common/exception';
// ✅ 使用NestJS的HttpException系列
import { BadRequestException, UnauthorizedException, ForbiddenException } from '@nestjs/common';
throw new BadRequestException({ msg_key: 'error.common.operation_failed' });
3.3 工具类
// ✅ 使用框架提供的工具类
import { JsonUtils, FileUtils, StringUtils, DateUtils } from '@wwjBoot';
// JSON操作
const data = JsonUtils.parse(jsonString);
const json = JsonUtils.stringify(obj);
// 字符串操作
const isEmpty = StringUtils.isEmpty(str);
const trimmed = StringUtils.trim(str);
步骤4:检查清单
每个Service方法对齐后,检查:
- 方法签名与Java完全一致
- 参数类型和验证逻辑对齐
- 数据库查询逻辑对齐
- 异常处理使用HttpException系列
- 返回值格式对齐
- 使用框架提供的工具类(不使用已删除的工具类)
- 依赖注入正确
- 没有TODO标记残留
📝 Controller层对齐步骤(逐文件)
步骤1:准备工作
- 打开Java Controller源码和对应的Service源码
左侧:Java Controller + Java ServiceImpl 右侧:NestJS Controller + NestJS ServiceImpl(已对齐)
步骤2:对齐路由和参数
2.1 路由路径对齐
// Java: @RequestMapping("/adminapi/member")
@Controller('/adminapi/member') // ✅ 路径完全一致
// Java: @GetMapping("/list")
@Get('list') // ✅ HTTP方法和路径一致
2.2 参数提取对齐
// Java: @RequestParam("pageNo") Integer pageNo
@Query('pageNo') pageNo: number // ✅ 参数名和类型一致
// Java: @PathVariable("id") Integer id
@Param('id') id: string // 注意:需要转换 Number(id)
// Java: @RequestBody MemberSaveParam param
@Body() param: MemberSaveParam // ✅ 直接使用DTO,不需要转换
2.3 权限控制对齐
// Java: @SaNotCheckLogin
@Public() // ✅ 使用@Public装饰器(已删除SaNotCheckLogin)
// Java: @Admin
@Admin() // ✅ 使用@Admin装饰器
// Java: 默认需要登录
// NestJS: 默认需要AuthGuard(已在全局注册)
步骤3:对齐方法体
// Java Controller
@GetMapping("/list")
public Result<PageResult<MemberVo>> getPage(
@RequestParam("pageNo") Integer pageNo,
@RequestParam("pageSize") Integer pageSize
) {
MemberSearchParam param = new MemberSearchParam();
param.setPageNo(pageNo);
param.setPageSize(pageSize);
PageResult<MemberVo> result = memberService.getPage(param);
return Result.success(result);
}
// NestJS Controller - 对齐后
@Get('list')
async getPage(
@Query('pageNo') pageNo: number,
@Query('pageSize') pageSize: number,
): Promise<Result<PageResult<MemberVo>>> {
const param = new MemberSearchParam();
param.pageNo = pageNo;
param.pageSize = pageSize;
const result = await this.memberService.getPage(param);
return Result.success(result);
}
步骤4:检查清单
每个Controller方法对齐后,检查:
- 路由路径与Java完全一致
- HTTP方法一致(GET/POST/PUT/DELETE)
- 参数名和类型对齐
- 参数转换正确(String → Number等)
- 调用Service方法正确
- 返回值格式对齐(Result包装)
- 权限装饰器使用正确(@Public/@Admin)
- 没有TODO标记残留
🎯 优先级排序
Service层优先级
P0 - 核心服务(必须优先完成)
services/admin/auth/*- 认证服务services/admin/user/*- 用户服务services/admin/site/*- 站点服务services/core/site/*- 核心站点服务
P1 - 基础服务
5. services/admin/sys/* - 系统服务
6. services/admin/dict/* - 字典服务
7. services/core/sys/* - 核心系统服务
P2 - 业务服务
8. services/admin/member/* - 会员服务
9. services/api/member/* - 前台会员服务
10. services/admin/pay/* - 支付服务
11. services/api/pay/* - 前台支付服务
P3 - 扩展服务
12. services/admin/addon/* - 插件服务
13. services/admin/wechat/* - 微信服务
14. services/admin/weapp/* - 小程序服务
Controller层优先级
P0 - 核心控制器
controllers/adminapi/login/*- 登录controllers/adminapi/auth/*- 认证controllers/api/login/*- 前台登录
P1 - 基础控制器
4. controllers/adminapi/sys/* - 系统管理
5. controllers/adminapi/user/* - 用户管理
6. controllers/adminapi/dict/* - 字典管理
P2 - 业务控制器
7. controllers/adminapi/member/* - 会员管理
8. controllers/adminapi/pay/* - 支付管理
9. controllers/api/member/* - 前台会员
10. controllers/api/pay/* - 前台支付
✅ 完成标准
单个文件完成标准
- 编译通过:无TypeScript编译错误
- 无TODO:所有TODO标记已实现
- 对齐验证:与Java版本逐行对比,逻辑一致
- 框架特性:使用NestJS原生特性,不使用已删除的机械Java迁移内容
模块完成标准
- 所有Service文件对齐完成
- 所有Controller文件对齐完成
- API测试通过:所有接口返回正确响应
- 功能验证:与Java版本功能100%一致
整体完成标准
- 所有109个Controller文件对齐完成
- 所有161个Service文件对齐完成
- 编译通过:无TypeScript编译错误
- 服务启动:所有模块正确加载
- API兼容:所有接口与Java版本100%一致
🚀 开始迁移
第一步:选择一个模块
建议从P0优先级开始,例如:
services/admin/auth/*controllers/adminapi/login/*
第二步:逐文件对齐
- 选择一个Service文件
- 打开对应的Java源码
- 逐方法对齐
- 使用检查清单验证
- 完成后标记
第三步:测试验证
- 编译项目:
npm run build - 启动服务:
docker-compose up -d - 测试接口:使用Postman或curl测试
- 对比结果:与Java版本响应对比
📌 注意事项
- 不要跳过依赖:如果Service依赖其他Service,先对齐依赖的Service
- 保持原样:Java的VO/Param/DTO保持原样,不要添加Dto后缀
- 使用框架:优先使用@wwjBoot提供的工具类和服务
- 异常统一:统一使用HttpException系列,不要使用BaseException
- 配置注入:使用AppConfigService,不要使用GlobalConfig
- 逐行对比:确保业务逻辑与Java版本100%一致
最后更新:2025-01-11
版本:v1.0