feat: 创建Java→V1框架全局映射器
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user