Skip to content

Spring Boot 企业级开发笔记 ​

前置基础:Java 基础、Java Web(Servlet/JSP)、MySQL 基础、Maven 基础 笔记定位:企业级实战导向,从入门到能上手干活,拒绝纯理论


前言:为什么要学 Spring Boot? ​

你需要知道的行业现状 ​

作为即将实习的网络专业学生,你可能会问:我学过 Java Web、Servlet、JSP,为什么还要学 Spring Boot?

现实情况是这样的:

  1. 市场主流就是 Spring Boot——现在去招聘网站搜 Java 后端开发,90% 以上的岗位要求会 Spring Boot。传统的 SSH(Struts2+Spring+Hibernate)、SSM 单独搭建的方式,在新项目中已经很少见了。
  2. 开发效率天差地别——传统 SSM 项目光搭建环境、配 XML 就要大半天,Spring Boot 几分钟就能跑起来一个可运行的 Web 项目。
  3. 微服务和云原生的基础——现在企业都在搞微服务、上云,Spring Boot + Spring Cloud 是事实标准。
  4. 你的 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/AOPXML 配置文件一大堆,搭建项目慢
第三代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.xJava 6+Spring 4.x停止维护老项目可能还在用
2.0 ~ 2.6Java 8+Spring 5.x停止维护大量存量项目
2.7.xJava 8+Spring 5.3.x开源维护结束,商业支持中目前存量最多的版本
3.0 ~ 3.1Java 17+Spring 6.x维护中新项目逐步采用
3.2+Java 17+Spring 6.1.x最新稳定版新项目首选

给你的建议(实习/求职向):

  1. 重点学 2.7.x——这是目前企业里用得最多的版本,面试也最常问。本笔记的代码示例基于 2.7.x。
  2. 了解 3.x 的变化——主要区别是 3.x 必须 JDK17+,而且 javax.* 包名改成了 jakarta.*(这是 Java EE 捐给 Eclipse 基金会后的改名)。
  3. 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 演示)

验证安装:

bash
java -version
javac -version

环境变量:确保 JAVA_HOME 和 PATH 配置正确。

实习生小贴士:公司里可能不同项目用不同 JDK 版本,建议学会用 IDEA 切换项目 JDK,而不是只装一个版本。

2. Maven 安装与配置 ​

推荐版本:Maven 3.6.x 及以上

验证安装:

bash
mvn -v

必须配置:阿里云镜像

Maven 默认从国外中央仓库下载依赖,速度很慢。一定要换成阿里云镜像。

打开 Maven 安装目录下的 conf/settings.xml,在 <mirrors> 节点中添加:

xml
<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项目使用的 JDK11
JavaJava 版本11
Packaging打包方式Jar

命名规范:Group 一般用公司域名倒写(如 com.xxx),Artifact 用项目名。包名全部小写。

步骤 3:选择依赖

点击 Next,进入依赖选择界面。入门阶段先选这一个:

  • Web → Spring Web(包含 Spring MVC + 内嵌 Tomcat)

步骤 4:完成创建

点击 Create,等待 IDEA 下载依赖并初始化项目。

方式 B:网页版创建 ​

如果 IDEA 用不了(比如网络问题连不上 Initializr 服务器),可以用网页版:

  1. 打开 https://start.spring.io/
  2. 填写项目信息(和上面一样)
  3. 选择依赖
  4. 点击 GENERATE 下载 zip 包
  5. 解压后用 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 配置文件

几个关键文件:

  1. 启动类 xxxApplication.java——项目的入口,运行它的 main 方法就能启动整个项目。
  2. application.properties——全局配置文件,端口号、数据库连接什么的都在这里配。
  3. pom.xml——Maven 配置文件,管理依赖。

pom.xml 解读 ​

打开 pom.xml,我们逐段来看:

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 中添加父工程和依赖

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:编写启动类

java
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 类:

java
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 要做什么:

  1. 写 Servlet 类
  2. 在 web.xml 里配置 Servlet 映射
  3. 部署到 Tomcat
  4. 启动 Tomcat
  5. 访问

用 Spring + Spring MVC 呢?

  1. 写 Controller 类
  2. 配置 spring-mvc.xml(组件扫描、视图解析器……)
  3. 配置 web.xml(ContextLoaderListener、DispatcherServlet……)
  4. 部署到 Tomcat
  5. 启动 Tomcat
  6. 访问

用 Spring Boot 呢?

  1. 写 Controller 类(2 个注解)
  2. 运行 main 方法
  3. 访问

