从零搭建 Spring Boot 3 企业级项目:模块划分 + 统一响应/异常封装实战

作者:忆笙智云官方 | 发布时间:2026-05-23 09:15 | 更新时间:2026-06-23 09:15

从零搭建 Spring Boot 3 企业级项目架构

引言

在 Java 后端开发领域,Spring Boot 已经成为事实上的标准框架。然而,从零搭建一个企业级项目架构并非简单地引入 Spring Boot Starter 那么容易——模块如何划分?依赖如何管理?异常如何统一处理?响应如何统一封装?这些问题如果没有在项目初期就规划好,后期重构的成本将非常高。

本文将分享基于 Spring Boot 3.3.x + Java 21 搭建企业级项目架构的实战经验,涵盖模块划分、依赖管理、统一异常处理和统一响应封装四个核心主题。

一、模块划分策略

1.1 模块结构设计

企业级项目通常采用多模块(Multi-Module)结构,按职责将代码划分为不同层次:

project-root/
├── pom.xml                    # 父POM,统一依赖管理
├── project-common/            # 通用模块:工具类、常量、枚举
├── project-infra/             # 基础设施模块:Redis、MQ、存储等
├── project-system/            # 系统管理模块:用户、角色、权限
└── project-module-xxx/        # 业务模块:按业务域划分

1.2 模块依赖关系

graph TB
    A[project-module-xxx<br/>业务模块] --> B[project-system<br/>系统管理模块]
    A --> C[project-infra<br/>基础设施模块]
    B --> C
    B --> D[project-common<br/>通用模块]
    C --> D
    A --> D

    style D fill:#e1f5fe,stroke:#0288d1
    style C fill:#f3e5f5,stroke:#7b1fa2
    style B fill:#e8f5e9,stroke:#388e3c
    style A fill:#fff3e0,stroke:#f57c00

核心原则

1.3 模块 POM 配置示例

<!-- 父POM:统一管理版本 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.3.3</version>
</parent>

<properties>
    <java.version>21</java.version>
    <mybatis-plus.version>3.5.7</mybatis-plus.version>
    <sa-token.version>1.39.0</sa-token.version>
</properties>

<dependencyManagement>
    <dependencies>
        <!-- 内部模块 -->
        <dependency>
            <groupId>com.example</groupId>
            <artifactId>project-common</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!-- 第三方依赖统一版本 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
    </dependencies>
</dependencyManagement>

二、依赖管理最佳实践

2.1 版本集中管理

在父 POM 的 <dependencyManagement> 中统一声明所有第三方依赖版本,子模块只需引入 <groupId><artifactId>,无需指定版本号:

<!-- 子模块:无需写版本号 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency>

2.2 依赖范围控制

依赖类型 scope 说明
Spring Boot Starter 默认 compile 运行时必需
Lombok provided 仅编译期使用
单元测试依赖 test 仅测试时使用
数据库驱动 runtime 仅运行时需要
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <scope>provided</scope>
</dependency>

2.3 避免依赖冲突

使用 Maven Enforcer 插件禁止引入重复依赖:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-enforcer-plugin</artifactId>
    <executions>
        <execution>
            <id>ban-duplicate-classes</id>
            <goals><goal>enforce</goal></goals>
            <configuration>
                <rules>
                    <banDuplicateClasses>
                        <ignoreClasses>
                            <ignoreClass>javax.*</ignoreClass>
                        </ignoreClasses>
                    </banDuplicateClasses>
                </rules>
            </configuration>
        </execution>
    </executions>
</plugin>

三、统一响应封装

3.1 通用响应对象

所有 API 返回值统一使用 R<T> 泛型类封装,确保前端接收到的数据结构一致:

/**
 * 统一响应结果封装
 * @param <T> 数据类型
 */
public class R<T> {

    /** 状态码 */
    private int code;

    /** 消息 */
    private String msg;

    /** 数据 */
    private T data;

    /** 时间戳 */
    private long timestamp;

    private R() {
        this.timestamp = System.currentTimeMillis();
    }

    /** 成功响应 */
    public static <T> R<T> ok(T data) {
        R<T> r = new R<>();
        r.code = 200;
        r.msg = "操作成功";
        r.data = data;
        return r;
    }

