SpringBoot

43 阅读43分钟

SpringBoot 简介

SpringBoot 是由 Pivotal 团队提供的全新框架,其设计目的是为了简化 Spring 应用的初始搭建开发过程

Spring 框架本身已经在一定程度上简化了 Java 企业级开发,而 SpringBoot 则是在此基础上进一步简化。由此可见,SpringBoot 旨在追求极致的开发简便性与广泛适用性。

为了理解 SpringBoot 带来的简化,我们可以先回顾一下传统 SpringMVC 应用的开发流程:

  1. 创建工程,并在 pom.xml 配置文件中配置所依赖的坐标
<dependencies>
    <!-- Spring MVC -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <!-- Servlet API -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>${servlet-api.version}</version>
        <scope>provided</scope>
    </dependency>
</dependencies>
  • 需要手动创建 Maven 工程。
  • pom.xml 中精确配置 SpringMVC、Servlet API 等相关依赖的坐标,并处理可能的版本兼容性问题。
  1. 编写 web3.0 的配置类
// 这是Spring 3.2+提供的更高级别的抽象
public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        // 返回Spring根容器的配置类(用于Service、DAO等非Web组件)
        return new Class[]{SpringConfig.class};
    }
    @Override
    protected Class<?>[] getServletConfigClasses() {
        // 返回SpringMVC的配置类(用于Controller等Web组件)
        return new Class[]{SpringMvcConfig.class};
    }
    @Override
    protected String[] getServletMappings() {
        // 配置DispatcherServlet的映射路径
        return new String[]{"/"};
    }
    // 还可以重写其他方法进行更多配置
    @Override
    protected Filter[] getServletFilters() {
        // 添加过滤器
        return new Filter[]{new CharacterEncodingFilter("UTF-8")};
    }
}
  • 需要编写一个类来实现 WebApplicationInitializer 接口,用于替代传统的 web.xml 文件。
  • 在此类中,需手动注册 Spring 的 DispatcherServlet,并指定配置文件位置、URL 映射等,代码较为模板化且繁琐。
  1. 编写 SpringMVC 配置类
@Configuration
@EnableWebMvc  // 启用Spring MVC
@ComponentScan("com.example.controller")  // 扫描控制器组件
public class SpringMvcConfig {
}
  • 需要创建配置类(使用 @Configuration 注解)。
  • 在该类中启用 MVC 注解驱动(@EnableWebMvc)、配置视图解析器、静态资源处理等组件。这仅完成了应用程序基础框架的搭建。
  1. 编写业务 Controller
@RestController  // 声明这是一个REST风格的控制器,所有方法返回JSON数据
@RequestMapping("/books")  // 定义该类所有请求的基础路径为"/books"
public class BookController {
    @Autowired   // 自动注入BookService实例
    private BookService bookService;
    
    // 处理HTTP GET请求,路径为"/books/{id}"
    @GetMapping("/{id}")
    // 定义查询方法,参数id来自URL路径
    public Result getById(@PathVariable Integer id) {
        // 调用业务层方法,根据id查询书籍信息
        Book book = bookService.getById(id);
        // 根据查询结果设置状态码:成功或失败
        Integer code = book != null ? Code.GET_OK : Code.GET_ERR;
        // 根据查询结果设置消息:成功时为空,失败时显示错误信息
        String msg = book != null ? "" : "数据查询失败,请重试!";
        // 返回统一格式的结果对象,包含状态码、数据和消息
        return new Result(code, book, msg);
    }
}
  • 至此,才能开始编写真正的业务逻辑,例如提供一个简单的 Controller 类和请求处理方法。

从以上流程可以看出,步骤 1 到 3 主要集中于环境搭建和配置,这些步骤相对固定且重复。SpringBoot 的核心价值正是为了自动化这些初始配置步骤,让开发者能更专注于业务代码的编写。

接下来,我们将通过一个入门案例来具体展示 SpringBoot 是如何极大地简化 Spring 应用开发的。

SpringBoot 快速入门

开发步骤

SpringBoot 开发起来特别简单,分为如下几步:

  1. 创建新模块,选择 Spring Initializr,并配置模块相关基础信息
  2. 选择当前模块需要使用的技术集
  3. 开发控制器类
  4. 运行自动生成的 Application 类

接下来我们进行具体的操作。

1. 创建新模块

操作步骤:

  1. 配置项目基本信息
    新建项目 界面,在 生成器 栏找到并点击 Spring Boot ,填写 名称项目文件位置,选择 类型:Maven打包:Jar

    image.png

    类型:Maven打包:Jar 选择理由

    • 我们使用这种方式构建的 SpringBoot 工程其实也是 Maven 工程,而该方式只是一种快速构建的方式
    • 打包方式这里需要设置为 Jar(这是 SpringBoot 的默认打包方式,不同于传统的 war 包)
  2. 选择依赖
    找到 依赖项 - Web - Spring Web,并勾选。Spring Boot版本按需选择。

    image.png

    理解
    由于我们需要开发一个 web 程序,使用到了 SpringMVC 技术,所以需要勾选 Spring Web 依赖
    这些依赖相当于我们传统 Maven 项目中的 pom.xml 依赖配置,但 Spring Initializr 帮我们自动添加了

  3. 完成创建
    经过以上步骤后会创建如下结构的模块:

    image.png

为方便后续学习,项目结构保持与资料基本一致,图中的包名、java类名经过重命名。重命名后直接运行失败,执行 “构建-构建项目Build Project”后解决,运行按钮旁出现两个 Application,删除旧的绿色无效配置

清理建议

创建好的项目会自动生成一些文件,这些文件目前对我们学习来说不是必需的,可以删除以下目录和文件以保持项目简洁:

  • .mvn/ 目录(Maven 包装器相关,如果不需要跨环境一致可以删除)
  • .gitignore 文件(如果要使用 Git 管理,建议保留)
  • HELP.md 文件
  • mvnwmvnw.cmd 文件(Maven 包装器脚本)
2. 创建 Controller

com.itheima 包下创建controller包,再在其中创建 BookController.java 类,代码如下:

/**
 * BookController - 书籍控制器类
 * 
 * 这个类演示了 SpringBoot 中 RESTful API 的基本写法
 * 
 * 知识点讲解:
 * 1. @RestController:表示这是一个控制器类,方法的返回值直接作为 HTTP 响应体,而不是视图名称
 *    因此,所有方法的返回值都会自动转换为 JSON 格式
 * 
 * 2. @RequestMapping("/books"):类级别的映射注解
 *    - 指定这个控制器处理以 "/books" 开头的所有请求
 *    - 这个路径会与方法的映射路径拼接起来,形成完整的 URL
 * 
 * 3. @GetMapping("/{id}"):方法级别的映射注解
 *    - 表示这个方法处理 HTTP GET 请求
 *    - "/{id}" 是路径变量,用 {} 括起来的部分表示这是一个可变部分
 *    - 完整的访问路径是:GET http://localhost:8080/books/{id}
 * 
 * 4. @PathVariable Integer id:路径变量绑定
 *    - 将 URL 中的 {id} 部分绑定到方法的参数 id 上
 *    - 参数名必须与 @PathVariable 中的变量名一致(如果省略参数名,需要确保变量名与占位符名称一致)
 */
