主要修改: 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接口正常响应
349 lines
11 KiB
JavaScript
349 lines
11 KiB
JavaScript
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;
|