#!/bin/bash

# 提示用户输入项目名称
read -p "输入你要生成的项目名 (如: my-project): " PROJECT_NAME_INPUT

# 使用 sed 将所有连续的空格替换为单个连字符，并移除前后连字符
PROJECT_NAME=$(echo "$PROJECT_NAME_INPUT" | sed 's/^[[:space:]]//;s/[[:space:]]$//;s/[[:space:]]\+/-/g')

# 检查项目名称是否符合允许的格式（仅字母和连字符，且不以连字符开头或结尾，不含多个连续连字符）
if [[ ! "$PROJECT_NAME" =~ ^[a-zA-Z]+(-[a-zA-Z]+)*$ ]]; then 
    echo "项目名称格式不正确。请使用字母和空格组合（空格将被替换为单个连字符）。" 
    exit 1 
fi

# 转换为小写并移除连字符，用于包名
PACKAGE_NAME=$(echo "$PROJECT_NAME" | tr '[:upper:]' '[:lower:]' | tr -d '-')

# 修复的驼峰命名转换方法
# 首先将项目名按连字符分割，然后每个部分首字母大写，其余小写，最后拼接
CLASS_NAME=""
for part in $(echo $PROJECT_NAME | tr '-' ' '); do
    initial=$(echo ${part:0:1} | tr '[:lower:]' '[:upper:]')
    rest=$(echo ${part:1} | tr '[:upper:]' '[:lower:]')
    CLASS_NAME="${CLASS_NAME}${initial}${rest}"
done

# 确认 CLASS_NAME 不为空
if [[ -z "$CLASS_NAME" ]]; then
    echo "生成的类名为空，请检查项目名称输入。"
    exit 1
fi
# 检查是否在项目根目录
if [ -d "$PROJECT_NAME" ]; then
    echo "项目目录 '$PROJECT_NAME' 已存在。"
    read -p "是否覆盖现有目录？(y/n): " choice
    case "$choice" in
        y | Y) rm -rf "$PROJECT_NAME" ;;
        *) echo "脚本终止。"; exit 1 ;;
    esac
fi

# 创建项目根目录和必要的子目录
BASE_DIR="$PROJECT_NAME/src/main/java/com/jackasher/$PACKAGE_NAME"
TEST_DIR="$PROJECT_NAME/src/test/java/com/jackasher/$PACKAGE_NAME"

# 创建完整的目录结构
mkdir -p "$BASE_DIR/controller"
mkdir -p "$BASE_DIR/service/impl"
mkdir -p "$BASE_DIR/mapper"

# 基础模型目录
mkdir -p "$BASE_DIR/model/pojo"
mkdir -p "$BASE_DIR/model/request"
mkdir -p "$BASE_DIR/model/response"
mkdir -p "$BASE_DIR/model/dto"
mkdir -p "$BASE_DIR/model/vo"
mkdir -p "$BASE_DIR/model/param"
mkdir -p "$BASE_DIR/model/enums"
mkdir -p "$BASE_DIR/model/form"
mkdir -p "$BASE_DIR/model/event"
# CQRS模型目录
mkdir -p "$BASE_DIR/model/query"
mkdir -p "$BASE_DIR/model/command"


mkdir -p "$BASE_DIR/config"
mkdir -p "$BASE_DIR/common"
mkdir -p "$BASE_DIR/constant"
mkdir -p "$BASE_DIR/exception"
mkdir -p "$BASE_DIR/util"
mkdir -p "$BASE_DIR/job"
mkdir -p "$PROJECT_NAME/src/main/resources/static"
mkdir -p "$PROJECT_NAME/src/main/resources/templates"
mkdir -p "$PROJECT_NAME/src/main/resources/mapper"
mkdir -p "$TEST_DIR"

echo "目录结构创建完成。"

