#!/bin/bash #============================================================================= # 项目模板重构脚本 # 用于将coder-common-thin-backend项目重构为新的项目模板 # # 功能: # 1. 重构项目名称和模块名 # 2. 修改包名和groupId # 3. 更新配置文件中的包名引用 # 4. 重命名SQL文件和数据库名 # 5. 处理多层级子模块结构 # 6. 更新数据库连接字符串 # 7. 更新文件路径配置 # # 作者: Leocoder # 版本: 1.2.3 #============================================================================= set -e # 遇到错误立即退出 # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # 日志函数 log_info() { echo -e "${GREEN}[INFO]${NC} $1" } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" } log_step() { echo -e "${BLUE}[STEP]${NC} $1" } # 当前项目信息 CURRENT_PROJECT_NAME="coder-common-thin-backend" CURRENT_GROUP_ID="org.leocoder.thin" CURRENT_PACKAGE_NAME="org.leocoder.thin" CURRENT_MODULE_PREFIX="coder-common-thin" CURRENT_DB_NAME="coder-common-thin" # 脚本目录 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" log_info "=== 项目模板重构脚本 v1.2.3 ===" log_info "项目根目录: $PROJECT_ROOT" # 验证当前目录 if [[ ! -f "$PROJECT_ROOT/pom.xml" ]]; then log_error "当前目录不是有效的Maven项目根目录" exit 1 fi # 获取用户输入 echo "" log_step "请输入新项目的配置信息:" read -p "新项目名称 (例如: my-project-backend): " NEW_PROJECT_NAME read -p "新的GroupId (例如: com.company.project): " NEW_GROUP_ID read -p "新的包名 (例如: com.company.project): " NEW_PACKAGE_NAME read -p "新的模块前缀 (例如: my-project): " NEW_MODULE_PREFIX read -p "新的数据库名 (例如: my_project_db): " NEW_DB_NAME # 验证输入 if [[ -z "$NEW_PROJECT_NAME" || -z "$NEW_GROUP_ID" || -z "$NEW_PACKAGE_NAME" || -z "$NEW_MODULE_PREFIX" || -z "$NEW_DB_NAME" ]]; then log_error "所有参数都不能为空" exit 1 fi # 显示配置信息确认 echo "" log_info "=== 重构配置确认 ===" echo "项目名称: $CURRENT_PROJECT_NAME -> $NEW_PROJECT_NAME" echo "GroupId: $CURRENT_GROUP_ID -> $NEW_GROUP_ID" echo "包名: $CURRENT_PACKAGE_NAME -> $NEW_PACKAGE_NAME" echo "模块前缀: $CURRENT_MODULE_PREFIX -> $NEW_MODULE_PREFIX" echo "数据库名: $CURRENT_DB_NAME -> $NEW_DB_NAME" echo "" read -p "确认开始重构?[y/N]: " CONFIRM if [[ ! "$CONFIRM" =~ ^[Yy]$ ]]; then log_info "重构已取消" exit 0 fi # 备份项目 BACKUP_DIR="${PROJECT_ROOT}_backup_$(date +%Y%m%d_%H%M%S)" log_step "创建项目备份: $BACKUP_DIR" cp -r "$PROJECT_ROOT" "$BACKUP_DIR" log_info "备份完成" # 重构函数 # 1. 重命名模块目录 rename_module_directories() { log_step "重命名模块目录..." cd "$PROJECT_ROOT" # 主模块重命名 local modules=( "$CURRENT_MODULE_PREFIX-web" "$CURRENT_MODULE_PREFIX-common" "$CURRENT_MODULE_PREFIX-model" "$CURRENT_MODULE_PREFIX-mybatisplus" "$CURRENT_MODULE_PREFIX-modules" "$CURRENT_MODULE_PREFIX-plugins" ) for module in "${modules[@]}"; do if [[ -d "$module" ]]; then new_module="${module/$CURRENT_MODULE_PREFIX/$NEW_MODULE_PREFIX}" log_info "重命名: $module -> $new_module" mv "$module" "$new_module" fi done # 递归重命名所有子模块(modules、plugins等) local parent_modules=( "$NEW_MODULE_PREFIX-modules" "$NEW_MODULE_PREFIX-plugins" ) for parent_module in "${parent_modules[@]}"; do if [[ -d "$parent_module" ]]; then log_info "处理子模块目录: $parent_module" cd "$parent_module" # 重命名当前目录下的所有子模块 for sub_dir in $CURRENT_MODULE_PREFIX-*; do if [[ -d "$sub_dir" ]]; then new_sub_dir="${sub_dir/$CURRENT_MODULE_PREFIX/$NEW_MODULE_PREFIX}" log_info "重命名子模块: $sub_dir -> $new_sub_dir" mv "$sub_dir" "$new_sub_dir" # 递归处理子模块中的子子模块(如果存在) if [[ -d "$new_sub_dir" ]]; then cd "$new_sub_dir" for sub_sub_dir in $CURRENT_MODULE_PREFIX-*; do if [[ -d "$sub_sub_dir" ]]; then new_sub_sub_dir="${sub_sub_dir/$CURRENT_MODULE_PREFIX/$NEW_MODULE_PREFIX}" log_info "重命名子子模块: $sub_sub_dir -> $new_sub_sub_dir" mv "$sub_sub_dir" "$new_sub_sub_dir" fi done cd ".." fi fi done cd "$PROJECT_ROOT" fi done log_info "模块目录重命名完成" } # 2. 更新POM文件 update_pom_files() { log_step "更新POM文件..." # 查找所有pom.xml文件 find "$PROJECT_ROOT" -name "pom.xml" -type f | while read pom_file; do log_info "更新POM: $pom_file" # 使用sed进行替换 sed -i.bak \ -e "s|$CURRENT_GROUP_ID|$NEW_GROUP_ID|g" \ -e "s|$CURRENT_PROJECT_NAME|$NEW_PROJECT_NAME|g" \ -e "s|$CURRENT_PROJECT_NAME|$NEW_PROJECT_NAME|g" \ -e "s|$CURRENT_MODULE_PREFIX-|$NEW_MODULE_PREFIX-|g" \ "$pom_file" # 删除备份文件 rm -f "${pom_file}.bak" done log_info "POM文件更新完成" } # 3. 更新Java包结构 update_java_packages() { log_step "更新Java包结构..." # 转换包名路径 local current_package_path="${CURRENT_PACKAGE_NAME//./\/}" local new_package_path="${NEW_PACKAGE_NAME//./\/}" log_info "包路径转换: $current_package_path -> $new_package_path" # 查找所有Java文件并更新包名和import语句 find "$PROJECT_ROOT" -name "*.java" -type f | while read java_file; do log_info "更新Java文件内容: $java_file" # 更新package声明和import语句,使用更精确的匹配(避免转义字符问题) sed -i.bak \ -e "s|^package ${CURRENT_PACKAGE_NAME};|package ${NEW_PACKAGE_NAME};|g" \ -e "s|^package ${CURRENT_PACKAGE_NAME}[.]|package ${NEW_PACKAGE_NAME}.|g" \ -e "s|^import ${CURRENT_PACKAGE_NAME};|import ${NEW_PACKAGE_NAME};|g" \ -e "s|^import ${CURRENT_PACKAGE_NAME}[.]|import ${NEW_PACKAGE_NAME}.|g" \ -e "s|${CURRENT_PACKAGE_NAME}[.]|${NEW_PACKAGE_NAME}.|g" \ "$java_file" rm -f "${java_file}.bak" done # 重构Java包目录结构 log_info "开始重构Java包目录结构..." # 查找所有包含当前包路径的java源码目录 find "$PROJECT_ROOT" -path "*/src/main/java/$current_package_path" -type d | while read old_package_dir; do log_info "处理包目录: $old_package_dir" # 获取java源码根目录 local java_root="${old_package_dir%/$current_package_path}" local new_package_dir="$java_root/$new_package_path" log_info " 源目录: $old_package_dir" log_info " 目标目录: $new_package_dir" # 创建新的包目录结构 mkdir -p "$(dirname "$new_package_dir")" # 移动整个包目录到新位置 if [[ -d "$old_package_dir" && "$old_package_dir" != "$new_package_dir" ]]; then mv "$old_package_dir" "$new_package_dir" log_info " 已移动包目录" # 清理空的父级目录 local old_parent="$(dirname "$old_package_dir")" while [[ "$old_parent" != "$java_root" && -d "$old_parent" ]]; do if [[ -z "$(ls -A "$old_parent" 2>/dev/null)" ]]; then rmdir "$old_parent" 2>/dev/null && log_info " 清理空目录: $old_parent" old_parent="$(dirname "$old_parent")" else break fi done fi done log_info "Java包结构更新完成" } # 4. 清理目录名中的反斜杠(独立函数) cleanup_backslash_directories() { log_step "清理目录名中的反斜杠..." local fixed_count=0 local attempts=0 # 重复检查和修复,直到没有反斜杠目录或达到最大尝试次数 while [[ $attempts -lt 5 ]]; do local found_backslash=false # 查找包含反斜杠的目录 for dir_path in $(find "$PROJECT_ROOT" -path "*/src/main/java/*" -type d 2>/dev/null); do if [[ ! -d "$dir_path" ]]; then continue fi dir_name=$(basename "$dir_path") # 检查目录名是否包含反斜杠 if [[ "$dir_name" == *"\\"* ]]; then found_backslash=true # 清理反斜杠,获取正确的目录名 clean_dir_name="${dir_name//\\/}" parent_dir=$(dirname "$dir_path") new_dir_path="$parent_dir/$clean_dir_name" log_info "修复目录名: '$dir_name' -> '$clean_dir_name'" # 重命名目录 if [[ "$dir_path" != "$new_dir_path" && ! -e "$new_dir_path" ]]; then if mv "$dir_path" "$new_dir_path" 2>/dev/null; then log_info " ✓ 目录重命名成功: $(basename "$new_dir_path")" ((fixed_count++)) else log_warn " ✗ 目录重命名失败: $dir_path" fi fi fi done # 如果没有找到反斜杠目录,退出循环 if [[ "$found_backslash" == false ]]; then break fi ((attempts++)) sleep 0.1 # 短暂等待,确保文件系统操作完成 done if [[ $fixed_count -gt 0 ]]; then log_info "总共修复了 $fixed_count 个包含反斜杠的目录(用了 $attempts 轮处理)" else log_info "未发现包含反斜杠的目录" fi log_info "反斜杠清理完成" } # 5. 更新配置文件 update_config_files() { log_step "更新配置文件..." # 更新application配置文件 find "$PROJECT_ROOT" -name "application*.yml" -o -name "application*.yaml" -o -name "application*.properties" | while read config_file; do log_info "更新配置文件: $config_file" # 计算新的配置名称(兼容各种bash版本) local new_pool_name="$(echo "$NEW_MODULE_PREFIX" | tr '[:lower:]' '[:upper:]')-HIKARI-DEV" local new_project_name="$(echo "$NEW_MODULE_PREFIX" | tr '[:lower:]' '[:upper:]')-ADMIN" sed -i.bak \ -e "s|packages-to-scan: $CURRENT_PACKAGE_NAME|packages-to-scan: $NEW_PACKAGE_NAME|g" \ -e "s|$CURRENT_PACKAGE_NAME|$NEW_PACKAGE_NAME|g" \ -e "s|name: coder-web|name: ${NEW_MODULE_PREFIX}-web|g" \ -e "s|projectName: CORDER-ADMIN-THIN|projectName: $new_project_name|g" \ -e "s|pool-name: CORDER-HIKARI-DEV|pool-name: $new_pool_name|g" \ -e "s|jdbc:mysql://localhost:3306/$CURRENT_DB_NAME|jdbc:mysql://localhost:3306/$NEW_DB_NAME|g" \ -e "s|jdbc:mysql://localhost:3306/$CURRENT_DB_NAME-backup|jdbc:mysql://localhost:3306/$NEW_DB_NAME-backup|g" \ -e "s|/$CURRENT_PROJECT_NAME/|/$NEW_PROJECT_NAME/|g" \ -e "s|$CURRENT_MODULE_PREFIX|$NEW_MODULE_PREFIX|g" \ "$config_file" rm -f "${config_file}.bak" done # 更新logback配置文件(专门处理logback特有的配置) find "$PROJECT_ROOT" -name "logback*.xml" | while read logback_file; do log_info "更新Logback配置: $logback_file" # 计算新的日志配置名称(兼容各种bash版本) local new_context_name="${NEW_MODULE_PREFIX}-logback" local new_property_name="$(echo "$NEW_MODULE_PREFIX" | tr '[:lower:]' '[:upper:]')_ADMIN_LOGS" sed -i.bak \ -e "s|$CURRENT_PACKAGE_NAME|$NEW_PACKAGE_NAME|g" \ -e "s|$CURRENT_MODULE_PREFIX-logback|$new_context_name|g" \ -e "s|CORDER_ADMIN_LOGS|$new_property_name|g" \ -e "s|name=\"CORDER_ADMIN_LOGS\"|name=\"$new_property_name\"|g" \ "$logback_file" rm -f "${logback_file}.bak" done # 更新MyBatis XML文件(处理namespace和resultType) find "$PROJECT_ROOT" -name "*.xml" -path "*/mapper/*" | while read mapper_file; do log_info "更新MyBatis配置: $mapper_file" sed -i.bak \ -e "s|namespace=\"$CURRENT_PACKAGE_NAME|namespace=\"$NEW_PACKAGE_NAME|g" \ -e "s|resultType=\"$CURRENT_PACKAGE_NAME|resultType=\"$NEW_PACKAGE_NAME|g" \ -e "s|parameterType=\"$CURRENT_PACKAGE_NAME|parameterType=\"$NEW_PACKAGE_NAME|g" \ "$mapper_file" rm -f "${mapper_file}.bak" done log_info "配置文件更新完成" } # 6. 更新SQL文件 update_sql_files() { log_step "更新SQL文件..." local sql_dir="$PROJECT_ROOT/sql" if [[ -d "$sql_dir" ]]; then # 重命名SQL文件 local current_sql_file="$sql_dir/$CURRENT_DB_NAME.sql" local new_sql_file="$sql_dir/$NEW_DB_NAME.sql" if [[ -f "$current_sql_file" ]]; then log_info "重命名SQL文件: $CURRENT_DB_NAME.sql -> $NEW_DB_NAME.sql" mv "$current_sql_file" "$new_sql_file" # 更新SQL文件内容中的数据库名引用 sed -i.bak \ -e "s|Source Schema.*: $CURRENT_DB_NAME|Source Schema : $NEW_DB_NAME|g" \ -e "s|$CURRENT_DB_NAME|$NEW_DB_NAME|g" \ "$new_sql_file" rm -f "${new_sql_file}.bak" fi fi log_info "SQL文件更新完成" } # 7. 更新其他文件 update_other_files() { log_step "更新其他相关文件..." # 更新README文件 find "$PROJECT_ROOT" -name "README*" -type f | while read readme_file; do log_info "更新README: $readme_file" sed -i.bak \ -e "s|$CURRENT_PROJECT_NAME|$NEW_PROJECT_NAME|g" \ -e "s|$CURRENT_MODULE_PREFIX|$NEW_MODULE_PREFIX|g" \ -e "s|$CURRENT_PACKAGE_NAME|$NEW_PACKAGE_NAME|g" \ "$readme_file" rm -f "${readme_file}.bak" done # 更新CLAUDE.md文件 if [[ -f "$PROJECT_ROOT/CLAUDE.md" ]]; then log_info "更新CLAUDE.md" sed -i.bak \ -e "s|$CURRENT_PROJECT_NAME|$NEW_PROJECT_NAME|g" \ -e "s|$CURRENT_MODULE_PREFIX|$NEW_MODULE_PREFIX|g" \ -e "s|$CURRENT_PACKAGE_NAME|$NEW_PACKAGE_NAME|g" \ "$PROJECT_ROOT/CLAUDE.md" rm -f "$PROJECT_ROOT/CLAUDE.md.bak" fi # 更新其他配置文件(如果存在) find "$PROJECT_ROOT" -name "*.properties" -o -name "*.yml" -o -name "*.yaml" | while read prop_file; do if [[ "$prop_file" != *"application"* ]]; then log_info "更新属性文件: $prop_file" sed -i.bak \ -e "s|$CURRENT_PACKAGE_NAME|$NEW_PACKAGE_NAME|g" \ -e "s|$CURRENT_MODULE_PREFIX|$NEW_MODULE_PREFIX|g" \ "$prop_file" rm -f "${prop_file}.bak" fi done log_info "其他文件更新完成" } # 8. 清理和验证 cleanup_and_verify() { log_step "清理临时文件和验证..." # 清理备份文件 find "$PROJECT_ROOT" -name "*.bak" -delete # 验证重构结果 log_info "验证重构结果..." # 检查是否还有旧的引用(排除脚本文件、日志文件、备份等) local old_refs=$(grep -r "$CURRENT_PACKAGE_NAME" "$PROJECT_ROOT" \ --exclude-dir=".git" \ --exclude-dir="target" \ --exclude-dir=".idea" \ --exclude-dir="script" \ --exclude="*.log" \ --exclude="spy.log" \ --exclude="*.bak" \ --exclude="*.sh" \ 2>/dev/null | wc -l) if [[ $old_refs -gt 0 ]]; then log_warn "发现 $old_refs 处旧包名引用,请手动检查" grep -r "$CURRENT_PACKAGE_NAME" "$PROJECT_ROOT" \ --exclude-dir=".git" \ --exclude-dir="target" \ --exclude-dir=".idea" \ --exclude-dir="script" \ --exclude="*.log" \ --exclude="spy.log" \ --exclude="*.bak" \ --exclude="*.sh" \ 2>/dev/null | head -10 else log_info "✓ 验证通过:未发现旧包名引用" fi log_info "清理完成" } # 9. 重命名项目根目录 rename_project_directory() { log_step "重命名项目根目录..." # 获取当前项目目录名 local current_dir_name=$(basename "$PROJECT_ROOT") local parent_dir=$(dirname "$PROJECT_ROOT") local new_project_dir="$parent_dir/$NEW_PROJECT_NAME" log_info "项目目录重命名: $current_dir_name -> $NEW_PROJECT_NAME" # 检查目标目录是否已存在 if [[ -d "$new_project_dir" && "$PROJECT_ROOT" != "$new_project_dir" ]]; then log_warn "目标目录已存在: $new_project_dir" log_warn "跳过项目目录重命名" return fi # 重命名项目目录 if [[ "$PROJECT_ROOT" != "$new_project_dir" ]]; then log_info "移动项目目录: $PROJECT_ROOT -> $new_project_dir" # 切换到父目录 cd "$parent_dir" # 重命名目录 if mv "$current_dir_name" "$NEW_PROJECT_NAME" 2>/dev/null; then log_info "✓ 项目目录重命名成功" log_info "新的项目路径: $new_project_dir" # 更新PROJECT_ROOT变量为新路径 PROJECT_ROOT="$new_project_dir" else log_warn "✗ 项目目录重命名失败,请手动重命名" fi else log_info "项目目录名已正确,无需重命名" fi log_info "项目目录处理完成" } # 执行重构 echo "" log_info "=== 开始执行重构 ===" rename_module_directories update_pom_files update_java_packages cleanup_backslash_directories update_config_files update_sql_files update_other_files cleanup_and_verify rename_project_directory echo "" log_info "=== 重构完成 ===" log_info "新项目名称: $NEW_PROJECT_NAME" log_info "新的GroupId: $NEW_GROUP_ID" log_info "新的包名: $NEW_PACKAGE_NAME" log_info "新的模块前缀: $NEW_MODULE_PREFIX" log_info "新的数据库名: $NEW_DB_NAME" echo "" log_info "项目备份位置: $BACKUP_DIR" log_info "新项目位置: $PROJECT_ROOT" echo "" log_warn "重构完成后请执行以下操作:" echo "1. 进入新项目目录: cd \"$PROJECT_ROOT\"" echo "2. 验证项目能否正常编译: mvn clean compile" echo "3. 更新数据库连接配置中的数据库名" echo "4. 在IDE中重新导入项目,检查包结构" echo "5. 提交代码到新的Git仓库" echo "" log_info "感谢使用项目模板重构脚本!"