feat: 创建Java→V1框架全局映射器

This commit is contained in:
wanwu
2025-10-29 15:12:22 +08:00
parent 7a259e5138
commit 7e6cf74808
4 changed files with 622 additions and 101 deletions

View File

@@ -0,0 +1,258 @@
# Java → wwjcloud-boot 能力映射表
> 本文档定义Java常用工具类/API与wwjcloud-boot框架能力的映射关系
>
> **核心原则**: 不改业务逻辑只替换Java写法为V1框架写法
## 📦 工具类映射
### 1. JSON处理
| Java | wwjcloud-boot | 导入路径 | 说明 |
|------|---------------|---------|------|
| `JSONUtil.parseObj(str)` | `JSON.parse(str)` | 原生JS | 解析JSON字符串 |
| `JSONUtil.toJsonStr(obj)` | `JSON.stringify(obj)` | 原生JS | 对象转JSON字符串 |
| `JSONUtil.toBean(json, Class)` | `Object.assign(new Class(), json)` | 原生JS | JSON转对象 |
| `JSONObject` | `Record<string, any>` | 原生TS | JSON对象类型 |
| `JsonLoadUtils.loadJsonString(file, name)` | `JSON.parse(fs.readFileSync(path.join(file, name), 'utf-8'))` | `fs`, `path` | 读取JSON文件 |
### 2. 字符串工具
| Java | wwjcloud-boot | 导入路径 | 说明 |
|------|---------------|---------|------|
| `StringUtils.isEmpty(str)` | `StringUtils.isEmpty(str)` | `@wwjBoot` | 字符串为空判断 |
| `StringUtils.isNotEmpty(str)` | `StringUtils.isNotEmpty(str)` | `@wwjBoot` | 字符串非空判断 |
| `StringUtils.isBlank(str)` | `StringUtils.isEmpty(str)` | `@wwjBoot` | 同isEmpty |
| `String.equals(str)` | `=== str` | 原生JS | 字符串相等 |
| `String.equalsIgnoreCase(str)` | `.toLowerCase() === str.toLowerCase()` | 原生JS | 忽略大小写相等 |
| `String.contains(str)` | `.includes(str)` | 原生JS | 包含字符串 |
### 3. 集合工具
| Java | wwjcloud-boot | 导入路径 | 说明 |
|------|---------------|---------|------|
| `CollectionUtil.isEmpty(list)` | `StringUtils.isEmptyArray(list)` | `@wwjBoot` | 数组为空判断 |
| `CollectionUtil.isNotEmpty(list)` | `StringUtils.isNotEmptyArray(list)` | `@wwjBoot` | 数组非空判断 |
| `list.add(item)` | `list.push(item)` | 原生JS | 添加元素 |
| `list.size()` | `list.length` | 原生JS | 数组长度 |
| `list.isEmpty()` | `list.length === 0` | 原生JS | 数组为空 |
### 4. 对象工具
| Java | wwjcloud-boot | 导入路径 | 说明 |
|------|---------------|---------|------|
| `ObjectUtil.isEmpty(obj)` | `!obj` | 原生JS | 对象为空 |
| `ObjectUtil.isNotEmpty(obj)` | `!!obj` | 原生JS | 对象非空 |
| `BeanUtils.copyProperties(src, dest)` | `Object.assign(dest, src)` | 原生JS | 属性复制 |
### 5. 文件工具
| Java | wwjcloud-boot | 导入路径 | 说明 |
|------|---------------|---------|------|
| `Files.list(Paths.get(dir))` | `fs.readdirSync(dir)` | `fs` | 列出目录 |
| `Paths.get(path)` | `path.join(path)` | `path` | 路径拼接 |
| `file.exists()` | `fs.existsSync(file)` | `fs` | 文件是否存在 |
| `file.isDirectory()` | `fs.statSync(file).isDirectory()` | `fs` | 是否目录 |
| `file.getName()` | `path.basename(file)` | `path` | 文件名 |
| `file.listFiles()` | `fs.readdirSync(file)` | `fs` | 列出文件 |
| `FileUtils.cleanDirectory(dir)` | `fs.rmSync(dir, { recursive: true, force: true })` | `fs` | 清空目录 |
| `FileUtils.copyFile(src, dest)` | `fs.copyFileSync(src, dest)` | `fs` | 复制文件 |
| `FileUtils.deleteDirectory(dir)` | `fs.rmSync(dir, { recursive: true, force: true })` | `fs` | 删除目录 |
| `FileUtils.readFileToString(file)` | `fs.readFileSync(file, 'utf-8')` | `fs` | 读取文件 |
| `FileUtils.writeStringToFile(file, data)` | `fs.writeFileSync(file, data, 'utf-8')` | `fs` | 写入文件 |
### 6. Stream API
| Java | wwjcloud-boot | 导入路径 | 说明 |
|------|---------------|---------|------|
| `list.stream()` | `list` | 原生JS | 数组本身支持map/filter |
| `.filter(predicate)` | `.filter(predicate)` | 原生JS | 过滤 |
| `.map(mapper)` | `.map(mapper)` | 原生JS | 映射 |
| `.collect(Collectors.toList())` | 无需操作 | 原生JS | 数组方法返回数组 |
| `Collectors.toList()` | 无需操作 | 原生JS | 删除即可 |
### 7. 断言工具
| Java | wwjcloud-boot | 导入路径 | 说明 |
|------|---------------|---------|------|
| `Assert.notNull(obj, msg)` | `if (!obj) throw new BadRequestException(msg)` | `@nestjs/common` | 非空断言 |
| `Assert.isTrue(condition, msg)` | `if (!condition) throw new BadRequestException(msg)` | `@nestjs/common` | 条件断言 |
### 8. 系统工具
| Java | wwjcloud-boot | 导入路径 | 说明 |
|------|---------------|---------|------|
| `System.out.println(msg)` | `console.log(msg)` | 原生JS | 控制台输出 |
| `System.err.println(msg)` | `console.error(msg)` | 原生JS | 错误输出 |
| `System.currentTimeMillis()` | `Date.now()` | 原生JS | 当前时间戳(毫秒) |
| `System.currentTimeMillis() / 1000` | `Math.floor(Date.now() / 1000)` | 原生JS | 当前时间戳(秒) |
### 9. 异常处理
| Java | wwjcloud-boot | 导入路径 | 说明 |
|------|---------------|---------|------|
| `throw new CommonException(msg)` | `throw new BadRequestException(msg)` | `@nestjs/common` | 业务异常 |
| `throw new AuthException(msg)` | `throw new UnauthorizedException(msg)` | `@nestjs/common` | 认证异常 |
| `catch (Exception e)` | `catch (e)` | 原生JS | 捕获异常 |
| `catch (IOException e)` | `catch (e)` | 原生JS | 捕获异常 |
| `e.getMessage()` | `e.message` | 原生JS | 异常消息 |
| `e.printStackTrace()` | `console.error(e)` | 原生JS | 打印堆栈 |
### 10. 日期时间
| Java | wwjcloud-boot | 导入路径 | 说明 |
|------|---------------|---------|------|
| `LocalDateTime.now()` | `new Date()` | 原生JS | 当前时间 |
| `LocalDate.now()` | `new Date()` | 原生JS | 当前日期 |
| `Date` | `Date` | 原生JS | 日期类型 |
| `Timestamp` | `Date` | 原生JS | 时间戳类型 |
## 🗄️ MyBatis → TypeORM 映射
### 1. 查询构造器
| Java (MyBatis) | wwjcloud-boot (TypeORM) | 说明 |
|----------------|------------------------|------|
| `QueryWrapper<Entity>` | `查询条件对象` | 需要转换为TypeORM查询 |
| `new QueryWrapper<>()` | `{}` | 初始化为空对象 |
| `.eq("field", value)` | `{ field: value }` | 等于条件 |
| `.like("field", value)` | `{ field: Like(\`%${value}%\`) }` | 模糊查询 |
| `.in("field", list)` | `{ field: In(list) }` | IN查询 |
### 2. 分页查询
| Java (MyBatis) | wwjcloud-boot (TypeORM) | 说明 |
|----------------|------------------------|------|
| `IPage<Entity>` | `[Entity[], number]` | 分页结果 |
| `new Page<>(page, limit)` | `{ skip: (page-1)*limit, take: limit }` | 分页参数 |
| `mapper.selectPage(page, wrapper)` | `repository.findAndCount({ where, skip, take })` | 分页查询 |
| `iPage.getTotal()` | `total` | 总数 |
| `iPage.getRecords()` | `records` | 记录列表 |
### 3. Mapper方法
| Java (MyBatis) | wwjcloud-boot (TypeORM) | 说明 |
|----------------|------------------------|------|
| `mapper.selectOne(wrapper)` | `repository.findOne({ where })` | 查询单条 |
| `mapper.selectList(wrapper)` | `repository.find({ where })` | 查询列表 |
| `mapper.insert(entity)` | `repository.save(entity)` | 插入 |
| `mapper.updateById(entity)` | `repository.save(entity)` | 更新 |
| `mapper.deleteById(id)` | `repository.delete(id)` | 删除 |
| `mapper.delete(wrapper)` | `repository.delete({ where })` | 条件删除 |
| `mapper.selectCount(wrapper)` | `repository.count({ where })` | 计数 |
## 🎯 特殊业务工具映射
### Java特有工具 → Core层实现
以下Java工具是业务特定的需要在Core层实现或标记TODO
| Java工具 | 处理方式 | 说明 |
|---------|---------|------|
| `ImageUtils.imageToBase64()` | TODO | 图片转Base64需Core层实现 |
| `AddonInstallJavaTools` | TODO | 插件安装工具需Core层实现 |
| `LocalMavenTools` | TODO | Maven工具需Core层实现 |
| `niucloudService` | 注入Service | 业务Service通过DI注入 |
| `coreAddonService` | 注入Service | 业务Service通过DI注入 |
## 🔄 转换示例
### 示例1: 文件操作
**Java代码**:
```java
String addonPath = WebAppEnvs.get().webRootDownAddon + addon + "/";
if (!Files.exists(Paths.get(addonPath))) {
throw new CommonException("插件不存在");
}
FileUtils.cleanDirectory(addonPath);
```
**V1代码**:
```typescript
const addonPath = this.appConfig.webRootDownAddon + addon + "/";
if (!fs.existsSync(addonPath)) {
throw new BadRequestException("插件不存在");
}
fs.rmSync(addonPath, { recursive: true, force: true });
```
### 示例2: JSON操作
**Java代码**:
```java
JSONObject info = JSONUtil.parseObj(JsonLoadUtils.loadJsonString(file, "info.json"));
AddonInfo addonInfo = JSONUtil.toBean(info, AddonInfo.class);
```
**V1代码**:
```typescript
const info = JSON.parse(fs.readFileSync(path.join(file, "info.json"), 'utf-8'));
const addonInfo = Object.assign(new AddonInfo(), info);
```
### 示例3: 集合操作
**Java代码**:
```java
List<String> localAddons = Files.list(Paths.get(addonPath))
.filter(file -> file.isDirectory())
.map(file -> file.getName())
.collect(Collectors.toList());
if (CollectionUtil.isNotEmpty(searchParam.getSearch()) && list.size() > 0) {
list = list.stream()
.filter(item -> item.getTitle().contains(searchParam.getSearch()))
.collect(Collectors.toList());
}
```
**V1代码**:
```typescript
const localAddons = fs.readdirSync(addonPath)
.filter(file => fs.statSync(path.join(addonPath, file)).isDirectory());
if (StringUtils.isNotEmpty(searchParam.getSearch()) && list.length > 0) {
list = list.filter(item => item.getTitle().includes(searchParam.getSearch()));
}
```
### 示例4: MyBatis查询
**Java代码**:
```java
QueryWrapper<AddonLog> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("site_id", siteId);
IPage<AddonLog> iPage = addonLogMapper.selectPage(
new Page<>(page, limit),
queryWrapper
);
return PageResult.build(page, limit, iPage.getTotal()).setData(iPage.getRecords());
```
**V1代码**:
```typescript
const [records, total] = await this.addonLogRepository.findAndCount({
where: { siteId },
skip: (page - 1) * limit,
take: limit
});
return PageResult.build(page, limit, total).setData(records);
```
## 📌 转换优先级
1. **原生JS/TS能力** (最高优先级)
2. **wwjcloud-boot工具类**
3. **NestJS内置功能**
4. **TypeORM API**
5. **Core层业务实现** (最低优先级标记TODO)
---
**更新日期**: 2025-01-XX
**维护者**: Migration Tool Team