# 创建 pom.xml
cat >"$PROJECT_NAME/pom.xml" <<EOL
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <!-- 父项目依赖 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.7</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <!-- 项目信息 -->
    <groupId>com.jackasher.${PACKAGE_NAME}</groupId>
    <artifactId>${PACKAGE_NAME}</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>${CLASS_NAME}</name>
    <description>${CLASS_NAME}服务</description>

    <!-- 项目属性配置 -->
    <properties>
        <java.version>17</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <maven.compiler.source>\${java.version}</maven.compiler.source>
        <maven.compiler.target>\${java.version}</maven.compiler.target>

        <!-- 依赖版本管理 -->
        <mybatis-plus.version>3.5.7</mybatis-plus.version>
        <mybatis-spring.version>3.0.4</mybatis-spring.version>
        <commons-lang3.version>3.14.0</commons-lang3.version>
        <lombok.version>1.18.30</lombok.version>
        <springdoc.version>2.3.0</springdoc.version>
        <hutool.version>5.8.25</hutool.version>
        <druid.version>1.2.20</druid.version>
        <fastjson2.version>2.0.45</fastjson2.version>
        <easyexcel.version>3.3.3</easyexcel.version>
        <redisson.version>3.25.2</redisson.version>
    </properties>

    <!-- 依赖管理 -->
    <dependencies>
        <!-- Spring Boot 核心依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        
        <!-- knife4j -->
        <!-- http://127.0.0.1:8080/doc.html -->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
            <version>4.4.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- 数据库相关 -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>\${mybatis-spring.version}</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>\${mybatis-plus.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>\${druid.version}</version>
        </dependency>

        <!-- 缓存相关 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson-spring-boot-starter</artifactId>
            <version>\${redisson.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>

        <!-- API文档 -->
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
            <version>\${springdoc.version}</version>
        </dependency>

        <!-- 工具类库 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>\${lombok.version}</version>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>\${commons-lang3.version}</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.15.1</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>\${hutool.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.fastjson2</groupId>
            <artifactId>fastjson2</artifactId>
            <version>\${fastjson2.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>\${easyexcel.version}</version>
        </dependency>

        <!-- 日志 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
        </dependency>

        <!-- 测试相关 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter-test</artifactId>
            <version>\${mybatis-spring.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!-- 构建配置 -->
    <build>
        <finalName>\${project.artifactId}</finalName>
        <plugins>
            <!-- Spring Boot Maven 插件 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>

            <!-- Maven 编译插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <source>\${java.version}</source>
                    <target>\${java.version}</target>
                    <encoding>\${project.build.sourceEncoding}</encoding>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                            <version>\${lombok.version}</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>

            <!-- 资源插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>3.3.1</version>
                <configuration>
                    <encoding>\${project.build.sourceEncoding}</encoding>
                </configuration>
            </plugin>

            <!-- 打包跳过测试 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <skip>true</skip>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <!-- 多环境配置 -->
    <profiles>
        <profile>
            <id>dev</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <spring.profiles.active>dev</spring.profiles.active>
            </properties>
        </profile>
        <profile>
            <id>test</id>
            <properties>
                <spring.profiles.active>test</spring.profiles.active>
            </properties>
        </profile>
        <profile>
            <id>prod</id>
            <properties>
                <spring.profiles.active>prod</spring.profiles.active>
            </properties>
        </profile>
    </profiles>
</project>
EOL

echo "pom.xml 创建完成。"

# 创建主应用类
cat >"$BASE_DIR/${CLASS_NAME}Application.java" <<EOL
package com.jackasher.${PACKAGE_NAME};

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@MapperScan("com.jackasher.${PACKAGE_NAME}.mapper")
@EnableScheduling
public class ${CLASS_NAME}Application {
    public static void main(String[] args) {
        SpringApplication.run(${CLASS_NAME}Application.class, args);
    }
}
EOL

echo "主应用类 ${CLASS_NAME}Application.java 创建完成。"

# 创建 Swagger 配置类
cat >"$BASE_DIR/config/SwaggerConfig.java" <<EOL
package com.jackasher.${PACKAGE_NAME}.config;

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.Contact;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SwaggerConfig {
    
    @Bean
    public OpenAPI ${PACKAGE_NAME}OpenAPI() {
        return new OpenAPI()
                .info(new Info()
                        .title("${CLASS_NAME} API")
                        .description("${CLASS_NAME} API文档")
                        .version("1.0")
                        .contact(new Contact()
                                .name("JackAsher")
                                .email("jackasher36@gmail.com")));
    }
}
EOL


# 创建 MybatisPlus 配置类
cat >"$BASE_DIR/config/MybatisPlusConfig.java" <<EOL
package com.jackasher.${PACKAGE_NAME}.config;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MybatisPlusConfig {

    /**
     * 配置MyBatis-Plus拦截器，添加分页功能支持
     *
     * @return MybatisPlusInterceptor 包含分页拦截器的拦截器实例，用于处理分页查询逻辑
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        // 创建MyBatis-Plus拦截器核心对象
        MybatisPlusInterceptor mpInterceptor=new MybatisPlusInterceptor();

        // 添加内置分页拦截器，用于自动处理SQL分页语句
        mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());

        return mpInterceptor;
    }
}
EOL


# 创建 Web 配置类
cat >"$BASE_DIR/config/WebConfig.java" <<EOL
package com.jackasher.${PACKAGE_NAME}.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 配置类，用于配置 Spring MVC 的相关设置，这里主要处理跨域请求。
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {

    /**
     * 从配置文件中读取允许的跨域源，将其注入到 allowedOrigins 数组中。
     * 配置文件中应包含类似 cors.allowed-origins=http://example1.com,http://example2.com 的配置。
     */
    @Value("\${cors.allowed-origins:http://localhost:3000}")
    private String[] allowedOrigins;

    /**
     * 重写 WebMvcConfigurer 接口的 addCorsMappings 方法，用于配置跨域请求映射。
     *
     * @param registry 用于注册跨域映射的对象。
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 配置所有的请求路径都支持跨域
        registry.addMapping("/**")
                // 使用允许的源模式匹配，允许来自 allowedOrigins 数组中指定的源的请求
                .allowedOriginPatterns(allowedOrigins)
                // 允许的 HTTP 请求方法
                .allowedMethods("GET", "POST", "PUT", "DELETE")
                // 明确允许的请求头，这里允许 Content-Type 和 Authorization 头
                .allowedHeaders("Content-Type", "Authorization")
                // 允许携带凭证（如 cookies）进行跨域请求
                .allowCredentials(true);
    }
}
EOL


# 创建 Redis 配置类
cat >"$BASE_DIR/config/RedisConfig.java" <<EOL
package com.jackasher.${PACKAGE_NAME}.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(connectionFactory);
        
        // 使用StringRedisSerializer来序列化和反序列化redis的key值
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        
        // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}
EOL



# 创建 Redis 服务类
cat >"$BASE_DIR/util/RedisService.java" <<EOL
package com.jackasher.${PACKAGE_NAME}.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Component
public class RedisService {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    /**
     * 设置缓存
     */
    public void set(String key, Object value) {
        redisTemplate.opsForValue().set(key, value);
    }
    
    /**
     * 设置缓存并设置过期时间
     */
    public void set(String key, Object value, long time) {
        if (time > 0) {
            redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
        } else {
            set(key, value);
        }
    }
    
    /**
     * 获取缓存
     */
    public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }
    
    /**
     * 删除缓存
     */
    public Boolean delete(String key) {
        return redisTemplate.delete(key);
    }
}
EOL



# 创建数据库工具类
cat >"$BASE_DIR/util/DBUtil.java" <<EOL
package com.jackasher.${PACKAGE_NAME}.util;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

@Slf4j
public class DBUtil {
    // 数据库工具类
    private static final String URL = "jdbc:mysql://localhost:3306/${PACKAGE_NAME}?useSSL=false&serverTimezone=UTC";
    private static final String USERNAME = "root";
    private static final String PASSWORD = "root";
    
    /**
     * 获取数据库连接
     */
    public static Connection getConnection() {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            return DriverManager.getConnection(URL, USERNAME, PASSWORD);
        } catch (ClassNotFoundException | SQLException e) {
            log.error("获取数据库连接失败", e);
            throw new RuntimeException("获取数据库连接失败", e);
        }
    }
    
    /**
     * 关闭数据库连接
     */
    public static void closeConnection(Connection connection) {
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                log.error("关闭数据库连接失败", e);
            }
        }
    }
    
    /**
     * SQL注入检查
     */
    public static boolean containsSqlInjection(String str) {
        if (StrUtil.isBlank(str)) {
            return false;
        }
        
        // SQL注入关键字
        String[] sqlKeywords = {"and", "or", "delete", "drop", "truncate", "update", "insert", "select", "union", 
                                "exec", "execute", "declare", "create", "alter", "database", "master"};
        
        String checkStr = str.toLowerCase();
        for (String keyword : sqlKeywords) {
            if (checkStr.contains(" " + keyword + " ") || checkStr.contains(";" + keyword + " ")) {
                return true;
            }
        }
        
        return false;
    }
}
EOL


# 创建 ErrorCode 枚举类
cat >"$BASE_DIR/common/ErrorCode.java" <<EOL
package com.jackasher.${PACKAGE_NAME}.common;

/**
 * 错误码枚举
 */
public enum ErrorCode {
    SUCCESS(0, "ok"),
    PARAMS_ERROR(40001, "请求参数错误"),
    NULL_ERROR(40002, "请求数据为空"),
    NOT_LOGIN(40100, "未登录"),
    NO_AUTH(40101, "无权限"),
    SYSTEM_ERROR(50000, "系统内部异常"),
    OPERATION_ERROR(50001, "操作失败"),
    NOT_FOUND(40400,"未查询到" );

    private final int code;
    private final String message;

    ErrorCode(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}
EOL


# 创建 BaseResponse 类
cat >"$BASE_DIR/common/BaseResponse.java" <<EOL
package com.jackasher.${PACKAGE_NAME}.common;

import lombok.Data;

import java.io.Serializable;

/**
 * 通用返回类
 */
@Data
public class BaseResponse<T> implements Serializable {
    private int code;
    private String message;
    private T data;

    public BaseResponse(int code, T data, String message) {
        this.code = code;
        this.data = data;
        this.message = message;
    }

    public BaseResponse(int code, T data) {
        this.code = code;
        this.data = data;
        this.message = "";
    }

    public BaseResponse(ErrorCode errorCode) {
        this.code = errorCode.getCode();
        this.message = errorCode.getMessage();
        this.data = null;
    }
}
EOL

# 创建 ResultUtils 类
cat >"$BASE_DIR/common/ResultUtils.java" <<EOL
package com.jackasher.${PACKAGE_NAME}.common;

/**
 * 返回工具类
 */
public class ResultUtils {
    /**
     * 成功
     *
     * @param data 数据
     * @param <T>  类型
     * @return 通用返回类
     */
    public static <T> BaseResponse<T> success(T data) {
        return new BaseResponse<>(0, data, "ok");
    }

    /**
     * 失败
     *
     * @param errorCode 错误码
     * @param <T>       类型
     * @return 通用返回类
     */
    public static <T> BaseResponse<T> error(ErrorCode errorCode) {
        return new BaseResponse<>(errorCode.getCode(), null, errorCode.getMessage());
    }

    /**
     * 失败
     *
     * @param errorCode 错误码
     * @param message   错误信息
     * @param <T>       类型
     * @return 通用返回类
     */
    public static <T> BaseResponse<T> error(ErrorCode errorCode, String message) {
        return new BaseResponse<>(errorCode.getCode(), null, message);
    }

    /**
     * 失败
     *
     * @param code    错误码
     * @param message 错误信息
     * @param <T>     类型
     * @return 通用返回类
     */
    public static <T> BaseResponse<T> error(int code, String message) {
        return new BaseResponse<>(code, null, message);
    }
}
EOL

# 创建异常类
cat >"$BASE_DIR/exception/BusinessException.java" <<EOL
package com.jackasher.${PACKAGE_NAME}.exception;

import com.jackasher.${PACKAGE_NAME}.common.ErrorCode;

/**
 * 业务异常类
 */
public class BusinessException extends RuntimeException {
    private final int code;
    private final String description;

    public BusinessException(int code, String message, String description) {
        super(message);
        this.code = code;
        this.description = description;
    }

    public BusinessException(ErrorCode errorCode) {
        super(errorCode.getMessage());
        this.code = errorCode.getCode();
        this.description = errorCode.getMessage();
    }

    public BusinessException(ErrorCode errorCode, String description) {
        super(errorCode.getMessage());
        this.code = errorCode.getCode();
        this.description = description;
    }

    public int getCode() {
        return code;
    }

    public String getDescription() {
        return description;
    }
}
EOL

# 创建全局异常处理类
cat >"$BASE_DIR/exception/GlobalExceptionHandler.java" <<EOL
package com.jackasher.${PACKAGE_NAME}.exception;

import com.jackasher.${PACKAGE_NAME}.common.BaseResponse;
import com.jackasher.${PACKAGE_NAME}.common.ErrorCode;
import com.jackasher.${PACKAGE_NAME}.common.ResultUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 全局异常处理器
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    @ExceptionHandler(BusinessException.class)
    public BaseResponse<?> businessExceptionHandler(BusinessException e) {
        log.error("BusinessException: {}", e.getMessage(), e);
        return ResultUtils.error(e.getCode(), e.getDescription());
    }

    @ExceptionHandler(RuntimeException.class)
    public BaseResponse<?> runtimeExceptionHandler(RuntimeException e) {
        log.error("RuntimeException", e);
        return ResultUtils.error(ErrorCode.SYSTEM_ERROR, e.getMessage());
    }

    @ExceptionHandler(Exception.class)
    public BaseResponse<?> exceptionHandler(Exception e) {
        log.error("Exception", e);
        return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "系统错误");
    }
}
EOL



