01 Spring Boot 项目创建
JDK 17、Spring Boot 3.3.x、包名
com.example.demo。
1. 本章目标与前置阅读
本章目标
学完本章,你应该能够:
- 使用 start.spring.io 或 IDEA 创建 Spring Boot 3 项目
- 读懂
pom.xml关键段落,理解 Starter 机制 - 认识标准 Maven 目录与
src/main/resources - 编写启动类
@SpringBootApplication并理解组件扫描范围 - 配置
application.yml(端口、应用名、profile 入门) - 理解 Maven 目录与 Java 包的结构划分,按统一规范落地骨架,编写第一个
HelloController - 配置本地敏感配置与
.gitignore,避免密钥入库
2. 为什么项目里需要它
Spring Boot 解决的是「传统 Spring 配置繁重、嵌入式服务器与依赖版本难对齐」的问题。在团队里,统一的建项方式意味着:
- 新人 clone 后一条命令能跑起来
- 依赖版本由 BOM(Bill of Materials)管理,减少冲突
- 约定优于配置:缺省内嵌 Tomcat、自动装配数据源(后续章节启用)
没有标准骨架,后面的 MyBatis、Result 封装、全局异常将无处安放。
flowchart TB
subgraph 项目骨架
POM[pom.xml 依赖与版本]
APP[DemoApplication 启动入口]
YML[application.yml 配置]
PKG[包结构 module/common/config]
CTRL[HelloController 第一个接口]
end
POM --> APP
YML --> APP
APP --> PKG
PKG --> CTRL
3. 依赖与配置
3.1 使用 start.spring.io 生成项目
访问 start.spring.io/ ,建议选项:
| 项 | 值 |
|---|---|
| Project | Maven |
| Language | Java |
| Spring Boot | 3.3.x(与 README 表一致) |
| Packaging | Jar |
| Java | 17 |
| Group | com.example |
| Artifact | demo |
| Name | demo |
Dependencies(本章最小集):
- Spring Web(
spring-boot-starter-web)
生成后解压,用 IDEA Open 该目录。
Gradle 用户:结构类似,依赖写在
build.gradle;本书主线以 Maven 为例,Gradle 仅作对照。
3.2 pom.xml 关键解读
<?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>
<!-- 继承 Spring Boot 父 POM,统一管理依赖版本 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.5</version><!-- 与 README 表 3.3.x 对齐,patch 可随官方更新 -->
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Spring Boot beginner demo</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<!-- Web:Spring MVC + 内嵌 Tomcat + Jackson JSON -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
读懂这三点即可跟做后续章节:
<parent>引入 Boot 依赖版本清单,子依赖往往不写 versionspring-boot-starter-web是一个 Starter,一次性拉齐 Web 开发常用库spring-boot-maven-plugin支持mvn spring-boot:run与打可执行 fat jar
3.3 标准目录结构
demo/
├── pom.xml
├── src/
│ ├── main/
│ │ ├── java/com/example/demo/
│ │ │ └── DemoApplication.java
│ │ └── resources/
│ │ ├── application.yml
│ │ └── application-local.yml # 本地专用,不提交 Git
│ └── test/
│ └── java/com/example/demo/
│ └── DemoApplicationTests.java
└── .gitignore
3.4 application.yml
src/main/resources/application.yml:
spring:
application:
name: demo
# 默认激活 local profile(本地开发);生产环境由部署平台覆盖
profiles:
active: local
server:
port: 8080
src/main/resources/application-local.yml(本地密码放这里):
# 示例:后续 02 章数据源会用到,此处先占位
# spring:
# datasource:
# url: jdbc:mysql://localhost:3306/demo?useSSL=false&serverTimezone=Asia/Shanghai
# username: root
# password: your-password
3.5 .gitignore 与本地配置
在项目根 .gitignore 中增加(若 IDEA 模板未包含):
# 本地敏感配置 —— 切勿提交真实密码
application-local.yml
**/application-local.yml
target/
.idea/
*.iml
.DS_Store
团队约定:仓库内只保留 application.yml + application-dev.yml 等无真实密钥的示例;个人机器差异放 application-local.yml。
4. 最小可运行示例
4.1 启动类
src/main/java/com/example/demo/DemoApplication.java:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
@SpringBootApplication 是组合注解,等价于:
@Configuration:当前类可作为配置源@EnableAutoConfiguration:启用 Boot 自动配置@ComponentScan:默认扫描 当前包及其子包(com.example.demo.**)
因此,com.example.demo.module.user 下的 Controller 会被自动发现;若把类放在 com.other 包则扫描不到。
4.2 结构划分(Maven 目录 + Java 包)详解
Spring Boot 项目有两层「结构」要同时搞清:
- Maven 标准目录:源码、配置、测试各放哪
- Java 包划分:业务类按域与分层怎么拆
4.2.1 Maven 工程目录
demo/ # 项目根(与 artifact 同名)
├── pom.xml # 依赖与构建
├── .gitignore
└── src
├── main
│ ├── java # 业务与配置 Java 源码
│ │ └── com/example/demo/
│ └── resources # 非 Java 资源(yml、XML、静态文件)
│ ├── application.yml
│ ├── application-local.yml # 本地敏感配置,勿提交
│ ├── mapper/ # MyBatis XML(02 起)
│ │ └── user/
│ └── static/ # 可选:静态资源
└── test
└── java # 单元/集成测试
| 路径 | 放什么 | 常见误区 |
|---|---|---|
src/main/java | 所有 .java | 不要把 yml / XML 塞进 java 包目录 |
src/main/resources | yml、MyBatis XML、schema.sql 等 | 不要把业务类放进 resources |
src/test/java | 测试类 | 测试包名通常与被测类镜像 |
项目根 pom.xml | Maven 坐标与依赖 | 不要在源码里硬编码依赖 jar 路径 |
4.2.2 Java 包划分
在 com.example.demo 下按「公共能力 / 配置 / 业务域 / 安全」拆:
com.example.demo
├── DemoApplication.java # 启动类:必须在根包,才能扫到子包
├── common/ # 跨模块公共
│ ├── result/ # 03 Result<T>
│ ├── error/ # 错误码
│ └── exception/ # 04 BizException、Advice
├── config/ # Redis / MQ / Mail / Knife4j / WebSocket 等
├── security/ # 09 JWT(Filter、签发校验)
└── module/ # 按业务域拆分
├── user/
│ ├── controller/ # HTTP 入口
│ ├── service/ # 业务编排、事务
│ ├── mapper/ # 02 MyBatis 接口
│ ├── entity/ # 与表对应的实体
│ └── dto/ # 请求/响应/消息体
└── order/ # 结构与 user 对称
flowchart TB
subgraph root["com.example.demo"]
APP[DemoApplication]
COM[common]
CFG[config]
SEC[security]
MOD[module]
end
MOD --> USER[user]
MOD --> ORDER[order]
USER --> C[controller]
USER --> S[service]
USER --> M[mapper]
C --> S
S --> M
S --> COM
S --> CFG
C --> SEC
4.2.3 每个包解决什么问题
| 包 | 一句话职责 | 后续哪一章填充 |
|---|---|---|
DemoApplication | 启动入口;组件扫描根 | 本章 |
common.* | 与具体业务无关的横切能力 | 03、04、13 |
config | 「怎么连中间件」,无业务 if/else | 05–08、10、11 |
module.{域}.controller | 收参、校验入口、返回统一响应 | 01 起 |
module.{域}.service | 业务编排、事务边界 | 02 起 |
module.{域}.mapper + resources/mapper | SQL / 数据访问 | 02、12 |
module.{域}.entity / dto | 持久化模型 / 传输对象 | 02、07 |
security | 认证鉴权,与业务域解耦 | 09 |
4.2.4 分层约定(域内再拆层)
同一业务域内固定 Controller → Service → Mapper:
| 层 | 可以做 | 禁止做 |
|---|---|---|
| Controller | 参数绑定、调用 Service、包装 Result | 写 SQL;堆砌 Redis/MQ 细节 |
| Service | 编排、@Transactional、调 Mapper/发消息 | 直接拼 HTTP 协议细节 |
| Mapper | SQL、结果映射 | 业务判断、发邮件 |
新功能先问:「属于哪个 域(user/order)?落在哪一层?」再决定建哪个包下的类。完整空包骨架 +
package-info说明见examples/01-structure/。
4.3 HelloController
src/main/java/com/example/demo/module/user/controller/HelloController.java:
package com.example.demo.module.user.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
@RequestMapping("/api/hello")
public class HelloController {
@GetMapping
public Map<String, String> hello() {
return Map.of(
"message", "Hello, Spring Boot!",
"app", "demo"
);
}
}
@RestController=@Controller+@ResponseBody,返回值序列化为 JSON@RequestMapping("/api/hello")为类级别路径前缀
4.4 运行与验证
IDEA:右键 DemoApplication → Run。
命令行:
mvn spring-boot:run
预期结果:
- 控制台出现
Started DemoApplication,监听8080 - 浏览器或 curl 访问:
curl http://localhost:8080/api/hello
响应示例:
{"message":"Hello, Spring Boot!","app":"demo"}
5. 使用规范 / 团队约定
| Do | Don't |
|---|---|
包名统一 com.example.demo,业务按 module/{domain} 拆分 | 把所有类堆在根包或 controller 一个包 |
API 路径统一前缀 /api/ | 有的接口带前缀、有的不带 |
配置分环境:默认 yml + application-local.yml | 在 yml 里写真实生产密码并 commit |
| 启动类放在根包,保证扫描子包 | 启动类放进 module.user 导致漏扫 common |
新依赖加在 pom.xml 后刷新 Maven | 手动拷贝 jar 到 lib |
| 端口、应用名写在 yml,不写死在代码 | new Server(8080) 这类硬编码 |
6. 原理简述
嵌入式容器:spring-boot-starter-web 引入 Tomcat(默认),main 方法启动即启动 Web 服务器,无需外部部署 WAR。
自动配置:Classpath 存在 Spring MVC 相关类时,Boot 自动注册 DispatcherServlet、JSON 转换器等。条件装配由 @ConditionalOnClass 等实现——你只需加 Starter,不必手写 XML。
组件扫描与 Bean:带 @Component / @Service / @RestController 等的类被注册为 Bean,由 IoC 容器管理生命周期与依赖注入(DI)。
sequenceDiagram
participant Main as main()
participant Boot as SpringApplication
participant Ctx as ApplicationContext
participant Tomcat as Embedded Tomcat
Main->>Boot: run(DemoApplication)
Boot->>Ctx: 扫描 @SpringBootApplication 包
Ctx->>Ctx: 注册 Bean(Controller 等)
Boot->>Tomcat: 启动 Web 容器
Tomcat-->>Main: 监听 server.port
7. 常见错误与排查
| 现象 | 可能原因 | 排查 |
|---|---|---|
启动报 Port 8080 was already in use | 端口被占用 | 改 server.port 或结束占用进程 |
| 访问 404 | 路径写错或 Controller 未被扫描 | 检查 @RequestMapping;启动类包是否在 com.example.demo 根 |
| 访问 404 | 应用未启动完成 | 看日志是否 Started |
YAML 启动失败 DuplicateKeyException | 同一文件重复 key | 合并重复的 spring: 块 |
| YAML 解析失败 | Tab 缩进或冒号后缺空格 | 改用空格缩进,格式 key: value |
| 改 yml 不生效 | 改错文件或 profile 未激活 | 确认 spring.profiles.active 与文件名一致 |
| Maven 依赖下载失败 | 网络或镜像 | 配置国内 Maven 镜像;IDEA Reload |
| Java 版本报错 | 本地 JDK 非 17 | IDEA Project Structure → SDK 17 |
8. 练习题
- 改端口:将应用改为
9090,用 curl 验证 Hello 接口。 - 新接口:新增
GET /api/hello/version,返回{"version":"0.0.1"}。 - 包结构:创建
module/order/controller空包,写注释说明 order 模块将来放什么。 - profile:新增
application-dev.yml,设置server.port: 8081;切换spring.profiles.active观察端口变化。 - Git:确认
application-local.yml已被.gitignore忽略(git status不应出现该文件)。
完整例子
1. 改端口为 9090
src/main/resources/application.yml:
spring:
application:
name: demo
profiles:
active: local
server:
port: 9090
验证:
curl http://localhost:9090/api/hello
2. 新增 GET /api/hello/version
src/main/java/com/example/demo/module/user/controller/HelloController.java:
package com.example.demo.module.user.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
@RequestMapping("/api/hello")
public class HelloController {
@GetMapping
public Map<String, String> hello() {
return Map.of(
"message", "Hello, Spring Boot!",
"app", "demo"
);
}
@GetMapping("/version")
public Map<String, String> version() {
return Map.of("version", "0.0.1");
}
}
验证:curl http://localhost:9090/api/hello/version → {"version":"0.0.1"}。
3. order 模块空包说明
src/main/java/com/example/demo/module/order/controller/package-info.java:
/**
* 订单模块 Controller 包。
* <p>
* 后续放置:订单 CRUD、下单接口、订单查询/取消等 HTTP 入口。
* 配套目录:service / mapper / entity / dto。
*/
package com.example.demo.module.order.controller;
4. profile:application-dev.yml 端口 8081
src/main/resources/application-dev.yml:
server:
port: 8081
主配置切换 profile(application.yml):
spring:
application:
name: demo
profiles:
active: dev
server:
port: 8080
启动后日志应出现 Tomcat started on port(s): 8081(dev 覆盖主配置端口)。
5. .gitignore 忽略本地敏感配置
项目根 .gitignore:
# 本地敏感配置 —— 切勿提交真实密码
application-local.yml
**/application-local.yml
target/
.idea/
*.iml
.DS_Store
本地创建 src/main/resources/application-local.yml 后执行:
git status
输出中不应出现 application-local.yml。
9.源码
源码地址 01-structure