@RestController
@RequestMapping("/books")
public class BookController {

    /**
     * 根据ID获取书籍信息
     * 
     * 示例:访问 http://localhost:8080/books/1
     * - 会匹配到这个方法
     * - id 参数会获取到 1
     * - 方法返回的字符串会直接作为 HTTP 响应体
     * 
     * @param id 书籍ID,从URL路径中获取
     * @return 返回一个简单的字符串(实际项目中通常会返回对象或JSON)
     */
    @GetMapping("/{id}")
    public String getById(@PathVariable Integer id) {
        // 在实际项目中,这里通常会调用Service层获取数据
        // 例如:Book book = bookService.getById(id);
        // 返回:return book;
        
        System.out.println("id ==> " + id);
        return "hello, spring boot!";
    }
}

创建控制器类步骤

// 第一步:导入必要的注解
import org.springframework.web.bind.annotation.*;

// 第二步:添加 @RestController 注解
@RestController
// 第三步:添加 @RequestMapping 定义基础路径(可选)
@RequestMapping("/books")
public class BookController {
    
    // 第四步:编写处理请求的方法
    // 示例1:GET请求,带路径参数
    @GetMapping("/{id}")
    public String getById(@PathVariable Integer id) {
        return "ID: " + id;
    }
    
    // 示例2:GET请求,不带参数
    @GetMapping
    public String getAll() {
        return "所有数据";
    }
    
    // 示例3:POST请求
    @PostMapping
    public String create(@RequestBody Book book) {
        return "创建成功";
    }
}

常见映射注解

  • @GetMapping - 处理 GET 请求
  • @PostMapping - 处理 POST 请求
  • @PutMapping - 处理 PUT 请求
  • @DeleteMapping - 处理 DELETE 请求
  • @PatchMapping - 处理 PATCH 请求
3. 启动服务器

运行 SpringBoot 工程不需要使用本地的 Tomcat 和插件,只需运行项目 com.itheima 包下的 Application 类。 运行后控制台会显示类似以下信息:

image.png

关键信息解读:

  1. Tomcat initialized with port(s): 8080 (http) - 内嵌的 Tomcat 服务器已启动,监听 8080 端口
  2. Started Application in 1.168 seconds - 应用启动耗时 1.168 秒
  3. with context path '/' - 应用上下文路径为空,表示根路径

与传统的 Spring MVC 对比:

传统 Spring MVCSpringBoot
需要外部 Tomcat内嵌 Tomcat,无需安装配置
需要 web.xml 配置零 XML 配置
需要手动配置 DispatcherServlet自动配置
部署时需要打 war 包可执行 jar 包,直接运行
4. 进行测试

使用 Postman 工具来测试我们的程序:

Postman 测试步骤:

  1. 打开 Postman:如果没有安装,可以从官网下载
  2. 创建新请求
    • 请求方法:GET
    • 请求 URL:http://localhost:8080/books/1
  3. 发送请求:点击 Send 按钮
  4. 查看响应:在响应体部分应该看到 hello, spring boot!
image.png

通过上面的入门案例我们可以看到使用 SpringBoot 进行开发,使整个开发变得很简单,那它是如何做到的呢?
要研究这个问题,我们需要看看 Application 类和 pom.xml 都书写了什么:

Application 类分析:

// 导入必要的包
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * SpringBoot 应用的主启动类
 * 
 * 这个类是整个应用的入口点,也是 SpringBoot 应用的核心
 * 
 * @SpringBootApplication 注解详解:
 * 这个注解告诉 Spring Boot:
 * 1. 这是一个 Spring Boot 应用
 * 2. 启用自动配置
 * 3. 扫描当前包及其子包下的组件
 */
@SpringBootApplication
public class Application {
    
    /**
     * 主方法 - 应用启动入口
     * 
     * 这个方法只有一个核心操作:SpringApplication.run()
     * 
     * SpringApplication.run() 方法的作用:
     * 1. 创建 Spring 应用上下文(ApplicationContext)
     * 2. 注册所有 Bean(包括自动配置的 Bean)
     * 3. 启动内嵌的 Web 服务器(如 Tomcat)
     * 4. 启动 Spring Boot 应用
     * 
     * 方法的参数说明:
     * - Application.class: 主配置类
     * - args: 命令行参数
     * 
     * 方法的返回值:ConfigurableApplicationContext,可以用于获取 Bean
     */
    public static void main(String[] args) {
        // 这行代码完成了传统 Spring MVC 中的所有配置工作
        SpringApplication.run(Application.class, args);
        
        // 启动后,应用会一直运行,直到收到关闭信号
        // 可以通过 Ctrl+C 或调用 context.close() 来关闭应用
    }
}

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>
    
    <!-- 
    这是父工程配置,指定了一个父工程 - SpringBoot 的精髓之一
    作用:
    1. 版本管理:统一管理所有依赖的版本
    2. 默认配置:提供合理的默认配置
    3. 依赖继承:子工程可以继承父工程的依赖
    
    传统 Maven 项目需要为每个依赖指定版本号,容易冲突
    SpringBoot 通过父工程统一管理,避免版本冲突
    -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.0</version>
    </parent>
    
    <!-- 项目坐标 -->
    <groupId>com.itheima</groupId>
    <artifactId>springboot_01_quickstart</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    
    <!-- 项目属性 -->
    <properties>
        <!-- 指定 JDK 版本 -->
        <java.version>8</java.version>
    </properties>
    
    <!-- 项目依赖 -->
    <dependencies>
        <!-- 
        Spring Web Starter - Web 应用起步依赖,是我们在创建 SpringBoot 工程勾选的那个 Spring Web 产生的
        这个依赖是 SpringBoot 简化开发的关键
        
        什么是起步依赖(Starter)?
        起步依赖是一组预配置的依赖集合,它包含了开发某种应用所需的所有基础依赖。
        
        传统方式:需要手动添加几十个依赖,并解决版本冲突
        SpringBoot:只需要添加这一个起步依赖
        -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <!-- 注意:这里没有指定版本号,版本由父工程统一管理 -->
        </dependency>
        
        <!-- 
        测试起步依赖
        作用:提供测试所需的依赖(JUnit, Mockito, Spring Test等)
        注意:scope 为 test,表示只在测试时使用,不会打包到生产环境
        -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
    <!-- 构建配置 -->
    <build>
        <plugins>
            <!-- 
            Spring Boot Maven 插件
            作用:
            1. 将应用打包成可执行的 JAR 文件(包含所有依赖)
            2. 提供运行、打包等 Maven 目标(goals)
            3. 支持热部署(spring-boot:run)
            
            传统方式:
            - 打 war 包,需要部署到外部 Tomcat
            - 依赖需要单独部署
            
            SpringBoot 方式:
            - 打可执行 JAR 包,包含所有依赖和内嵌服务器
            - 直接运行:java -jar app.jar
            -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

对比

做完 SpringBoot 的入门案例后,接下来对比一下 Spring 程序和 SpringBoot 程序。如下图

