coder-common-thin-backend/script/project-template-refactor.sh
Leo f262820a76 docs(script): 新增项目脚本和文档
- 新增script/README.md脚本使用说明文档
- 新增script/project-template-refactor.sh项目模板重构脚本
- 完善脚本工具集,提高开发效率
2025-09-22 23:10:11 +08:00

567 lines
19 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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|<groupId>$CURRENT_GROUP_ID</groupId>|<groupId>$NEW_GROUP_ID</groupId>|g" \
-e "s|<artifactId>$CURRENT_PROJECT_NAME</artifactId>|<artifactId>$NEW_PROJECT_NAME</artifactId>|g" \
-e "s|<name>$CURRENT_PROJECT_NAME</name>|<name>$NEW_PROJECT_NAME</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|<contextName>$CURRENT_MODULE_PREFIX-logback</contextName>|<contextName>$new_context_name</contextName>|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 "感谢使用项目模板重构脚本!"