# 创建常量类
cat >"$BASE_DIR/constant/${CLASS_NAME}Constant.java" <<EOL
package com.jackasher.${PACKAGE_NAME}.constant;

/**
 * ${CLASS_NAME} 常量
 */
public interface ${CLASS_NAME}Constant {
    /**
     * 用户登录态键
     */
    String USER_LOGIN_STATE = "userLoginState";

    /**
     * 默认角色
     */
    int DEFAULT_ROLE = 0;

    /**
     * 管理员角色
     */
    int ADMIN_ROLE = 1;
}
EOL


# 创建 POJO 类
cat >"$BASE_DIR/model/pojo/${CLASS_NAME}.java" <<EOL
package com.jackasher.${PACKAGE_NAME}.model.pojo;

import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**
 * ${CLASS_NAME} 实体类
 */
@Data
@TableName("${PACKAGE_NAME}")
public class ${CLASS_NAME} implements Serializable {
    /**
     * 主键
     */
    @TableId(type = IdType.AUTO)
    private Long id;

    /**
     * 创建时间
     */
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;

    /**
     * 更新时间
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;

    /**
     * 是否删除(0-未删, 1-已删)
     */
    @TableLogic
    private Integer isDelete;

    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
}
EOL

# 创建 Mapper 接口
cat >"$BASE_DIR/mapper/${CLASS_NAME}Mapper.java" <<EOL
package com.jackasher.${PACKAGE_NAME}.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jackasher.${PACKAGE_NAME}.model.pojo.${CLASS_NAME};
import org.apache.ibatis.annotations.Mapper;