image.png
  • 坐标
    Spring 程序中的坐标需要自己编写,而且坐标非常多
    SpringBoot 程序中的坐标是我们在创建工程时进行勾选自动生成的
  • web3.0配置类
    Spring 程序需要自己编写这个配置类。这个配置类大家之前编写过,肯定感觉很复杂
    SpringBoot 程序不需要我们自己书写
  • 配置类
    Spring/SpringMVC 程序的配置类需要自己书写。而 SpringBoot 程序则不需要书写。
  • 基于 Idea 的 Spring Initializr 需要联网,因为它需要从 Spring 官方服务器获取模板和依赖列表
  • 如果无法联网,可以:
    • 手动创建 Maven 项目,添加 SpringBoot 依赖
    • 使用本地缓存(如果之前下载过)

官网构建工程

通过IDEA快速创建的Spring Boot工程,其底层实现实际上是调用了Spring官方提供的在线构建工具——Spring Initializr

了解如何在官网直接使用Spring Initializr构建工程,不仅能理解其原理,还能确保在没有IDEA或其他IDE的环境下,依然可以创建项目。

访问 Spring Initializr

直接在浏览器中输入Spring Initializr的地址:start.spring.io

打开后的界面如下图所示,它与你在IDEA中看到的创建向导在核心功能上完全一致:

image.png

配置项目信息与依赖

在Spring Initializr页面上,你需要完成与IDEA中类似的配置:

1. 项目基础信息
你需要填写或选择页面顶部的几个关键元数据:

  • Project: 选择构建工具,如 MavenGradle
  • Language: 选择编程语言,如 Java
  • Spring Boot: 选择Spring Boot的版本(建议选择标注有 (SNAPSHOT) 以外的稳定版本)。
  • Project Metadata
    • Group: 组织标识,通常使用倒写的域名(例如 com.example)。
    • Artifact: 项目标识,即你的项目名(例如 demo)。
    • 其他如 NameDescriptionPackage name 会根据前两项自动生成,通常无需修改。

2. 添加项目依赖
这是Spring Initializr的核心功能之一,用于为你的项目自动生成对应的依赖配置。

  • 点击 “ADD DEPENDENCIES” 按钮(或按 Ctrl + B 快捷键),会弹出依赖搜索面板。
  • 在搜索框中输入你需要的技术名称,例如 “Web”
  • 从搜索结果中选择 “Spring Web” 依赖,它将负责添加构建一个Web应用所需的所有基础库(包含内嵌的Tomcat服务器、Spring MVC等)。
  • 你还可以根据需要添加更多依赖,例如 “Spring Data JPA”、“MySQL Driver”、“Lombok” 等。

3. 生成并下载项目

所有信息配置完成后:

  1. 点击页面底部的 “GENERATE” 按钮(或按 Ctrl + 回车)。
  2. 浏览器会自动下载一个以你填写的 Artifact 命名的 .zip 压缩包(例如 demo.zip)。

4. 解压与导入IDE

  1. 将下载的 .zip 文件解压到你本地的工作目录。
  2. 解压后的目录结构与你用IDEA生成的项目完全一致,标准的Maven项目结构如下: demo/ ├── src/ │ ├── main/ │ │ ├── java/com/example/demo/ │ │ │ └── DemoApplication.java # Spring Boot 主启动类 │ │ └── resources/ │ │ ├── static/ │ │ ├── templates/ │ │ └── application.properties # 配置文件 │ └── test/ # 测试目录 └── pom.xml # Maven 项目核心配置文件
  3. 打开 pom.xml 文件,你可以看到Spring Boot父工程坐标以及你刚才选择的 “Spring Web” 依赖都已经自动配置好了。
  4. 最后,你可以用IDEA、Eclipse等IDE的 “Open”“Import” 功能,选择这个解压后的项目目录,将其导入为现有项目进行开发。

工程快速启动-Jar包

问题导入:解决前后端协作的部署依赖

在前后端分离的协作开发中,前端开发者通常需要后端服务处于运行状态,以便测试接口、调试页面功能。这会造成前端工作进度受制于后端开发者本地的开发环境。

传统方式的局限:如果让前端开发者在自己电脑上配置完整的后端开发环境(如安装JDK、Tomcat、Idea,并导入项目),过程非常繁琐且不现实。

SpringBoot的解决方案:利用SpringBoot可以将工程打包成一个独立可执行的Jar文件。这个Jar包内嵌了Web服务器(如Tomcat),因此运行它不需要预先安装任何外部的Tomcat或IDE,只需要目标机器上有Java运行环境(JRE)即可。

这样,后端开发者只需将打包好的Jar文件交给前端,前端开发者(或任何需要的人)就可以在自己的电脑上,通过一条简单的命令独立启动后端服务,唯一的前提是能访问到项目所需的数据库等外部资源

打包:生成可执行Jar包

SpringBoot工程能够打包成“可执行Jar”(也称为“Fat Jar”),核心在于 pom.xml 中配置的 spring-boot-maven-plugin 插件。

打包步骤

  1. 确认插件:确保你的 pom.xml 文件的 <build> -> <plugins> 部分包含该插件配置。

    <build>
        <plugins>
            <!-- 这是生成可执行Jar的关键插件 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    

    重要提示:使用Spring Initializr创建的工程默认已包含此配置。如果缺失,打包出的Jar将无法以 java -jar 方式直接启动。

  2. 执行打包

在IDEA中打包Spring Boot项目,有两种直观的方法:

方法一:使用IDEA右侧的Maven图形化工具

  1. 打开Maven工具窗口:在IDEA主界面右侧,找到并点击 「Maven」 标签栏。如果没看到,请通过顶部菜单 View(视图) → Tool Windows(工具窗口) → Maven 打开。
  2. 找到你的项目:在展开的Maven面板中,你会看到你的项目名(例如 springboot_01_quickstart)。点开它下面的 Lifecycle(生存期) 文件夹。
  3. 执行打包:在 Lifecycle 里,找到 package双击它。IDEA就会开始执行打包过程。

执行时你会看到:IDEA底部会弹出「Run」工具窗口,显示详细的Maven构建日志。最后出现 BUILD SUCCESS 就表示打包成功。

方法二:使用IDEA内置的终端(命令行)

这个方法更接近真实的生产环境操作。

  1. 打开终端:在IDEA左边栏下部,找到并点击 Terminal(终端) 标签页。它会自动打开并定位在你的项目根目录(即 pom.xml 文件所在的目录)。
  2. 输入命令:在终端里,直接输入以下命令并按回车:
    mvn clean package
    

执行时你会看到:同样会在终端里滚动输出构建信息,直到出现 BUILD SUCCESS

  1. 获取产物:命令执行成功后,在项目的 target 目录下即可找到生成的Jar包,其命名格式通常为 项目名-版本号.jar(例如 springboot_01_quickstart-0.0.1-SNAPSHOT.jar)。
启动:运行Jar包

启动这个Jar包非常简单,无需任何容器。

  1. 打开命令行:进入 target 目录(cd target),或者记住Jar包的完整路径。
  2. 执行启动命令
    java -jar Jar包名
    
  3. 观察日志:执行命令后,SpringBoot的启动日志会直接输出在控制台,你将会看到熟悉的启动信息,包括内嵌Tomcat的端口号。

上述可以 在IDEA的终端中操作,也可以在系统的命令行中操作。

SpringBoot 概述