    /** 失败响应 */
    public static <T> R<T> fail(int code, String msg) {
        R<T> r = new R<>();
        r.code = code;
        r.msg = msg;
        return r;
    }

    /** 常用失败响应 */
    public static <T> R<T> fail(String msg) {
        return fail(500, msg);
    }
}

3.2 Controller 使用示例

@RestController
@RequestMapping("/api/user")
public class UserController {

    @GetMapping("/{id}")
    public R<UserVO> getUser(@PathVariable Long id) {
        UserVO user = userService.getById(id);
        return R.ok(user);
    }

    @PostMapping
    public R<Void> createUser(@RequestBody UserDTO dto) {
        userService.create(dto);
        return R.ok(null);
    }
}

3.3 响应封装流程

sequenceDiagram
    participant C as Controller
    participant S as Service
    participant R as R<T>封装

    C->>S: 调用业务方法
    alt 成功
        S-->>C: 返回业务数据
        C->>R: R.ok(data)
        R-->>C: {code:200, msg:"操作成功", data:...}
    else 业务异常
        S-->>C: 抛出 BusinessException
        C->>R: R.fail(code, msg)
        R-->>C: {code:1001, msg:"用户不存在", data:null}
    end

四、统一异常处理

4.1 异常分类体系

graph TD
    A[Throwable] --> B[Exception]
    B --> C[RuntimeException]
    C --> D[BaseException<br/>基础业务异常]
    D --> E[BusinessException<br/>业务异常]
    D --> F[AuthException<br/>认证异常]
    D --> G[ForbiddenException<br/>授权异常]
    B --> H[SQLException<br/>数据库异常]
    B --> I[IOException<br/>IO异常]

    style D fill:#ffcdd2,stroke:#c62828
    style E fill:#fff9c4,stroke:#f9a825
    style F fill:#e1bee7,stroke:#7b1fa2
    style G fill:#e1bee7,stroke:#7b1fa2

4.2 自定义业务异常

/**
 * 业务异常基类
 */
public class BaseException extends RuntimeException {

    /** 错误码 */
    private final int code;

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

    public int getCode() {
        return code;
    }
}

/**
 * 通用业务异常
 */
public class BusinessException extends BaseException {

    public BusinessException(String message) {
        super(500, message);
    }

    public BusinessException(int code, String message) {
        super(code, message);
    }
}

4.3 全局异常处理器

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 业务异常处理
     */
    @ExceptionHandler(BaseException.class)
    public R<Void> handleBusinessException(BaseException e) {
        log.warn("业务异常: code={}, msg={}", e.getCode(), e.getMessage());
        return R.fail(e.getCode(), e.getMessage());
    }

    /**
     * 参数校验异常处理
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public R<Void> handleValidException(MethodArgumentNotValidException e) {
        String message = e.getBindingResult().getFieldErrors().stream()
                .map(fe -> fe.getField() + ": " + fe.getDefaultMessage())
                .collect(Collectors.joining("; "));
        return R.fail(400, message);
    }

    /**
     * 兜底异常处理
     */
    @ExceptionHandler(Exception.class)
    public R<Void> handleException(Exception e) {
        log.error("系统异常", e);
        return R.fail(500, "系统繁忙,请稍后重试");
    }
}

五、Java 21 新特性在项目中的应用

5.1 Record 类替代 Lombok @Value

// 传统方式
@Value
public class UserDTO {
    String username;
    String email;
}

// Java 21 Record
public record UserDTO(String username, String email) {}

5.2 Switch 表达式优化

// 优化前
String desc;
switch (status) {
    case 1: desc = "启用"; break;
    case 2: desc = "禁用"; break;
    default: desc = "未知";
}

// Java 21 Switch 表达式
String desc = switch (status) {
    case 1 -> "启用";
    case 2 -> "禁用";
    default -> "未知";
};

结论与建议

架构搭建核心要点

  1. 模块划分先行:项目启动前先确定模块边界和依赖方向,避免后期循环依赖
  2. 版本统一管理:父 POM 集中管理版本号,子模块禁止硬编码版本
  3. 响应统一封装:所有 API 返回 R<T> 格式,前端只需处理一套数据结构
  4. 异常分类处理:业务异常与系统异常分离,全局处理器兜底,避免异常信息泄露

避坑建议

相关资源