/**
 * ${CLASS_NAME} Mapper 接口
 */
@Mapper
public interface ${CLASS_NAME}Mapper extends BaseMapper<${CLASS_NAME}> {
}
EOL


# 创建 Mapper XML
cat >"$PROJECT_NAME/src/main/resources/mapper/${CLASS_NAME}Mapper.xml" <<EOL
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jackasher.${PACKAGE_NAME}.mapper.${CLASS_NAME}Mapper">

    <resultMap id="BaseResultMap" type="com.jackasher.${PACKAGE_NAME}.model.pojo.${CLASS_NAME}">
        <id property="id" column="id" jdbcType="BIGINT"/>
        <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
        <result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
        <result property="isDelete" column="is_delete" jdbcType="TINYINT"/>
    </resultMap>

    <sql id="Base_Column_List">
        id,create_time,update_time,is_delete
    </sql>
</mapper>
EOL

# 创建请求类
cat >"$BASE_DIR/model/request/${CLASS_NAME}Request.java" <<EOL
package com.jackasher.${PACKAGE_NAME}.model.request;

import lombok.Data;

/**
 * ${CLASS_NAME} 请求类
 */
@Data
public class ${CLASS_NAME}Request {
    private Long id;
}
EOL


# 创建服务接口
cat >"$BASE_DIR/service/${CLASS_NAME}Service.java" <<EOL
package com.jackasher.${PACKAGE_NAME}.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.jackasher.${PACKAGE_NAME}.model.pojo.${CLASS_NAME};