SpringBoot 是由 Pivotal 团队提供的全新框架,其设计目的就是简化 Spring 应用的初始搭建开发过程

通过与原始 Spring 环境对比,可以清晰看到 SpringBoot 的核心价值:

原始 Spring 开发痛点SpringBoot 对应的解决方案
配置繁琐
需要大量 XML 或 Java 配置
自动配置 (Auto Configuration)
根据类路径和设置,自动配置 Bean 和组件。
依赖设置繁琐
需要手动管理大量依赖及其兼容版本
起步依赖 (Starter Dependencies)
提供预设的、版本协调好的依赖包。
部署依赖外部服务器
需要独立安装和配置 Tomcat 等服务器
辅助功能 (如内置服务器)
内置 Tomcat、Jetty 等服务器,打包即可独立运行。

起步依赖

在使用 Spring Initializr 创建工程时,pom.xml 中自动生成的、名称中包含 starter 的依赖,就是 起步依赖。它们是简化依赖管理的核心。

起步依赖的实现机制主要基于两个关键设计:继承父工程 (parent)引入启动器 (starter)

探索父工程:统一版本管理

在项目的 pom.xml 中,通过 <parent> 指定了一个父工程(如 spring-boot-starter-parent)。这个父工程的核心作用是进行统一的依赖版本管理,而非直接引入所有依赖。

  • 版本仓库 (<properties>):父工程的 pom.xml 中,<properties> 标签像一个大仓库,定义了数百个常用技术依赖(如 Servlet、MySQL Driver、Jackson 等)的兼容版本号
  • 依赖管理 (<dependencyManagement>)<dependencyManagement> 标签则利用这个仓库,对大部分可能用到的依赖进行了版本锁定
  • 对你的影响:正因为继承了此父工程,当你在项目中添加依赖时,通常只需指定 groupIdartifactId,无需再写 version。SpringBoot 会自动从父工程管理的版本仓库中选取一个经过兼容性测试的版本,这从根本上避免了版本冲突问题。
探索起步依赖:功能聚合包

spring-boot-starter-web 为例,当你在 pom.xml 中声明此依赖后,它实际上会引入一个功能相关的依赖包集合,而不仅仅是一个库。

进入 spring-boot-starter-webpom.xml,你会发现它自身又引入了多个协调好的依赖:

  • spring-webspring-webmvc(用于实现 Spring MVC Web 框架)
  • spring-boot-starter-tomcat(内嵌了 Tomcat 服务器)
  • spring-boot-starter-json(提供了 JSON 处理能力)

结论starter 是一个功能导向的依赖描述。你需要什么功能(例如做 Web 开发、操作数据库、进行安全控制),就引入对应的 starter(例如 spring-boot-starter-webspring-boot-starter-data-jpaspring-boot-starter-security)。这个 starter 会帮你把实现该功能所需的一整套、版本协调好的技术依赖全部引入进来。

实际开发中的使用守则

  1. 引入依赖:通常只需要写 groupIdartifactId不写 version,依赖版本由父工程统一管理。
  2. 选择依赖:根据所需功能选择对应的 spring-boot-starter-*
  3. 处理版本冲突(特殊情况):如果必须使用特定版本,可以在 pom.xml 中手动指定 <version>,但需谨慎评估兼容性。

程序启动-引导类

在 Spring Boot 中,每个项目都有一个核心的入口类,通常称为 引导类 (Bootstrap Class) 或 主启动类。它通常是项目创建后自动生成的,类名格式默认为 [项目名]Application

// 示例:Springboot01QuickstartApplication 就是一个引导类
@SpringBootApplication // 核心注解:标记此为SpringBoot应用,并启用自动配置
public class Springboot01QuickstartApplication {
    
    public static void main(String[] args) {
        // 核心启动方法:这行代码负责启动整个SpringBoot应用
        SpringApplication.run(Springboot01QuickstartApplication.class, args);
    }
}

关键要点:

  1. 唯一入口main 方法是整个 Spring Boot 应用的唯一启动入口。
  2. 核心注解@SpringBootApplication 是一个组合注解,它整合了配置、组件扫描和自动配置启用等关键功能。
  3. 启动原理:当你运行 main 方法时,SpringApplication.run() 会:
    • 初始化 Spring 容器。
    • 启动内嵌的 Web 服务器(因为你引入了 spring-boot-starter-web 依赖,所以默认是 Tomcat)。
    • 运行你的应用程序。
  4. 打包方式:Spring Boot 默认采用 jar 包的打包方式(而非传统的 war 包)。这使得应用成为一个独立、可携带的单元,只需 JDK 环境即可通过 java -jar 命令运行,非常适合微服务和云原生部署。

切换 Web 服务器

Spring Boot 默认使用 Tomcat 作为内嵌服务器,但它支持轻松切换为其他服务器,如 Jetty 或 Undertow。

切换核心思想“先排除,后引入”——从当前 Web 起步依赖中排除默认的 Tomcat,然后引入你想要的服务器起步依赖。

操作步骤(以切换到 Jetty 为例)

第一步:排除默认的 Tomcat 依赖

pom.xml 文件中,修改 spring-boot-starter-web 依赖,添加 <exclusions> 标签来排除 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>

第二步:引入 Jetty 起步依赖

在同一个 pom.xml 文件中,添加 Jetty 的起步依赖。

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

第三步:验证切换

完成以上修改后,点击 “同步Maven更改” 以保存 pom.xml,再重新启动引导类(运行 main 方法)。在控制台输出的启动日志中,将不再看到 Tomcat 的字样,取而代之的是 Jetty 的相关信息,类似如下:

image.png

实践提示

  • 这个例子清晰地展示了 Spring Boot 起步依赖的强大之处:切换一项核心技术,通常只需要更换对应的 starter 即可,所有复杂的依赖传递和版本管理都由框架自动处理。
  • 在真实项目中,如果你没有对 Jetty 或 Undertow 的特殊需求,使用默认的 Tomcat 是最稳妥、兼容性最好的选择。

配置文件

Spring Boot 的强大之处在于其 “约定大于配置” 的理念,它提供了合理的默认值。但当我们需要自定义设置(如更改端口、配置数据库)时,就要用到配置文件。你可以将它理解为你应用程序的 “遥控器” ,通过修改它,无需改动代码就能改变程序的行为。

配置文件格式

核心作用:自定义应用设置

Spring Boot 应用启动时,许多设置(如服务器端口)都有默认值。如果想修改这些默认设置,就需要使用配置文件。

举个例子:默认的服务器端口是 8080,访问地址是 http://localhost:8080/books/1。如果想把端口改成更常见的 80(HTTP默认端口,访问时可省略),使得访问地址变为 http://localhost/books/1,就需要通过配置文件来实现。

Spring Boot 支持三种主流的配置文件格式,它们功能相同,只是语法不同。

格式文件后缀语法特点示例
.propertiesapplication.properties键值对,使用等号(=)连接。最传统,但层次结构不直观。server.port=80
.ymlapplication.yml树状结构,使用冒号(:)和缩进来表示层级。结构清晰,推荐使用。yaml server: port: 81
.yamlapplication.yaml.yml 完全相同,只是后缀名不同。.yml