View File

@@ -0,0 +1,300 @@
/**
* Java → wwjcloud-boot V1框架 全局映射器
*
* 核心原则不改业务逻辑只替换Java写法为V1框架写法
*
* 参考文档JAVA_TO_BOOT_MAPPING.md
*/
class JavaToV1Mapper {
constructor() {
this.bootImports = new Set();
this.nodeModules = new Set();
this.typeormImports = new Set();
this.nestjsImports = new Set();
}
/**
* 核心转换方法
*/
convert(javaCode) {
let tsCode = javaCode;
// 执行转换(按依赖顺序)
tsCode = this.convertTypes(tsCode);
tsCode = this.convertMyBatis(tsCode);
tsCode = this.convertJavaUtils(tsCode);
tsCode = this.convertStreamAPI(tsCode);
tsCode = this.convertExceptions(tsCode);
tsCode = this.convertSystemCalls(tsCode);
return tsCode;
}
/**
* 1. 类型转换
*/
convertTypes(code) {
let result = code;
// 基础类型
result = result.replace(/\bInteger\b/g, 'number');
result = result.replace(/\bLong\b/g, 'number');
result = result.replace(/\bDouble\b/g, 'number');
result = result.replace(/\bFloat\b/g, 'number');
result = result.replace(/\bBoolean\b/g, 'boolean');
// 集合类型
result = result.replace(/List<([^>]+)>/g, '$1[]');
result = result.replace(/ArrayList<([^>]+)>/g, '$1[]');
result = result.replace(/LinkedList<([^>]+)>/g, '$1[]');
result = result.replace(/Set<([^>]+)>/g, '$1[]');
result = result.replace(/HashSet<([^>]+)>/g, '$1[]');
result = result.replace(/Map<([^,]+),\s*([^>]+)>/g, 'Record<$1, $2>');
result = result.replace(/HashMap<([^,]+),\s*([^>]+)>/g, 'Record<$1, $2>');
// JSON类型
result = result.replace(/\bJSONObject\b/g, 'Record<string, any>');
// 日期类型
result = result.replace(/\bLocalDateTime\b/g, 'Date');
result = result.replace(/\bLocalDate\b/g, 'Date');
result = result.replace(/\bTimestamp\b/g, 'Date');
// ID类型
result = result.replace(/\bId\b/g, 'number');
return result;
}
/**
* 2. MyBatis → TypeORM
*/
convertMyBatis(code) {
let result = code;
// QueryWrapper
result = result.replace(/QueryWrapper<[^>]+>\s*/g, '');
result = result.replace(/new\s+QueryWrapper<[^>]*>\(\)/g, '{}');
// Page/IPage
result = result.replace(/IPage<[^>]+>\s*/g, '');
result = result.replace(/new\s+Page<[^>]*>\([^)]+\)/g, '{ /* pagination */ }');
// Mapper调用 → Repository调用
// xxxMapper.selectOne() → this.xxxRepository.findOne()
result = result.replace(/(\w+)Mapper\.selectOne\(/g, 'this.$1Repository.findOne(');
result = result.replace(/(\w+)Mapper\.selectList\(/g, 'this.$1Repository.find(');
result = result.replace(/(\w+)Mapper\.selectPage\(/g, 'this.$1Repository.findAndCount(');
result = result.replace(/(\w+)Mapper\.insert\(/g, 'this.$1Repository.save(');
result = result.replace(/(\w+)Mapper\.updateById\(/g, 'this.$1Repository.save(');
result = result.replace(/(\w+)Mapper\.deleteById\(/g, 'this.$1Repository.delete(');
result = result.replace(/(\w+)Mapper\.delete\(/g, 'this.$1Repository.delete(');
result = result.replace(/(\w+)Mapper\.selectCount\(/g, 'this.$1Repository.count(');
// PageResult保持不变来自@wwjBoot
// iPage.getTotal() → total
result = result.replace(/(\w+)\.getTotal\(\)/g, 'total');
result = result.replace(/(\w+)\.getRecords\(\)/g, 'records');
this.bootImports.add('PageResult');
return result;
}
/**
* 3. Java工具类 → V1框架工具类
*/
convertJavaUtils(code) {
let result = code;
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【JSON工具】
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// JSONUtil.parseObj() → JSON.parse()
result = result.replace(/JSONUtil\.parseObj\(/g, 'JSON.parse(');
// JSONUtil.toJsonStr() → JSON.stringify()
result = result.replace(/JSONUtil\.toJsonStr\(/g, 'JSON.stringify(');
// JSONUtil.toBean(json, Class.class) → Object.assign(new Class(), json)
result = result.replace(/JSONUtil\.toBean\(([^,]+),\s*(\w+)\.class\)/g, 'Object.assign(new $2(), $1)');
// JsonLoadUtils.loadJsonString(file, name) → JSON.parse(fs.readFileSync(path.join(file, name), 'utf-8'))
if (result.includes('JsonLoadUtils.loadJsonString')) {
result = result.replace(/JsonLoadUtils\.loadJsonString\(([^,]+),\s*([^)]+)\)/g,
'JSON.parse(fs.readFileSync(path.join($1, $2), \'utf-8\'))');
this.nodeModules.add('fs');
this.nodeModules.add('path');
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【Bean工具】
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// BeanUtils.copyProperties() → Object.assign()
result = result.replace(/BeanUtils\.copyProperties\(([^,]+),\s*([^)]+)\)/g, 'Object.assign($2, $1)');
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【断言工具】
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Assert.notNull(obj, msg) → if (!obj) throw new BadRequestException(msg)
result = result.replace(/Assert\.notNull\(([^,]+),\s*([^)]+)\);?/g,
'if (!$1) throw new BadRequestException($2);');
// Assert.isTrue(condition, msg) → if (!condition) throw new BadRequestException(msg)
result = result.replace(/Assert\.isTrue\(([^,]+),\s*([^)]+)\);?/g,
'if (!($1)) throw new BadRequestException($2);');
this.nestjsImports.add('BadRequestException');
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【文件工具】(已在file.converter.js中处理)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Files.list(Paths.get()) → fs.readdirSync()
if (result.includes('Files.list(Paths.get(')) {
result = result.replace(/Files\.list\(Paths\.get\(([^)]+)\)\)/g, 'fs.readdirSync($1)');
this.nodeModules.add('fs');
}
// Paths.get() → path.join()
result = result.replace(/Paths\.get\(/g, 'path.join(');
if (result.includes('path.join')) {
this.nodeModules.add('path');
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【对象工具】
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// ObjectUtil.isEmpty() → !obj
result = result.replace(/ObjectUtil\.isEmpty\(([^)]+)\)/g, '!$1');
// ObjectUtil.isNotEmpty() → !!obj
result = result.replace(/ObjectUtil\.isNotEmpty\(([^)]+)\)/g, '!!$1');
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【字符串工具】保留StringUtils from wwjBoot
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// StringUtils保持不变已在string.converter.js中处理
if (result.includes('StringUtils.')) {
this.bootImports.add('StringUtils');
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【集合工具】保留StringUtils from wwjBoot
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// CollectionUtil转换为StringUtils (已在collection.converter.js中处理)
// CollectionUtil.isEmpty() → StringUtils.isEmptyArray()
// CollectionUtil.isNotEmpty() → StringUtils.isNotEmptyArray()
return result;
}
/**
* 4. Stream API → 数组方法
*/
convertStreamAPI(code) {
let result = code;
// list.stream() → 移除
result = result.replace(/\.stream\(\)/g, '');
// .collect(Collectors.toList()) → 移除
result = result.replace(/\.collect\(Collectors\.toList\(\)\)/g, '');
// .filter() / .map() 保持不变JS原生支持
// list.add() → list.push()
result = result.replace(/(\w+)\.add\(/g, '$1.push(');
// list.size() → list.length
result = result.replace(/(\w+)\.size\(\)/g, '$1.length');
// list.isEmpty() → list.length === 0
result = result.replace(/(\w+)\.isEmpty\(\)/g, '$1.length === 0');
// !list.isEmpty() → list.length > 0
result = result.replace(/!(\w+)\.length === 0/g, '$1.length > 0');
return result;
}
/**
* 5. 异常处理
*/
convertExceptions(code) {
let result = code;
// throw new CommonException() → throw new BadRequestException()
result = result.replace(/throw new CommonException\(/g, 'throw new BadRequestException(');
// throw new AuthException() → throw new UnauthorizedException()
result = result.replace(/throw new AuthException\(/g, 'throw new UnauthorizedException(');
// catch (Exception e) → catch (e)
// catch (IOException e) → catch (e)
result = result.replace(/catch\s*\(\s*\w+Exception\s+(\w+)\s*\)/g, 'catch ($1)');
// e.getMessage() → e.message
result = result.replace(/(\w+)\.getMessage\(\)/g, '$1.message');
// e.printStackTrace() → console.error(e)
result = result.replace(/(\w+)\.printStackTrace\(\);?/g, 'console.error($1);');
this.nestjsImports.add('BadRequestException');
this.nestjsImports.add('UnauthorizedException');
return result;
}
/**
* 6. 系统调用
*/
convertSystemCalls(code) {
let result = code;
// System.out.println() → console.log()
result = result.replace(/System\.out\.println\(/g, 'console.log(');
// System.err.println() → console.error()
result = result.replace(/System\.err\.println\(/g, 'console.error(');
// System.currentTimeMillis() / 1000 → Math.floor(Date.now() / 1000)
result = result.replace(/System\.currentTimeMillis\(\)\s*\/\s*1000/g, 'Math.floor(Date.now() / 1000)');
// System.currentTimeMillis() → Date.now()
result = result.replace(/System\.currentTimeMillis\(\)/g, 'Date.now()');
return result;
}
/**
* 获取所有需要导入的模块
*/
getImports() {
return {
boot: Array.from(this.bootImports),
typeorm: Array.from(this.typeormImports),
nestjs: Array.from(this.nestjsImports),
nodeModules: Array.from(this.nodeModules)
};
}
/**
* 重置imports
*/
resetImports() {
this.bootImports.clear();
this.nodeModules.clear();
this.typeormImports.clear();
this.nestjsImports.clear();
}
}
module.exports = JavaToV1Mapper;

View File

@@ -1,7 +1,9 @@
/**
* QueryWrapper转换器
*
* MyBatis QueryWrapper → TypeORM QueryBuilder
* MyBatis QueryWrapper → 移除(TypeORM直接使用where对象
*
* 策略QueryWrapper是MyBatis的查询构造器在TypeORM中直接使用where条件对象即可
*/
class QueryWrapperConverter {
/**
@@ -10,19 +12,33 @@ class QueryWrapperConverter {
convert(javaCode) {
let tsCode = javaCode;
// 1. new QueryWrapper<Entity>() → 需要转换为TypeORM查询
// 暂时标记为TODO因为需要更复杂的上下文
tsCode = tsCode.replace(/new\s+QueryWrapper<(\w+)>\(\)/g, '/* TODO: TypeORM Query for $1 */{}');
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【策略】直接移除QueryWrapper相关代码简化为where条件
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 2. queryWrapper.eq("field", value) → TODO
tsCode = tsCode.replace(/(\w+)\.eq\(([^,]+),\s*([^)]+)\)/g, '/* TODO: .where("$2 = :value", { value: $3 }) */$1');
// 1. 移除QueryWrapper类型声明
// QueryWrapper<Entity> → 删除
tsCode = tsCode.replace(/QueryWrapper<[^>]+>\s*/g, '');
// 3. queryWrapper.like("field", value) → TODO
tsCode = tsCode.replace(/(\w+)\.like\(([^,]+),\s*([^)]+)\)/g, '/* TODO: .where("$2 LIKE :value", { value: `%${$3}%` }) */$1');
// 2. 移除new QueryWrapper<>()
// new QueryWrapper<>() → {}
// new QueryWrapper<Entity>() → {}
tsCode = tsCode.replace(/new\s+QueryWrapper<[^>]*>\(\)/g, '{}');
// 3. 简化链式调用
// queryWrapper.eq("field", value) → 保留但简化处理
// 实际在mapper.converter.js中会将整个查询转换为TypeORM findOne/find
return tsCode;
}
/**
* 分析需要的imports
*/
analyzeImports(tsCode) {
// QueryWrapper不需要额外import
return [];
}
}
module.exports = QueryWrapperConverter;

View File

@@ -10,49 +10,29 @@
* 4. 分析需要的imports
*/
// 导入各个转换器
const BasicSyntaxConverter = require('./syntax/basic-syntax.converter');
const TypeConverter = require('./syntax/type.converter');
const ExceptionConverter = require('./syntax/exception.converter');
// 导入全局映射器(新)
const JavaToV1Mapper = require('./java-to-v1-mapper');
// 导入各个转换器(保留用于特定场景)
const BasicSyntaxConverter = require('./syntax/basic-syntax.converter');
const ConfigConverter = require('./utils/config.converter');
const FileConverter = require('./utils/file.converter');
const StringConverter = require('./utils/string.converter');
const CollectionConverter = require('./utils/collection.converter');
const JsonConverter = require('./utils/json.converter');
const ObjectConverter = require('./utils/object.converter');
const QueryWrapperConverter = require('./mybatis/query-wrapper.converter');
const MapperConverter = require('./mybatis/mapper.converter');
const PaginationConverter = require('./mybatis/pagination.converter');
const GetterSetterConverter = require('./method/getter-setter.converter');
const MethodCallConverter = require('./method/method-call.converter');
const StreamApiConverter = require('./method/stream-api.converter');
const PostProcessor = require('./post-processor');
class ServiceMethodConverter {
constructor() {
// 初始化所有转换器
this.basicSyntax = new BasicSyntaxConverter();
this.type = new TypeConverter();
this.exception = new ExceptionConverter();
// 初始化全局映射器(优先使用)
this.v1Mapper = new JavaToV1Mapper();
// 初始化特定转换器(用于特殊场景)
this.basicSyntax = new BasicSyntaxConverter();
this.config = new ConfigConverter();
this.file = new FileConverter();
this.string = new StringConverter();
this.collection = new CollectionConverter();
this.json = new JsonConverter();
this.object = new ObjectConverter();
this.queryWrapper = new QueryWrapperConverter();
this.mapper = new MapperConverter();
this.pagination = new PaginationConverter();
this.getterSetter = new GetterSetterConverter();
this.methodCall = new MethodCallConverter();
this.streamApi = new StreamApiConverter();
this.postProcessor = new PostProcessor();
}
@@ -72,52 +52,26 @@ class ServiceMethodConverter {
let tsBody = javaMethodBody;
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【阶段1】基础语法转换
// 【核心转换】使用全局映射器Java → V1框架
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
tsBody = this.basicSyntax.convert(tsBody);
this.v1Mapper.resetImports();
tsBody = this.v1Mapper.convert(tsBody);
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【阶段2】类型转换
// 【补充转换】特定场景处理
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
tsBody = this.type.convert(tsBody);
tsBody = this.basicSyntax.convert(tsBody); // Lambda、for-each等语法
tsBody = this.config.convert(tsBody); // WebAppEnvs/GlobalConfig → AppConfigService
tsBody = this.file.convert(tsBody); // 文件操作补充转换
tsBody = this.string.convert(tsBody); // String工具补充
tsBody = this.collection.convert(tsBody); // Collection工具补充
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【阶段3】工具类转换
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
tsBody = this.config.convert(tsBody);
tsBody = this.file.convert(tsBody);
tsBody = this.string.convert(tsBody);
tsBody = this.collection.convert(tsBody);
tsBody = this.json.convert(tsBody);
tsBody = this.object.convert(tsBody);
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【阶段4】MyBatis → TypeORM转换
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
tsBody = this.queryWrapper.convert(tsBody);
tsBody = this.mapper.convert(tsBody, context);
tsBody = this.pagination.convert(tsBody);
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【阶段5】方法调用转换
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
tsBody = this.streamApi.convert(tsBody);
tsBody = this.methodCall.convert(tsBody);
tsBody = this.getterSetter.convert(tsBody); // 最后转换getter/setter
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【阶段6】异常处理转换
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
tsBody = this.exception.convert(tsBody);
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【阶段7】后处理清理
// 【后处理】清理与格式化
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
tsBody = this.postProcessor.process(tsBody);
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【阶段8】添加缩进
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 添加缩进
tsBody = tsBody.split('\n').map(line => ' ' + line).join('\n');
return tsBody;
@@ -130,49 +84,42 @@ class ServiceMethodConverter {
* @returns {object} 需要导入的模块
*/
analyzeImports(convertedBody) {
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【核心】从全局映射器获取imports
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
const v1Imports = this.v1Mapper.getImports();
const imports = {
nestjs: new Set(),
boot: new Set(),
nodeModules: new Set()
nestjs: new Set(v1Imports.nestjs),
boot: new Set(v1Imports.boot),
typeorm: new Set(v1Imports.typeorm),
nodeModules: new Set(v1Imports.nodeModules)
};
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【NestJS异常】
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
const nestjsImports = this.exception.analyzeImports(convertedBody);
nestjsImports.forEach(imp => imports.nestjs.add(imp));
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【Node.js模块】
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
const nodeModules = this.file.analyzeNodeModules(convertedBody);
nodeModules.forEach(mod => imports.nodeModules.add(mod));
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【Boot层工具类】
// 【补充】从特定转换器获取额外imports
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// StringUtils
// AppConfigService (from config.converter.js)
const configImports = this.config.analyzeImports(convertedBody);
configImports.forEach(imp => imports.boot.add(imp));
// StringUtils (from string.converter.js)
const stringImports = this.string.analyzeImports(convertedBody);
stringImports.forEach(imp => imports.boot.add(imp));
// Collection判空可能需要StringUtils
// Collection utils (from collection.converter.js)
const collectionImports = this.collection.analyzeImports(convertedBody);
collectionImports.forEach(imp => imports.boot.add(imp));
// JsonUtils
const jsonImports = this.json.analyzeImports(convertedBody);
jsonImports.forEach(imp => imports.boot.add(imp));
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 【配置访问】AppConfigService (Boot层)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
const configImports = this.config.analyzeImports(convertedBody);
configImports.forEach(imp => imports.boot.add(imp));
// Node modules (from file.converter.js)
const nodeModules = this.file.analyzeNodeModules(convertedBody);
nodeModules.forEach(mod => imports.nodeModules.add(mod));
return {
nestjs: Array.from(imports.nestjs),
boot: Array.from(imports.boot),
typeorm: Array.from(imports.typeorm),
nodeModules: Array.from(imports.nodeModules)
};
}