一个经典的 Spring Boot + Maven 后端项目目录通常长什么样子呢?
SpringBoot 长什么样
答:像下面这个样子~
demo-project
├── pom.xml
├── README.md
├── .gitignore
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── demo
│ │ │ ├── DemoApplication.java
│ │ │ ├── controller
│ │ │ │ └── UserController.java
│ │ │ ├── service
│ │ │ │ ├── UserService.java
│ │ │ │ └── impl
│ │ │ │ └── UserServiceImpl.java
│ │ │ ├── mapper
│ │ │ │ └── UserMapper.java
│ │ │ ├── entity
│ │ │ │ └── User.java
│ │ │ ├── dto
│ │ │ │ └── UserDTO.java
│ │ │ ├── vo
│ │ │ │ └── UserVO.java
│ │ │ ├── config
│ │ │ │ └── WebConfig.java
│ │ │ ├── common
│ │ │ │ ├── Result.java
│ │ │ │ └── ErrorCode.java
│ │ │ ├── exception
│ │ │ │ ├── BusinessException.java
│ │ │ │ └── GlobalExceptionHandler.java
│ │ │ └── util
│ │ │ └── DateUtils.java
│ │ └── resources
│ │ ├── application.yml
│ │ ├── application-dev.yml
│ │ ├── application-prod.yml
│ │ ├── mapper
│ │ │ └── UserMapper.xml
│ │ ├── static
│ │ └── templates
│ └── test
│ └── java
│ └── com
│ └── example
│ └── demo
│ └── DemoApplicationTests.java
好长啊~ 让我们看看这些核心分层的含义:
controller 接收 HTTP 请求,做参数校验,返回结果
service 业务逻辑
mapper 数据库访问,常见于 MyBatis
entity 数据库表对应的实体类
dto 接收前端请求或服务间传输的数据对象
vo 返回给前端展示的数据对象
config 配置类
common 通用返回体、常量、枚举
exception 自定义异常和全局异常处理
util 工具类
resources 配置文件、Mapper XML、静态资源
test 测试代码
如果是小项目,可以简化成:
controller
service
mapper
entity
common
config
不一定一开始就拆很多包。经典目录的原则是:Controller 不写复杂业务,Service 不直接拼 HTTP,Mapper 只管数据库访问,层与层职责清楚。
有不明白的地方?不要担心,我们后面会讲到的。
这么多文件,这个 Spring Boot 项目启动中、后的流程是什么样子的呢?
先看一下项目入口、配置和主要包结构,然后按实际代码把 Spring Boot 启动链路串起来,而不是只讲通用流程。
项目结构很小,主线集中在 DemoApplication → Controller → Service → Mapper/XML → 数据库 。
这个项目的启动流程可以按两条线理解:应用启动流程 和 请求处理流程 。
应用启动流程
入口在 DemoApplication.java ,如下:
|
|
启动时大致发生这些事:
1. JVM 执行 main 方法。
2. SpringApplication.run(...) 创建并启动 Spring 容器。
3. @SpringBootApplication 生效,它包含三类核心能力:
- 标记这是 Spring Boot 应用
- 开启自动配置,比如 Web、JSON、数据源、MyBatis 等
- 从
com.example.demo包开始扫描Bean
4. Spring 扫描到这些组件:
UserControllerUserServiceImplUserMapperGlobalExceptionHandlerWebConfig
5. 读取 application.yml ,默认激活 dev 环境。
6. 继续读取 application-dev.yml,配置 H2 内存数据库。
7. 因为 spring.sql.init.mlde: always,启动时会执行:
schema.sql创建users表data.sql插入tom、alice两条演示数据
8. MyBatis 根据配置加载 UserMapper.xml 。
9. 内嵌 Tomcat 启动,监听 8080 端口。
如此,启动后,我们叫可以访问:
GET http://localhost:8080/api/users
GET http://localhost:8080/api/users/1
POST http://localhost:8080/api/users
那么,在请求访问的时候,又经过了哪些流程呢?
请求处理流程
一次请求的大致流向:
前端请求
-> Controller
-> Service
-> Mapper
-> Database
-> Mapper
-> Service
-> Controller
-> JSON 响应
下面,我们以查询用户列表为例,具体说明一下整个流程,如下:
浏览器/前端:
→ UserController
→ UserService
→ UserServiceImpl
→ UserMapper
→ UserMapper.xml
→ H2 数据库
→ 返回 Entity
→ 转成 VO
→ Result.success(...)
→ JSON 回应
我们来看看对应的代码链路:
1. 请求进入 UserController.java
|
|
2. Controller 调用 UserService.java 接口
3. 实际执行的是 UserServiceImpl.java ,因为它有:
|
|
4. Service 调用 UserMapper.java .
5. MyBatis 找到 UserMapper.xml 里的 SQL :
|
|
6. 查询结果先映射成 User ,再由 Service 正成 UserVO ,最后 Controller 包装成 Result.success(...) 返回。
请求过程中出现了问题怎么办呢?
异常流程处理
如果发生错误,不是在 Controller 里手写 try-catch ,而是进入 GlobalExceptionHandler.java 。
比如访问不存在的用户 GET /api/users/999 ,流程是:
UserController.getUser(...)
→ UserServiceImpl.getUser(...)
→ userMapper.findById(id)
→ 查不到,抛 BusinessException
→ GlobalExceptionHandler 捕获
→ Result.fail(...)
→ JSON 错误响应