关键规则:Spring Boot 配置文件的主文件名必须是 application,只有后缀名可以变化。

环境准备

创建一个新的 Spring Boot 项目(例如命名为 springboot_02_base_config)用来演示不同的配置文件,并创建一个简单的 BookController 控制器,用于后续测试配置是否生效。

image.png

在该工程中的 com.itheima.controller 包下创建一个名为 BookController 的控制器。内容如下:

@RestController
@RequestMapping("/books")
public class BookController {

    @GetMapping("/{id}")
    public String getById(@PathVariable Integer id){
        System.out.println("id ==> "+id);
        return "hello , spring boot!";
    }
}

三种配置文件演示

1. 使用 application.properties
src/main/resources/ 目录下找到或创建 application.properties 文件,添加一行配置:

server.port=80

启动应用,观察控制台日志,若看到 ↓,说明配置生效。

image.png

2. 使用 application.yml (推荐)
在相同目录中创建 application.yml 文件,将 .properties 文件中的所有配置项,转换为 YAML 语法后,完整写入 .yml 文件。再将原来的 application.properties 文件删除,或者将其重命名(例如改为 application.properties.bak 作为备份)。.yml 文件端口配置如下:

server:
  port: 81

启动应用,端口应变为 81

YAML语法注意

  1. 缩进必须使用空格(通常2个)进行缩进不能使用Tab键。同一层级的元素必须左对齐。
  2. 冒号:每个键的后面必须紧跟一个英文冒号和一个空格,然后才是值。
    • ✅ 正确:port: 80
    • ❌ 错误:port:80(缺少空格)或 port: 80(冒号错误)

3. 使用 application.yaml
操作与 .yml 完全一样,只是文件后缀名不同。application.yaml内容如下:

server:
  port: 82

启动应用,端口应变为 82

提示功能

三种配置文件都有提示功能,在 .yml 配置文件中,我们也可以在该文件中书写 port ,然后 IDEA 就会提示并书写成YAML格式:

image.png

配置文件的优先级

如果三种格式的配置文件同时存在,且配置了同一个属性(如端口),Spring Boot 会按以下优先级决定使用哪一个: application.properties > application.yml > application.yaml

高优先级的配置会覆盖低优先级的相同配置。在项目中,通常建议只使用一种格式(推荐 .yml),以避免混淆。

YAML 格式

YAML (YAML Ain‘t Markup Language) 是一种专门用来编写配置文件的数据序列化格式。近年来,它凭借清晰的层次结构,在 Spring Boot 等现代框架中已成为主导的配置格式。

与之前的配置格式相比,YAML 的优势非常明显。我们可以通过一个公司信息的例子来直观对比:

格式示例特点分析
XML (早期)<enterprise>
    <name>itcast</name>
    <age>16</age>
    <tel>4006184000</tel>
</enterprise>
注重格式:标签嵌套,结构严谨但冗余,可读性一般,数据被标签“包裹”。
Propertiesenterprise.name=itcast
enterprise.age=16
enterprise.tel=4006184000
平铺直叙:使用“点”分隔层级,结构简单但层级深时难以阅读。
YAML (主流)enterprise:
    name: itcast
    age: 16
    tel: 4006184000
注重数据树状缩进,层级一目了然,去除了不必要的符号,最易阅读和维护

文件扩展名.yml(最常用) 或 .yaml,两者完全等效。

语法规则

  • 大小写敏感
  • 属性层级关系使用多行描述,每行结尾使用冒号结束
  • 使用缩进表示层级关系,同层级左侧对齐,只允许使用空格(不允许使用Tab键)
    空格的个数并不重要,只要保证同层级的左侧对齐即可。
  • 属性值前面添加空格(属性名与属性值之间使用冒号+空格作为分隔)
  • # 表示注释,其后的内容会被忽略。
  • 数组(List)的表示
    在属性下方,使用 - 减号(后面跟一个空格)来表示数组中的一个元素。
    enterprise:
      subject:
        - Java       # 数组第一项
        - 前端        # 数组第二项
        - 大数据      # 数组第三项
    # 这等价于Java中的:List<String> subject = Arrays.asList("Java", "前端", "大数据");
    
    # 部门信息 (对象数组)
    departments:
    - name: 研发部
      manager: 张三
    - name: 市场部
      manager: 李四
    

YAML 配置文件数据读取

这一节我们将学习三种从 application.yml 配置文件中读取数据的方法,这是将静态配置转化为程序中可用变量的关键步骤。

下面我们开始具体的环境准备和三种方式的详解。

环境准备

新创建一个名为 springboot_03_read_dataSpringBoot 工程,目录结构如下:

image.png

com.itheima.controller 包写创建名为 BookController 的控制器,内容如下:

@RestController
@RequestMapping("/books")
public class BookController {

    @GetMapping("/{id}")
    public String getById(@PathVariable Integer id){
        System.out.println("id ==> "+id);
        return "hello , spring boot!";
    }
}

com.itheima.domain 包下创建一个名为 Enterprise 的实体类等会用来封装数据,内容如下:

public class Enterprise {
    private String name;
    private int age;
    private String tel;
    private String[] subject;
    
    //setter and getter
    
    //toString
}

resources 下创建一个名为 application.yml 的配置文件,里面配置了不同的数据,内容如下:

lesson: SpringBoot

server:
  port: 80

enterprise:
  name: itcast
  age: 16
  tel: 4006184000
  subject:
    - Java
    - 前端
    - 大数据

三种读取配置数据的方式

@Value 注解(读取单个值)

这种方式简单直接,适合读取少量、零散的配置值。

工作原理:在字段上使用 ${一级属性名.二级属性名……},Spring 会自动将对应的配置值注入到字段中。

BookController 中的使用示例

@RestController
@RequestMapping("/books")
public class BookController {

    // 1. 读取简单值 (lesson: SpringBoot)
    @Value("${lesson}")
    private String lesson;

    // 2. 读取嵌套值 (server.port)
    @Value("${server.port}")
    private Integer port;

    // 3. 读取数组中的第一个元素 (enterprise.subject[0])
    @Value("${enterprise.subject[0]}")
    private String subject_00;

    @GetMapping("/{id}")
    public String getById(@PathVariable Integer id) {
        System.out.println(lesson);
        System.out.println(port);
        System.out.println(subject_00);
        return "hello, spring boot!";
    }
}
注入 Environment 对象(动态读取)

这种方式将所有配置都加载到一个 Environment 对象中,可以动态地根据键名获取值。

BookController 中的使用示例

@RestController
@RequestMapping("/books")
public class BookController {

    // 自动注入Environment对象
    @Autowired
    private Environment env;

    @GetMapping("/{id}")
    public String getById(@PathVariable Integer id) {
        // 通过 getProperty 方法根据键名获取值
        System.out.println(env.getProperty("lesson"));
        System.out.println(env.getProperty("enterprise.name"));
        System.out.println(env.getProperty("enterprise.subject[0]"));
        return "hello, spring boot!";
    }
}

缺点

  1. 类型不安全getProperty 返回的是 String,需要自己转换类型。
  2. 键名拼写易错:配置键名以字符串形式书写,没有IDE的检查和提示,容易出错。 因此,在需要读取大量配置的常规业务开发中很少直接使用