这就是效率差距。

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-webmvc

parent vs starter 的区别 ​

这是初学者容易搞混的,一定要分清楚:

概念作用类比
spring-boot-starter-parent统一管理所有依赖的版本号价格表:告诉你每个东西多少钱
starter(如 spring-boot-starter-web)打包一组相关依赖套餐:给你配好一组东西
  • parent 管版本,starter 管依赖组合
  • 一个项目只有一个 parent,但可以有很多个 starter
  • starter 里的依赖版本由 parent 来保证一致性

常用 Starter 清单 ​

Starter功能什么时候用
spring-boot-starter-webWeb 开发(Spring MVC + 内嵌 Tomcat)做 Web 项目必选
spring-boot-starter-test测试(JUnit + MockMvc + ...)写单元测试
spring-boot-starter-data-jpaJPA 数据访问用 JPA/hibernate
spring-boot-starter-jdbcJDBC + 事务用原生 JDBC
spring-boot-starter-redisRedis 缓存用 Redis
spring-boot-starter-amqpRabbitMQ 消息队列用 RabbitMQ
spring-boot-starter-security安全认证授权做登录权限
spring-boot-starter-validation参数校验接口参数校验
spring-boot-starter-aopAOP 切面做日志、事务等切面
spring-boot-starter-devtools热部署开发阶段用
mybatis-spring-boot-starterMyBatis 整合用 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 个核心注解:

java
@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 中加一行配置:

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 单元测试 ​

为什么要写单元测试 ​

作为实习生,你可能会觉得"功能能跑就行,写测试浪费时间"。但在企业里:

  1. 保证代码质量——有测试的代码,改起来心里有底
  2. 便于回归测试——改了一个地方,跑一遍测试就知道有没有影响其他功能
  3. 专业素养——会写单元测试是初级和中级开发的分水岭之一
  4. 很多公司要求——提交代码必须有对应的测试用例

Spring Boot 测试体系 ​

Spring Boot 提供了 spring-boot-starter-test,里面集成了常用的测试框架:

框架用途
JUnit 5单元测试基础框架
Spring Test / Spring Boot TestSpring 集成测试支持
MockitoMock(模拟)对象
AssertJ流式断言
MockMvcWeb 层测试(模拟 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。

示例代码:

java
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 即可。

示例代码:

java
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);
    }
}

企业测试最佳实践 ​

  1. 测试方法命名:test_方法名_场景_预期结果,如 test_getUserById_userExists_returnUser
  2. 一个测试方法只测一个点:不要一个方法测一堆东西
  3. 测试数据要独立:不要依赖其他测试的数据,每个测试自己准备数据
  4. 关键业务必须有测试:核心逻辑、复杂计算、容易出 bug 的地方
  5. 不要为了覆盖率写测试:质量比数量重要

实习生小贴士:刚进公司先看项目里现有的测试是怎么写的,照着风格写。如果项目里没有测试,至少给自己写的核心功能补上测试。

1.4.2 热部署 ​

什么是热部署 ​

开发的时候,你改了代码,想要看到效果,就得重启项目。项目小还好,启动几秒;项目大了,启动几十秒甚至几分钟,改一行代码等半分钟,一天下来光等启动就浪费很多时间。

热部署就是:你改了代码,不用手动重启,项目自动重新加载。

DevTools 热部署配置 ​

Spring Boot 提供了 spring-boot-devtools 来实现热部署。

步骤 1:添加依赖

xml
<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,比整个项目重启快很多。

注意事项 ​

  1. 只在开发环境用——生产环境不要用 devtools
  2. 静态资源修改不会触发重启——因为静态资源不在 restart classloader 里
  3. 有时候还是需要手动重启——比如改了 pom.xml、改了配置文件的某些项
  4. 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 生成的项目默认就有):

xml
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

方式一:IDEA 图形化操作

  1. 打开 IDEA 右侧的 Maven 面板
  2. 展开项目 → Lifecycle
  3. 先点 clean(清理旧的编译结果)
  4. 再点 package(打包)

方式二:命令行

bash
mvn clean package

跳过测试打包(测试有问题但想先打包看看):

bash
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 目录:

bash
java -jar chapter01-demo-0.0.1-SNAPSHOT.jar

看到启动日志就说明运行成功了,浏览器访问 http://localhost:8080/hello 测试。

方式二:指定端口运行

不想用默认的 8080?可以在启动时指定:

bash
java -jar chapter01-demo-0.0.1-SNAPSHOT.jar --server.port=8081

方式三:指定配置文件运行(后面讲多环境配置时会详细说)

bash
java -jar xxx.jar --spring.profiles.active=prod

生产环境运行方式 ​

上面的方式在命令行运行,一关窗口程序就停了。生产环境不能这样。

Linux 服务器后台运行:

bash
# 后台运行,日志输出到 app.log
nohup java -jar xxx.jar > app.log 2>&1 &

解释:

  • nohup:不挂断运行,关闭终端也不停止
  • > app.log:标准输出重定向到 app.log
  • 2>&1:标准错误也重定向到标准输出(也就是都写到 app.log)
  • &:后台运行

查看日志:

bash
tail -f app.log  # 实时查看日志

停止应用:

bash
ps -ef | grep java  # 找到进程号
kill -9 进程号       # 强制杀掉

实习生小贴士:

  • 真实企业里一般不会直接用 java -jar 跑,会用 Docker 容器或者 Jenkins 自动化部署
  • 但你一定要会这种基础方式,排查问题的时候用得上
  • 日志一定要重定向到文件,不然出了问题没地方查

1.5.2 打包为 WAR 包 ​

什么时候需要 WAR 包 ​

虽然 JAR 包是主流,但有些场景还是需要 WAR 包:

  1. 公司统一用外部 Tomcat 部署——运维团队管理所有 Tomcat,所有项目都打成 WAR 包丢进去
  2. 老项目改造——原来的系统就是 WAR 包部署,不想改部署方式
  3. 一个 Tomcat 跑多个项目——节省服务器资源

WAR 包改造步骤 ​

以一个现有的 Spring Boot 项目为例,改成 WAR 包部署需要 4 步:

步骤 1:修改打包方式

在 pom.xml 中添加:

xml
<packaging>war</packaging>

步骤 2:排除内置 Tomcat

把内置的 Tomcat 排除掉,因为要用外部的 Tomcat:

xml
<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 范围)

xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <scope>provided</scope>  <!-- 编译和测试时用,打包时不包含 -->
</dependency>

为什么要加这个? 因为写代码的时候需要 Servlet API(比如 HttpServletRequest),所以编译时要有。但打包的时候不要把 Tomcat 打进去,因为用外部的。provided 范围就是干这个的。

步骤 4:修改启动类

启动类要继承 SpringBootServletInitializer,重写 configure 方法:

java
@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 包 ​

  1. 执行 mvn clean package 打包
  2. 把 target 目录下的 .war 文件复制到 Tomcat 的 webapps 目录下
  3. 启动 Tomcat(bin/startup.bat 或 bin/startup.sh)
  4. 访问: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 格式:

properties
# 服务器端口
server.port=8080
# 项目上下文路径
server.servlet.context-path=/demo
# 数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=123456

yml 格式 ​

YAML(YAML Ain't Markup Language)是一种结构化的配置格式,用缩进表示层级关系:

yaml
server:
  port: 8080
  servlet:
    context-path: /demo

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test
    username: root
    password: 123456

两种格式对比 ​

对比项propertiesyml
格式key=value,扁平结构缩进层级结构
可读性配置多时前缀重复,可读性差层级清晰,可读性好
支持列表不支持(要写数组很麻烦)支持列表
学习成本低,一看就懂稍高,要注意缩进
企业使用老项目可能用新项目基本都用

推荐用 yml 格式,结构清晰,配置多了不容易乱。

yml 语法要点 ​

  1. 缩进表示层级:用空格缩进,不能用 Tab。同一层级的缩进要对齐。
  2. 冒号后面要有空格:key: value,冒号后面必须有空格。
  3. 列表写法:
yaml
# 列表
fruits:
  - apple
  - banana
  - orange
  1. 注释:用 # 开头

配置文件优先级 ​

如果同一个目录下既有 application.properties 又有 application.yml,properties 优先级更高(会覆盖 yml 中的相同配置)。

但一般项目里只会用一种,不会混用。

1.6.2 读取配置的方式 ​

配置文件里的值,怎么在代码里用?有三种方式。

方式一:@Value 注解(最简单) ​

直接在字段上用 @Value("${配置key}") 注入:

java
@RestController
public class HelloController {

    // 读取配置文件中的 server.port
    @Value("${server.port}")
    private String port;

    @GetMapping("/port")
    public String getPort() {
        return "当前端口:" + port;
    }
}

适用场景:单个配置项的读取。

默认值:如果配置可能不存在,可以给默认值:

java
@Value("${server.port:8080}")  // 冒号后面是默认值
private String port;

方式二:@ConfigurationProperties(批量绑定) ​

如果一组配置项很多,一个个写 @Value 太麻烦,可以用 @ConfigurationProperties 批量绑定到一个类上。

示例:把数据库配置绑定到一个类

java
@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
}