/**
 * ${CLASS_NAME} 服务接口
 */
public interface ${CLASS_NAME}Service extends IService<${CLASS_NAME}> {
}
EOL


# 创建服务实现类
cat >"$BASE_DIR/service/impl/${CLASS_NAME}ServiceImpl.java" <<EOL
package com.jackasher.${PACKAGE_NAME}.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jackasher.${PACKAGE_NAME}.mapper.${CLASS_NAME}Mapper;
import com.jackasher.${PACKAGE_NAME}.model.pojo.${CLASS_NAME};
import com.jackasher.${PACKAGE_NAME}.service.${CLASS_NAME}Service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

/**
 * ${CLASS_NAME} 服务实现类
 */
@Service
@Slf4j
public class ${CLASS_NAME}ServiceImpl extends ServiceImpl<${CLASS_NAME}Mapper, ${CLASS_NAME}> 
    implements ${CLASS_NAME}Service {
    
}
EOL


# 创建控制器类
cat >"$BASE_DIR/controller/${CLASS_NAME}Controller.java" <<EOL
package com.jackasher.${PACKAGE_NAME}.controller;

import com.jackasher.${PACKAGE_NAME}.common.BaseResponse;
import com.jackasher.${PACKAGE_NAME}.common.ErrorCode;
import com.jackasher.${PACKAGE_NAME}.common.ResultUtils;
import com.jackasher.${PACKAGE_NAME}.exception.BusinessException;
import com.jackasher.${PACKAGE_NAME}.model.pojo.${CLASS_NAME};
import com.jackasher.${PACKAGE_NAME}.service.${CLASS_NAME}Service;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