自定义对象(用于正式项目)

这是最规范、最面向对象的方式,尤其适用于将一组逻辑相关的配置(如enterprise下的所有属性)一次性加载到一个自定义的JavaBean中

第一步:改造实体类 Enterprise
com.itheima.domain 包下的 Enterprise 类上添加关键注解:

@Component // 1. 将此类的对象交给Spring容器管理
@ConfigurationProperties(prefix = "enterprise") // 2. 指定要绑定配置的前缀
public class Enterprise {
    // 3. 字段名必须与配置文件中 ‘prefix.’ 后面的部分严格对应
    // 例如 ‘enterprise.name’ 对应字段 ‘name’
    private String name;
    private int age;
    private String tel;
    private String[] subject;

    // 4. 必须为每一个字段提供其getter和setter方法,否则Spring无法注入值
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    // ... 其他字段的getter/setter

    @Override
    public String toString() {
        return "Enterprise{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", tel='" + tel + '\'' +
                ", subject=" + Arrays.toString(subject) +
                '}';
    }
}

第二步:在 BookController 中注入使用

@RestController
@RequestMapping("/books")
public class BookController {

    // 像注入普通Bean一样注入配置绑定好的Enterprise对象
    @Autowired
    private Enterprise enterprise;

    @GetMapping("/{id}")
    public String getById(@PathVariable Integer id) {
        // 直接使用对象的getter方法获取配置值,类型安全,有代码提示
        System.out.println(enterprise.getName());
        System.out.println(enterprise.getAge());
        System.out.println(enterprise.getSubject());
        System.out.println(enterprise.getTel());
        System.out.println(enterprise.getSubject()[0]);
        return "hello, spring boot!";
    }
}

注意:消除 @ConfigurationProperties 的IDEA警告
在类上添加 @ConfigurationProperties 注解后,IDEA可能会显示一个警告(如黄色波浪线)。这个警告的意思是:“我(IDEA)不知道你配置了哪些属性,所以无法为你提供属性名的代码提示和拼写检查。”

解决方案:在 pom.xml 中添加一个编译期注解处理器依赖。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional> <!-- 注意:optional=true 表示此依赖不会传递到其他模块 -->
</dependency>

多环境配置

在实际开发中,应用通常需要在开发(dev)测试(test)生产(pro) 等不同环境中运行。每个环境的配置(如数据库地址、日志级别、服务器端口)往往不同。频繁手动修改配置文件不仅麻烦,而且容易出错。

image.png

Spring Boot 提供了强大的多环境配置支持,让你能轻松地在不同环境间切换。主要有以下三种方式:

YAML 文件配置(推荐)

YAML 文件支持在单个文件内使用 --- 分隔符定义多个环境配置,结构非常清晰。

基本语法与示例

# 第一部分:设置默认激活的环境 (必须放在最前面)
spring:
  config:
    activate:
      on-profile: dev # 这里设置默认激活的是dev环境

# 用三个减号(---)进行分隔
---
# 第二部分:开发环境配置
spring:
  config:
    activate:
      on-profile: dev # 为此段配置命名为 ‘dev’
server:
  port: 80
  servlet:
    context-path: /dev-api  # 为所有请求路径添加统一前缀,便于区分是什么环境中的接口
logging:        # logging.level根据不同环境设置不同的日志级别
  level:
    root: debug

---
# 第三部分:测试环境配置
spring:
  config:
    activate:
      on-profile: test # 为此段配置命名为 ‘test’
server:
  port: 81
logging:
  level:
    root: info

---
# 第四部分:生产环境配置
spring:
  config:
    activate:
      on-profile: pro # 为此段配置命名为 ‘pro’
server:
  port: 82
logging:
  level:
    root: warn

关键点说明

  1. 激活环境:通过 spring.config.activate.on-profile 属性设置在文件顶部,决定应用启动时默认使用哪一段配置。
  2. 分隔符--- 是YAML中定义文档段落的标记,Spring Boot用它来区分不同环境的配置。
  3. 环境命名
    • 新方式(推荐):使用 spring.config.activate.on-profile 为配置段命名(如 dev, test)。
    • 旧方式(已过时)spring.profiles 属性,新项目不建议再使用。

Properties 文件配置

Properties 格式通过创建多个文件来管理多环境配置,这是另一种常见的做法。

文件命名规则与结构
你需要创建一系列遵循特定命名规则的文件:

  • application.properties主配置文件,用于设置激活哪个环境。
  • application-{profile}.properties环境专属配置文件{profile} 替换为环境名(如 dev, test, pro)。

配置示例
1. 主配置文件 (application.properties)
在此文件中指定激活的环境配置

# 例如激活生产环境pro
spring.profiles.active=pro

2. 环境专属配置文件

  • application-dev.properties (开发环境):
    server.port=8080  # 这里配置端口号为 8080
    
  • application-test.properties (测试环境):
    server.port=8081
    
  • application-pro.properties (生产环境):
    server.port=80
    

启动应用时,Spring Boot 会加载 application.propertiesspring.profiles.active 指定的环境对应文件(此例为 application-pro.properties),并将其中配置与主文件合并。

命令行参数设置(最灵活)

SpringBoot 开发的程序打包成 JAR 文件后,仍然可以在启动时通过命令行参数临时覆盖或指定配置,而无需修改打包在 JAR 内的配置文件。

常用命令示例

  1. 激活指定环境

    java -jar your-app.jar --spring.profiles.active=test
    

    这会让应用使用 test 环境的配置,无论打包时默认设置的是什么。

  2. 临时修改特定配置项

    java -jar your-app.jar --server.port=8888
    

    这会临时将服务器端口改为 8888。

  3. 组合使用

    java -jar your-app.jar --spring.profiles.active=pro --server.port=443 --logging.level.root=error
    

    可以同时指定环境、修改端口和日志级别等多个参数。

配置优先级与实践建议

当同一个配置项通过多种方式(默认配置、环境配置、命令行等)被设置时,Spring Boot 遵循一个明确的优先级顺序,优先级高的会覆盖优先级低的。

配置的优先级在 SpringBoot 官网已经进行了说明,参见 Externalized Configuration,进入上面网站后会看到如下页面:

image.png

对比建议

配置方式适用场景优点缺点
YAML 多文档配置相对简单,且希望集中管理。结构清晰,所有配置在一个文件中。环境很多时文件会变得冗长。
Properties 多文件不同环境配置差异很大,或团队习惯文件分离。环境间隔离性好,便于按需打包。文件数量较多。
命令行参数生产部署、紧急调试、临时测试优先级最高,最灵活,无需改动文件。不适合作为常规配置方式。
  1. 开发阶段:在 application.yml 中使用多文档块,将 dev 设为默认环境,方便本地开发。
  2. 打包阶段:在 application.properties 中通过 spring.profiles.active=pro 设置好生产环境为默认,避免打包后忘记切换。
  3. 部署与运维阶段:掌握命令行参数覆盖技巧,以便在服务器上灵活调整配置。这是成为一名合格后端开发者的必备技能。

配置文件分类与优先级

想象一个场景:应用开发完成后,测试人员需要进行测试。由于测试环境和开发环境的配置(如数据库地址、服务端口等)通常不同,测试人员可能需要通过如下一长串复杂的命令行参数来启动应用,非常不便:

java –jar springboot.jar –-spring.profiles.active=test --server.port=85 --server.servlet.context-path=/heima ……(更多参数)

为了解决这个问题,并让应用能灵活适应不同部署环境,Spring Boot 设计了一套配置文件放置位置的规则。应用会从多个预定位置加载 application.ymlapplication.properties 文件,并且 “位置”本身决定了配置的优先级

优先级规则

Spring Boot 支持从4个标准位置加载配置文件,其优先级由高到低如下:

  1. 项目外部的 /config 目录。
  • 具体路径file:./config/
  • 含义:与最终打包的 JAR包(或WAR包)在同一目录下,且位于 config 子文件夹内的配置文件。
  1. 项目外部的根目录。
  • 具体路径file:./
  • 含义:与最终打包的 JAR包(或WAR包)在同一目录下的配置文件。
  1. 项目内部的 /config 目录。
  • 具体路径classpath:/config/
  • 含义:打包在 JAR/WAR包内部,位于类路径 config 目录下的配置文件。在开发项目中,对应 src/main/resources/config/ 目录。
  1. 项目内部的类路径根目录。
  • 具体路径classpath:/
  • 含义:打包在 JAR/WAR包内部,位于类路径根目录下的配置文件。在开发项目中,对应 src/main/resources/ 目录。

核心规则

  • 文件系统中JAR包外部的配置,优先级高于打包在JAR包内部的配置。
  • 无论在外部还是内部,位于 config 子目录下的配置,优先级高于直接放在根目录下的配置。
  • 覆盖原则:高优先级配置文件中的属性会覆盖低优先级配置文件中定义的相同属性

环境准备

下面我们通过实验来验证上述优先级规则。

创建一个名为 springboot_06_config_fileSpringBoot 工程,目录结构如下:

image.png

resources 下创建一个名为 config 的目录,在该目录中创建 application.yml 配置文件,而在该配置文件中将端口号设置为 81,内容如下:

# resources/config/application.yml,第3级,类路径下的config目录
server:
  port: 81

resources 下创建的 application.yml 配置文件中并将端口号设置为 80,内容如下:

# resources/application.yml,第4级,类路径根目录
server:
  port: 80

验证优先级

验证第3级与第4级的优先级

运行启动引导类,观察控制台日志。你会发现应用使用的端口是 81

结论:位于 classpath:/config/(第3级)的配置文件,其优先级高于 classpath:/(第4级)的配置文件。所以 81 覆盖了 80

验证第1级与第3级的优先级

接下来,我们创建一个更高优先级(第1级)的配置来覆盖之前的设置。

  1. 打包应用:在IDEA的Maven工具窗口中,双击 Lifecycle 下的 package,将工程打成 jar 包。
  2. 定位JAR包:在项目 target 目录下找到生成的 springboot_06_config_file-0.0.1-SNAPSHOT.jar 文件。
  3. 创建外部配置文件
    1. jar包所在的同级目录下,创建一个名为 config 的文件夹。
    2. 在该 config 文件夹内,创建一个 application.yml 文件,并设置端口:
    server:
    port: 82   # 端口设置为82
    
  4. 通过命令行启动:打开命令行,进入JAR包所在目录,执行:
    java -jar springboot_06_config_file-0.0.1-SNAPSHOT.jar
    

观察控制台日志,应用使用的端口是 82

结论:位于 file:./config/(第1级,JAR包外部的config目录)的配置文件,其优先级最高,覆盖了所有内部配置。

注意:
配置文件加载是叠加的:Spring Boot 会从所有这4个位置加载配置文件,并将它们合并。高优先级位置的配置值会覆盖低优先级位置的相同属性,而不同属性则会累积生效

实际应用意义

理解配置文件的优先级,在项目部署和运维中至关重要:

场景操作与好处
开发阶段使用 resources/application.yml (第4级),配置个人开发环境。
团队测试测试人员可以在JAR包外的 config/application.yml (第1级)放置测试数据库等配置,无需修改或重新打包项目
生产部署运维人员将包含数据库密码等敏感信息的生产配置放在服务器上JAR包外部的 config 目录下,实现代码与敏感配置分离,更安全。
临时调试在JAR包同级目录(第2级)放一个简易配置,可快速覆盖某个属性进行调试。

SpringBoot 整合 JUnit

单元测试是保证代码质量的重要环节。相较于传统的 Spring 项目,SpringBoot 整合测试框架变得特别简单。

环境准备

  1. 创建一个名为 springboot_07_testSpringBoot 工程,工程目录结构如下:

    image.png
  2. 创建业务层接口与实现类,这是待测试的目标。

  • 接口 (BookService): 在 com.itheima.service 包下。
    // 业务接口
    public interface BookService {
        public void save();
    }
    
  • 实现类 (BookServiceImpl): 在 com.itheima.service.impl 包下。@Service 注解将其声明为Spring容器管理的Bean。
    @Service // 关键:这个注解将该实现类注册为Spring的Bean
    public class BookServiceImpl implements BookService {
        @Override
        public void save() {
            System.out.println("book service is running ...");
        }
    }
    

编写测试类

src/test/java 下的对应包(通常与主代码包名一致,例如 com.itheima)中创建测试类,并将 BookService 注入到该测试类中。

核心步骤

  1. 添加测试注解:在类上标注 @SpringBootTest。这个注解是测试的基石,它会启动一个为测试准备的Spring应用上下文。
  2. 注入测试对象:使用 @Autowired 像在普通Spring Bean中一样,注入要测试的Service。
  3. 编写测试方法:在方法上使用JUnit的 @Test 注解。
// 1. 标记此类为SpringBoot测试类,运行测试时会加载完整的应用上下文
@SpringBootTest
class Springboot07TestApplicationTests {

    // 2. 自动注入要测试的业务组件
    @Autowired
    private BookService bookService;

    // 3. 测试方法
    @Test
    public void testSave() {
        // 调用方法并断言结果
        bookService.save();
        // 此处可以添加更多断言,例如:
        // assertThat(...).isEqualTo(...);
    }
}

执行测试
在IDEA中,你可以直接点击测试方法旁边的绿色箭头运行单个测试,或直接运行整个测试类。执行后控制台将看到:

  1. Spring Boot 测试上下文启动。
  2. 你的 BookServiceImpl 被成功注入。
  3. 控制台输出:book service is running ...
  4. 测试通过(通常以绿色对勾显示)。

最重要的规则:包位置约定

@SpringBootTest 注解在默认情况下,会从当前测试类所在的包开始,向上扫描,寻找主配置类(@SpringBootApplication 标注的类)。

为了保证主配置类能自动找到,请遵循以下约定:

测试类的逻辑包名(由类文件代码第一行的 package 语句定义),必须是主启动类的逻辑包名的子包或同一个包。
判断逻辑包名是否匹配,与这个类物理上位于 src/main/java 还是 src/test/java 无关。测试类放在 src/test/java/com/itheima,主启动类在 src/main/java/com/itheima,这是完全正确且能正常运行的,它们在逻辑上属于同一个包 com.itheima

不符合约定时如何解决?

