diff --git a/coder-common-thin-plugins/coder-common-thin-oss/pom.xml b/coder-common-thin-plugins/coder-common-thin-oss/pom.xml index 8eb6abe..b777965 100644 --- a/coder-common-thin-plugins/coder-common-thin-oss/pom.xml +++ b/coder-common-thin-plugins/coder-common-thin-oss/pom.xml @@ -25,7 +25,12 @@ com.aliyun.oss aliyun-sdk-oss - 3.17.4 + + + + + io.minio + minio diff --git a/coder-common-thin-plugins/coder-common-thin-oss/src/main/java/org/leocoder/thin/oss/config/MinioConfig.java b/coder-common-thin-plugins/coder-common-thin-oss/src/main/java/org/leocoder/thin/oss/config/MinioConfig.java new file mode 100644 index 0000000..c005ba3 --- /dev/null +++ b/coder-common-thin-plugins/coder-common-thin-oss/src/main/java/org/leocoder/thin/oss/config/MinioConfig.java @@ -0,0 +1,71 @@ +package org.leocoder.thin.oss.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * MinIO配置类 + * + * @author Leocoder + */ +@Data +@Component +@ConfigurationProperties(prefix = "coder.minio") +public class MinioConfig { + + /** + * MinIO服务端点 + */ + private String endpoint; + + /** + * Access Key + */ + private String accessKey; + + /** + * Secret Key + */ + private String secretKey; + + /** + * 存储桶名称 + */ + private String bucketName; + + /** + * 自定义域名 + */ + private String domain; + + /** + * 路径前缀 + */ + private String pathPrefix = "coder-files"; + + /** + * 连接超时时间(毫秒) + */ + private Long connectTimeout = 10000L; + + /** + * 写入超时时间(毫秒) + */ + private Long writeTimeout = 10000L; + + /** + * 读取超时时间(毫秒) + */ + private Long readTimeout = 10000L; + + /** + * 是否启用MinIO存储 + */ + private Boolean enabled = false; + + /** + * 区域设置(可选) + */ + private String region; +} \ No newline at end of file diff --git a/coder-common-thin-plugins/coder-common-thin-oss/src/main/java/org/leocoder/thin/oss/config/OssAutoConfiguration.java b/coder-common-thin-plugins/coder-common-thin-oss/src/main/java/org/leocoder/thin/oss/config/OssAutoConfiguration.java index 5637a6d..7a7ba62 100644 --- a/coder-common-thin-plugins/coder-common-thin-oss/src/main/java/org/leocoder/thin/oss/config/OssAutoConfiguration.java +++ b/coder-common-thin-plugins/coder-common-thin-oss/src/main/java/org/leocoder/thin/oss/config/OssAutoConfiguration.java @@ -3,8 +3,10 @@ package org.leocoder.thin.oss.config; import com.aliyun.oss.ClientBuilderConfiguration; import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; +import io.minio.MinioClient; import lombok.extern.slf4j.Slf4j; import org.leocoder.thin.oss.service.LocalStorageService; +import org.leocoder.thin.oss.service.MinioStorageService; import org.leocoder.thin.oss.service.OssStorageService; import org.leocoder.thin.oss.service.StorageServiceFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -21,7 +23,7 @@ import org.springframework.core.env.Environment; * @author Leocoder */ @Configuration -@EnableConfigurationProperties(OssConfig.class) +@EnableConfigurationProperties({OssConfig.class, MinioConfig.class}) @Slf4j public class OssAutoConfiguration { @@ -101,6 +103,57 @@ public class OssAutoConfiguration { return new LocalStorageService(environment); } + /** + * @description [MinIO客户端配置] + * @author Leocoder + */ + @Bean + @ConditionalOnProperty(name = "coder.minio.enabled", havingValue = "true") + @ConditionalOnMissingBean + public MinioClient minioClient(MinioConfig minioConfig) { + log.info("初始化MinIO客户端: endpoint={}, bucketName={}", + minioConfig.getEndpoint(), minioConfig.getBucketName()); + + try { + MinioClient.Builder builder = MinioClient.builder() + .endpoint(minioConfig.getEndpoint()) + .credentials(minioConfig.getAccessKey(), minioConfig.getSecretKey()); + + // 如果配置了区域,则设置区域 + if (minioConfig.getRegion() != null && !minioConfig.getRegion().trim().isEmpty()) { + builder.region(minioConfig.getRegion()); + } + + MinioClient minioClient = builder.build(); + + // 设置超时时间 + minioClient.setTimeout( + minioConfig.getConnectTimeout(), + minioConfig.getWriteTimeout(), + minioConfig.getReadTimeout() + ); + + log.info("MinIO客户端初始化成功"); + return minioClient; + + } catch (Exception e) { + log.error("MinIO客户端初始化失败", e); + throw new RuntimeException("MinIO客户端初始化失败: " + e.getMessage()); + } + } + + /** + * @description [MinIO存储服务] + * @author Leocoder + */ + @Bean + @ConditionalOnProperty(name = "coder.minio.enabled", havingValue = "true") + @ConditionalOnMissingBean + public MinioStorageService minioStorageService(MinioClient minioClient, MinioConfig minioConfig) { + log.info("初始化MinIO存储服务"); + return new MinioStorageService(minioClient, minioConfig); + } + /** * @description [存储服务工厂(始终可用)] * @author Leocoder diff --git a/coder-common-thin-plugins/coder-common-thin-oss/src/main/java/org/leocoder/thin/oss/service/LocalStorageService.java b/coder-common-thin-plugins/coder-common-thin-oss/src/main/java/org/leocoder/thin/oss/service/LocalStorageService.java index 8e2d7e8..94cd2b9 100644 --- a/coder-common-thin-plugins/coder-common-thin-oss/src/main/java/org/leocoder/thin/oss/service/LocalStorageService.java +++ b/coder-common-thin-plugins/coder-common-thin-oss/src/main/java/org/leocoder/thin/oss/service/LocalStorageService.java @@ -50,18 +50,7 @@ public class LocalStorageService implements StorageService { // 使用现有的上传工具类 Map fileMap = UploadUtil.coderSingleFile(file, fullPath, 2); - // 生成访问URL - String fileUploadPath = (String) fileMap.get("fileUploadPath"); - String protocol = IpUtil.getProtocol(ServletUtil.getRequest()); - if (!StringUtils.hasText(protocol)) { - protocol = "http"; - } - String hostIp = IpUtil.getHostIp(ServletUtil.getRequest()); - String hostPort = StringUtils.hasText(env.getProperty("server.port")) ? - env.getProperty("server.port") : "18099"; - - String fullUrl = protocol + "://" + hostIp + ":" + hostPort + fileUploadPath; - fileMap.put("fileUploadPath", fullUrl); + // UploadUtil已经返回了正确的相对路径,不需要再次构建URL log.info("本地存储上传成功: {}", fileMap.get("filePath")); return fileMap; diff --git a/coder-common-thin-plugins/coder-common-thin-oss/src/main/java/org/leocoder/thin/oss/service/MinioStorageService.java b/coder-common-thin-plugins/coder-common-thin-oss/src/main/java/org/leocoder/thin/oss/service/MinioStorageService.java new file mode 100644 index 0000000..1bda644 --- /dev/null +++ b/coder-common-thin-plugins/coder-common-thin-oss/src/main/java/org/leocoder/thin/oss/service/MinioStorageService.java @@ -0,0 +1,229 @@ +package org.leocoder.thin.oss.service; + +import io.minio.*; +import io.minio.errors.ErrorResponseException; +import io.minio.http.Method; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.leocoder.thin.common.constants.CoderConstants; +import org.leocoder.thin.common.exception.BusinessException; +import org.leocoder.thin.common.utils.file.FileTypeUtil; +import org.leocoder.thin.oss.config.MinioConfig; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; +import org.springframework.web.multipart.MultipartFile; + +import java.util.HashMap; +import java.util.Map; + +/** + * MinIO对象存储服务实现 + * + * @author Leocoder + */ +@RequiredArgsConstructor +@Slf4j +@Service +@ConditionalOnProperty(name = "coder.minio.enabled", havingValue = "true") +public class MinioStorageService implements StorageService { + + private final MinioClient minioClient; + private final MinioConfig minioConfig; + + /** + * @description [上传文件到MinIO] + * @author Leocoder + */ + @Override + public Map uploadFile(MultipartFile file, String fileName, String folderPath) { + try { + // 确保存储桶存在 + ensureBucketExists(); + + // 构建对象名称 + String objectName = buildObjectName(folderPath, fileName); + + // 上传文件 + minioClient.putObject( + PutObjectArgs.builder() + .bucket(minioConfig.getBucketName()) + .object(objectName) + .stream(file.getInputStream(), file.getSize(), -1) + .contentType(file.getContentType()) + .build() + ); + + // 构建返回结果Map(保持与现有接口兼容) + Map fileMap = new HashMap<>(); + fileMap.put("fileName", file.getOriginalFilename()); + fileMap.put("newName", fileName); + fileMap.put("fileSize", FileTypeUtil.getFileSize(file)); + fileMap.put("suffixName", FileTypeUtil.getFileType(file.getOriginalFilename())); + // MinIO对象名,用于删除操作 + fileMap.put("filePath", objectName); + // 完整的访问URL + fileMap.put("fileUploadPath", getFileUrl(objectName)); + + log.info("MinIO文件上传成功: {}", fileName); + return fileMap; + + } catch (Exception e) { + log.error("MinIO文件上传失败", e); + throw new BusinessException(500, "文件上传失败: " + e.getMessage()); + } + } + + /** + * @description [从MinIO删除文件] + * @author Leocoder + */ + @Override + public boolean deleteFile(String objectName) { + try { + if (!StringUtils.hasText(objectName)) { + log.warn("MinIO对象名为空,跳过删除"); + return true; + } + + log.info("MinIO删除文件: {}", objectName); + minioClient.removeObject( + RemoveObjectArgs.builder() + .bucket(minioConfig.getBucketName()) + .object(objectName) + .build() + ); + + log.info("MinIO删除成功: {}", objectName); + return true; + + } catch (Exception e) { + log.error("MinIO文件删除失败: {}", objectName, e); + return false; + } + } + + /** + * @description [获取文件访问URL] + * @author Leocoder + */ + @Override + public String getFileUrl(String objectName) { + if (!StringUtils.hasText(objectName)) { + return ""; + } + + try { + // 如果配置了自定义域名,构建直接访问URL + if (StringUtils.hasText(minioConfig.getDomain())) { + String cleanDomain = minioConfig.getDomain().replaceAll("/$", ""); + String cleanObjectName = objectName.startsWith("/") ? objectName.substring(1) : objectName; + String directUrl = cleanDomain + "/" + minioConfig.getBucketName() + "/" + cleanObjectName; + return directUrl; + } + + // 如果没有自定义域名,使用MinIO的预签名URL(有效期24小时) + String presignedUrl = minioClient.getPresignedObjectUrl( + GetPresignedObjectUrlArgs.builder() + .method(Method.GET) + .bucket(minioConfig.getBucketName()) + .object(objectName) + .expiry(24 * 60 * 60) + .build() + ); + return presignedUrl; + + } catch (Exception e) { + log.error("生成MinIO文件访问URL失败: {}", objectName, e); + return ""; + } + } + + /** + * @description [检查文件是否存在] + * @author Leocoder + */ + @Override + public boolean fileExists(String objectName) { + try { + if (!StringUtils.hasText(objectName)) { + return false; + } + + minioClient.statObject( + StatObjectArgs.builder() + .bucket(minioConfig.getBucketName()) + .object(objectName) + .build() + ); + return true; + + } catch (ErrorResponseException e) { + if ("NoSuchKey".equals(e.errorResponse().code())) { + return false; + } + log.error("检查MinIO文件是否存在失败: {}", objectName, e); + return false; + } catch (Exception e) { + log.error("检查MinIO文件是否存在失败: {}", objectName, e); + return false; + } + } + + /** + * @description [获取存储服务类型] + * @author Leocoder + */ + @Override + public String getStorageType() { + // MinIO存储对应数据库中的"2" + return CoderConstants.TWO_STRING; + } + + /** + * @description [构建MinIO对象名称] + * @author Leocoder + */ + private String buildObjectName(String folderPath, String fileName) { + StringBuilder nameBuilder = new StringBuilder(); + + // 添加路径前缀 + if (StringUtils.hasText(minioConfig.getPathPrefix())) { + nameBuilder.append(minioConfig.getPathPrefix()).append("/"); + } + + // 添加文件夹路径 + if (StringUtils.hasText(folderPath)) { + // 确保路径以/结尾 + String normalizedPath = folderPath.endsWith("/") ? folderPath : folderPath + "/"; + nameBuilder.append(normalizedPath); + } + + // 添加文件名 + nameBuilder.append(fileName); + + return nameBuilder.toString(); + } + + /** + * @description [确保存储桶存在] + * @author Leocoder + */ + private void ensureBucketExists() throws Exception { + boolean bucketExists = minioClient.bucketExists( + BucketExistsArgs.builder() + .bucket(minioConfig.getBucketName()) + .build() + ); + + if (!bucketExists) { + log.info("创建MinIO存储桶: {}", minioConfig.getBucketName()); + minioClient.makeBucket( + MakeBucketArgs.builder() + .bucket(minioConfig.getBucketName()) + .region(minioConfig.getRegion()) + .build() + ); + } + } +} \ No newline at end of file diff --git a/coder-common-thin-plugins/coder-common-thin-oss/src/main/java/org/leocoder/thin/oss/service/StorageServiceFactory.java b/coder-common-thin-plugins/coder-common-thin-oss/src/main/java/org/leocoder/thin/oss/service/StorageServiceFactory.java index 381b8ed..d90edfb 100644 --- a/coder-common-thin-plugins/coder-common-thin-oss/src/main/java/org/leocoder/thin/oss/service/StorageServiceFactory.java +++ b/coder-common-thin-plugins/coder-common-thin-oss/src/main/java/org/leocoder/thin/oss/service/StorageServiceFactory.java @@ -48,20 +48,26 @@ public class StorageServiceFactory { } /** - * @description [获取默认存储服务(OSS优先,如果不可用则使用本地存储)] + * @description [获取默认存储服务(MinIO优先,然后OSS,最后本地存储)] * @author Leocoder */ public StorageService getDefaultStorageService() { try { - // 优先尝试获取OSS服务 - return getStorageService("oss"); + // 优先尝试获取MinIO服务 + return getStorageService("minio"); } catch (Exception e) { - log.warn("OSS服务不可用,使用本地存储作为降级方案", e); + log.warn("MinIO服务不可用,尝试OSS服务", e); try { - return getStorageService("local"); + // 尝试获取OSS服务 + return getStorageService("oss"); } catch (Exception ex) { - log.error("本地存储服务也不可用", ex); - throw new BusinessException(500, "没有可用的存储服务"); + log.warn("OSS服务不可用,使用本地存储作为降级方案", ex); + try { + return getStorageService("local"); + } catch (Exception localEx) { + log.error("本地存储服务也不可用", localEx); + throw new BusinessException(500, "没有可用的存储服务"); + } } } } @@ -78,6 +84,8 @@ public class StorageServiceFactory { return serviceClassName.contains("local"); case "oss": return serviceClassName.contains("oss"); + case "minio": + return serviceClassName.contains("minio"); default: return false; } diff --git a/script/README.md b/script/README.md deleted file mode 100644 index 08a059e..0000000 --- a/script/README.md +++ /dev/null @@ -1,477 +0,0 @@ -# 项目重构脚本使用指南 - -这是一套用于Maven项目重构和包名修复的自动化脚本,可以帮助你快速将一个项目模板重构为新的项目,并修复常见的包名重复问题。 - -## 📋 脚本概览 - -本目录包含了用于项目重构和包名修复的自动化脚本: - -### 🔧 脚本文件说明 - -``` -script/ -├── project-refactor.sh # ⭐ 主要推荐:完整重构脚本 -├── simple-fix.sh # ⭐ 简单修复脚本 -├── fix-duplicate-packages.sh # 专门修复重复包名 -├── fix-directory-structure.sh # 目录结构重建脚本 -├── batch-refactor.sh # 批量重构脚本(配置文件) -├── refactor-config.example # 配置文件模板 -└── README.md # 本使用说明文件 -``` - -## 🎯 脚本选择建议 - -### 1. **主要推荐:`project-refactor.sh`** ⭐⭐⭐⭐⭐ - -**适用场景**: -- 完整的项目重构(包名、模块名、数据库名等全面修改) -- 从一个框架模板创建新项目 -- 大规模的包名重构 - -**功能特点**: -- ✅ 功能最完整(POM文件、Java文件、XML文件、配置文件全覆盖) -- ✅ 有备份功能 -- ✅ 有验证步骤 -- ✅ 支持嵌套模块处理 -- ✅ **已修复包名重复问题** - -### 2. **简单场景:`simple-fix.sh`** ⭐⭐⭐ - -**适用场景**: -- 只需要修复包名重复问题 -- 简单的包名调整 -- 紧急修复 - -**功能特点**: -- ✅ 执行速度快 -- ✅ 逻辑简单可靠 -- ✅ 不需要交互 - -### 3. **备用选择:`fix-duplicate-packages.sh`** ⭐⭐ - -**适用场景**: -- 专门修复包名重复问题 -- 需要详细的检测报告 - -## 🚀 新项目重构完整指南 - -### 步骤 1: 准备工作 - -1. **确保项目已提交到Git** - ```bash - cd /path/to/your/new/project - git status - git add . - git commit -m "Initial commit before refactoring" - ``` - -2. **准备重构信息** - - 新的包名信息(如:`org.leocoder.newproject`) - - 新的模块前缀(如:`coder-newproject`) - - 新的数据库名称(可选) - -### 步骤 2: 执行重构脚本 - -```bash -# 进入项目目录 -cd /path/to/your/new/project - -# 执行完整重构脚本 -bash script/project-refactor.sh -``` - -### 步骤 3: 交互式配置 - -脚本会提示你输入以下信息: - -#### 3.1 项目目录 -``` -请输入项目根目录路径 (默认: 当前目录): -项目路径: [直接回车使用当前目录] -``` - -#### 3.2 旧配置信息 -``` -旧的 GroupId (例如: org.leocoder.thin): org.leocoder.estate -旧的 ArtifactId (例如: coder-common-thin-backend): coder-estate-backend -旧的模块前缀 (例如: coder-common-thin): coder-estate -``` - -#### 3.3 新配置信息 -``` -新的 GroupId (例如: org.leocoder.course): org.leocoder.newproject -新的 ArtifactId (例如: coder-course-backend): coder-newproject-backend -新的模块前缀 (例如: coder-course): coder-newproject -``` - -#### 3.4 数据库配置(可选) -``` -旧的数据库名称 (留空跳过): coder_estate -新的数据库名称: coder_newproject -``` - -#### 3.5 确认执行 -``` -是否创建备份? (Y/n): Y -是否继续重构? (y/N): y -``` - -### 步骤 4: 验证重构结果 - -#### 4.1 检查目录结构 -```bash -# 检查是否还有重复目录 -find . -type d -path "*/org/leocoder/org/leocoder*" - -# 应该没有任何输出,如果有输出说明还存在重复目录 -``` - -#### 4.2 检查包名 -```bash -# 检查Java文件包名是否正确 -grep -r "package org.leocoder" . --include="*.java" | head -5 - -# 输出应该类似: -# ./src/main/java/org/leocoder/newproject/web/Application.java:package org.leocoder.newproject.web; -``` - -#### 4.3 检查import语句 -```bash -# 检查import语句是否正确 -grep -r "import org.leocoder" . --include="*.java" | head -5 - -# 输出应该使用新的包名 -``` - -#### 4.4 编译验证 -```bash -# 重新编译项目 -mvn clean compile - -# 如果编译成功,说明重构正确 -``` - -### 步骤 5: 测试验证 - -```bash -# 运行测试 -mvn test - -# 启动应用(如果是Spring Boot项目) -mvn spring-boot:run -``` - -## 🛠️ 常见问题处理 - -### 问题 1: 发现重复包名目录 - -**症状**: -```bash -find . -type d -path "*/org/leocoder/org/leocoder*" -# 有输出,存在重复目录 -``` - -**解决方案**: -```bash -# 使用简单修复脚本 -bash script/simple-fix.sh -``` - -### 问题 2: 编译失败 - -**可能原因**: -- 包名引用不一致 -- import语句错误 -- 配置文件中的包名未更新 - -**解决方案**: -```bash -# 1. 检查具体错误信息 -mvn clean compile - -# 2. 手动检查和修复特定文件 -grep -r "org\.leocoder\.estate" . --include="*.java" -grep -r "org\.leocoder\.estate" . --include="*.xml" -grep -r "org\.leocoder\.estate" . --include="*.yml" - -# 3. 如果需要,再次运行修复脚本 -bash script/fix-duplicate-packages.sh -``` - -### 问题 3: IDE中显示错误 - -**解决方案**: -1. **刷新项目**:在IDE中刷新整个项目 -2. **重新导入**:重新导入Maven项目 -3. **清理缓存**:清理IDE缓存和索引 -4. **重启IDE**:重启开发环境 - -## 📚 方法二:配置文件批量重构(推荐批量处理) - -```bash -# 1. 复制配置文件模板 -cp refactor-config.example my-project.conf - -# 2. 编辑配置文件 -vim my-project.conf - -# 3. 运行批量重构 -./batch-refactor.sh my-project.conf -``` - -#### 配置文件格式 - -```bash -# 项目基本信息 -PROJECT_DIR="/path/to/your/project" - -# 旧配置 -OLD_GROUP_ID="org.leocoder.thin" -OLD_ARTIFACT_ID="coder-common-thin-backend" -OLD_MODULE_PREFIX="coder-common-thin" -OLD_DATABASE_NAME="coder-common-thin" - -# 新配置 -NEW_GROUP_ID="org.leocoder.course" -NEW_ARTIFACT_ID="coder-course-backend" -NEW_MODULE_PREFIX="coder-course" -NEW_DATABASE_NAME="coder-course" - -# 其他选项 -CREATE_BACKUP="true" # 是否创建备份 -AUTO_CONFIRM="false" # 是否自动确认(跳过确认步骤) -``` - -## 📋 脚本详细说明 - -### `project-refactor.sh` 执行步骤 - -1. **步骤 1**: 获取重构参数 -2. **步骤 2**: 配置摘要确认 -3. **步骤 3**: 备份项目 -4. **步骤 4**: 修改 POM 文件 -5. **步骤 5**: 修改 Java 包名 -6. **步骤 6**: 修改 XML 映射文件 -7. **步骤 7**: 修改配置文件 -8. **步骤 8**: 重命名目录结构 -9. **步骤 9**: 处理遗漏的嵌套模块 -10. **步骤 10**: 修复重复包名 -11. **步骤 11**: 重命名 SQL 文件 -12. **步骤 12**: 清理和验证 - -### `simple-fix.sh` 执行内容 - -- 删除错误的目录结构 -- 清理空目录 -- 修复Java文件中的包名 -- 修复XML文件中的包名 -- 验证修复结果 - -## 🔧 重构内容说明 - -脚本会自动处理以下内容: - -### 1. POM文件修改 -- ✅ 修改根POM和所有子模块的 `` -- ✅ 修改根POM和所有子模块的 `` -- ✅ 修改 `` 标签 -- ✅ 修改 `` 引用 -- ✅ 修改依赖引用中的groupId和artifactId - -### 2. Java源码修改 -- ✅ 修改所有Java文件的 `package` 声明 -- ✅ 修改所有Java文件的 `import` 语句 -- ✅ 修改注解中的包名引用(如@SpringBootApplication的scanBasePackages) - -### 3. XML映射文件 -- ✅ 修改MyBatis Mapper文件的 `namespace` -- ✅ 修改 `resultType` 中的包名引用 - -### 4. 配置文件 -- ✅ 修改YAML/Properties文件中的包扫描配置 -- ✅ 修改数据库连接配置中的数据库名 -- ✅ 修改文件路径配置 - -### 5. 目录结构重构 -- ✅ 重命名Java包目录结构(src/main/java/com/old/package → src/main/java/com/new/package) -- ✅ 重命名模块目录(old-module-name → new-module-name) -- ✅ 重命名SQL文件 -- ✅ **修复重复包名问题** - -## 🎯 最佳实践 - -### 重构流程建议 - -```bash -# 1. 创建新分支 -git checkout -b refactor-to-newproject - -# 2. 执行重构 -bash script/project-refactor.sh - -# 3. 验证结果 -mvn clean compile -mvn test - -# 4. 提交变更 -git add . -git commit -m "refactor: change package from org.leocoder.estate to org.leocoder.newproject" - -# 5. 合并到主分支(如果一切正常) -git checkout main -git merge refactor-to-newproject -``` - -### 命名规范建议 - -- **包名**:`org.leocoder.{项目名}` -- **模块前缀**:`coder-{项目名}` -- **数据库名**:`coder_{项目名}` - -### 示例配置 - -``` -# 电商项目示例 -旧包名: org.leocoder.estate → 新包名: org.leocoder.ecommerce -旧模块: coder-estate → 新模块: coder-ecommerce -旧数据库: coder_estate → 新数据库: coder_ecommerce - -# 教育项目示例 -旧包名: org.leocoder.estate → 新包名: org.leocoder.education -旧模块: coder-estate → 新模块: coder-education -旧数据库: coder_estate → 新数据库: coder_education -``` - -## 💡 使用示例 - -### 示例1:从通用框架改造为选课系统 - -```bash -# 交互式输入 -./project-refactor.sh - -# 输入示例: -# 项目路径: /Users/leocoder/my-project -# 旧的 GroupId: org.leocoder.estate -# 旧的 ArtifactId: coder-estate-backend -# 旧的模块前缀: coder-estate -# 新的 GroupId: org.leocoder.course -# 新的 ArtifactId: coder-course-backend -# 新的模块前缀: coder-course -``` - -### 示例2:批量处理多个项目 - -```bash -# 为选课系统创建配置 -cat > course-system.conf << EOF -PROJECT_DIR="/Users/leocoder/course-project" -OLD_GROUP_ID="org.leocoder.estate" -OLD_ARTIFACT_ID="coder-estate-backend" -OLD_MODULE_PREFIX="coder-estate" -NEW_GROUP_ID="org.leocoder.course" -NEW_ARTIFACT_ID="coder-course-backend" -NEW_MODULE_PREFIX="coder-course" -CREATE_BACKUP="true" -AUTO_CONFIRM="false" -EOF - -# 为库存系统创建配置 -cat > inventory-system.conf << EOF -PROJECT_DIR="/Users/leocoder/inventory-project" -OLD_GROUP_ID="org.leocoder.estate" -OLD_ARTIFACT_ID="coder-estate-backend" -OLD_MODULE_PREFIX="coder-estate" -NEW_GROUP_ID="org.leocoder.inventory" -NEW_ARTIFACT_ID="coder-inventory-backend" -NEW_MODULE_PREFIX="coder-inventory" -CREATE_BACKUP="true" -AUTO_CONFIRM="false" -EOF - -# 执行批量重构 -./batch-refactor.sh course-system.conf -./batch-refactor.sh inventory-system.conf -``` - -## ⚠️ 重要注意事项 - -### 使用前必读 - -1. **备份项目**:始终在Git中提交代码后再执行脚本 -2. **关闭IDE**:执行脚本前关闭IDE,避免文件锁定 -3. **检查权限**:确保脚本有执行权限(`chmod +x script/*.sh`) -4. **逐步验证**:每个步骤完成后都进行验证 - -### 安全建议 - -1. **测试环境**:先在测试环境中执行,确认无误后再在生产代码中使用 -2. **分支操作**:建议在新的Git分支中执行重构操作 -3. **备份重要**:重要项目建议手动备份整个项目目录 - -### 重构后需要手动检查的项目 -- [ ] IDE中的运行配置(主类路径) -- [ ] 数据库连接配置 -- [ ] 第三方服务配置 -- [ ] 测试用例 -- [ ] 文档更新 - -## 🆘 获取帮助 - -如果在使用过程中遇到问题: - -1. **查看日志**:脚本执行过程中的详细日志 -2. **检查文件**:手动检查具体的错误文件 -3. **重新执行**:如果部分失败,可以重新执行脚本 -4. **手动修复**:对于特殊情况,可能需要手动修复部分文件 - -### 常见问题 - -**Q: 脚本执行后项目无法启动?** -A: 检查IDE的运行配置,确保主类路径已更新为新的包名。 - -**Q: 某些文件没有被修改?** -A: 检查文件是否在target目录下,脚本会跳过编译输出目录。 - -**Q: 包名格式验证失败?** -A: 确保包名符合Java命名规范,只能包含字母、数字、下划线和点号。 - -**Q: 权限被拒绝?** -A: 确保脚本有执行权限:`chmod +x *.sh` - -### 调试技巧 - -1. **查看详细日志**: 脚本会显示处理的文件信息 -2. **检查备份**: 如果出现问题,可以从备份恢复 -3. **分步执行**: 可以注释掉脚本中的某些步骤来分步调试 - -## 🔧 扩展功能 - -你可以根据需要扩展脚本功能: - -1. **添加新的文件类型**: 在相应的函数中添加处理逻辑 -2. **自定义替换规则**: 修改sed命令的正则表达式 -3. **集成到CI/CD**: 将脚本集成到自动化流水线中 - ---- - -**创建时间**: 2025-01-09 -**最后更新**: 2025-01-09 -**版本**: v2.0 -**作者**: Leocoder - -## 📝 更新日志 - -### v2.0 (2025-01-09) -- ✅ 新增重复包名检测和修复功能 -- ✅ 新增 `simple-fix.sh` 快速修复脚本 -- ✅ 新增 `fix-duplicate-packages.sh` 专门修复重复包名 -- ✅ 完善了使用指南和最佳实践 -- ✅ 增加了详细的问题排查步骤 -- ✅ 优化了目录结构处理逻辑 - -### v1.0 (2025-07-06) -- ✅ 基础项目重构功能 -- ✅ 支持POM文件、Java文件、XML文件修改 -- ✅ 支持配置文件批量处理 -- ✅ 基础的目录结构重命名功能 \ No newline at end of file diff --git a/script/demo.sh b/script/demo.sh deleted file mode 100755 index ddcfb18..0000000 --- a/script/demo.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash - -# 演示脚本 - 快速测试重构功能 -# Author: Leocoder - -# 颜色定义 -GREEN='\033[0;32m' -BLUE='\033[0;34m' -YELLOW='\033[1;33m' -NC='\033[0m' - -echo -e "${BLUE}" -echo "╔══════════════════════════════════════════════════════════════════════════════╗" -echo "║ 项目重构脚本演示 ║" -echo "╚══════════════════════════════════════════════════════════════════════════════╝" -echo -e "${NC}" - -echo -e "${GREEN}🚀 项目重构自动化脚本已就绪!${NC}" -echo "" -echo "包含以下脚本文件:" -echo "├── project-refactor.sh (交互式重构脚本)" -echo "├── batch-refactor.sh (批量重构脚本)" -echo "├── refactor-config.example (配置文件模板)" -echo "├── README.md (详细使用说明)" -echo "└── demo.sh (演示脚本)" -echo "" - -echo -e "${YELLOW}快速使用方法:${NC}" -echo "" -echo "1️⃣ 交互式重构(推荐新手):" -echo " ./project-refactor.sh" -echo "" -echo "2️⃣ 批量重构(推荐批量处理):" -echo " cp refactor-config.example my-config.conf" -echo " vim my-config.conf # 编辑配置" -echo " ./batch-refactor.sh my-config.conf" -echo "" - -echo -e "${GREEN}✨ 脚本功能特性:${NC}" -echo "• 🔄 自动修改 Maven POM 文件" -echo "• 📦 批量更新 Java 包名和 import" -echo "• 🗂️ 重命名目录结构" -echo "• ⚙️ 更新配置文件" -echo "• 🗃️ 处理 MyBatis XML 映射" -echo "• 💾 可选项目备份" -echo "• 📊 详细的进度显示" -echo "" - -echo -e "${YELLOW}查看完整使用说明:${NC}" -echo "cat README.md" -echo "" - -echo -e "${GREEN}🎯 现在你可以轻松地将任何 Maven 项目重构为新项目!${NC}" \ No newline at end of file diff --git a/script/fix-directory-structure.sh b/script/fix-directory-structure.sh deleted file mode 100755 index a2129ba..0000000 --- a/script/fix-directory-structure.sh +++ /dev/null @@ -1,286 +0,0 @@ -#!/bin/bash - -# 目录结构修复脚本 - 专门修复重复包名目录问题 -# Author: Leocoder -# Version: 1.0 - -# 颜色定义 -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -PURPLE='\033[0;35m' -CYAN='\033[0;36m' -WHITE='\033[1;37m' -NC='\033[0m' # No Color - -# 全局变量 -PROJECT_DIR="" - -# 打印信息 -print_step() { - echo -e "${BLUE}════════════════════════════════════════════════════════════════════════════════${NC}" - echo -e "${WHITE}$1${NC}" - echo -e "${BLUE}════════════════════════════════════════════════════════════════════════════════${NC}" -} - -print_success() { - echo -e "${GREEN}✓ $1${NC}" -} - -print_warning() { - echo -e "${YELLOW}⚠ $1${NC}" -} - -print_error() { - echo -e "${RED}✗ $1${NC}" -} - -print_info() { - echo -e "${PURPLE}ℹ $1${NC}" -} - -# 获取项目目录 -get_project_dir() { - if [ -z "$1" ]; then - PROJECT_DIR="$(pwd)" - else - PROJECT_DIR="$1" - fi - - if [ ! -d "$PROJECT_DIR" ]; then - print_error "项目目录不存在: $PROJECT_DIR" - exit 1 - fi - - if [ ! -f "$PROJECT_DIR/pom.xml" ]; then - print_error "这不是一个Maven项目" - exit 1 - fi - - print_success "项目目录: $PROJECT_DIR" -} - -# 备份重要文件 -backup_files() { - print_step "步骤 1: 备份重要文件" - - local backup_dir="/tmp/package_fix_backup_$(date +%Y%m%d_%H%M%S)" - mkdir -p "$backup_dir" - - # 查找所有Java文件并备份 - find "$PROJECT_DIR" -name "*.java" | while read java_file; do - local rel_path="${java_file#$PROJECT_DIR/}" - local target_file="$backup_dir/$rel_path" - mkdir -p "$(dirname "$target_file")" - cp "$java_file" "$target_file" - done - - print_success "文件已备份到: $backup_dir" -} - -# 收集所有Java文件 -collect_java_files() { - print_step "步骤 2: 收集所有Java文件" - - local temp_dir="/tmp/java_files_$(date +%Y%m%d_%H%M%S)" - mkdir -p "$temp_dir" - - # 查找所有Java文件并复制到临时目录 - find "$PROJECT_DIR" -name "*.java" -path "*/org/leocoder/*" | while read java_file; do - # 提取相对于org的路径 - local rel_path=$(echo "$java_file" | sed 's|.*/org/leocoder/|org/leocoder/|') - local target_file="$temp_dir/$rel_path" - - # 创建目标目录 - mkdir -p "$(dirname "$target_file")" - - # 复制文件 - cp "$java_file" "$target_file" - - print_info "收集文件: $rel_path" - done - - echo "$temp_dir" -} - -# 清理错误的目录结构 -cleanup_wrong_structure() { - print_step "步骤 3: 清理错误的目录结构" - - # 删除所有org目录 - find "$PROJECT_DIR" -type d -name "org" -path "*/src/main/java/*" | while read org_dir; do - print_info "删除目录: $org_dir" - rm -rf "$org_dir" - done - - print_success "已清理所有org目录" -} - -# 重建正确的目录结构 -rebuild_structure() { - print_step "步骤 4: 重建正确的目录结构" - - local temp_dir="$1" - local count=0 - - # 查找所有Java源码目录 - find "$PROJECT_DIR" -type d -path "*/src/main/java" | while read java_src_dir; do - print_info "处理目录: $java_src_dir" - - # 在每个java目录下重建org/leocoder/estate结构 - local target_base="$java_src_dir/org/leocoder/estate" - mkdir -p "$target_base" - - # 从临时目录复制对应的文件 - if [ -d "$temp_dir/org/leocoder/estate" ]; then - # 获取模块名称来判断应该复制哪些文件 - local module_name=$(echo "$java_src_dir" | grep -o 'coder-estate-[^/]*' | head -1) - - case "$module_name" in - "coder-estate-common") - if [ -d "$temp_dir/org/leocoder/estate/common" ]; then - cp -r "$temp_dir/org/leocoder/estate/common" "$target_base/" - print_info "复制common模块文件" - fi - ;; - "coder-estate-model") - if [ -d "$temp_dir/org/leocoder/estate/domain" ]; then - cp -r "$temp_dir/org/leocoder/estate/domain" "$target_base/" - print_info "复制model模块文件" - fi - ;; - "coder-estate-system") - if [ -d "$temp_dir/org/leocoder/estate/system" ]; then - cp -r "$temp_dir/org/leocoder/estate/system" "$target_base/" - print_info "复制system模块文件" - fi - ;; - "coder-estate-web") - if [ -d "$temp_dir/org/leocoder/estate/web" ]; then - cp -r "$temp_dir/org/leocoder/estate/web" "$target_base/" - print_info "复制web模块文件" - fi - ;; - "coder-estate-mybatisplus") - if [ -d "$temp_dir/org/leocoder/estate/mybatisplus" ]; then - cp -r "$temp_dir/org/leocoder/estate/mybatisplus" "$target_base/" - print_info "复制mybatisplus模块文件" - fi - ;; - *plugin*) - # 处理插件模块 - local plugin_type=$(echo "$module_name" | sed 's/coder-estate-//') - if [ -d "$temp_dir/org/leocoder/estate/$plugin_type" ]; then - cp -r "$temp_dir/org/leocoder/estate/$plugin_type" "$target_base/" - print_info "复制${plugin_type}插件文件" - fi - ;; - esac - fi - - ((count++)) - done - - print_success "已重建 $count 个模块的目录结构" -} - -# 修复文件内容中的包名 -fix_package_names() { - print_step "步骤 5: 修复文件内容中的包名" - - local count=0 - - # 查找所有Java文件并修复包名 - find "$PROJECT_DIR" -name "*.java" -path "*/org/leocoder/estate/*" | while read java_file; do - # 检查是否包含错误的包名 - if grep -q "org\.leocoder\.org\.leocoder" "$java_file"; then - print_info "修复包名: $(basename "$java_file")" - - # 修复包名 - sed -i '' 's|org\.leocoder\.org\.leocoder\.estate|org.leocoder.estate|g' "$java_file" - sed -i '' 's|org\.leocoder\.org\.leocoder|org.leocoder|g' "$java_file" - - ((count++)) - fi - done - - print_success "已修复 $count 个文件的包名" -} - -# 验证修复结果 -verify_result() { - print_step "步骤 6: 验证修复结果" - - # 检查是否还有重复目录 - local duplicate_dirs=$(find "$PROJECT_DIR" -type d -path "*/org/leocoder/org/leocoder*" 2>/dev/null) - if [ -n "$duplicate_dirs" ]; then - print_warning "仍然存在重复目录:" - echo "$duplicate_dirs" - return 1 - fi - - # 检查Java文件数量 - local java_count=$(find "$PROJECT_DIR" -name "*.java" -path "*/org/leocoder/estate/*" | wc -l) - print_info "Java文件总数: $java_count" - - # 检查模块结构 - local modules=$(find "$PROJECT_DIR" -type d -path "*/src/main/java/org/leocoder/estate" | wc -l) - print_info "模块数量: $modules" - - print_success "目录结构修复完成" -} - -# 清理临时文件 -cleanup_temp() { - local temp_dir="$1" - if [ -d "$temp_dir" ]; then - rm -rf "$temp_dir" - print_info "已清理临时文件" - fi -} - -# 主函数 -main() { - echo -e "${CYAN}" - echo "╔══════════════════════════════════════════════════════════════════════════════╗" - echo "║ 目录结构修复脚本 ║" - echo "║ Directory Structure Fix Tool ║" - echo "║ Version 1.0 ║" - echo "╚══════════════════════════════════════════════════════════════════════════════╝" - echo -e "${NC}" - - get_project_dir "$1" - - echo "" - echo -e "${YELLOW}警告: 此操作将重新组织项目目录结构,建议先备份项目!${NC}" - echo "" - read -p "是否继续? (y/N): " confirm - if [[ ! "$confirm" =~ ^[Yy]$ ]]; then - print_info "操作已取消" - exit 0 - fi - - # 执行修复步骤 - backup_files - local temp_dir=$(collect_java_files) - cleanup_wrong_structure - rebuild_structure "$temp_dir" - fix_package_names - verify_result - cleanup_temp "$temp_dir" - - echo -e "${GREEN}" - echo "╔══════════════════════════════════════════════════════════════════════════════╗" - echo "║ 目录结构修复完成! ║" - echo "║ ║" - echo "║ 下一步建议: ║" - echo "║ 1. 重新编译项目验证修复效果 ║" - echo "║ 2. 检查IDE中的导入语句 ║" - echo "║ 3. 运行测试确保功能正常 ║" - echo "╚══════════════════════════════════════════════════════════════════════════════╝" - echo -e "${NC}" -} - -# 脚本入口 -main "$@" \ No newline at end of file diff --git a/script/fix-duplicate-packages.sh b/script/fix-duplicate-packages.sh deleted file mode 100755 index 3c5dd01..0000000 --- a/script/fix-duplicate-packages.sh +++ /dev/null @@ -1,493 +0,0 @@ -#!/bin/bash - -# 包名重复修复脚本 - 专门用于修复已经重复的包名 -# Author: Leocoder -# Version: 1.0 - -# 颜色定义 -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -PURPLE='\033[0;35m' -CYAN='\033[0;36m' -WHITE='\033[1;37m' -NC='\033[0m' # No Color - -# 全局变量 -PROJECT_DIR="" - -# 打印banner -print_banner() { - echo -e "${CYAN}" - echo "╔══════════════════════════════════════════════════════════════════════════════╗" - echo "║ 包名重复修复脚本 ║" - echo "║ Fix Duplicate Packages Tool ║" - echo "║ Version 1.0 ║" - echo "╚══════════════════════════════════════════════════════════════════════════════╝" - echo -e "${NC}" -} - -# 打印步骤标题 -print_step() { - echo -e "${BLUE}════════════════════════════════════════════════════════════════════════════════${NC}" - echo -e "${WHITE}$1${NC}" - echo -e "${BLUE}════════════════════════════════════════════════════════════════════════════════${NC}" -} - -# 打印成功信息 -print_success() { - echo -e "${GREEN}✓ $1${NC}" -} - -# 打印警告信息 -print_warning() { - echo -e "${YELLOW}⚠ $1${NC}" -} - -# 打印错误信息 -print_error() { - echo -e "${RED}✗ $1${NC}" -} - -# 打印信息 -print_info() { - echo -e "${PURPLE}ℹ $1${NC}" -} - -# 获取项目目录 -get_project_dir() { - print_step "步骤 1: 获取项目目录" - - # 获取项目根目录 - echo -e "${CYAN}请输入项目根目录路径 (默认: 当前目录):${NC}" - read -p "项目路径: " PROJECT_DIR - if [ -z "$PROJECT_DIR" ]; then - PROJECT_DIR="$(pwd)" - fi - - # 检查项目目录是否存在 - if [ ! -d "$PROJECT_DIR" ]; then - print_error "项目目录不存在: $PROJECT_DIR" - exit 1 - fi - - # 检查是否是Maven项目 - if [ ! -f "$PROJECT_DIR/pom.xml" ]; then - print_error "这不是一个Maven项目 (未找到pom.xml)" - exit 1 - fi - - print_success "项目目录: $PROJECT_DIR" -} - -# 检测重复包名 -detect_duplicate_packages() { - print_step "步骤 2: 检测重复包名" - - local all_files=$(find "$PROJECT_DIR" -name "*.java" -o -name "*.xml" -o -name "*.yml" -o -name "*.yaml" -o -name "*.properties" | grep -v target) - local found_duplicates=false - - echo -e "${WHITE}检测结果:${NC}" - - # 1. 检测目录结构中的重复 - echo -e "${CYAN}1. 检测目录结构重复:${NC}" - local duplicate_dirs=$(find "$PROJECT_DIR" -type d -path "*/org/leocoder/org/leocoder*" 2>/dev/null) - if [ -n "$duplicate_dirs" ]; then - found_duplicates=true - echo -e "${YELLOW}发现重复目录结构:${NC}" - echo "$duplicate_dirs" | while read dir; do - echo " - $dir" - done - else - echo -e "${GREEN}目录结构正常${NC}" - fi - - # 2. 检测文件内容中的重复包名 - echo -e "${CYAN}2. 检测文件内容重复:${NC}" - local duplicate_patterns=( - "org\.leocoder\.org\.leocoder" - "org\.leocoder\.thin\.org\.leocoder" - "org\.leocoder\.course\.org\.leocoder" - "org\.leocoder\.estate\.org\.leocoder" - ) - - local file_duplicates_found=false - for pattern in "${duplicate_patterns[@]}"; do - local files_with_pattern=$(grep -l "$pattern" $all_files 2>/dev/null | head -10) - if [ -n "$files_with_pattern" ]; then - found_duplicates=true - file_duplicates_found=true - echo -e "${YELLOW}发现重复模式: $pattern${NC}" - echo "$files_with_pattern" | while read file; do - echo " - $(basename $file)" - done - fi - done - - # 通用重复检测 - local general_duplicates=$(grep -l "org\.leocoder\.[^.]*\.org\.leocoder" $all_files 2>/dev/null | head -10) - if [ -n "$general_duplicates" ]; then - found_duplicates=true - file_duplicates_found=true - echo -e "${YELLOW}发现其他重复模式:${NC}" - echo "$general_duplicates" | while read file; do - echo " - $(basename $file)" - done - fi - - if [ "$file_duplicates_found" = false ]; then - echo -e "${GREEN}文件内容正常${NC}" - fi - - if [ "$found_duplicates" = false ]; then - echo -e "${GREEN}未发现重复包名问题${NC}" - exit 0 - fi - - echo "" - echo -e "${YELLOW}警告: 发现重复包名问题,建议进行修复!${NC}" - echo "" - read -p "是否继续修复? (y/N): " confirm - if [[ ! "$confirm" =~ ^[Yy]$ ]]; then - print_info "操作已取消" - exit 0 - fi -} - -# 备份项目 -backup_project() { - print_step "步骤 3: 备份项目" - - local backup_dir="${PROJECT_DIR}_backup_fix_$(date +%Y%m%d_%H%M%S)" - - echo -e "${CYAN}是否创建项目备份?${NC}" - read -p "创建备份到 $backup_dir (Y/n): " create_backup - - if [[ "$create_backup" =~ ^[Nn]$ ]]; then - print_warning "跳过备份步骤" - return - fi - - print_info "正在创建备份..." - cp -r "$PROJECT_DIR" "$backup_dir" - - if [ $? -eq 0 ]; then - print_success "备份创建成功: $backup_dir" - else - print_error "备份创建失败" - exit 1 - fi -} - -# 清理现有错误的目录结构 -cleanup_existing_duplicates() { - print_step "步骤 3.5: 清理现有错误的目录结构" - - local cleaned_count=0 - - # 清理空的org目录 - echo -e "${CYAN}清理空的org目录:${NC}" - local empty_org_dirs=$(find "$PROJECT_DIR" -type d -name "org" -exec sh -c 'for dir; do if [ -z "$(ls -A "$dir" 2>/dev/null)" ]; then echo "$dir"; fi; done' _ {} +) - if [ -n "$empty_org_dirs" ]; then - echo "$empty_org_dirs" | while read empty_dir; do - if [ -d "$empty_dir" ]; then - print_info "删除空目录: $empty_dir" - rmdir "$empty_dir" 2>/dev/null || true - ((cleaned_count++)) - fi - done - fi - - # 清理重复的配置文件(如果存在) - echo -e "${CYAN}清理重复的配置文件:${NC}" - local config_files=$(find "$PROJECT_DIR" -name "*.java" -path "*/config/*" | grep -E "(OpenApiConfig|CoderApplication)" | sort) - if [ -n "$config_files" ]; then - local prev_file="" - echo "$config_files" | while read config_file; do - if [ -n "$prev_file" ] && [ "$(basename "$config_file")" = "$(basename "$prev_file")" ]; then - # 检查文件内容是否相同 - if diff "$config_file" "$prev_file" > /dev/null 2>&1; then - print_info "删除重复文件: $config_file" - rm -f "$config_file" - ((cleaned_count++)) - fi - fi - prev_file="$config_file" - done - fi - - print_success "清理完成,已处理 $cleaned_count 个项目" -} - -# 修复重复包名 -fix_duplicate_packages() { - print_step "步骤 4: 修复重复包名" - - local file_count=0 - local dir_count=0 - - # 1. 修复目录结构重复 - echo -e "${CYAN}1. 修复目录结构重复:${NC}" - - # 找到所有重复的根目录(org/leocoder/org/leocoder) - local duplicate_root_dirs=$(find "$PROJECT_DIR" -type d -path "*/org/leocoder/org/leocoder" ! -path "*/org/leocoder/org/leocoder/*" 2>/dev/null) - - if [ -n "$duplicate_root_dirs" ]; then - echo "$duplicate_root_dirs" | while read duplicate_root; do - if [ -d "$duplicate_root" ]; then - # 计算正确的目标目录 - local java_dir=$(dirname "$duplicate_root") - local correct_target="$java_dir/org/leocoder" - - print_info "处理重复目录: $duplicate_root" - print_info "目标目录: $correct_target" - - # 创建正确的目标目录(如果不存在) - mkdir -p "$correct_target" - - # 移动所有文件和子目录到正确位置 - if [ -d "$duplicate_root" ] && [ "$(ls -A "$duplicate_root" 2>/dev/null)" ]; then - # 移动所有内容 - for item in "$duplicate_root"/*; do - if [ -e "$item" ]; then - local item_name=$(basename "$item") - local target_item="$correct_target/$item_name" - - if [ -d "$item" ] && [ -d "$target_item" ]; then - # 如果是目录且目标已存在,递归合并 - cp -r "$item/"* "$target_item/" 2>/dev/null || true - else - # 直接移动 - mv "$item" "$target_item" 2>/dev/null || true - fi - fi - done - fi - - # 删除重复的目录结构 - rm -rf "$duplicate_root" 2>/dev/null || true - - # 清理空的父目录 - local cleanup_dir=$(dirname "$duplicate_root") - while [ "$cleanup_dir" != "$java_dir" ] && [ -d "$cleanup_dir" ]; do - # 检查目录是否为空 - if [ -z "$(ls -A "$cleanup_dir" 2>/dev/null)" ]; then - rmdir "$cleanup_dir" 2>/dev/null || true - cleanup_dir=$(dirname "$cleanup_dir") - else - break - fi - done - - ((dir_count++)) - fi - done - - print_success "已处理重复目录结构" - else - echo -e "${GREEN}目录结构正常${NC}" - fi - - # 2. 修复文件内容中的重复包名 - echo -e "${CYAN}2. 修复文件内容重复:${NC}" - local all_files=$(find "$PROJECT_DIR" -name "*.java" -o -name "*.xml" -o -name "*.yml" -o -name "*.yaml" -o -name "*.properties" | grep -v target) - - # 检查常见的重复模式 - local duplicate_patterns=( - "org\.leocoder\.org\.leocoder" - "org\.leocoder\.thin\.org\.leocoder" - "org\.leocoder\.course\.org\.leocoder" - "org\.leocoder\.estate\.org\.leocoder" - ) - - for file in $all_files; do - local modified=false - local temp_file=$(mktemp) - - # 处理每个重复模式 - cp "$file" "$temp_file" - - for pattern in "${duplicate_patterns[@]}"; do - if grep -q "$pattern" "$temp_file"; then - # 修复重复的包名,保留最后一个正确的部分 - case "$pattern" in - "org\.leocoder\.org\.leocoder") - sed -i '' "s|org\.leocoder\.org\.leocoder|org.leocoder|g" "$temp_file" - modified=true - ;; - "org\.leocoder\.thin\.org\.leocoder") - sed -i '' "s|org\.leocoder\.thin\.org\.leocoder|org.leocoder|g" "$temp_file" - modified=true - ;; - "org\.leocoder\.course\.org\.leocoder") - sed -i '' "s|org\.leocoder\.course\.org\.leocoder|org.leocoder.course|g" "$temp_file" - modified=true - ;; - "org\.leocoder\.estate\.org\.leocoder") - sed -i '' "s|org\.leocoder\.estate\.org\.leocoder|org.leocoder.estate|g" "$temp_file" - modified=true - ;; - esac - fi - done - - # 通用重复修复:修复任何 org.leocoder.*.org.leocoder.* 的模式 - if grep -q "org\.leocoder\.[^.]*\.org\.leocoder" "$temp_file"; then - # 更精确的处理:提取中间部分并重构 - sed -i '' 's|org\.leocoder\.\([^.]*\)\.org\.leocoder\.\(.*\)|org.leocoder.\1.\2|g' "$temp_file" - modified=true - fi - - # 检查是否有实际变化 - if [ "$modified" = true ] && ! diff "$file" "$temp_file" > /dev/null; then - mv "$temp_file" "$file" - print_info "修复文件内容: $(basename $file)" - ((file_count++)) - else - rm -f "$temp_file" - fi - done - - echo "" - print_success "已修复 $dir_count 个目录结构和 $file_count 个文件中的重复包名" -} - -# 验证修复结果 -verify_fix() { - print_step "步骤 5: 验证修复结果" - - local all_files=$(find "$PROJECT_DIR" -name "*.java" -o -name "*.xml" -o -name "*.yml" -o -name "*.yaml" -o -name "*.properties" | grep -v target) - local remaining_duplicates=false - - # 1. 验证目录结构 - echo -e "${CYAN}1. 验证目录结构:${NC}" - local duplicate_dirs=$(find "$PROJECT_DIR" -type d -path "*/org/leocoder/org/leocoder*" 2>/dev/null) - if [ -n "$duplicate_dirs" ]; then - remaining_duplicates=true - echo -e "${RED}仍然存在重复目录结构:${NC}" - echo "$duplicate_dirs" | while read dir; do - echo " - $dir" - done - else - echo -e "${GREEN}目录结构正常${NC}" - fi - - # 检查是否有孤立的org目录需要清理 - local orphan_org_dirs=$(find "$PROJECT_DIR" -type d -name "org" -exec sh -c 'for dir; do if [ -z "$(ls -A "$dir" 2>/dev/null)" ]; then echo "$dir"; fi; done' _ {} +) - if [ -n "$orphan_org_dirs" ]; then - echo -e "${YELLOW}发现空的org目录,建议清理:${NC}" - echo "$orphan_org_dirs" | while read dir; do - echo " - $dir" - rmdir "$dir" 2>/dev/null || true - done - fi - - # 2. 验证文件内容 - echo -e "${CYAN}2. 验证文件内容:${NC}" - - # 检查是否还有重复 - local duplicate_patterns=( - "org\.leocoder\.org\.leocoder" - "org\.leocoder\.thin\.org\.leocoder" - "org\.leocoder\.course\.org\.leocoder" - "org\.leocoder\.estate\.org\.leocoder" - ) - - local file_duplicates_found=false - for pattern in "${duplicate_patterns[@]}"; do - local files_with_pattern=$(grep -l "$pattern" $all_files 2>/dev/null) - if [ -n "$files_with_pattern" ]; then - remaining_duplicates=true - file_duplicates_found=true - echo -e "${RED}仍然存在重复模式: $pattern${NC}" - echo "$files_with_pattern" | while read file; do - echo " - $(basename $file)" - done - fi - done - - # 通用重复检测 - local general_duplicates=$(grep -l "org\.leocoder\.[^.]*\.org\.leocoder" $all_files 2>/dev/null) - if [ -n "$general_duplicates" ]; then - remaining_duplicates=true - file_duplicates_found=true - echo -e "${RED}仍然存在其他重复模式${NC}" - echo "$general_duplicates" | while read file; do - echo " - $(basename $file)" - done - fi - - if [ "$file_duplicates_found" = false ]; then - echo -e "${GREEN}文件内容正常${NC}" - fi - - echo "" - if [ "$remaining_duplicates" = false ]; then - print_success "所有重复包名已成功修复" - else - print_warning "部分重复包名可能需要手动修复" - fi -} - -# 清理临时文件 -cleanup() { - print_step "步骤 6: 清理工作" - - # 清理可能遗留的临时文件 - find "$PROJECT_DIR" -name "*.bak" -type f -delete 2>/dev/null - find "$PROJECT_DIR" -name ".DS_Store" -type f -delete 2>/dev/null - - # 显示统计信息 - local java_files_count=$(find "$PROJECT_DIR" -name "*.java" -type f | wc -l) - local xml_files_count=$(find "$PROJECT_DIR" -name "*.xml" -type f | wc -l) - local config_files_count=$(find "$PROJECT_DIR" -name "*.yml" -o -name "*.yaml" -o -name "*.properties" | wc -l) - - echo "" - echo -e "${WHITE}项目文件统计:${NC}" - echo -e "${CYAN}Java 文件:${NC} $java_files_count" - echo -e "${CYAN}XML 文件:${NC} $xml_files_count" - echo -e "${CYAN}配置文件:${NC} $config_files_count" - - print_success "清理完成" -} - -# 主函数 -main() { - # 检查依赖 - if ! command -v sed &> /dev/null; then - print_error "sed 命令未找到,请安装 sed" - exit 1 - fi - - print_banner - - get_project_dir - detect_duplicate_packages - backup_project - - # 进入项目目录 - cd "$PROJECT_DIR" || exit 1 - - # 执行修复步骤 - cleanup_existing_duplicates - fix_duplicate_packages - verify_fix - cleanup - - print_step "🎉 修复完成!" - - echo -e "${GREEN}" - echo "╔══════════════════════════════════════════════════════════════════════════════╗" - echo "║ 重复包名修复完成! ║" - echo "║ ║" - echo "║ 下一步建议: ║" - echo "║ 1. 重新编译项目验证修复效果 ║" - echo "║ 2. 检查IDE中的导入语句 ║" - echo "║ 3. 运行测试确保功能正常 ║" - echo "╚══════════════════════════════════════════════════════════════════════════════╝" - echo -e "${NC}" -} - -# 脚本入口 -main "$@" \ No newline at end of file diff --git a/script/refactor-config.example b/script/refactor-config.example deleted file mode 100644 index 7857b77..0000000 --- a/script/refactor-config.example +++ /dev/null @@ -1,21 +0,0 @@ -# 项目重构配置文件示例 -# 复制此文件为 refactor-config.conf 并修改相应值 - -# 项目基本信息 -PROJECT_DIR="/path/to/your/project" - -# 旧配置 -OLD_GROUP_ID="org.leocoder.thin" -OLD_ARTIFACT_ID="coder-common-thin-backend" -OLD_MODULE_PREFIX="coder-common-thin" -OLD_DATABASE_NAME="coder-common-thin" - -# 新配置 -NEW_GROUP_ID="org.leocoder.course" -NEW_ARTIFACT_ID="coder-course-backend" -NEW_MODULE_PREFIX="coder-course" -NEW_DATABASE_NAME="coder-course" - -# 其他选项 -CREATE_BACKUP="true" -AUTO_CONFIRM="false" \ No newline at end of file diff --git a/script/simple-fix.sh b/script/simple-fix.sh deleted file mode 100755 index 7e73017..0000000 --- a/script/simple-fix.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -# 简单目录修复脚本 -# Author: Leocoder - -echo "开始修复目录结构..." - -PROJECT_DIR="/Users/leocoder/leocoder/develop/2025/estate/coder-estate-backend" - -# 1. 删除所有错误的org目录结构 -echo "删除错误的目录结构..." -find "$PROJECT_DIR" -type d -path "*/org/leocoder/org/leocoder*" -exec rm -rf {} + 2>/dev/null - -# 2. 清理空的org目录 -echo "清理空目录..." -find "$PROJECT_DIR" -type d -name "org" -empty -delete 2>/dev/null - -# 3. 查找所有包含重复包名的Java文件并修复 -echo "修复Java文件中的包名..." -find "$PROJECT_DIR" -name "*.java" -exec sed -i '' 's|org\.leocoder\.org\.leocoder\.estate|org.leocoder.estate|g' {} + 2>/dev/null -find "$PROJECT_DIR" -name "*.java" -exec sed -i '' 's|org\.leocoder\.org\.leocoder|org.leocoder|g' {} + 2>/dev/null - -# 4. 修复XML文件中的包名 -echo "修复XML文件中的包名..." -find "$PROJECT_DIR" -name "*.xml" -exec sed -i '' 's|org\.leocoder\.org\.leocoder\.estate|org.leocoder.estate|g' {} + 2>/dev/null -find "$PROJECT_DIR" -name "*.xml" -exec sed -i '' 's|org\.leocoder\.org\.leocoder|org.leocoder|g' {} + 2>/dev/null - -# 5. 验证结果 -echo "验证修复结果..." -duplicate_count=$(find "$PROJECT_DIR" -type d -path "*/org/leocoder/org/leocoder*" | wc -l) -if [ "$duplicate_count" -eq 0 ]; then - echo "✅ 目录结构修复成功!" -else - echo "⚠️ 仍然存在 $duplicate_count 个重复目录" -fi - -# 6. 统计Java文件数量 -java_count=$(find "$PROJECT_DIR" -name "*.java" -path "*/org/leocoder/estate/*" | wc -l) -echo "📊 Java文件总数: $java_count" - -echo "修复完成!" \ No newline at end of file