/**
 * ${CLASS_NAME} 控制器
 */
@RestController
@RequestMapping("/${PACKAGE_NAME}")
@Slf4j
@Tag(name = "${CLASS_NAME}接口", description = "${CLASS_NAME}相关接口")
public class ${CLASS_NAME}Controller {

    @Resource
    private ${CLASS_NAME}Service ${PACKAGE_NAME}Service;

    @GetMapping("/hello")
    @Operation(summary = "测试接口", description = "Hello World测试接口")
    public BaseResponse<String> hello() {
        return ResultUtils.success("Hello, ${CLASS_NAME}!");
    }
    
    @GetMapping("/get/{id}")
    @Operation(summary = "获取${CLASS_NAME}信息", description = "根据ID获取${CLASS_NAME}详情")
    public BaseResponse<${CLASS_NAME}> getById(@PathVariable("id") Long id) {
        if (id <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        ${CLASS_NAME} ${PACKAGE_NAME} = ${PACKAGE_NAME}Service.getById(id);
        if (${PACKAGE_NAME} == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND);
        }
        return ResultUtils.success(${PACKAGE_NAME});
    }
}
EOL


# 创建定时任务类
cat >"$BASE_DIR/job/${CLASS_NAME}Job.java" <<EOL
package com.jackasher.${PACKAGE_NAME}.job;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