然后在需要的地方注入这个类:

java
@RestController
public class HelloController {

    @Autowired
    private DataSourceProperties dataSourceProperties;

    @GetMapping("/db")
    public String getDbInfo() {
        return dataSourceProperties.getUrl();
    }
}

适用场景:一组相关的配置项,特别是自定义配置。

配合 Lombok 使用更爽:用 @Data 注解自动生成 getter/setter,不用手写。后面会讲 Lombok。

方式三:Environment(动态获取) ​

注入 Environment 对象,动态获取配置:

java
@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:

yaml
server:
  port: 8080
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/dev_db
    username: root
    password: 123456

application-prod.yml:

yaml
server:
  port: 80
spring:
  datasource:
    url: jdbc:mysql://生产IP:3306/prod_db
    username: prod_user
    password: 生产密码

步骤 2:在主配置文件中激活指定环境

application.yml:

yaml
spring:
  profiles:
    active: dev  # 激活 dev 环境

激活 Profile 的几种方式 ​

优先级从高到低:

  1. 命令行参数(最高优先级):

    bash
    java -jar xxx.jar --spring.profiles.active=prod
  2. JVM 参数:

    bash
    java -Dspring.profiles.active=prod -jar xxx.jar
  3. 配置文件:

    yaml
    spring:
      profiles:
        active: dev
  4. 环境变量: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 的用户

对应的注解:

注解说明
@GetMappingGET 请求
@PostMappingPOST 请求
@PutMappingPUT 请求
@DeleteMappingDELETE 请求
@RequestMapping通用(可以指定 method)

参数接收的几种方式 ​

这是写接口最基础的,每种方式都要会。

1. 普通参数(query 参数) ​

URL 后面跟 ?key=value 形式的参数:

java
@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 路径中:

java
@GetMapping("/user/{id}")
public String getUserById(@PathVariable("id") Integer id) {
    return "用户ID:" + id;
}

访问:http://localhost:8080/user/1

3. 请求体(JSON 参数) ​

POST/PUT 请求,参数在请求体中(JSON 格式):

先定义一个接收参数的类:

java
public class User {
    private Integer id;
    private String name;
    private Integer age;
    // getter/setter
}

接口:

java
@PostMapping("/user")
public String addUser(@RequestBody User user) {
    return "新增用户:" + user.getName();
}

用 Postman 测试时,选择 POST 请求,Body → raw → JSON,填入:

json
{
    "id": 1,
    "name": "张三",
    "age": 20
}
  • @RequestBody:把请求体的 JSON 自动转换成 Java 对象
4. 表单参数 ​

传统的 form 表单提交:

java
@PostMapping("/login")
public String login(@RequestParam String username,
                    @RequestParam String password) {
    return "登录:" + username;
}

或者直接用对象接收(不用 @RequestBody):

java
@PostMapping("/login")
public String login(User user) {
    return "登录:" + user.getUsername();
}
java
@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:添加依赖

xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

步骤 2:在实体类上加校验注解

java
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

java
@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数值最小/最大值
@Email邮箱格式
@Pattern正则表达式匹配

企业最佳实践:参数校验是必须的,不能信任前端传过来的任何数据。前端校验是为了用户体验,后端校验是为了安全。

统一返回结果 ​

企业里的接口返回格式都是统一的,不会有的返回字符串、有的返回对象。一般长这样:

json
{
    "code": 200,
    "msg": "操作成功",
    "data": { ... }
}

定义统一返回结果类:

java
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
}

使用:

java
@GetMapping("/user/{id}")
public Result<User> getUserById(@PathVariable Integer id) {
    User user = new User();
    user.setId(id);
    user.setName("张三");
    return Result.success(user);
}

返回的 JSON:

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 前缀,直接就是根路径。

自定义静态资源路径 ​

如果默认的路径不够用,可以自己配置:

yaml
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 ​

java
@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, "系统异常,请稍后重试");
    }
}

自定义业务异常:

java
public class BusinessException extends RuntimeException {
    private Integer code;

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

    public Integer getCode() {
        return code;
    }
}

