diff --git a/ruoyi-admin/src/test/java/org/dromara/test/MavenModuleRefactorTest.java b/ruoyi-admin/src/test/java/org/dromara/test/MavenModuleRefactorTest.java
new file mode 100644
index 000000000..635cd6ea1
--- /dev/null
+++ b/ruoyi-admin/src/test/java/org/dromara/test/MavenModuleRefactorTest.java
@@ -0,0 +1,2276 @@
+package org.dromara.test;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.io.*;
+import java.nio.charset.Charset;
+
+import java.nio.file.*;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.Comparator;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+/**
+ * Maven模块重构工具
+ * 基于Maven项目结构自动分析和重构,输出到指定目录
+ *
+ * 使用说明:
+ * 1. 修改 refactor-config.properties 配置文件
+ * 2. 运行 refactorMavenModules() 方法执行重构
+ *
+ * @author whj
+ */
+@DisplayName("Maven模块重构工具")
+public class MavenModuleRefactorTest {
+
+ // 配置文件路径
+ private static final String CONFIG_FILE = "refactor-config.properties";
+
+ // 配置属性
+ private Properties config;
+
+ // 项目内部模块信息缓存
+ private final Set internalPackages = new HashSet<>();
+ private final Set internalArtifacts = new HashSet<>();
+ private final Map artifactToPackageMap = new HashMap<>();
+
+ // 排除的依赖包缓存
+ private final Set excludePackages = new HashSet<>();
+
+ // 跨平台配置缓存
+ private String pathSeparator;
+ private String lineSeparator;
+ private String fileEncoding;
+
+ /**
+ * 加载配置文件
+ */
+ private void loadConfig() {
+ config = new Properties();
+ try (InputStream input = getClass().getClassLoader().getResourceAsStream(CONFIG_FILE)) {
+ if (input == null) {
+ throw new RuntimeException("无法找到配置文件: " + CONFIG_FILE);
+ }
+ config.load(input);
+ System.out.println("配置文件加载成功: " + CONFIG_FILE);
+
+ // 初始化跨平台配置
+ initializeCrossPlatformConfig();
+
+ // 加载排除依赖配置
+ loadExcludePackages();
+
+ } catch (IOException e) {
+ throw new RuntimeException("加载配置文件失败: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * 获取配置值
+ */
+ private String getConfig(String key) {
+ return config.getProperty(key);
+ }
+
+ /**
+ * 获取布尔配置值
+ */
+ private boolean getBooleanConfig(String key) {
+ return Boolean.parseBoolean(config.getProperty(key, "false"));
+ }
+
+ /**
+ * 初始化跨平台配置
+ */
+ private void initializeCrossPlatformConfig() {
+ // 路径分隔符配置
+ String pathSepStrategy = getConfig("path.separator.strategy");
+ if ("auto".equals(pathSepStrategy) || pathSepStrategy == null) {
+ this.pathSeparator = File.separator;
+ } else if ("unix".equals(pathSepStrategy)) {
+ this.pathSeparator = "/";
+ } else if ("windows".equals(pathSepStrategy)) {
+ this.pathSeparator = "\\";
+ } else {
+ this.pathSeparator = File.separator;
+ }
+
+ // 文件编码配置
+ this.fileEncoding = getConfig("file.encoding");
+ if (this.fileEncoding == null || this.fileEncoding.trim().isEmpty()) {
+ this.fileEncoding = "UTF-8";
+ }
+
+ // 换行符配置
+ String lineSepStrategy = getConfig("line.separator.strategy");
+ if ("auto".equals(lineSepStrategy) || lineSepStrategy == null) {
+ this.lineSeparator = System.lineSeparator();
+ } else if ("unix".equals(lineSepStrategy)) {
+ this.lineSeparator = "\n";
+ } else if ("windows".equals(lineSepStrategy)) {
+ this.lineSeparator = "\r\n";
+ } else {
+ this.lineSeparator = System.lineSeparator();
+ }
+
+ System.out.println("跨平台配置初始化完成:");
+ System.out.println(" 路径分隔符: " + this.pathSeparator);
+ System.out.println(" 文件编码: " + this.fileEncoding);
+ System.out.println(" 换行符: " + (this.lineSeparator.equals("\n") ? "LF" : "CRLF"));
+ }
+
+ /**
+ * 加载排除依赖配置
+ */
+ private void loadExcludePackages() {
+ excludePackages.clear();
+
+ // 加载排除的依赖包配置
+ String excludeConfig = getConfig("exclude.packages");
+ if (excludeConfig != null && !excludeConfig.trim().isEmpty()) {
+ String[] packages = excludeConfig.split(",");
+ for (String pkg : packages) {
+ String trimmedPkg = pkg.trim();
+ if (!trimmedPkg.isEmpty()) {
+ excludePackages.add(trimmedPkg);
+ System.out.println(" 排除依赖: " + trimmedPkg);
+ }
+ }
+ }
+
+ System.out.println("排除依赖配置加载完成,共 " + excludePackages.size() + " 个排除规则");
+ }
+
+ @Test
+ @DisplayName("Maven模块重构")
+ public void refactorMavenModules() {
+ try {
+ // 加载配置
+ loadConfig();
+
+ System.out.println("开始Maven模块重构...");
+
+ // 验证配置
+ validateConfig();
+
+ // 分析项目依赖关系
+ analyzeProjectDependencies();
+
+ // 执行重构renamePackageDirectories
+ executeRefactoring();
+
+ System.out.println("\n=== 重构完成!===");
+ System.out.println("重构后的项目位于: " + getConfig("output.project.root"));
+ System.out.println("请在新目录中验证项目是否正常工作");
+
+ } catch (Exception e) {
+ System.err.println("重构过程中出现错误: " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+
+
+ /**
+ * 验证配置
+ */
+ private void validateConfig() {
+ String sourceRoot = getConfig("source.project.root");
+ String outputRoot = getConfig("output.project.root");
+ String oldGroupId = getConfig("old.groupId");
+ String newGroupId = getConfig("new.groupId");
+
+ if (sourceRoot == null || sourceRoot.trim().isEmpty()) {
+ throw new RuntimeException("source.project.root 配置不能为空");
+ }
+
+ if (outputRoot == null || outputRoot.trim().isEmpty()) {
+ throw new RuntimeException("output.project.root 配置不能为空");
+ }
+
+ if (!Files.exists(Paths.get(sourceRoot))) {
+ throw new RuntimeException("源项目目录不存在: " + sourceRoot);
+ }
+
+ if (oldGroupId == null || oldGroupId.trim().isEmpty()) {
+ throw new RuntimeException("old.groupId 配置不能为空");
+ }
+
+ if (newGroupId == null || newGroupId.trim().isEmpty()) {
+ throw new RuntimeException("new.groupId 配置不能为空");
+ }
+
+ if (oldGroupId.equals(newGroupId)) {
+ throw new RuntimeException("新旧GroupId不能相同");
+ }
+
+ System.out.println("配置验证通过");
+ }
+
+ /**
+ * 分析项目依赖关系
+ */
+ private void analyzeProjectDependencies() {
+ try {
+ System.out.println("\n=== 分析项目依赖关系 ===");
+
+ // 清空缓存
+ internalPackages.clear();
+ internalArtifacts.clear();
+ artifactToPackageMap.clear();
+
+ // 收集所有pom.xml文件
+ List pomFiles = collectPomFiles();
+ System.out.println("找到 " + pomFiles.size() + " 个pom.xml文件");
+
+ // 分析每个pom文件
+ for (Path pomFile : pomFiles) {
+ analyzePomFile(pomFile);
+ }
+
+ // 如果没有分析出内部包,进行额外的包扫描
+ if (internalPackages.isEmpty()) {
+ System.out.println("未从POM文件分析出内部包,开始扫描Java源码...");
+ scanJavaSourcesForInternalPackages();
+ }
+
+ System.out.println("分析完成:");
+ System.out.println("- 内部模块: " + internalArtifacts.size() + " 个");
+ System.out.println("- 内部包前缀: " + internalPackages.size() + " 个");
+ if (!internalPackages.isEmpty()) {
+ System.out.println("- 内部包列表: " + internalPackages);
+ }
+
+ } catch (Exception e) {
+ System.err.println("依赖分析失败: " + e.getMessage());
+ throw new RuntimeException("依赖分析失败", e);
+ }
+ }
+
+ /**
+ * 执行重构
+ */
+ private void executeRefactoring() throws IOException {
+ String sourceRoot = getConfig("source.project.root");
+ String outputRoot = getConfig("output.project.root");
+
+ Path sourcePath = Paths.get(sourceRoot);
+ Path outputPath = Paths.get(outputRoot);
+
+ // 创建输出目录
+ if (Files.exists(outputPath)) {
+ System.out.println("输出目录已存在,将清空: " + outputPath);
+ deleteDirectory(outputPath);
+ }
+ Files.createDirectories(outputPath);
+
+ // 复制项目到输出目录
+ System.out.println("\n=== 复制项目到输出目录 ===");
+ copyProject(sourcePath, outputPath);
+
+ // 修改输出目录中的文件
+ System.out.println("\n=== 修改项目文件 ===");
+ modifyProjectInOutputDirectory(outputPath);
+ }
+
+ /**
+ * 复制项目到输出目录
+ */
+ private void copyProject(Path source, Path target) throws IOException {
+ Set excludeDirs = getExcludeDirectories();
+ Set excludeFiles = getExcludeFiles();
+
+ Files.walkFileTree(source, new SimpleFileVisitor() {
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+ // 添加空值检查,防止根目录导致的空指针异常
+ Path fileName = dir.getFileName();
+ if (fileName != null) {
+ String dirName = fileName.toString();
+ if (excludeDirs.contains(dirName)) {
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+ }
+
+ Path targetDir = target.resolve(source.relativize(dir));
+ Files.createDirectories(targetDir);
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+ // 添加空值检查,防止特殊文件导致的空指针异常
+ Path fileName = file.getFileName();
+ if (fileName == null) {
+ return FileVisitResult.CONTINUE;
+ }
+
+ String fileNameStr = fileName.toString();
+
+ // 检查是否为排除文件
+ if (shouldExcludeFile(fileNameStr, excludeFiles)) {
+ System.out.println("跳过排除文件: " + fileNameStr);
+ return FileVisitResult.CONTINUE;
+ }
+
+ Path targetFile = target.resolve(source.relativize(file));
+ Files.copy(file, targetFile, StandardCopyOption.REPLACE_EXISTING);
+ return FileVisitResult.CONTINUE;
+ }
+ });
+
+ System.out.println("项目复制完成");
+ }
+
+ /**
+ * 修改输出目录中的项目文件
+ */
+ private void modifyProjectInOutputDirectory(Path projectRoot) throws IOException {
+ // 1. 修改所有pom.xml文件
+ List pomFiles = collectPomFilesInDirectory(projectRoot);
+ System.out.println("修改 " + pomFiles.size() + " 个pom.xml文件");
+ modifyPomFiles(pomFiles);
+
+ // 2. 修改聚合POM文件中的modules引用
+ System.out.println("修改聚合POM文件中的modules引用...");
+ modifyAggregatorPomModules(pomFiles);
+
+ // 3. 修改所有Java源文件
+ List javaFiles = collectJavaFilesInDirectory(projectRoot);
+ System.out.println("修改 " + javaFiles.size() + " 个Java文件");
+ modifyJavaFiles(javaFiles);
+
+ // 4. 修改配置文件
+ List configFiles = collectConfigFilesInDirectory(projectRoot);
+ System.out.println("修改Spring Boot配置文件...");
+ modifyConfigFiles(configFiles);
+
+ // 5. 重命名目录结构
+ System.out.println("重命名目录结构");
+ renameDirectoryStructure(projectRoot);
+
+ // 6. 清理旧的包目录结构
+ System.out.println("清理旧的包目录结构...");
+ cleanupOldPackageDirectories(projectRoot);
+
+ // 7. 多轮清理空目录
+ if (getBooleanConfig("cleanup.empty.directories")) {
+ System.out.println("开始多轮清理空目录...");
+
+ // 进行多轮清理,确保彻底清除空目录
+ for (int round = 1; round <= 3; round++) {
+ System.out.println("第 " + round + " 轮清理空目录...");
+ int deletedCount = cleanupEmptyDirectories(projectRoot);
+
+ if (deletedCount == 0) {
+ System.out.println("第 " + round + " 轮未发现空目录,清理完成");
+ break;
+ }
+ }
+
+ // 额外清理可能遗留的空包目录结构
+ System.out.println("清理遗留的空包目录结构...");
+ cleanupEmptyPackageStructure(projectRoot);
+ }
+ }
+
+ /**
+ * 收集pom.xml文件
+ */
+ private List collectPomFiles() throws IOException {
+ return collectPomFilesInDirectory(Paths.get(getConfig("source.project.root")));
+ }
+
+ /**
+ * 在指定目录收集pom.xml文件
+ */
+ private List collectPomFilesInDirectory(Path rootPath) throws IOException {
+ List pomFiles = new ArrayList<>();
+ Set excludeDirs = getExcludeDirectories();
+
+ Files.walkFileTree(rootPath, new SimpleFileVisitor() {
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
+ // 添加空值检查,防止根目录导致的空指针异常
+ Path fileName = dir.getFileName();
+ if (fileName != null) {
+ String dirName = fileName.toString();
+ if (excludeDirs.contains(dirName)) {
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+ }
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+ // 添加空值检查,防止特殊文件导致的空指针异常
+ Path fileName = file.getFileName();
+ if (fileName != null && fileName.toString().equals("pom.xml")) {
+ pomFiles.add(file);
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ });
+
+ return pomFiles;
+ }
+
+ /**
+ * 在指定目录收集Java文件
+ */
+ private List collectJavaFilesInDirectory(Path rootPath) throws IOException {
+ List javaFiles = new ArrayList<>();
+ Set excludeDirs = getExcludeDirectories();
+ Set excludeFiles = getExcludeFiles();
+
+ Files.walkFileTree(rootPath, new SimpleFileVisitor() {
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
+ // 添加空值检查,防止根目录导致的空指针异常
+ Path fileName = dir.getFileName();
+ if (fileName != null) {
+ String dirName = fileName.toString();
+ if (excludeDirs.contains(dirName)) {
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+ }
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+ // 添加空值检查,防止特殊文件导致的空指针异常
+ Path fileName = file.getFileName();
+ if (fileName != null) {
+ String fileNameStr = fileName.toString();
+
+ // 检查文件是否在排除列表中
+ if (shouldExcludeFile(fileNameStr, excludeFiles)) {
+ return FileVisitResult.CONTINUE;
+ }
+
+ if (fileNameStr.endsWith(".java")) {
+ javaFiles.add(file);
+ }
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ });
+
+ return javaFiles;
+ }
+
+ /**
+ * 收集配置文件
+ */
+ private List collectConfigFilesInDirectory(Path directory) throws IOException {
+ List configFiles = new ArrayList<>();
+ Set excludeDirs = getExcludeDirectories();
+ Set excludeFiles = getExcludeFiles();
+
+ Files.walkFileTree(directory, new SimpleFileVisitor() {
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
+ // 添加空值检查,防止根目录导致的空指针异常
+ Path fileName = dir.getFileName();
+ if (fileName != null) {
+ String dirName = fileName.toString();
+ if (excludeDirs.contains(dirName)) {
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+ }
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+ // 添加空值检查,防止特殊文件导致的空指针异常
+ Path fileName = file.getFileName();
+ if (fileName == null) {
+ return FileVisitResult.CONTINUE;
+ }
+
+ String fileNameStr = fileName.toString();
+ String filePath = file.toString();
+
+ // 检查文件是否在排除列表中
+ if (shouldExcludeFile(fileNameStr, excludeFiles)) {
+ return FileVisitResult.CONTINUE;
+ }
+
+ // 收集Spring Boot自动配置文件和其他需要处理包名的文件
+ if (fileNameStr.equals("org.springframework.boot.autoconfigure.AutoConfiguration.imports") ||
+ fileNameStr.equals("spring.factories") ||
+ fileNameStr.equals("application.yml") ||
+ fileNameStr.equals("application.yaml") ||
+ fileNameStr.equals("application.properties") ||
+ fileNameStr.equals("bootstrap.yml") ||
+ fileNameStr.equals("bootstrap.yaml") ||
+ fileNameStr.equals("bootstrap.properties") ||
+ fileNameStr.endsWith(".vm") || // 添加Velocity模板文件
+ fileNameStr.endsWith(".json") || // 添加JSON文件
+ fileNameStr.endsWith(".xml") || // 添加XML文件(除了pom.xml)
+ fileNameStr.endsWith(".ftl") || // 添加FreeMarker模板文件
+ fileNameStr.endsWith(".sql") || // 添加SQL文件
+ filePath.contains("META-INF") && (fileNameStr.endsWith(".imports") || fileNameStr.endsWith(".factories"))) {
+ // 排除pom.xml文件,因为它们有专门的处理方法
+ if (!fileNameStr.equals("pom.xml")) {
+ configFiles.add(file);
+ }
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ });
+
+ return configFiles;
+ }
+
+ /**
+ * 分析单个pom文件
+ */
+ private void analyzePomFile(Path pomFile) {
+ try {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Document doc = builder.parse(pomFile.toFile());
+ doc.getDocumentElement().normalize();
+
+ // 获取当前模块的groupId和artifactId
+ String groupId = getElementText(doc, "groupId");
+ String artifactId = getElementText(doc, "artifactId");
+
+ // 如果当前模块没有groupId,尝试从parent获取
+ if (groupId == null || groupId.trim().isEmpty()) {
+ Element parent = getFirstElement(doc, "parent");
+ if (parent != null) {
+ groupId = getElementText(parent, "groupId");
+ }
+ }
+
+ if (groupId != null && artifactId != null) {
+ // 检查是否是项目内部模块
+ String oldGroupId = getConfig("old.groupId");
+ String oldArtifactPrefix = getConfig("old.artifactPrefix");
+
+ if (groupId.equals(oldGroupId) ||
+ (oldArtifactPrefix != null && artifactId.startsWith(oldArtifactPrefix))) {
+
+ internalArtifacts.add(artifactId);
+
+ // 推断包名
+ String packageName = inferPackageName(pomFile, groupId, artifactId);
+ if (packageName != null) {
+ internalPackages.add(packageName);
+ artifactToPackageMap.put(artifactId, packageName);
+ }
+ }
+ }
+
+ } catch (Exception e) {
+ System.err.println("解析pom文件失败: " + pomFile + ", 错误: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 推断模块的包名
+ */
+ private String inferPackageName(Path pomFile, String groupId, String artifactId) {
+ try {
+ // 查找src/main/java目录
+ Path moduleDir = pomFile.getParent();
+ Path srcMainJava = moduleDir.resolve("src" + getPathSeparator() + "main" + getPathSeparator() + "java");
+
+ Set foundPackages = new HashSet<>();
+
+ if (Files.exists(srcMainJava)) {
+ // 查找所有Java文件并分析其包声明
+ Files.walk(srcMainJava)
+ .filter(path -> path.toString().endsWith(".java"))
+ .limit(10) // 限制扫描文件数量,提高性能
+ .forEach(javaFile -> {
+ String packageName = extractPackageFromJavaFile(javaFile);
+ if (packageName != null && packageName.startsWith(groupId)) {
+ foundPackages.add(packageName);
+ }
+ });
+
+ // 如果找到了包,返回最短的包名(通常是根包)
+ if (!foundPackages.isEmpty()) {
+ return foundPackages.stream()
+ .min(Comparator.comparing(String::length))
+ .orElse(groupId);
+ }
+ }
+
+ // 如果找不到Java文件,使用groupId作为包名
+ return groupId;
+
+ } catch (Exception e) {
+ System.err.println("推断包名失败: " + pomFile + ", 错误: " + e.getMessage());
+ return groupId;
+ }
+ }
+
+ /**
+ * 扫描Java源码以识别内部包
+ * 当POM文件分析无法识别内部包时使用此方法
+ */
+ private void scanJavaSourcesForInternalPackages() {
+ try {
+ Path sourceRoot = Paths.get(getConfig("source.project.root"));
+ String oldPackagePrefix = getConfig("old.packagePrefix");
+ Set foundPackages = new HashSet<>();
+
+ // 查找所有Java源码目录
+ Files.walkFileTree(sourceRoot, new SimpleFileVisitor() {
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
+ // 添加空值检查,防止根目录导致的空指针异常
+ Path fileName = dir.getFileName();
+ if (fileName != null) {
+ String dirName = fileName.toString();
+ Set excludeDirs = getExcludeDirectories();
+ if (excludeDirs.contains(dirName)) {
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+ }
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+ if (file.toString().endsWith(".java")) {
+ String packageName = extractPackageFromJavaFile(file);
+ if (packageName != null && packageName.startsWith(oldPackagePrefix)) {
+ // 提取包的根前缀
+ String[] parts = packageName.split("\\.");
+ if (parts.length >= 3) {
+ // 通常取前3段作为基础包名,如 com.ruoyi.xxx
+ String basePackage = String.join(".", Arrays.copyOf(parts, Math.min(3, parts.length)));
+ foundPackages.add(basePackage);
+ } else {
+ foundPackages.add(packageName);
+ }
+ }
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ });
+
+ // 将找到的包添加到内部包集合中
+ internalPackages.addAll(foundPackages);
+
+ System.out.println("从Java源码扫描到 " + foundPackages.size() + " 个内部包前缀: " + foundPackages);
+
+ } catch (Exception e) {
+ System.err.println("扫描Java源码失败: " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * 从Java文件中提取包名
+ */
+ private String extractPackageFromJavaFile(Path javaFile) {
+ try {
+ String content = Files.readString(javaFile, Charset.forName(getFileEncoding()));
+ Pattern pattern = Pattern.compile("package\\s+([a-zA-Z0-9_.]+)\\s*;");
+ Matcher matcher = pattern.matcher(content);
+ if (matcher.find()) {
+ return matcher.group(1);
+ }
+ } catch (Exception e) {
+ // 忽略错误
+ }
+ return null;
+ }
+
+ /**
+ * 修改pom文件
+ */
+ private void modifyPomFiles(List pomFiles) {
+ String oldGroupId = getConfig("old.groupId");
+ String newGroupId = getConfig("new.groupId");
+ String oldArtifactPrefix = getConfig("old.artifactPrefix");
+ String newArtifactPrefix = getConfig("new.artifactPrefix");
+
+ int modifiedCount = 0;
+
+ for (Path pomFile : pomFiles) {
+ try {
+ String content = Files.readString(pomFile, Charset.forName(getFileEncoding()));
+ String originalContent = content;
+ String modifiedContent = content;
+
+ // 修改groupId
+ modifiedContent = modifiedContent.replaceAll(
+ "" + Pattern.quote(oldGroupId) + "",
+ "" + newGroupId + ""
+ );
+
+ // 修改artifactId中的前缀
+ if (oldArtifactPrefix != null && newArtifactPrefix != null) {
+ Pattern artifactPattern = Pattern.compile("(" + Pattern.quote(oldArtifactPrefix) + "[^<]*)");
+ Matcher artifactMatcher = artifactPattern.matcher(modifiedContent);
+ StringBuffer sb = new StringBuffer();
+
+ while (artifactMatcher.find()) {
+ String oldArtifactId = artifactMatcher.group(1);
+ String newArtifactId = oldArtifactId.replace(oldArtifactPrefix, newArtifactPrefix);
+ artifactMatcher.appendReplacement(sb, "" + newArtifactId + "");
+ }
+ artifactMatcher.appendTail(sb);
+ modifiedContent = sb.toString();
+
+ // 修改依赖中的artifactId前缀
+ modifiedContent = modifiedContent.replaceAll(
+ "" + Pattern.quote(oldArtifactPrefix),
+ "" + newArtifactPrefix
+ );
+ }
+
+ // 只有内容发生变化时才写回文件
+ if (!originalContent.equals(modifiedContent)) {
+ Files.writeString(pomFile, modifiedContent, Charset.forName(getFileEncoding()));
+ modifiedCount++;
+ }
+
+ } catch (IOException e) {
+ System.err.println("修改pom文件失败: " + pomFile + ", 错误: " + e.getMessage());
+ }
+ }
+
+ System.out.println("POM文件修改完成,共修改了 " + modifiedCount + " 个文件");
+ }
+
+ /**
+ * 修改Java文件
+ */
+ private void modifyJavaFiles(List javaFiles) {
+ String oldPackagePrefix = getConfig("old.packagePrefix");
+ String newPackagePrefix = getConfig("new.packagePrefix");
+
+ int modifiedCount = 0;
+
+ for (Path javaFile : javaFiles) {
+ try {
+ String content = Files.readString(javaFile, Charset.forName(getFileEncoding()));
+ String originalContent = content;
+ String modifiedContent = modifyJavaFileIntelligently(content, oldPackagePrefix, newPackagePrefix);
+
+ // 如果内容有变化,写回文件
+ if (!originalContent.equals(modifiedContent)) {
+ Files.writeString(javaFile, modifiedContent, Charset.forName(getFileEncoding()));
+ modifiedCount++;
+ }
+
+ } catch (IOException e) {
+ System.err.println("修改Java文件失败: " + javaFile + ", 错误: " + e.getMessage());
+ }
+ }
+
+ System.out.println("Java文件修改完成,共修改了 " + modifiedCount + " 个文件");
+ }
+
+ /**
+ * 修改配置文件
+ */
+ private void modifyConfigFiles(List configFiles) {
+ String oldPackagePrefix = getConfig("old.packagePrefix");
+ String newPackagePrefix = getConfig("new.packagePrefix");
+ String oldGroupId = getConfig("old.groupId");
+ String newGroupId = getConfig("new.groupId");
+ String oldArtifactPrefix = getConfig("old.artifactPrefix");
+ String newArtifactPrefix = getConfig("new.artifactPrefix");
+
+ int modifiedCount = 0;
+
+ for (Path configFile : configFiles) {
+ try {
+ String content = Files.readString(configFile, Charset.forName(getFileEncoding()));
+ String originalContent = content;
+ String modifiedContent = content;
+
+ // 修改包名引用
+ if (oldPackagePrefix != null && newPackagePrefix != null) {
+ // 修改包名,只修改项目内部包
+ modifiedContent = modifyConfigPackageReferences(modifiedContent, oldPackagePrefix, newPackagePrefix);
+ }
+
+ // 修改groupId引用
+ if (oldGroupId != null && newGroupId != null) {
+ modifiedContent = modifiedContent.replace(oldGroupId, newGroupId);
+ }
+
+ // 修改artifactId引用
+ if (oldArtifactPrefix != null && newArtifactPrefix != null) {
+ modifiedContent = modifiedContent.replaceAll(oldArtifactPrefix + "([a-zA-Z0-9-]*)", newArtifactPrefix + "$1");
+ }
+
+ // 如果内容有变化,写回文件
+ if (!originalContent.equals(modifiedContent)) {
+ Files.writeString(configFile, modifiedContent, Charset.forName(getFileEncoding()));
+ modifiedCount++;
+ System.out.println(" 修改配置文件: " + configFile.getFileName());
+ }
+
+ } catch (IOException e) {
+ System.err.println("修改配置文件失败: " + configFile + ", 错误: " + e.getMessage());
+ }
+ }
+
+ System.out.println("配置文件修改完成,共修改了 " + modifiedCount + " 个文件");
+ }
+
+ /**
+ * 修改配置文件中的包名引用
+ */
+ private String modifyConfigPackageReferences(String content, String oldPackagePrefix, String newPackagePrefix) {
+ String[] lines = content.split("\n");
+ StringBuilder result = new StringBuilder();
+
+ for (String line : lines) {
+ String trimmedLine = line.trim();
+ String modifiedLine = line;
+
+ // 处理Spring Boot自动配置文件中的类名
+ if (trimmedLine.startsWith(oldPackagePrefix) && isInternalPackage(trimmedLine)) {
+ modifiedLine = applyGlobalPackageReplacementToLine(line, oldPackagePrefix, newPackagePrefix);
+ }
+ // 处理包含包名的行
+ else if (trimmedLine.contains(oldPackagePrefix)) {
+ // 对于配置文件,检查是否是包名配置
+ if (isPackageConfiguration(trimmedLine, oldPackagePrefix)) {
+ modifiedLine = applyGlobalPackageReplacementToLine(line, oldPackagePrefix, newPackagePrefix);
+ }
+ // 对于其他文件类型(如.vm、.json、.xml等),直接应用包名映射
+ else {
+ modifiedLine = applyPackageMappingToLine(line, oldPackagePrefix, newPackagePrefix);
+ }
+ }
+
+ result.append(modifiedLine);
+ if (!modifiedLine.equals(lines[lines.length - 1])) {
+ result.append("\n");
+ }
+ }
+
+ return result.toString();
+ }
+
+ /**
+ * 判断是否是包名配置
+ */
+ /**
+ * 对单行内容应用包名映射
+ */
+ private String applyPackageMappingToLine(String line, String oldPackagePrefix, String newPackagePrefix) {
+ String modifiedLine = line;
+
+ // 使用正则表达式匹配所有包名
+ Pattern packagePattern = Pattern.compile("\\b" + Pattern.quote(oldPackagePrefix) + "(?:\\.[a-zA-Z_][a-zA-Z0-9_]*)*\\b");
+ Matcher matcher = packagePattern.matcher(modifiedLine);
+ StringBuffer sb = new StringBuffer();
+
+ while (matcher.find()) {
+ String foundPackage = matcher.group();
+ boolean shouldExclude = false;
+
+ // 检查是否应该排除这个包名
+ for (String excludePackage : excludePackages) {
+ if (foundPackage.equals(excludePackage) || foundPackage.startsWith(excludePackage + ".")) {
+ shouldExclude = true;
+ break;
+ }
+ }
+
+ if (shouldExclude) {
+ // 保持原样,不替换
+ matcher.appendReplacement(sb, Matcher.quoteReplacement(foundPackage));
+ } else if (isInternalPackage(foundPackage)) {
+ // 应用通用前缀替换
+ String newPackage = foundPackage.replace(oldPackagePrefix, newPackagePrefix);
+ matcher.appendReplacement(sb, Matcher.quoteReplacement(newPackage));
+ } else {
+ matcher.appendReplacement(sb, Matcher.quoteReplacement(foundPackage));
+ }
+ }
+ matcher.appendTail(sb);
+
+ return sb.toString();
+ }
+
+ private boolean isPackageConfiguration(String line, String packagePrefix) {
+ String trimmed = line.trim();
+
+ // 跳过注释行(支持多种注释格式)
+ if (trimmed.startsWith("#") || trimmed.startsWith("//") ||
+ trimmed.startsWith("/*") || trimmed.startsWith("