Spring Boot 企业级开发笔记
前置基础:Java 基础、Java Web(Servlet/JSP)、MySQL 基础、Maven 基础 笔记定位:企业级实战导向,从入门到能上手干活,拒绝纯理论
前言:为什么要学 Spring Boot?
你需要知道的行业现状
作为即将实习的网络专业学生,你可能会问:我学过 Java Web、Servlet、JSP,为什么还要学 Spring Boot?
现实情况是这样的:
- 市场主流就是 Spring Boot——现在去招聘网站搜 Java 后端开发,90% 以上的岗位要求会 Spring Boot。传统的 SSH(Struts2+Spring+Hibernate)、SSM 单独搭建的方式,在新项目中已经很少见了。
- 开发效率天差地别——传统 SSM 项目光搭建环境、配 XML 就要大半天,Spring Boot 几分钟就能跑起来一个可运行的 Web 项目。
- 微服务和云原生的基础——现在企业都在搞微服务、上云,Spring Boot + Spring Cloud 是事实标准。
- 你的 Java Web 基础不会白费——Spring Boot 底层还是 Servlet、Spring MVC,你学过的知识都能用得上,只是被封装得更好用了。
这份笔记的学习路线
第1章 入门 → 第2章 Web开发 → 第3章 数据访问 → 第4章 企业级特性 → 第5章 项目实战
↓ ↓ ↓ ↓ ↓
跑通项目 写接口 连数据库 安全/缓存/消息 完整项目学习建议
- 动手第一:每一个示例都要自己敲一遍,不要光看。
- 理解原理但不钻牛角尖:先会用,再深入理解原理。实习的时候首先要能干活。
- 结合 Java Web 知识对比学:遇到 Servlet、Filter 这些概念,想想以前学的和 Spring Boot 里的有什么联系。
第 1 章 Spring Boot 开发入门
1.1 Spring Boot 概述
1.1.1 Spring Boot 是什么
从 Spring 到 Spring Boot 的演进
在 Spring Boot 出现之前,Java 企业级开发经历了这样的演进:
| 阶段 | 代表技术 | 特点 | 痛点 |
|---|---|---|---|
| 第一代 | EJB(Java EE) | 官方标准,功能全 | 极其笨重,配置复杂,学习成本极高 |
| 第二代 | Spring(XML时代) | 轻量级,IoC/AOP | XML 配置文件一大堆,搭建项目慢 |
| 第三代 | Spring(注解时代) | 注解替代XML | 还是要配很多东西,依赖管理麻烦 |
| 第四代 | Spring Boot | 约定大于配置,开箱即用 | —— |
Spring Boot 的本质:它不是一个新框架,而是 Spring 框架的"增强包",或者说"快速启动器"。它本身不提供 Spring 的核心功能,而是让你用最少的配置、最快的速度把 Spring 项目跑起来。
打个比方:如果 Spring 是一堆电脑零件(CPU、内存、主板……),Spring Boot 就是品牌整机——你不用自己选配件、自己组装、自己装系统,开箱就能用。而且如果你想升级某个配件,它也支持你自己换。
Spring Boot 与 Spring、Java EE 的关系
┌─────────────────────────────────────────┐
│ Spring Boot │
│ (自动配置 + 起步依赖 + 内嵌服务器) │
├─────────────────────────────────────────┤
│ Spring Framework │
│ (IoC容器 + AOP + Spring MVC + ...) │
├─────────────────────────────────────────┤
│ Java EE 基础规范 │
│ (Servlet + JPA + JDBC + ...) │
└─────────────────────────────────────────┘- Spring Boot 底层就是 Spring——你学过的 Spring 知识全部适用。
- Spring Boot 复用了 Java EE 的基础规范——Servlet、JPA 这些标准它都在用,只是把 EJB、JSF 这些老旧重型的东西抛弃了。
1.1.2 Spring Boot 的核心特性
Spring Boot 官方总结了 6 大特性,我们从企业开发的角度来理解它们的价值:
1. 可快速构建独立的 Spring 应用
传统方式:新建项目 → 导一堆依赖 → 写 web.xml → 写 Spring 配置 → 配 Tomcat → 部署 → 启动测试,顺利的话半天,不顺利的话一天。
Spring Boot 方式:3 分钟生成项目,写个 Controller,直接运行 main 方法,浏览器访问就通了。
企业价值:新项目启动快,新人上手快,减少"搭环境"这种无产出的工作量。
2. 直接嵌入 Web 容器,无须部署 WAR 文件
传统方式:项目打成 WAR 包,放到 Tomcat 的 webapps 目录下,启动 Tomcat。
Spring Boot 方式:项目打成 JAR 包,里面自带 Tomcat,java -jar xxx.jar 直接运行。
企业价值:
- 部署简单,服务器上只要有 JRE 就能跑
- 一个服务器跑多个项目互不干扰(各自有独立的 Tomcat)
- 适合 Docker 容器化部署
3. 提供固化的"starter"依赖,简化构建配置
传统方式:用 Spring MVC 要导 spring-webmvc、jackson、validation……版本号还要自己对,一不小心就版本冲突。
Spring Boot 方式:一个 spring-boot-starter-web 全搞定,版本号都帮你管好了。
企业价值:
- 依赖管理简单,不用记一堆 jar 包
- 版本经过官方测试,基本不会有冲突
- 新人不会因为导错包而卡壳
4. 大量自动配置,开箱即用
传统方式:配置视图解析器、配置静态资源映射、配置文件上传解析器、配置事务管理器……每个都要写配置。
Spring Boot 方式:什么都不用配,默认就给你配好了。想改的话,在配置文件里改几行就行。
企业价值:
- 90% 的场景用默认配置就够了
- 减少配置错误
- 团队的项目配置风格统一
5. 提供生产就绪功能
传统方式:监控、健康检查、指标统计这些都要自己搞。
Spring Boot 方式:Actuator starter 一引入,健康检查、指标、配置信息全有了。
企业价值:运维方便,出问题能快速定位。
6. 无须生成代码和 XML 配置文件
传统方式:各种 XML 配置,还有的框架要生成代码。
Spring Boot 方式:纯注解开发,零 XML 配置(除非你自己想用)。
企业价值:代码简洁,维护方便。
1.1.3 版本选择与 JDK 对应关系
这是实习/工作中一定会遇到的问题——用哪个版本?
| Spring Boot 版本 | 最低 JDK 要求 | Spring 版本 | 状态 | 企业使用情况 |
|---|---|---|---|---|
| 1.x | Java 6+ | Spring 4.x | 停止维护 | 老项目可能还在用 |
| 2.0 ~ 2.6 | Java 8+ | Spring 5.x | 停止维护 | 大量存量项目 |
| 2.7.x | Java 8+ | Spring 5.3.x | 开源维护结束,商业支持中 | 目前存量最多的版本 |
| 3.0 ~ 3.1 | Java 17+ | Spring 6.x | 维护中 | 新项目逐步采用 |
| 3.2+ | Java 17+ | Spring 6.1.x | 最新稳定版 | 新项目首选 |
给你的建议(实习/求职向):
- 重点学 2.7.x——这是目前企业里用得最多的版本,面试也最常问。本笔记的代码示例基于 2.7.x。
- 了解 3.x 的变化——主要区别是 3.x 必须 JDK17+,而且
javax.*包名改成了jakarta.*(这是 Java EE 捐给 Eclipse 基金会后的改名)。 - JDK 选择:企业里 JDK 8 和 JDK 11 用得最多,JDK 17 在逐步普及。学习的话 JDK 11 或 17 都行。
注意:Spring Boot 3.x 最大的变化就是
javax.servlet→jakarta.servlet,javax.persistence→jakarta.persistence。如果你看到代码里是jakarta开头,那就是 Spring Boot 3.x。
1.2 Spring Boot 快速入门
1.2.1 环境准备
在开始之前,确保你的电脑上装好了以下工具。
1. JDK 安装与配置
推荐版本:JDK 11 或 JDK 17(本笔记用 JDK 11 演示)
验证安装:
java -version
javac -version环境变量:确保 JAVA_HOME 和 PATH 配置正确。
实习生小贴士:公司里可能不同项目用不同 JDK 版本,建议学会用 IDEA 切换项目 JDK,而不是只装一个版本。
2. Maven 安装与配置
推荐版本:Maven 3.6.x 及以上
验证安装:
mvn -v必须配置:阿里云镜像
Maven 默认从国外中央仓库下载依赖,速度很慢。一定要换成阿里云镜像。
打开 Maven 安装目录下的 conf/settings.xml,在 <mirrors> 节点中添加:
<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>实习生小贴士:这是每个 Java 开发必做的配置,没配的话下载依赖能急死你。如果公司有自己的私服,还要配私服地址。
3. IDEA 安装与常用插件
推荐版本:IntelliJ IDEA Ultimate(旗舰版)
学生可以用教育邮箱免费申请旗舰版授权。社区版也能用,但旗舰版功能更全。
必装插件:
- Lombok:简化 Java 代码(getter/setter/构造器等)
- MyBatisX:MyBatis 开发辅助
- Rainbow Brackets:彩虹括号,代码更易读
实习生小贴士:刚进公司先把开发工具配好,这是专业度的体现。
4. 环境检查清单
开始写代码前,确认以下几点:
- [ ] JDK 安装正确,
java -version能输出版本号 - [ ] Maven 安装正确,
mvn -v能输出版本号 - [ ] Maven 已配置阿里云镜像
- [ ] IDEA 已安装,能正常打开
- [ ] IDEA 中配置了正确的 JDK 和 Maven
1.2.2 方式一:Spring Initializr 创建项目(推荐)
Spring Initializr 是官方提供的项目生成工具,就像"在线配电脑"——你选好配置,它给你生成一个完整的项目骨架。
方式 A:IDEA 内置创建(最常用)
步骤 1:新建项目
打开 IDEA → New Project → 选择左侧的 Spring Initializr
步骤 2:填写项目基本信息
| 配置项 | 说明 | 示例 |
|---|---|---|
| Name | 项目名称 | chapter01-demo |
| Location | 项目存放路径 | D:\workspace\chapter01-demo |
| Language | 开发语言 | Java |
| Type | 构建工具 | Maven |
| Group | 组织标识(包名前缀) | com.itheima |
| Artifact | 项目标识 | chapter01-demo |
| Package name | 包名 | com.itheima.chapter01 |
| JDK | 项目使用的 JDK | 11 |
| Java | Java 版本 | 11 |
| Packaging | 打包方式 | Jar |
命名规范:Group 一般用公司域名倒写(如 com.xxx),Artifact 用项目名。包名全部小写。
步骤 3:选择依赖
点击 Next,进入依赖选择界面。入门阶段先选这一个:
- Web → Spring Web(包含 Spring MVC + 内嵌 Tomcat)
步骤 4:完成创建
点击 Create,等待 IDEA 下载依赖并初始化项目。
方式 B:网页版创建
如果 IDEA 用不了(比如网络问题连不上 Initializr 服务器),可以用网页版:
- 打开 https://start.spring.io/
- 填写项目信息(和上面一样)
- 选择依赖
- 点击 GENERATE 下载 zip 包
- 解压后用 IDEA 打开
项目结构详解
创建好的项目结构是这样的:
chapter01-demo/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/itheima/chapter01/
│ │ │ └── Chapter01DemoApplication.java ← 启动类(最重要)
│ │ └── resources/
│ │ ├── static/ ← 静态资源(CSS/JS/图片)
│ │ ├── templates/ ← 模板页面(Thymeleaf等)
│ │ └── application.properties ← 配置文件
│ └── test/
│ └── java/
│ └── com/itheima/chapter01/
│ └── Chapter01DemoApplicationTests.java ← 测试类
└── pom.xml ← Maven 配置文件几个关键文件:
- 启动类
xxxApplication.java——项目的入口,运行它的 main 方法就能启动整个项目。 application.properties——全局配置文件,端口号、数据库连接什么的都在这里配。pom.xml——Maven 配置文件,管理依赖。
pom.xml 解读
打开 pom.xml,我们逐段来看:
<!-- 父工程:统一管理版本号 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.6</version>
<relativePath/>
</parent>
<!-- 项目基本信息 -->
<groupId>com.itheima</groupId>
<artifactId>chapter01-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>chapter01-demo</name>
<!-- JDK 版本 -->
<properties>
<java.version>11</java.version>
</properties>
<!-- 依赖列表 -->
<dependencies>
<!-- Web 开发起步依赖(核心) -->
<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>重点理解 parent 的作用:
spring-boot-starter-parent 是 Spring Boot 提供的父工程,它里面定义了几百个常用依赖的版本号。你引入依赖时不用写 <version>,它会自动用父工程里管理的版本,这样就不会出现版本冲突问题。
和 Java Web 对比:以前你可能要自己找 spring-webmvc 的版本、jackson 的版本、servlet-api 的版本,还要确保它们互相兼容。现在一个 parent 全搞定。
1.2.3 方式二:Maven 手动创建项目
了解一下就行,实际开发中基本都用 Initializr。但如果在没有网络的环境下,或者想深入理解原理,手动创建也是必要的。
步骤 1:创建普通 Maven 项目
IDEA → New Project → Maven → 不选 Archetype → 填写 Group/Artifact → Create
步骤 2:在 pom.xml 中添加父工程和依赖
<!-- 继承 Spring Boot 父工程 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.6</version>
</parent>
<dependencies>
<!-- Web 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>步骤 3:编写启动类
package com.itheima.chapter01;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication // 核心注解:标记这是一个 Spring Boot 应用
public class Chapter01Application {
public static void main(String[] args) {
// 启动 Spring Boot 应用
SpringApplication.run(Chapter01Application.class, args);
}
}步骤 4:刷新 Maven
右键项目 → Maven → Reload Project,等待依赖下载完成。
什么时候用这种方式?
- 网络不好,Initializr 连不上
- 想从一个普通 Maven 项目改成 Spring Boot 项目
- 学习原理,理解 Spring Boot 项目到底是怎么组成的
1.2.4 第一个接口:Hello World
项目建好了,我们来写第一个接口,感受一下 Spring Boot 的开发效率。
步骤 1:创建 Controller
在 com.itheima.chapter01 包下创建 controller 包,然后创建 HelloController 类:
package com.itheima.chapter01.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController // 标记这是一个控制器,返回值直接作为响应体(JSON或字符串)
public class HelloController {
@RequestMapping("/hello") // 映射请求路径
public String sayHello() {
return "Hello, Spring Boot!";
}
}步骤 2:启动项目
找到启动类 Chapter01Application.java,点击 main 方法左边的绿色三角,或者右键 → Run。
观察控制台输出,看到类似这样的信息就说明启动成功了:
Tomcat started on port(s): 8080 (http) with context path ''
Started Chapter01Application in 2.345 seconds几个关键信息:
- 端口号:8080(默认)
- 启动时间:2 秒多(是不是比传统 Tomcat 快多了?)
步骤 3:访问测试
打开浏览器,访问:http://localhost:8080/hello
看到页面显示 Hello, Spring Boot!,就成功了!
与传统 Spring MVC 对比
回想一下你学 Java Web 时写一个 Servlet 要做什么:
- 写 Servlet 类
- 在 web.xml 里配置 Servlet 映射
- 部署到 Tomcat
- 启动 Tomcat
- 访问
用 Spring + Spring MVC 呢?
- 写 Controller 类
- 配置 spring-mvc.xml(组件扫描、视图解析器……)
- 配置 web.xml(ContextLoaderListener、DispatcherServlet……)
- 部署到 Tomcat
- 启动 Tomcat
- 访问
用 Spring Boot 呢?
- 写 Controller 类(2 个注解)
- 运行 main 方法
- 访问
这就是效率差距。
1.2.5 项目结构与开发规范
企业里的项目不是随便乱放的,有标准的结构和规范。刚进公司一定要先搞清楚项目结构。
标准包结构
com.xxx.项目名/
├── controller/ # 控制层:接收请求,调用 Service,返回结果
├── service/ # 业务层:业务逻辑处理
│ └── impl/ # Service 实现类
├── mapper/ # 数据访问层(MyBatis)/ repository(JPA)
├── entity/ # 实体类(对应数据库表)
├── dto/ # 数据传输对象(接收前端参数)
├── vo/ # 视图对象(返回给前端的数据)
├── config/ # 配置类
├── exception/ # 自定义异常
├── utils/ # 工具类
└── 项目名Application.java # 启动类三层架构
这是 Java Web 开发的经典分层,Spring Boot 项目也遵循:
浏览器 → Controller → Service → Mapper → 数据库- Controller(控制层):接收请求、参数校验、调用 Service、返回结果。不写业务逻辑。
- Service(业务层):核心业务逻辑在这里。事务控制也在这一层。
- Mapper/Repository(数据访问层):和数据库打交道,增删改查。
为什么要分层?
- 职责清晰,各司其职
- 便于维护(改业务逻辑只动 Service,改 SQL 只动 Mapper)
- 便于测试(每层可以单独测试)
- 团队协作方便(不同人负责不同层)
命名规范
| 类型 | 命名规则 | 示例 |
|---|---|---|
| 包名 | 全小写,用点分隔 | com.itheima.user.controller |
| 类名 | 大驼峰(PascalCase) | UserController、UserService |
| 方法名 | 小驼峰(camelCase) | getUserById、addUser |
| 变量名 | 小驼峰 | userName、pageSize |
| 常量名 | 全大写,下划线分隔 | MAX_PAGE_SIZE |
| Controller | 以 Controller 结尾 | UserController |
| Service 接口 | 以 Service 结尾 | UserService |
| Service 实现类 | 以 ServiceImpl 结尾 | UserServiceImpl |
| Mapper 接口 | 以 Mapper 结尾 | UserMapper |
| 实体类 | 直接用业务名 | User、Order |
实习生小贴士:进公司先看现有代码的命名风格,跟着走。团队一致比"正确"更重要。
1.3 Spring Boot 核心原理
这一节偏原理,面试常问。先有个印象,等用熟了再回头深入理解。
1.3.1 起步依赖(Starter)
什么是起步依赖
起步依赖(Starter)是 Spring Boot 的核心概念之一。简单说,一个 starter 就是一组相关依赖的打包。
比如你要做 Web 开发,以前需要自己找:
- spring-webmvc
- jackson-databind
- spring-boot-starter-tomcat
- hibernate-validator
- ……
现在只需要引入一个 spring-boot-starter-web,它会把上面这些依赖全部自动引入进来,而且版本都是经过测试、确定兼容的。
Starter 的本质
Starter 本身没有代码,它就是一个 pom.xml 文件,里面声明了一堆依赖。你引入 starter,就等于引入了它 pom 里声明的所有依赖(Maven 的依赖传递机制)。
spring-boot-starter-web
├── spring-boot-starter
├── spring-boot-starter-json
├── spring-boot-starter-tomcat
├── spring-web
└── spring-webmvcparent vs starter 的区别
这是初学者容易搞混的,一定要分清楚:
| 概念 | 作用 | 类比 |
|---|---|---|
| spring-boot-starter-parent | 统一管理所有依赖的版本号 | 价格表:告诉你每个东西多少钱 |
| starter(如 spring-boot-starter-web) | 打包一组相关依赖 | 套餐:给你配好一组东西 |
- parent 管版本,starter 管依赖组合
- 一个项目只有一个 parent,但可以有很多个 starter
- starter 里的依赖版本由 parent 来保证一致性
常用 Starter 清单
| Starter | 功能 | 什么时候用 |
|---|---|---|
| spring-boot-starter-web | Web 开发(Spring MVC + 内嵌 Tomcat) | 做 Web 项目必选 |
| spring-boot-starter-test | 测试(JUnit + MockMvc + ...) | 写单元测试 |
| spring-boot-starter-data-jpa | JPA 数据访问 | 用 JPA/hibernate |
| spring-boot-starter-jdbc | JDBC + 事务 | 用原生 JDBC |
| spring-boot-starter-redis | Redis 缓存 | 用 Redis |
| spring-boot-starter-amqp | RabbitMQ 消息队列 | 用 RabbitMQ |
| spring-boot-starter-security | 安全认证授权 | 做登录权限 |
| spring-boot-starter-validation | 参数校验 | 接口参数校验 |
| spring-boot-starter-aop | AOP 切面 | 做日志、事务等切面 |
| spring-boot-starter-devtools | 热部署 | 开发阶段用 |
| mybatis-spring-boot-starter | MyBatis 整合 | 用 MyBatis(第三方) |
注意命名规则:
- 官方 starter:
spring-boot-starter-xxx- 第三方 starter:
xxx-spring-boot-starter(如 mybatis-spring-boot-starter)
1.3.2 自动配置(Auto Configuration)
自动配置是 Spring Boot 最核心的思想——约定大于配置(Convention over Configuration)。
什么是"约定大于配置"
传统的 Spring 开发,什么都要你自己配:组件扫描包、视图解析器、静态资源映射、文件上传解析器、事务管理器……
Spring Boot 的思路是:大部分项目的配置都是一样的,我先给你配好默认值。如果你觉得默认的不行,再自己改。
这就是"约定大于配置"——大家都遵守一套约定(默认配置),就不用每个项目都写一遍配置了。
@SpringBootApplication 注解拆解
启动类上的 @SpringBootApplication 是一个复合注解,它包含了 3 个核心注解:
@SpringBootApplication
= @SpringBootConfiguration // 标记这是一个配置类
+ @EnableAutoConfiguration // 开启自动配置(核心!)
+ @ComponentScan // 组件扫描我们一个一个来看:
1. @SpringBootConfiguration
这个注解的作用就是标记当前类是一个 Spring 配置类(相当于以前的 applicationContext.xml)。
它其实就是 @Configuration 的包装,功能一样。被它标记的类可以用 @Bean 注解往容器里放对象。
2. @EnableAutoConfiguration(最重要)
这是自动配置的开关,也是 Spring Boot 的灵魂。
它的作用是:根据项目中引入的依赖,自动配置对应的功能。
比如:
- 引入了
spring-boot-starter-web→ 自动配置 Spring MVC、Tomcat - 引入了
spring-boot-starter-jdbc→ 自动配置数据源、JdbcTemplate - 引入了
spring-boot-starter-redis→ 自动配置 RedisTemplate
它是怎么做到的?
@EnableAutoConfiguration 会去 classpath 下的 META-INF/spring.factories 文件(Spring Boot 2.7 及之前)或 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件(Spring Boot 2.7+ 新方式)中读取所有自动配置类,然后根据条件判断哪些配置类需要生效。
自动配置的判断条件——条件注解:
不是所有自动配置类都会生效,要满足一定条件才会生效。常用的条件注解:
| 条件注解 | 作用 |
|---|---|
| @ConditionalOnClass | 类路径下有指定的类才生效 |
| @ConditionalOnMissingClass | 类路径下没有指定的类才生效 |
| @ConditionalOnBean | 容器中有指定的 Bean 才生效 |
| @ConditionalOnMissingBean | 容器中没有指定的 Bean 才生效 |
| @ConditionalOnProperty | 配置文件中有指定的属性才生效 |
| @ConditionalOnWebApplication | 是 Web 应用才生效 |
举个例子,DataSourceAutoConfiguration(数据源自动配置)的生效条件:
- 类路径下有
DataSource.class、EmbeddedDatabaseType.class - 容器中还没有 DataSource 类型的 Bean
- 配置文件中有相关配置
所以:你引入了数据库驱动 + 配置了数据库连接信息 → 自动配置数据源。
3. @ComponentScan
组件扫描,扫描指定包下的 @Component、@Service、@Controller、@Repository 等注解,把这些类注册到 Spring 容器中。
默认扫描哪里?——启动类所在的包及其子包。
重要!为什么你的 Controller 要放在启动类的子包下? 因为 @ComponentScan 默认扫描启动类所在的包。如果你把 Controller 放到了启动类外面的包里,它扫描不到,就不会生效,访问就会 404。
这是初学者最常踩的坑之一!
自动配置流程总结
项目启动
↓
@SpringBootApplication 生效
↓
@EnableAutoConfiguration 开启自动配置
↓
读取 spring.factories / AutoConfiguration.imports 中的所有自动配置类
↓
根据条件注解(@ConditionalOn...)判断哪些配置类生效
↓
生效的配置类往容器中注册对应的 Bean
↓
Spring 容器初始化完成,项目启动成功怎么看哪些自动配置生效了?
在 application.properties 中加一行配置:
debug=true启动项目,控制台会输出自动配置报告:
- Positive matches:生效的自动配置
- Negative matches:没生效的自动配置(以及原因)
调试的时候很有用。
1.3.3 启动执行流程
你可能会好奇:就一行 SpringApplication.run(xxx.class, args),怎么就把整个项目启动起来了?
简单说,它做了两件大事:
第一步:创建 SpringApplication 实例
new SpringApplication()
├── 推断 Web 应用类型(Servlet / Reactive / 非Web)
├── 加载 ApplicationContextInitializer(上下文初始化器)
├── 加载 ApplicationListener(应用监听器)
└── 推断主应用类(找到 main 方法所在的类)第二步:执行 run() 方法
run() 方法核心步骤:
├── 1. 获取并启动运行监听器(SpringApplicationRunListener)
├── 2. 准备环境(Environment):加载配置文件、配置参数等
├── 3. 打印 Banner(就是启动时那个 Spring 图案)
├── 4. 创建应用上下文(ApplicationContext)
├── 5. 准备上下文:把启动类注册进去
├── 6. 刷新上下文(refresh)→ 这一步最核心!
│ └── 初始化所有单例 Bean,执行自动配置
├── 7. 执行刷新后的后置处理
├── 8. 发布应用启动完成事件
└── 9. 执行 CommandLineRunner / ApplicationRunner第 6 步是核心中的核心——refresh() 方法会初始化所有的 Bean,执行所有的自动配置,完成 Spring 容器的初始化。
面试常问:Spring Boot 的启动流程? 记住这几个关键词:SpringApplication 实例化 → 准备环境 → 创建上下文 → 刷新上下文(Bean 初始化+自动配置) → 启动完成。 不用背源码细节,能说清楚大致流程就行。
1.4 单元测试与热部署
1.4.1 单元测试
为什么要写单元测试
作为实习生,你可能会觉得"功能能跑就行,写测试浪费时间"。但在企业里:
- 保证代码质量——有测试的代码,改起来心里有底
- 便于回归测试——改了一个地方,跑一遍测试就知道有没有影响其他功能
- 专业素养——会写单元测试是初级和中级开发的分水岭之一
- 很多公司要求——提交代码必须有对应的测试用例
Spring Boot 测试体系
Spring Boot 提供了 spring-boot-starter-test,里面集成了常用的测试框架:
| 框架 | 用途 |
|---|---|
| JUnit 5 | 单元测试基础框架 |
| Spring Test / Spring Boot Test | Spring 集成测试支持 |
| Mockito | Mock(模拟)对象 |
| AssertJ | 流式断言 |
| MockMvc | Web 层测试(模拟 HTTP 请求) |
@SpringBootTest 注解
这是 Spring Boot 测试的核心注解,标记在测试类上。
它有一个重要属性 webEnvironment,用来控制测试时是否启动 Web 环境:
| 取值 | 说明 | 适用场景 |
|---|---|---|
| MOCK(默认) | 加载 Web 上下文,提供模拟 Servlet 环境 | 测试 Controller 但不想启动真实 Tomcat |
| RANDOM_PORT | 启动真实 Web 服务器,用随机端口 | 完整的集成测试 |
| DEFINED_PORT | 启动真实 Web 服务器,用配置文件中的端口 | 需要固定端口的测试 |
| NONE | 不启动 Web 环境 | 测试 Service / Mapper 层 |
测试类型一:Web 层测试(MockMvc)
当你想测试 Controller 接口,但又不想真的启动 Tomcat 时,用 MockMvc。
示例代码:
package com.itheima.chapter01;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc // 开启 MockMvc 自动配置
public class WebTest {
@Autowired
private MockMvc mockMvc;
@Test
void testHello() throws Exception {
// 模拟发送 GET 请求到 /hello
mockMvc.perform(MockMvcRequestBuilders.get("/hello"))
// 期望状态码是 200
.andExpect(MockMvcResultMatchers.status().isOk())
// 期望返回内容是 "Hello, Spring Boot!"
.andExpect(MockMvcResultMatchers.content().string("Hello, Spring Boot!"));
}
}MockMvc 常用方法:
| 方法 | 作用 |
|---|---|
| MockMvcRequestBuilders.get/post/put/delete | 构建请求 |
| .param() | 添加请求参数 |
| .contentType() | 设置请求体类型 |
| .content() | 设置请求体内容 |
| MockMvcResultMatchers.status().isOk() | 断言状态码 |
| MockMvcResultMatchers.jsonPath() | 断言 JSON 返回值 |
| MockMvcResultMatchers.content().string() | 断言返回字符串 |
测试类型二:Service 层测试
测试 Service 层不需要 Web 环境,设置 webEnvironment = NONE 即可。
示例代码:
package com.itheima.chapter01;
import com.itheima.chapter01.service.HelloService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class ServiceTest {
@Autowired
private HelloService helloService;
@Test
void testSayHello() {
String result = helloService.sayHello("张三");
// 断言结果不为空
org.junit.jupiter.api.Assertions.assertNotNull(result);
System.out.println(result);
}
}企业测试最佳实践
- 测试方法命名:
test_方法名_场景_预期结果,如test_getUserById_userExists_returnUser - 一个测试方法只测一个点:不要一个方法测一堆东西
- 测试数据要独立:不要依赖其他测试的数据,每个测试自己准备数据
- 关键业务必须有测试:核心逻辑、复杂计算、容易出 bug 的地方
- 不要为了覆盖率写测试:质量比数量重要
实习生小贴士:刚进公司先看项目里现有的测试是怎么写的,照着风格写。如果项目里没有测试,至少给自己写的核心功能补上测试。
1.4.2 热部署
什么是热部署
开发的时候,你改了代码,想要看到效果,就得重启项目。项目小还好,启动几秒;项目大了,启动几十秒甚至几分钟,改一行代码等半分钟,一天下来光等启动就浪费很多时间。
热部署就是:你改了代码,不用手动重启,项目自动重新加载。
DevTools 热部署配置
Spring Boot 提供了 spring-boot-devtools 来实现热部署。
步骤 1:添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>步骤 2:开启 IDEA 自动编译
File → Settings → Build, Execution, Deployment → Compiler → 勾选 Build project automatically
步骤 3:允许运行时自动构建
File → Settings → Advanced Settings → Compiler → 勾选 Allow auto-make to start even if developed application is currently running
步骤 4:测试
启动项目,修改 Controller 里的返回值,等几秒(默认 5 秒),刷新浏览器,看看内容变了没有。
DevTools 的原理
DevTools 的原理是类加载器隔离:
- 不变的类(第三方 jar 包里的):用 base classloader 加载
- 你自己写的类:用 restart classloader 加载
当代码变化时,只重启 restart classloader,比整个项目重启快很多。
注意事项
- 只在开发环境用——生产环境不要用 devtools
- 静态资源修改不会触发重启——因为静态资源不在 restart classloader 里
- 有时候还是需要手动重启——比如改了 pom.xml、改了配置文件的某些项
- JRebel 比 DevTools 更快——商业软件,很多公司会买,效果比 DevTools 好很多
实习生小贴士:如果公司用 JRebel,一定要让前辈帮你装好,开发效率提升不止一倍。如果没有,先用 DevTools 凑合。
1.5 项目打包与运行
项目开发完了,怎么部署到服务器上运行?这是实习时一定会遇到的问题。
Spring Boot 项目有两种打包方式:JAR 包和 WAR 包。
1.5.1 打包为 JAR 包(推荐)
这是 Spring Boot 最推荐的方式,也是企业里最常用的方式。
什么是可执行 JAR 包
普通的 JAR 包就是一堆 class 文件,不能直接运行。Spring Boot 的可执行 JAR 包(也叫 fat jar / uber jar)里面:
- 你的代码
- 所有依赖的 jar 包
- 内嵌的 Tomcat
- 启动配置
所以一个 JAR 包就是一个完整的应用,服务器上只要有 JRE 就能跑。
打包步骤
前提:pom.xml 里要有 Spring Boot Maven 插件(Initializr 生成的项目默认就有):
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>方式一:IDEA 图形化操作
- 打开 IDEA 右侧的 Maven 面板
- 展开项目 → Lifecycle
- 先点 clean(清理旧的编译结果)
- 再点 package(打包)
方式二:命令行
mvn clean package跳过测试打包(测试有问题但想先打包看看):
mvn clean package -DskipTests打包结果
打包成功后,在项目的 target 目录下会生成两个 jar 包:
xxx-0.0.1-SNAPSHOT.jar——可执行 JAR 包(fat jar,比较大,几十 MB 起步)xxx-0.0.1-SNAPSHOT.jar.original——原始 JAR 包(只有你的代码,很小)
我们用的是第一个。
运行 JAR 包
方式一:命令行直接运行
打开 cmd / terminal,进入 target 目录:
java -jar chapter01-demo-0.0.1-SNAPSHOT.jar看到启动日志就说明运行成功了,浏览器访问 http://localhost:8080/hello 测试。
方式二:指定端口运行
不想用默认的 8080?可以在启动时指定:
java -jar chapter01-demo-0.0.1-SNAPSHOT.jar --server.port=8081方式三:指定配置文件运行(后面讲多环境配置时会详细说)
java -jar xxx.jar --spring.profiles.active=prod生产环境运行方式
上面的方式在命令行运行,一关窗口程序就停了。生产环境不能这样。
Linux 服务器后台运行:
# 后台运行,日志输出到 app.log
nohup java -jar xxx.jar > app.log 2>&1 &解释:
nohup:不挂断运行,关闭终端也不停止> app.log:标准输出重定向到 app.log2>&1:标准错误也重定向到标准输出(也就是都写到 app.log)&:后台运行
查看日志:
tail -f app.log # 实时查看日志停止应用:
ps -ef | grep java # 找到进程号
kill -9 进程号 # 强制杀掉实习生小贴士:
- 真实企业里一般不会直接用 java -jar 跑,会用 Docker 容器或者 Jenkins 自动化部署
- 但你一定要会这种基础方式,排查问题的时候用得上
- 日志一定要重定向到文件,不然出了问题没地方查
1.5.2 打包为 WAR 包
什么时候需要 WAR 包
虽然 JAR 包是主流,但有些场景还是需要 WAR 包:
- 公司统一用外部 Tomcat 部署——运维团队管理所有 Tomcat,所有项目都打成 WAR 包丢进去
- 老项目改造——原来的系统就是 WAR 包部署,不想改部署方式
- 一个 Tomcat 跑多个项目——节省服务器资源
WAR 包改造步骤
以一个现有的 Spring Boot 项目为例,改成 WAR 包部署需要 4 步:
步骤 1:修改打包方式
在 pom.xml 中添加:
<packaging>war</packaging>步骤 2:排除内置 Tomcat
把内置的 Tomcat 排除掉,因为要用外部的 Tomcat:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!-- 排除内置 Tomcat -->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>步骤 3:添加 Servlet 依赖(provided 范围)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope> <!-- 编译和测试时用,打包时不包含 -->
</dependency>为什么要加这个? 因为写代码的时候需要 Servlet API(比如 HttpServletRequest),所以编译时要有。但打包的时候不要把 Tomcat 打进去,因为用外部的。
provided范围就是干这个的。
步骤 4:修改启动类
启动类要继承 SpringBootServletInitializer,重写 configure 方法:
@SpringBootApplication
public class Chapter01Application extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(Chapter01Application.class);
}
public static void main(String[] args) {
SpringApplication.run(Chapter01Application.class, args);
}
}为什么要这样改?
外部 Tomcat 启动时,它不知道你的 Spring Boot 入口在哪里。继承 SpringBootServletInitializer 就是告诉外部 Tomcat:"我是个 Spring Boot 应用,从这里启动"。
部署 WAR 包
- 执行
mvn clean package打包 - 把 target 目录下的
.war文件复制到 Tomcat 的webapps目录下 - 启动 Tomcat(
bin/startup.bat或bin/startup.sh) - 访问:
http://localhost:8080/项目名/接口路径
注意:WAR 包部署的访问路径会带项目名(就是 WAR 包的名字),和 JAR 包直接访问根路径不一样。
常见问题
Tomcat 启动失败,提示 JRE_HOME 未定义:
- 原因:Tomcat 找不到 JRE
- 解决:配置
JRE_HOME环境变量,指向 JDK 安装目录
控制台乱码:
- 原因:Tomcat 默认日志编码和系统编码不一致
- 解决:修改 Tomcat 的
conf/logging.properties,把java.util.logging.ConsoleHandler.encoding改成GBK(Windows)或UTF-8(Linux)
Spring Boot 版本和 Tomcat 版本不兼容:
- Spring Boot 2.7.x 对应 Tomcat 9.x
- Spring Boot 3.x 对应 Tomcat 10.x
- 版本不匹配会启动失败
1.5.3 JAR vs WAR 怎么选
| 对比项 | JAR 包 | WAR 包 |
|---|---|---|
| 部署方式 | java -jar 直接运行 | 部署到外部 Tomcat |
| 服务器要求 | 只要有 JRE | 需要安装 Tomcat |
| 资源占用 | 每个项目一个 Tomcat,占用多 | 多个项目共享一个 Tomcat,占用少 |
| 运维方式 | 每个项目独立管理 | 统一管理 Tomcat |
| 适合场景 | 微服务、云原生、Docker | 传统部署、老项目维护 |
| 开发效率 | 高(直接运行 main 方法) | 稍低(要配 Tomcat) |
企业现状:
- 新项目、微服务项目 → 几乎都是 JAR 包
- 老项目、传统企业 → 可能还有 WAR 包
- 你两种都要会,但重点掌握 JAR 包方式
1.6 配置文件详解
配置文件是 Spring Boot 项目中非常重要的一部分,端口号、数据库连接、各种功能的开关都在这里配置。
1.6.1 配置文件格式
Spring Boot 支持两种配置文件格式:.properties 和 .yml(或 .yaml)。
properties 格式
传统的 key=value 格式:
# 服务器端口
server.port=8080
# 项目上下文路径
server.servlet.context-path=/demo
# 数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=123456yml 格式
YAML(YAML Ain't Markup Language)是一种结构化的配置格式,用缩进表示层级关系:
server:
port: 8080
servlet:
context-path: /demo
spring:
datasource:
url: jdbc:mysql://localhost:3306/test
username: root
password: 123456两种格式对比
| 对比项 | properties | yml |
|---|---|---|
| 格式 | key=value,扁平结构 | 缩进层级结构 |
| 可读性 | 配置多时前缀重复,可读性差 | 层级清晰,可读性好 |
| 支持列表 | 不支持(要写数组很麻烦) | 支持列表 |
| 学习成本 | 低,一看就懂 | 稍高,要注意缩进 |
| 企业使用 | 老项目可能用 | 新项目基本都用 |
推荐用 yml 格式,结构清晰,配置多了不容易乱。
yml 语法要点
- 缩进表示层级:用空格缩进,不能用 Tab。同一层级的缩进要对齐。
- 冒号后面要有空格:
key: value,冒号后面必须有空格。 - 列表写法:
# 列表
fruits:
- apple
- banana
- orange- 注释:用
#开头
配置文件优先级
如果同一个目录下既有 application.properties 又有 application.yml,properties 优先级更高(会覆盖 yml 中的相同配置)。
但一般项目里只会用一种,不会混用。
1.6.2 读取配置的方式
配置文件里的值,怎么在代码里用?有三种方式。
方式一:@Value 注解(最简单)
直接在字段上用 @Value("${配置key}") 注入:
@RestController
public class HelloController {
// 读取配置文件中的 server.port
@Value("${server.port}")
private String port;
@GetMapping("/port")
public String getPort() {
return "当前端口:" + port;
}
}适用场景:单个配置项的读取。
默认值:如果配置可能不存在,可以给默认值:
@Value("${server.port:8080}") // 冒号后面是默认值
private String port;方式二:@ConfigurationProperties(批量绑定)
如果一组配置项很多,一个个写 @Value 太麻烦,可以用 @ConfigurationProperties 批量绑定到一个类上。
示例:把数据库配置绑定到一个类
@Component
@ConfigurationProperties(prefix = "spring.datasource") // 配置前缀
public class DataSourceProperties {
private String url;
private String username;
private String password;
private String driverClassName;
// getter 和 setter
public String getUrl() { return url; }
public void setUrl(String url) { this.url = url; }
// ... 其他 getter/setter
}然后在需要的地方注入这个类:
@RestController
public class HelloController {
@Autowired
private DataSourceProperties dataSourceProperties;
@GetMapping("/db")
public String getDbInfo() {
return dataSourceProperties.getUrl();
}
}适用场景:一组相关的配置项,特别是自定义配置。
配合 Lombok 使用更爽:用
@Data注解自动生成 getter/setter,不用手写。后面会讲 Lombok。
方式三:Environment(动态获取)
注入 Environment 对象,动态获取配置:
@RestController
public class HelloController {
@Autowired
private Environment env;
@GetMapping("/env")
public String getEnv() {
return env.getProperty("server.port");
}
}适用场景:配置 key 是动态的,或者需要在代码中判断配置是否存在。
三种方式对比
| 方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| @Value | 简单直接 | 配置多时写起来麻烦 | 少量配置项 |
| @ConfigurationProperties | 批量绑定,类型安全 | 需要写配置类 | 一组相关配置 |
| Environment | 灵活,动态获取 | 代码里硬编码 key | 动态获取配置 |
1.6.3 多环境配置
为什么需要多环境
一个项目在开发过程中,至少会有这些环境:
- 开发环境(dev):你自己写代码时用的环境,数据库是本地的
- 测试环境(test):测试人员测试用的环境,数据库是测试库
- 生产环境(prod):线上正式运行的环境,数据库是生产库
每个环境的配置(数据库地址、端口、各种开关)都不一样。怎么方便地切换?
Profile 机制
Spring Boot 提供了 Profile(剖面)机制来管理多环境配置。
命名规则:application-{profile名}.yml
比如:
application.yml——主配置文件(所有环境共用的配置)application-dev.yml——开发环境配置application-test.yml——测试环境配置application-prod.yml——生产环境配置
使用方式
步骤 1:创建各环境的配置文件
application-dev.yml:
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/dev_db
username: root
password: 123456application-prod.yml:
server:
port: 80
spring:
datasource:
url: jdbc:mysql://生产IP:3306/prod_db
username: prod_user
password: 生产密码步骤 2:在主配置文件中激活指定环境
application.yml:
spring:
profiles:
active: dev # 激活 dev 环境激活 Profile 的几种方式
优先级从高到低:
命令行参数(最高优先级):
bashjava -jar xxx.jar --spring.profiles.active=prodJVM 参数:
bashjava -Dspring.profiles.active=prod -jar xxx.jar配置文件:
yamlspring: profiles: active: dev环境变量:Linux 上设置
SPRING_PROFILES_ACTIVE=prod
企业最佳实践:
- 配置文件里默认激活 dev 环境(开发时方便)
- 生产环境用命令行参数或环境变量指定 prod,避免把生产配置写死在代码里
- 生产环境的密码等敏感信息,不要直接写在配置文件里(用配置中心或环境变量)
1.7 Web 开发基础
Spring Boot Web 开发是日常工作中用得最多的部分,一定要熟练掌握。
1.7.1 请求处理
RESTful 风格
现在的接口基本都是 RESTful 风格的。简单说,就是用 HTTP 请求方法来表示对资源的操作:
| HTTP 方法 | 操作 | 示例 |
|---|---|---|
| GET | 查询 | GET /users — 获取用户列表 |
| GET | 查询单个 | GET /users/1 — 获取 id=1 的用户 |
| POST | 新增 | POST /users — 新增用户 |
| PUT | 修改 | PUT /users/1 — 修改 id=1 的用户 |
| DELETE | 删除 | DELETE /users/1 — 删除 id=1 的用户 |
对应的注解:
| 注解 | 说明 |
|---|---|
| @GetMapping | GET 请求 |
| @PostMapping | POST 请求 |
| @PutMapping | PUT 请求 |
| @DeleteMapping | DELETE 请求 |
| @RequestMapping | 通用(可以指定 method) |
参数接收的几种方式
这是写接口最基础的,每种方式都要会。
1. 普通参数(query 参数)
URL 后面跟 ?key=value 形式的参数:
@GetMapping("/user")
public String getUser(@RequestParam("id") Integer id,
@RequestParam(value = "name", required = false, defaultValue = "默认值") String name) {
return "id=" + id + ", name=" + name;
}访问:http://localhost:8080/user?id=1&name=张三
@RequestParam:明确指定这是请求参数required = false:参数不是必须的defaultValue:参数不传时的默认值
2. 路径参数(RESTful 风格)
参数在 URL 路径中:
@GetMapping("/user/{id}")
public String getUserById(@PathVariable("id") Integer id) {
return "用户ID:" + id;
}访问:http://localhost:8080/user/1
3. 请求体(JSON 参数)
POST/PUT 请求,参数在请求体中(JSON 格式):
先定义一个接收参数的类:
public class User {
private Integer id;
private String name;
private Integer age;
// getter/setter
}接口:
@PostMapping("/user")
public String addUser(@RequestBody User user) {
return "新增用户:" + user.getName();
}用 Postman 测试时,选择 POST 请求,Body → raw → JSON,填入:
{
"id": 1,
"name": "张三",
"age": 20
}@RequestBody:把请求体的 JSON 自动转换成 Java 对象
4. 表单参数
传统的 form 表单提交:
@PostMapping("/login")
public String login(@RequestParam String username,
@RequestParam String password) {
return "登录:" + username;
}或者直接用对象接收(不用 @RequestBody):
@PostMapping("/login")
public String login(User user) {
return "登录:" + user.getUsername();
}5. 请求头 / Cookie
@GetMapping("/header")
public String getHeader(@RequestHeader("User-Agent") String userAgent) {
return userAgent;
}
@GetMapping("/cookie")
public String getCookie(@CookieValue("token") String token) {
return token;
}参数校验
前端传过来的参数不能直接用,要校验合法性。Spring Boot 集成了 JSR-303 校验规范。
步骤 1:添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>步骤 2:在实体类上加校验注解
public class User {
@NotNull(message = "ID不能为空")
private Integer id;
@NotBlank(message = "用户名不能为空")
@Size(min = 2, max = 20, message = "用户名长度在2-20之间")
private String name;
@Min(value = 0, message = "年龄不能小于0")
@Max(value = 150, message = "年龄不能大于150")
private Integer age;
@Email(message = "邮箱格式不正确")
private String email;
// getter/setter
}步骤 3:在 Controller 上加 @Valid
@PostMapping("/user")
public String addUser(@Valid @RequestBody User user, BindingResult result) {
// 如果有校验错误
if (result.hasErrors()) {
return result.getFieldError().getDefaultMessage();
}
return "新增成功";
}常用校验注解:
| 注解 | 作用 |
|---|---|
| @NotNull | 不能为 null |
| @NotBlank | 不能为 null 且不能是空字符串(去掉首尾空格后) |
| @NotEmpty | 不能为 null 且不能为空(集合/数组/字符串) |
| @Size(min=, max=) | 长度范围 |
| @Min / @Max | 数值最小/最大值 |
| 邮箱格式 | |
| @Pattern | 正则表达式匹配 |
企业最佳实践:参数校验是必须的,不能信任前端传过来的任何数据。前端校验是为了用户体验,后端校验是为了安全。
统一返回结果
企业里的接口返回格式都是统一的,不会有的返回字符串、有的返回对象。一般长这样:
{
"code": 200,
"msg": "操作成功",
"data": { ... }
}定义统一返回结果类:
public class Result<T> {
private Integer code; // 状态码:200成功,其他失败
private String msg; // 提示信息
private T data; // 返回数据
// 成功
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.setCode(200);
result.setMsg("操作成功");
result.setData(data);
return result;
}
// 失败
public static <T> Result<T> error(Integer code, String msg) {
Result<T> result = new Result<>();
result.setCode(code);
result.setMsg(msg);
return result;
}
// getter/setter
}使用:
@GetMapping("/user/{id}")
public Result<User> getUserById(@PathVariable Integer id) {
User user = new User();
user.setId(id);
user.setName("张三");
return Result.success(user);
}返回的 JSON:
{
"code": 200,
"msg": "操作成功",
"data": {
"id": 1,
"name": "张三",
"age": null
}
}为什么要统一返回格式?
- 前端好处理——不用每个接口都猜返回什么格式
- 状态码统一——成功/失败一眼就能看出来
- 便于全局处理——比如统一加日志、统一异常处理
1.7.2 静态资源
静态资源存放位置
Spring Boot 默认会从以下位置加载静态资源(优先级从高到低):
1. classpath:/META-INF/resources/
2. classpath:/resources/
3. classpath:/static/ ← 最常用
4. classpath:/public/一般都放在 static 目录下。
访问静态资源
把一张图片 logo.png 放到 resources/static/ 下,直接访问:
http://localhost:8080/logo.png
不用加 /static 前缀,直接就是根路径。
自定义静态资源路径
如果默认的路径不够用,可以自己配置:
spring:
web:
resources:
static-locations: classpath:/static/, file:D:/upload/这样 D:/upload/ 目录下的文件也能通过 URL 访问了。
前后端分离项目注意:现在的项目大多是前后端分离的,静态资源(HTML/CSS/JS)由前端部署到 Nginx,后端只提供接口。这种情况下后端的 static 目录基本不用。
1.7.3 全局异常处理
程序运行中难免会出异常,如果不处理,用户就会看到一堆错误堆栈,很不友好。Spring Boot 提供了全局异常处理机制。
@RestControllerAdvice + @ExceptionHandler
@RestControllerAdvice // 全局异常处理,返回 JSON
public class GlobalExceptionHandler {
// 处理业务异常
@ExceptionHandler(BusinessException.class)
public Result<Void> handleBusinessException(BusinessException e) {
return Result.error(e.getCode(), e.getMessage());
}
// 处理参数校验异常
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<Void> handleValidationException(MethodArgumentNotValidException e) {
String msg = e.getBindingResult().getFieldError().getDefaultMessage();
return Result.error(400, msg);
}
// 处理其他所有异常(兜底)
@ExceptionHandler(Exception.class)
public Result<Void> handleException(Exception e) {
e.printStackTrace(); // 打印日志,方便排查
return Result.error(500, "系统异常,请稍后重试");
}
}自定义业务异常:
public class BusinessException extends RuntimeException {
private Integer code;
public BusinessException(Integer code, String message) {
super(message);
this.code = code;
}
public Integer getCode() {
return code;
}
}使用:
@GetMapping("/user/{id}")
public Result<User> getUserById(@PathVariable Integer id) {
if (id < 0) {
throw new BusinessException(400, "用户ID不合法");
}
// ...
}这样,不管哪里抛出异常,都会被全局异常处理器捕获,返回统一格式的错误信息。
为什么要用全局异常处理?
- 接口返回格式统一
- 不用在每个 Controller 里 try-catch
- 便于日志记录和问题排查
- 不会把系统内部错误暴露给用户
1.8 企业开发必备工具与规范
这些是企业开发中几乎必用的工具和规范,提前掌握,实习时少走弯路。
1.8.1 Lombok——简化 Java 代码
Lombok 是什么
Lombok 是一个代码生成工具,通过注解自动生成 getter/setter、构造方法、toString 等样板代码。
你以前写一个实体类:
public class User {
private Integer id;
private String name;
private Integer age;
public User() {}
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
@Override
public String toString() {
return "User{id=" + id + ", name='" + name + "', age=" + age + "}";
}
}用了 Lombok 之后:
@Data
public class User {
private Integer id;
private String name;
private Integer age;
}一行 @Data 顶上面几十行。
使用步骤
步骤 1:添加依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>步骤 2:IDEA 安装 Lombok 插件
Settings → Plugins → 搜索 Lombok → 安装 → 重启 IDEA
步骤 3:开启注解处理
Settings → Build, Execution, Deployment → Compiler → Annotation Processors → 勾选 Enable annotation processing
常用注解
| 注解 | 作用 |
|---|---|
| @Getter / @Setter | 生成 getter/setter 方法 |
| @ToString | 生成 toString 方法 |
| @EqualsAndHashCode | 生成 equals 和 hashCode 方法 |
| @Data | = @Getter + @Setter + @ToString + @EqualsAndHashCode |
| @NoArgsConstructor | 生成无参构造方法 |
| @AllArgsConstructor | 生成全参构造方法 |
| @Builder | 生成 Builder 模式(链式调用) |
| @Slf4j | 生成 log 对象,方便打日志 |
@Slf4j 打日志
以前打日志要自己写 private static final Logger log = LoggerFactory.getLogger(xxx.class);,用 Lombok 直接:
@Slf4j
@RestController
public class HelloController {
@GetMapping("/hello")
public String sayHello() {
log.info("调用了 sayHello 方法");
return "Hello";
}
}注意:Lombok 是编译期生成代码,运行时和手写的一样,不影响性能。但要确保 IDEA 装了插件,不然代码会报红(但不影响运行)。
1.8.2 接口文档——Knife4j / Swagger
前后端分离开发,接口文档是必须的。Swagger / Knife4j 可以根据代码自动生成在线接口文档,还能在线调试。
快速集成 Knife4j
Knife4j 是 Swagger 的增强版,界面更好看,功能更强大。
步骤 1:添加依赖
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>步骤 2:配置类
@Configuration
public class Knife4jConfig {
@Bean
public Docket defaultApi2() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.itheima.chapter01.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("接口文档")
.description("Spring Boot 项目接口文档")
.version("1.0")
.build();
}
}步骤 3:访问文档
启动项目,访问:http://localhost:8080/doc.html
就能看到自动生成的接口文档了,还能在线调试。
常用注解
给接口加注释,让文档更清晰:
@Api(tags = "用户管理") // 给 Controller 分组加标题
@RestController
@RequestMapping("/user")
public class UserController {
@ApiOperation("根据ID查询用户") // 接口说明
@GetMapping("/{id}")
public Result<User> getUserById(
@ApiParam("用户ID") @PathVariable Integer id) { // 参数说明
// ...
}
}实体类也可以加注释:
@ApiModel("用户信息")
public class User {
@ApiModelProperty("用户ID")
private Integer id;
@ApiModelProperty("用户名")
private String name;
}注意:生产环境要关闭接口文档!可以用 profile 控制,只在 dev/test 环境开启。
1.8.3 日志配置
Spring Boot 默认日志
Spring Boot 默认用 Logback 作为日志框架,不用额外配置就能用。
日志级别
从低到高:trace < debug < info < warn < error
设置日志级别后,只会输出大于等于该级别的日志。
配置日志
在 application.yml 中配置:
logging:
level:
root: info # 全局日志级别
com.itheima.chapter01: debug # 指定包的日志级别
file:
name: logs/app.log # 日志文件名
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"企业日志最佳实践
- 关键操作必须打日志:用户登录、数据增删改、调用第三方接口
- 异常必须打日志:catch 块里一定要打 error 日志,带上异常堆栈
- 日志级别要合理:调试信息用 debug,正常流程用 info,警告用 warn,异常用 error
- 不要打敏感信息:密码、身份证号、手机号等不要打到日志里
- 生产环境不要打 debug:日志量太大,影响性能,占磁盘
1.8.4 Git 协作规范
实习时一定是团队协作,Git 是必备技能。
常用 Git 命令
git clone 地址 # 克隆项目
git pull # 拉取最新代码
git add . # 添加所有修改
git commit -m "提交信息" # 提交
git push # 推送到远程
git checkout -b 分支名 # 创建并切换分支
git merge 分支名 # 合并分支
git status # 查看状态
git log # 查看提交历史分支管理
企业里一般这样分:
- main/master:主分支,生产环境代码
- develop:开发分支
- feature/xxx:功能分支,开发新功能
- hotfix/xxx:紧急修复分支
提交信息规范
提交信息要清晰,别人一看就知道改了什么:
feat: 新增用户登录接口
fix: 修复用户查询分页bug
docs: 更新README
style: 代码格式化
refactor: 重构用户Service
test: 添加用户Service单元测试
chore: 升级依赖版本格式:类型: 描述
实习生小贴士:
- 提交前先 pull,避免冲突
- 一个提交只做一件事,不要一个提交改一堆东西
- 提交信息要写清楚,不要写"修改"、"更新"这种没营养的
- 不要把本地配置文件、编译产物提交到 Git
1.9 常见问题与排查
刚学 Spring Boot 容易遇到一些问题,这里列出最常见的几个和解决方法。
1. 访问接口 404
可能原因:
- Controller 不在启动类的子包下(最常见!)
- 请求路径写错了
- 请求方法不对(GET 写成 POST 了)
解决:
- 检查包结构,Controller 必须在启动类所在包或其子包下
- 检查 URL 路径
- 检查请求方式
2. 启动失败,端口被占用
错误信息:Port 8080 was already in use
解决:
- 改端口:
server.port=8081 - 或者杀掉占用 8080 的进程
3. 依赖下载慢 / 下载失败
解决:
- 检查 Maven 有没有配阿里云镜像
- 检查网络
- IDEA 中 Maven → Reload Project 重新加载
4. 热部署不生效
检查:
- DevTools 依赖有没有加
- IDEA 自动编译有没有开
- Allow auto-make... 有没有勾
- 有没有用 Debug 模式启动(有时候 Debug 模式下热部署更灵敏)
5. 配置文件不生效
可能原因:
- 配置文件名写错了(必须是 application.yml / application.properties)
- 配置放错位置了(必须在 resources 目录下)
- 缩进不对(yml 格式问题)
- 优先级更高的配置覆盖了(比如命令行参数)
附录
A. 学习资源推荐
- 官方文档:https://docs.spring.io/spring-boot/docs/2.7.6/reference/html/ (最权威,英文)
- Spring 官方指南:https://spring.io/guides (各种快速上手教程)
- B站视频:搜"Spring Boot 黑马程序员"、"Spring Boot 尚硅谷"等
- 技术博客:掘金、CSDN、知乎上有大量 Spring Boot 教程
B. 面试高频问题(入门级)
Spring Boot 的核心注解是什么?它包含哪几个注解?
- @SpringBootApplication,包含 @SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan
Spring Boot 自动配置原理?
- @EnableAutoConfiguration 开启自动配置
- 从 spring.factories 读取自动配置类
- 根据条件注解(@ConditionalOn...)判断哪些配置生效
Spring Boot starter 是什么?
- 一组相关依赖的打包,简化依赖管理
Spring Boot 项目的启动类要放在哪里?为什么?
- 放在最外层的包下,因为 @ComponentScan 默认扫描启动类所在的包及其子包
Spring Boot 打成 JAR 包和 WAR 包的区别?
- JAR 包内嵌 Tomcat,java -jar 直接运行
- WAR 包需要部署到外部 Tomcat
Spring Boot 怎么实现热部署?
- DevTools 工具,原理是类加载器隔离
Spring Boot 怎么读取配置文件?
- @Value、@ConfigurationProperties、Environment
Spring Boot 多环境配置怎么弄?
- Profile 机制,application-dev.yml / application-prod.yml,spring.profiles.active 切换
C. 实习准备建议
- 把本笔记的代码都敲一遍——光看不练假把式
- 做一个完整的小项目——比如用户管理系统(增删改查 + 分页 + 登录)
- 准备好简历上的项目——能讲清楚技术栈、你负责什么、遇到什么问题怎么解决的
- Git 一定要会用——这是团队协作的基础
- Linux 基础命令要会——部署、查日志都要用
- MySQL 要熟练——增删改查、索引、事务这些基础要扎实
- 了解一下微服务概念——不用深入,但要知道 Spring Cloud 是什么
- 保持学习心态——实习就是去学习的,不懂就问,但问之前先自己查
写在最后: Spring Boot 入门很简单,但要学好、学精不容易。作为即将实习的同学,先把基础打牢,能独立完成简单的 CRUD 接口,能看懂项目结构,能排查常见问题,就已经超过很多人了。剩下的,在实习中边做边学,成长最快。
加油!
笔记版本:v1.0 | 基于 Spring Boot 2.7.x | 适用于网络专业实习入门