Files
wwjcloud-nest-v1/wwjcloud-nest-v1/docs/逐层手写迁移指南.md

11 KiB
Raw Blame History

逐层手写迁移指南

🎯 核心思路

清理机械Java迁移 → 优先使用NestJS特性 → 逐层手写对齐 → 完成迁移

通过逐层手写确保每个文件都与Java版本100%对齐同时充分利用NestJS v11框架特性。


📊 当前状态

控制器层Controllers

  • 总数109个文件
  • 待对齐63个文件包含TODO199个TODO标记
  • 已完成约46个文件基本完成

服务层Services

  • 总数161个文件
  • 待对齐107个文件包含TODO690个TODO标记
  • 已完成约54个文件基本完成

🔄 迁移策略

策略选择:先Service后Controller

原因

  1. Service层是业务逻辑核心Controller只负责调用
  2. Service对齐后Controller只需要调整参数传递和返回值包装
  3. 避免在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准备工作

  1. 打开Java源码

    左侧Java ServiceImpl源码
    右侧NestJS ServiceImpl文件
    
  2. 确认依赖注入

    // 检查需要的依赖是否已注入
    constructor(
      @InjectRepository(Entity) private readonly repository: Repository<Entity>,
      private readonly appConfig: AppConfigService,
      // ... 其他依赖
    ) {}
    
  3. 确认工具类使用

    // 使用框架提供的工具类,不要自己写
    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准备工作

  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 - 核心服务(必须优先完成)

  1. services/admin/auth/* - 认证服务
  2. services/admin/user/* - 用户服务
  3. services/admin/site/* - 站点服务
  4. 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 - 核心控制器

  1. controllers/adminapi/login/* - 登录
  2. controllers/adminapi/auth/* - 认证
  3. 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/* - 前台支付


完成标准

单个文件完成标准

  1. 编译通过无TypeScript编译错误
  2. 无TODO所有TODO标记已实现
  3. 对齐验证与Java版本逐行对比逻辑一致
  4. 框架特性使用NestJS原生特性不使用已删除的机械Java迁移内容

模块完成标准

  1. 所有Service文件对齐完成
  2. 所有Controller文件对齐完成
  3. API测试通过:所有接口返回正确响应
  4. 功能验证与Java版本功能100%一致

整体完成标准

  1. 所有109个Controller文件对齐完成
  2. 所有161个Service文件对齐完成
  3. 编译通过无TypeScript编译错误
  4. 服务启动:所有模块正确加载
  5. API兼容所有接口与Java版本100%一致

🚀 开始迁移

第一步:选择一个模块

建议从P0优先级开始,例如:

  • services/admin/auth/*
  • controllers/adminapi/login/*

第二步:逐文件对齐

  1. 选择一个Service文件
  2. 打开对应的Java源码
  3. 逐方法对齐
  4. 使用检查清单验证
  5. 完成后标记

第三步:测试验证

  1. 编译项目:npm run build
  2. 启动服务:docker-compose up -d
  3. 测试接口使用Postman或curl测试
  4. 对比结果与Java版本响应对比

📌 注意事项

  1. 不要跳过依赖如果Service依赖其他Service先对齐依赖的Service
  2. 保持原样Java的VO/Param/DTO保持原样不要添加Dto后缀
  3. 使用框架:优先使用@wwjBoot提供的工具类和服务
  4. 异常统一统一使用HttpException系列不要使用BaseException
  5. 配置注入使用AppConfigService不要使用GlobalConfig
  6. 逐行对比确保业务逻辑与Java版本100%一致

最后更新2025-01-11
版本v1.0