/**
 * ${CLASS_NAME} 定时任务
 */
@Component
@Slf4j
public class ${CLASS_NAME}Job {

    /**
     * 每天凌晨2点执行
     */
    @Scheduled(cron = "0 0 2 * * ?")
    public void cronJob() {
        log.info("定时任务开始执行");
        // TODO 定时任务逻辑
        log.info("定时任务执行完毕");
    }
}
EOL

# 创建测试类
cat >"$TEST_DIR/${CLASS_NAME}ApplicationTests.java" <<EOL
package com.jackasher.${PACKAGE_NAME};

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

/**
 * 应用测试类
 */
@SpringBootTest
class ${CLASS_NAME}ApplicationTests {

    @Test
    void contextLoads() {
    }
}
EOL

echo "${CLASS_NAME}ApplicationTests.java 创建完成。"

# 创建 application.properties
cat >"$PROJECT_NAME/src/main/resources/application.properties" <<EOL
# Spring Boot 配置示例

# 服务器端口
server.port=8080

spring.session.store-type=redis

# 数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/user-center?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=casio233.
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

# 逻辑删除
mybatis-plus.global-config.db-config.logic-delete-field=isDelete
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

server.servlet.context-path=/api/

# 设置 session 过期时间 30s
server.servlet.session.timeout=3600

spring.data.redis.host=127.0.0.1
spring.data.redis.port=6379
spring.data.redis.database=0

# 支持多个源用逗号分隔，支持通配符
cors.allowed-origins=http://172.20.10.3:3000,http://localhost:3000




EOL

echo "application.properties 创建完成。"

# 创建开发环境配置
cat >"$PROJECT_NAME/src/main/resources/application-dev.properties" <<EOL
# 开发环境配置
server.port=8080

# 开发环境数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/${PACKAGE_NAME}_dev?useSSL=false&serverTimezone=UTC&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=root

# 开发环境日志级别
logging.level.com.jackasher.${PACKAGE_NAME}=debug
EOL

echo "application-dev.properties 创建完成。"

# 创建测试环境配置
cat >"$PROJECT_NAME/src/main/resources/application-test.properties" <<EOL
# 测试环境配置
server.port=8080

# 测试环境数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/${PACKAGE_NAME}_test?useSSL=false&serverTimezone=UTC&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=root

# 测试环境日志级别
logging.level.com.jackasher.${PACKAGE_NAME}=info
EOL

echo "application-test.properties 创建完成。"

# 创建生产环境配置
cat >"$PROJECT_NAME/src/main/resources/application-prod.properties" <<EOL
# 生产环境配置
server.port=8080

# 生产环境数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/${PACKAGE_NAME}_prod?useSSL=false&serverTimezone=UTC&characterEncoding=utf-8
spring.datasource.username=production_user
spring.datasource.password=strong_password

# 生产环境日志级别
logging.level.root=warn
logging.level.com.jackasher.${PACKAGE_NAME}=info

# 禁用开发相关功能
springdoc.api-docs.enabled=false
springdoc.swagger-ui.enabled=false
knife4j.enable=false
spring.devtools.restart.enabled=false
spring.devtools.livereload.enabled=false
EOL

echo "application-prod.properties 创建完成。"


echo "所有文件创建完成。"
echo "项目 '$PROJECT_NAME' 构建完成。"
echo "进入项目目录并使用 Maven 构建项目："
echo "cd '$PROJECT_NAME'"
echo "mvn clean install -DskipTests"