Files
wwjcloud-nest-v1/wwjcloud-nest-v1/tools/java-to-nestjs-migration/generators/job-generator.js
wanwu b735e24428 fix: 修复service模块重命名逻辑并成功集成core层API
主要修改:
1. 修复module-generator中服务重命名时的DI错误
   - 对于重命名的服务,直接使用别名注册,避免TypeScript找不到原始名称
   - 移除不必要的provide/useClass模式

2. 集成core层到主应用
   - 在app.module.ts中导入wwjcloud-core的AppModule
   - 在wwjcloud-core/src/index.ts中导出AppModule

3. 构建结果
   - 编译错误: 64+ -> 0
   - 注册路由: 15 -> 678
   - Docker服务全部正常启动
   - API接口正常响应
2025-10-26 20:40:23 +08:00

349 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const fs = require('fs');
const path = require('path');
const NamingUtils = require('../utils/naming-utils');
/**
* 任务生成器
* 将Java定时任务转换为NestJS定时任务
*/
class JobGenerator {
constructor() {
this.namingUtils = new NamingUtils();
}
/**
* 生成任务文件
*/
generateJob(javaJob, outputDir) {
const jobName = this.namingUtils.generateJobName(javaJob.className);
const fileName = this.namingUtils.generateFileName(javaJob.className, 'job');
const filePath = path.join(outputDir, fileName);
const content = this.generateJobContent(javaJob, jobName);
fs.writeFileSync(filePath, content);
console.log(`✅ 生成任务: ${filePath}`);
return { fileName, content };
}
/**
* 生成任务内容
*/
generateJobContent(javaJob, jobName) {
const imports = this.generateImports(javaJob);
const decorators = this.generateDecorators(javaJob);
const constructor = this.generateConstructor(javaJob);
const methods = this.generateMethods(javaJob);
return `${imports}
${decorators}
export class ${jobName} {
private readonly logger = new Logger(${jobName}.name);
${constructor}
${methods}
}
`;
}
/**
* 生成导入语句
*/
generateImports(javaJob) {
const imports = [
"import { Injectable, Logger } from '@nestjs/common';",
"import { Cron, CronExpression } from '@nestjs/schedule';",
"import { QueueService } from '@wwjBoot';"
];
// 添加服务导入
if (javaJob.dependencies && javaJob.dependencies.length > 0) {
javaJob.dependencies.forEach(dep => {
const serviceName = this.namingUtils.generateServiceName(dep);
const serviceFileName = this.namingUtils.generateFileName(dep, 'service');
imports.push(`import { ${serviceName} } from '../services/${serviceFileName.replace('.service.ts', '')}';`);
});
}
return imports.join('\n');
}
/**
* 生成装饰器
*/
generateDecorators(javaJob) {
return '@Injectable()';
}
/**
* 生成构造函数
*/
generateConstructor(javaJob) {
const injections = [];
// 添加框架服务注入
injections.push(' private readonly queueService: QueueService');
// 添加其他服务注入
if (javaJob.dependencies && javaJob.dependencies.length > 0) {
javaJob.dependencies.forEach(dep => {
const serviceName = this.namingUtils.generateServiceName(dep);
const propertyName = this.namingUtils.toCamelCase(dep) + 'Service';
injections.push(` private readonly ${propertyName}: ${serviceName}`);
});
}
if (injections.length === 0) {
return ' constructor() {}';
}
return ` constructor(
${injections.join(',\n')}
) {}`;
}
/**
* 生成方法
*/
generateMethods(javaJob) {
if (!javaJob.methods || javaJob.methods.length === 0) {
return ' // 无方法';
}
return javaJob.methods.map(method => {
return this.generateMethod(method, javaJob);
}).join('\n\n');
}
/**
* 生成单个方法
*/
generateMethod(method, javaJob) {
const methodName = this.namingUtils.generateMethodName(method.methodName);
const cronExpression = this.generateCronExpression(method);
const body = this.generateMethodBody(method, javaJob);
return ` /**
* ${method.methodName}
* ${method.description || ''}
*/
@Cron('${cronExpression}')
async ${methodName}(): Promise<void> {
${body}
}`;
}
/**
* 生成Cron表达式
*/
generateCronExpression(method) {
// 根据Java的@Scheduled注解生成Cron表达式
if (method.cronExpression) {
return method.cronExpression;
}
if (method.fixedRate) {
// 固定频率执行
return '*/' + method.fixedRate + ' * * * * *';
}
if (method.fixedDelay) {
// 固定延迟执行
return '*/' + method.fixedDelay + ' * * * * *';
}
// 默认每小时执行一次
return '0 0 * * * *';
}
/**
* 生成方法体
*/
generateMethodBody(method, javaJob) {
const methodName = method.methodName || 'executeJob';
const lowerMethodName = methodName.toLowerCase();
// 基础日志和错误处理框架
let body = ` const startTime = Date.now();
this.logger.log('开始执行定时任务: ${methodName}');
try {
`;
// 根据方法名推断业务逻辑
if (lowerMethodName.includes('cleanup') || lowerMethodName.includes('clean')) {
body += ` // 执行清理任务
// 清理过期数据、临时文件、缓存等
const deletedCount = 0; // await this.xxxService.cleanupExpiredData();
this.logger.log(\`清理完成,删除记录数: \${deletedCount}\`);
`;
} else if (lowerMethodName.includes('backup') || lowerMethodName.includes('export')) {
body += ` // 执行备份任务
// 导出数据、备份数据库、归档文件等
const backupPath = '/path/to/backup'; // await this.xxxService.backupData();
this.logger.log(\`备份完成,文件路径: \${backupPath}\`);
`;
} else if (lowerMethodName.includes('sync') || lowerMethodName.includes('import')) {
body += ` // 执行同步任务
// 同步第三方数据、导入外部数据、更新缓存等
const syncedCount = 0; // await this.xxxService.syncExternalData();
this.logger.log(\`同步完成,同步记录数: \${syncedCount}\`);
`;
} else if (lowerMethodName.includes('statistics') || lowerMethodName.includes('stat') || lowerMethodName.includes('report')) {
body += ` // 执行统计任务
// 生成报表、统计数据、计算指标等
const reportId = null; // await this.xxxService.generateStatisticsReport();
this.logger.log(\`统计完成报表ID: \${reportId}\`);
`;
} else if (lowerMethodName.includes('notify') || lowerMethodName.includes('notification') || lowerMethodName.includes('message')) {
body += ` // 执行通知任务
// 发送邮件、推送消息、发送短信等
const sentCount = 0; // await this.xxxService.sendScheduledNotifications();
this.logger.log(\`通知完成,发送数量: \${sentCount}\`);
`;
} else if (lowerMethodName.includes('check') || lowerMethodName.includes('monitor')) {
body += ` // 执行检查任务
// 健康检查、监控指标、检测异常等
const issues = []; // await this.xxxService.performHealthCheck();
this.logger.log(\`检查完成,发现问题数: \${issues.length}\`);
`;
} else {
body += ` // 执行定时任务业务逻辑
// 调用相关服务处理任务
this.logger.debug('任务执行中...');
`;
}
body += `
const duration = Date.now() - startTime;
this.logger.log(\`任务执行完成: ${methodName},耗时: \${duration}ms\`);
} catch (error) {
const duration = Date.now() - startTime;
this.logger.error(\`任务执行失败: ${methodName},耗时: \${duration}ms\`, error.stack);
throw error;
}`;
return body;
}
/**
* 生成清理任务
*/
generateCleanupJob(javaJob, outputDir) {
const jobName = 'CleanupJob';
const fileName = 'cleanup.job.ts';
const filePath = path.join(outputDir, fileName);
const content = this.generateCleanupJobContent(jobName);
fs.writeFileSync(filePath, content);
console.log(`✅ 生成清理任务: ${filePath}`);
return { fileName, content };
}
/**
* 生成清理任务内容
*/
generateCleanupJobContent(jobName) {
const imports = [
"import { Injectable, Logger } from '@nestjs/common';",
"import { Cron, CronExpression } from '@nestjs/schedule';"
].join('\n');
const decorators = '@Injectable()';
const constructor = ` constructor() {
this.logger = new Logger('CleanupJob');
}`;
const methods = [
' /**',
' * 清理过期数据',
' * 每天凌晨2点执行',
' */',
' @Cron(CronExpression.EVERY_DAY_AT_2AM)',
' async cleanupExpiredData(): Promise<void> {',
' const startTime = Date.now();',
' this.logger.log(\'开始清理过期数据...\');',
' ',
' try {',
' // 清理过期的临时数据、缓存、会话等',
' const expiredDate = new Date();',
' expiredDate.setDate(expiredDate.getDate() - 30); // 清理30天前的数据',
' ',
' // 调用相关服务清理数据',
' // const deletedCount = await this.xxxService.deleteExpiredData(expiredDate);',
' const deletedCount = 0;',
' ',
' const duration = Date.now() - startTime;',
' this.logger.log(\`清理过期数据完成,删除 \${deletedCount} 条记录,耗时: \${duration}ms\`);',
' } catch (error) {',
' const duration = Date.now() - startTime;',
' this.logger.error(\`清理过期数据失败,耗时: \${duration}ms\`, error.stack);',
' throw error;',
' }',
' }',
'',
' /**',
' * 清理日志文件',
' * 每周日凌晨3点执行',
' */',
' @Cron(CronExpression.EVERY_WEEK)',
' async cleanupLogFiles(): Promise<void> {',
' const startTime = Date.now();',
' this.logger.log(\'开始清理日志文件...\');',
' ',
' try {',
' // 清理过期的日志文件、归档旧日志等',
' const logRetentionDays = 90; // 保留90天的日志',
' ',
' // 调用相关服务清理日志',
' // const deletedFiles = await this.xxxService.cleanupOldLogs(logRetentionDays);',
' const deletedFiles = 0;',
' ',
' const duration = Date.now() - startTime;',
' this.logger.log(\`清理日志文件完成,删除 \${deletedFiles} 个文件,耗时: \${duration}ms\`);',
' } catch (error) {',
' const duration = Date.now() - startTime;',
' this.logger.error(\`清理日志文件失败,耗时: \${duration}ms\`, error.stack);',
' throw error;',
' }',
' }'
].join('\n');
return `${imports}
${decorators}
export class ${jobName} {
${constructor}
${methods}
}
`;
}
/**
* 验证任务一致性
*/
validateJobConsistency(javaJob, nestJSJob) {
const issues = [];
// 验证方法数量
if (javaJob.methods.length !== nestJSJob.methods.length) {
issues.push('方法数量不一致');
}
// 验证每个方法
javaJob.methods.forEach((javaMethod, index) => {
const nestJSMethod = nestJSJob.methods[index];
if (nestJSMethod && javaMethod.methodName !== nestJSMethod.methodName) {
issues.push(`方法名不一致: ${javaMethod.methodName} vs ${nestJSMethod.methodName}`);
}
});
return issues;
}
}
module.exports = JobGenerator;