如果测试类无法放在约定范围内,必须在 @SpringBootTest 注解中显式指定主启动类

// 当测试类不在主启动类所在包或其子包下时
@SpringBootTest(classes = Springboot07TestApplication.class) // 手动指定主启动类的Class对象
class OtherPackageTest {
    ......
}

同时也建议在 @SpringBootTest 注解中,总是通过 classes 属性显式指定主启动类。这是最明确、最可靠的方式。

SpringBoot 整合 Mybatis

回顾传统 Spring 整合 Mybatis 的复杂性

传统的 Spring 整合 Mybatis 需要编写大量的配置类,步骤繁琐,主要体现在:

  1. 数据源配置:需手动读取 jdbc.properties 并创建 DataSource Bean。
  2. Mybatis 集成:需手动配置 SqlSessionFactoryBeanMapperScannerConfigurer
  3. 配置组装:需通过 @Import 将多个配置类组合。

这种方式配置项分散,依赖管理复杂,容易出错。

SpringBoot 整合 Mybatis(极简步骤)

SpringBoot 通过 “起步依赖”“自动配置” 极大简化了整合过程。只需几步:

  1. 创建模块并选择依赖
    使用 Spring Initializr 创建模块勾选依赖时,勾选上 SQL -> MyBatis FrameworkMySQL Driver。IDEA 会自动在 pom.xml 中添加相应依赖。

    image.png
  2. 定义实体类 (Book)
    com.itheima.domain 包下创建,包含属性及 getter/setter。

    public class Book {
        private Integer id;
        private String name;
        private String type;
        private String description;
        // ... getter, setter, toString
    }
    
  3. 定义 Dao 接口 (BookDao)
    com.itheima.dao 包下创建。在接口上添加 @Mapper 注解,这样 MyBatis 才会为其创建实现类并交给 Spring 管理。

    @Mapper // 关键注解:标识这是一个 MyBatis 的 Mapper 接口
    public interface BookDao {
        @Select("select * from tbl_book where id = #{id}") // MyBatis 注解,定义 SQL
        public Book getById(Integer id);
    }
    
  4. 定义测试类
    src/test/java 的对应包(如 com.itheima)下创建。

    @SpringBootTest
    class Springboot08MybatisApplicationTests {
        @Autowired
        private BookDao bookDao; // 直接注入 MyBatis Mapper
    
        @Test
        void testGetById() {
            Book book = bookDao.getById(1);
            System.out.println(book);
        }
    }
    
  5. 编写数据库配置 (application.yml)
    所有配置集中于一个文件,结构清晰。

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver # 数据库驱动
    url: jdbc:mysql://localhost:3306/ssm_db?serverTimezone=UTC # 数据库连接URL,注意时区参数
    username: root # 用户名
    password: root # 密码

注意:若使用 SpringBoot 版本低于2.4.3(不含),Mysql驱动版本高于8.0时,,必须在 url 中配置时区,如 serverTimezone=UTCAsia/Shanghai,否则可能连接失败。

  1. 切换为 Druid 数据源(可选)
    SpringBoot 默认使用 HikariCP 数据源,如需换为阿里 Druid:
    1. 添加 Druid 依赖 (pom.xml):
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.16</version>
    </dependency>
    
    1. 修改配置文件 (application.yml),通过 type 指定数据源类型:
    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/ssm_db?serverTimezone=UTC
        username: root
        password: root
        type: com.alibaba.druid.pool.DruidDataSource # 关键:指定使用 Druid 数据源
    

综合案例:将传统 SSM 项目迁移至 SpringBoot

这个案例旨在将你之前用 Spring + SpringMVC + MyBatis (SSM) 完成的整合项目,改造成 SpringBoot 项目。

改造的核心是 “做减法”:移除 XML 和 Java 配置类,利用 SpringBoot 的自动配置和起步依赖。下图清晰地展示了从传统 SSM 迁移到 SpringBoot 的核心变化与操作流程:

deepseek_mermaid_20260201_a514c0.png

创建 SpringBoot 工程

  1. 使用 Spring Initializr 创建新模块,命名为 springboot_09_ssm
  2. 关键步骤:在选择依赖时,必须勾选:
    • Spring Web (提供Web能力)
    • MyBatis Framework (整合MyBatis)
    • MySQL Driver (连接MySQL)
  3. 由于案例使用 Druid 数据源,还需在创建后,手动在 pom.xml 中添加其依赖坐标。
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.16</version>
    </dependency>
    

代码迁移与改造

将原有 SSM 项目 (springmvc_11_page) 中的业务代码直接拷贝到新工程的对应包下。这是迁移中最大的一块工作,但主要是复制粘贴

image.png

需要进行的改造非常有限,只有以下三点:

  • 删除config 包及包内所有配置类(/config 目录),SpringBoot 的自动配置已经替代了这些手动配置。
  • dao 包下的接口拷贝到 springboot_09-ssm 工程中后,在每一个接口定义上方添加 @Mapper 注解

    替代方案:如果Dao接口很多,不想每个都加,可以在主启动类上添加 @MapperScan(“com.itheima.dao”) 注解,一次性扫描整个包。但在此案例中为求清晰,推荐使用 @Mapper

  • BookServiceTest 测试需要改成 SpringBoot 整合 junit 的形式。

编写配置文件 (application.yml)

application.yml 配置文件中需要配置如下内容

  • 服务的端口号
  • 连接数据库的信息
  • 数据源
# 服务器配置
server:
  port: 80  # 将端口改为80,访问时可省略端口号

# Spring相关配置
spring:
  datasource:
    # 1. 指定使用 Druid 数据源
    type: com.alibaba.druid.pool.DruidDataSource
    # 2. 数据库驱动 (MySQL 8.0+ 使用 `cj.jdbc.Driver`)
    driver-class-name: com.mysql.cj.jdbc.Driver
    # 3. 数据库连接URL,注意时区参数
    url: jdbc:mysql://localhost:3306/ssm_db?serverTimezone=Asia/Shanghai
    # 4. 用户名和密码
    username: root
    password: root

说明

  • type:指定数据源类型。如果不指定,SpringBoot 默认使用高性能的 HikariDataSource
  • serverTimezone:连接 MySQL 8.0 或更高版本时,强烈建议在URL中设置时区,如 Asia/ShanghaiUTC,否则可能因时区不一致导致连接失败或时间错误。

处理静态资源(页面、图片、CSS/JS)

这是与SSM项目结构上差异最大的地方。

  • SSM 惯例:静态资源放在 webapp 目录下(如 webapp/pages/)。
  • SpringBoot 惯例没有 webapp 目录。静态资源需要放在 src/main/resources 下的特定子目录中。

SpringBoot 寻找静态资源的默认路径(优先级从高到低)

  1. classpath:/META-INF/resources/
  2. classpath:/resources/
  3. classpath:/static/ (最常用、推荐的位置)
  4. classpath:/public/

操作:将旧项目 webapp 下的所有内容(如 .html, .css, .js, 图片),整体拷贝到新项目的 src/main/resources/static/ 目录下即可。

例如,你的 index.html 原来在 webapp/pages/index.html,现在应该放在 src/main/resources/static/pages/index.html。启动应用后,可以直接通过 http://localhost/pages/index.html 访问。