使用:

java
@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 等样板代码。

你以前写一个实体类:

java
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 之后:

java
@Data
public class User {
    private Integer id;
    private String name;
    private Integer age;
}

一行 @Data 顶上面几十行。

使用步骤 ​

步骤 1:添加依赖

xml
<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 直接:

java
@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:添加依赖

xml
<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-spring-boot-starter</artifactId>
    <version>3.0.3</version>
</dependency>

步骤 2:配置类

java
@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

就能看到自动生成的接口文档了,还能在线调试。

常用注解 ​

给接口加注释,让文档更清晰:

java
@Api(tags = "用户管理")  // 给 Controller 分组加标题
@RestController
@RequestMapping("/user")
public class UserController {

    @ApiOperation("根据ID查询用户")  // 接口说明
    @GetMapping("/{id}")
    public Result<User> getUserById(
            @ApiParam("用户ID") @PathVariable Integer id) {  // 参数说明
        // ...
    }
}

实体类也可以加注释:

java
@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 中配置:

yaml
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"

企业日志最佳实践 ​

  1. 关键操作必须打日志:用户登录、数据增删改、调用第三方接口
  2. 异常必须打日志:catch 块里一定要打 error 日志,带上异常堆栈
  3. 日志级别要合理:调试信息用 debug,正常流程用 info,警告用 warn,异常用 error
  4. 不要打敏感信息:密码、身份证号、手机号等不要打到日志里
  5. 生产环境不要打 debug:日志量太大,影响性能,占磁盘

1.8.4 Git 协作规范 ​

实习时一定是团队协作,Git 是必备技能。

常用 Git 命令 ​

bash
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. 学习资源推荐 ​

  1. 官方文档:https://docs.spring.io/spring-boot/docs/2.7.6/reference/html/ (最权威,英文)
  2. Spring 官方指南:https://spring.io/guides (各种快速上手教程)
  3. B站视频:搜"Spring Boot 黑马程序员"、"Spring Boot 尚硅谷"等
  4. 技术博客:掘金、CSDN、知乎上有大量 Spring Boot 教程

B. 面试高频问题(入门级) ​

  1. Spring Boot 的核心注解是什么?它包含哪几个注解?

    • @SpringBootApplication,包含 @SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan
  2. Spring Boot 自动配置原理?

    • @EnableAutoConfiguration 开启自动配置
    • 从 spring.factories 读取自动配置类
    • 根据条件注解(@ConditionalOn...)判断哪些配置生效
  3. Spring Boot starter 是什么?

    • 一组相关依赖的打包,简化依赖管理
  4. Spring Boot 项目的启动类要放在哪里?为什么?

    • 放在最外层的包下,因为 @ComponentScan 默认扫描启动类所在的包及其子包
  5. Spring Boot 打成 JAR 包和 WAR 包的区别?

    • JAR 包内嵌 Tomcat,java -jar 直接运行
    • WAR 包需要部署到外部 Tomcat
  6. Spring Boot 怎么实现热部署?

    • DevTools 工具,原理是类加载器隔离
  7. Spring Boot 怎么读取配置文件?

    • @Value、@ConfigurationProperties、Environment
  8. Spring Boot 多环境配置怎么弄?

    • Profile 机制,application-dev.yml / application-prod.yml,spring.profiles.active 切换

C. 实习准备建议 ​

  1. 把本笔记的代码都敲一遍——光看不练假把式
  2. 做一个完整的小项目——比如用户管理系统(增删改查 + 分页 + 登录)
  3. 准备好简历上的项目——能讲清楚技术栈、你负责什么、遇到什么问题怎么解决的
  4. Git 一定要会用——这是团队协作的基础
  5. Linux 基础命令要会——部署、查日志都要用
  6. MySQL 要熟练——增删改查、索引、事务这些基础要扎实
  7. 了解一下微服务概念——不用深入,但要知道 Spring Cloud 是什么
  8. 保持学习心态——实习就是去学习的,不懂就问,但问之前先自己查

写在最后: Spring Boot 入门很简单,但要学好、学精不容易。作为即将实习的同学,先把基础打牢,能独立完成简单的 CRUD 接口,能看懂项目结构,能排查常见问题,就已经超过很多人了。剩下的,在实习中边做边学,成长最快。

加油!


笔记版本:v1.0 | 基于 Spring Boot 2.7.x | 适用于网络专业实习入门

基于 Vite 强力驱动 | 纯静态轻量托管