Spring Boot 实战入门:从零构建 CRUD Web 应用与 RESTful API
Spring Boot 应该怎么学?如果你觉得它概念多、配置杂、上手慢,那这篇文章就是为你准备的。我们不谈空泛的理论,直接聚焦于“能不能用”和“怎么用”。Spring Boot 的核心价值在于,它能让你用最少的配置,快速构建出独立运行、生产就绪的 Spring 应用。对于 Java 开发者,尤其是刚接触企业级开发或想从传统 Spring MVC 项目转型的同学来说,掌握 Spring Boot 意味着开发效率的质变。
这篇文章将采用一种直击要害的方式,带你快速上手 Spring Boot。我们会重点关注几个实际开发中最关心的问题:环境门槛高不高?启动一个项目到底需要几步?如何集成 MyBatis、MySQL 这些必备组件?怎么处理 Web 请求和前后端交互?以及最终如何打包部署。整个过程会围绕一个具体的实战项目展开,你将看到从零到一构建一个具备基础 CRUD 和 API 接口的 Web 应用的全过程。无论你是想快速完成课程设计、毕业设计,还是为面试积累实战经验,这篇内容都能提供一条清晰的路径。
1. 核心能力速览
在深入细节之前,我们先快速了解 Spring Boot 能为你做什么,以及它的核心特点。
| 能力项 | 说明与价值 |
|---|---|
| 项目类型 | 用于快速构建独立、生产级的 Spring 应用框架。 |
| 核心主张 | “约定大于配置”,极大简化了传统 Spring 繁琐的 XML 和 Java 配置。 |
| 内嵌服务器 | 默认集成 Tomcat、Jetty 或 Undertow,应用可打包为可直接运行的 JAR 文件,无需单独部署 WAR 到外部服务器。 |
| 自动配置 | 根据项目依赖(如 spring-boot-starter-web, spring-boot-starter-data-jpa)自动配置 Spring 应用上下文和第三方库。 |
| 起步依赖 | 提供一系列spring-boot-starter-*依赖,一站式引入某技术栈所需的所有库及其兼容版本。 |
| 生产就绪特性 | 内置健康检查、指标监控、外部化配置等功能,开箱即用。 |
| 环境门槛 | 仅需 JDK 8+ 和 Maven/Gradle 构建工具,对硬件无特殊要求,普通开发机即可运行。 |
| 启动方式 | 通过main方法直接运行,或使用java -jar命令启动打包后的 JAR 文件。 |
| 适合场景 | 微服务、RESTful API、全栈 Web 应用、批处理作业、集成测试等。特别适合需要快速原型开发和迭代的项目。 |
2. 适用场景与使用边界
Spring Boot 并非万能,明确其适用边界能帮助你更好地决策。
它非常适合以下场景:
- 快速原型与验证:当你有一个新想法需要快速验证时,Spring Boot 能让你在几分钟内搭建起一个可运行的后端服务。
- 微服务架构:每个微服务都是独立的、轻量级的 JAR,Spring Boot 是构建微服务的理想选择。
- 传统企业应用现代化:将老旧的、配置复杂的 Spring 项目迁移到 Spring Boot,能显著简化部署和运维。
- 学生与初学者:对于学习 Java Web 开发的同学,Spring Boot 绕开了大量环境配置和整合的坑,让你更专注于业务逻辑和核心概念。
- 需要内嵌容器的应用:开发需要独立交付、不依赖外部应用服务器的工具或应用。
它可能不是最佳选择,或需要额外考虑的场景:
- 极度轻量级的任务:如果只是写一个简单的脚本或工具,引入完整的 Spring Boot 框架可能显得臃肿。
- 已有复杂 XML 配置的大型遗留项目:直接迁移到 Spring Boot 的改造成本可能很高,需要评估。
- 对启动速度有极端要求的应用:虽然 Spring Boot 2.x 以后启动速度已大幅优化,但与原生编译(如 Spring Native)或更轻量的框架相比仍有差距。
- 需要深度定制 Servlet 容器:虽然可以定制,但 Spring Boot 的强项在于“开箱即用”,过度定制可能违背其设计初衷。
安全与合规边界:
- 依赖安全:定期检查并升级
spring-boot-starter-parent或依赖版本,以获取安全补丁。 - 配置安全:切勿将数据库密码、API密钥等敏感信息硬编码在代码或
application.properties中。应使用环境变量、配置服务器或加密方式管理。 - API 暴露:生产环境务必关闭不必要的 Actuator 端点(如
/env,/heapdump),或为其配置严格的访问控制。
3. 环境准备与前置条件
开始之前,确保你的开发环境已经就绪。这个过程非常简单。
- Java 开发工具包:Spring Boot 3.x 需要JDK 17或更高版本;Spring Boot 2.x 需要JDK 8或更高版本。建议使用 JDK 17 或 21 以获得更好的性能和长期支持。在终端输入
java -version验证。 - 构建工具:Maven或Gradle。本文以 Maven 为例,因为它与 Spring Boot 的集成更广泛。在终端输入
mvn -v验证。 - 集成开发环境:IntelliJ IDEA(社区版或旗舰版)或Eclipse。IDEA 对 Spring Boot 的支持更为出色,能提供强大的代码提示、运行和调试功能。
- 数据库:按需准备。例如学习常用MySQL,可下载安装 MySQL Community Server,或使用 Docker 运行。也可以使用内存数据库如H2进行快速测试,无需安装。
- 其他工具:Git(版本控制)、Postman或curl(API 测试)、浏览器。
验证环境:打开命令行,依次执行以下命令,确认输出正常。
java -version # 应输出类似:openjdk version "17.0.10" 2024-01-16 mvn -v # 应输出 Apache Maven 版本信息,如 3.9.64. 创建第一个 Spring Boot 项目
我们将使用 Spring Initializr,这是官方推荐的、最快捷的项目生成方式。
4.1 通过 IDEA 创建(推荐)
- 打开 IntelliJ IDEA,选择New Project。
- 在左侧选择Spring Initializr。
- Project SDK选择你安装的 JDK 17 或更高版本。
- 在
Spring Initializr服务 URL 处使用默认地址即可。 - 填写项目元数据:
- Group:
com.example(通常为公司域名倒写) - Artifact:
demo(项目名称) - Name:
demo - Package name:
com.example.demo - Packaging:
Jar(默认) - Java Version:
17(与你安装的 JDK 版本对应)
- Group:
- 点击Next,进入依赖选择页面。这是关键步骤,我们为第一个项目添加:
- Spring Web: 用于构建 Web 应用,包含 RESTful API 支持。
- Spring Boot DevTools: 开发工具,支持热加载,提升开发效率。
- Lombok: 通过注解简化 Java Bean 的编写(如 getter/setter)。
- (可选)MySQL Driver: 如果你打算连接 MySQL。
- (可选)Spring Data JPA: 用于数据库操作。
- 点击Next,选择项目存储位置,然后点击Finish。
IDEA 会自动下载项目模板并构建,完成后你会看到一个标准的 Spring Boot 项目结构。
4.2 通过网站创建
访问 start.spring.io ,在网页上填写与上述类似的项目信息、选择依赖,然后点击Generate下载一个 ZIP 压缩包,解压后用 IDEA 打开即可。
4.3 项目结构解析
生成的项目结构如下:
demo ├── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ └── example │ │ │ └── demo │ │ │ └── DemoApplication.java // 主启动类 │ │ └── resources │ │ ├── application.properties // 配置文件 │ │ └── static // 静态资源 (HTML, CSS, JS) │ │ └── templates // 模板文件 (Thymeleaf, Freemarker) │ └── test // 测试代码 └── pom.xml // Maven 依赖管理文件核心文件说明:
DemoApplication.java: 包含main方法的启动类。@SpringBootApplication注解是关键。application.properties: 应用配置文件,可以配置服务器端口、数据库连接等。pom.xml: 管理项目依赖。Spring Boot 父项目 (spring-boot-starter-parent) 统一管理了大量依赖的版本。
5. 编写第一个 RESTful API
现在,让我们创建一个简单的接口,验证项目是否能跑通。
- 创建 Controller:在
com.example.demo包下新建一个类HelloController.java。package com.example.demo; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController // 声明这是一个 REST 控制器,返回值直接写入 HTTP 响应体 public class HelloController { @GetMapping("/hello") // 处理 GET 请求,路径为 /hello public String sayHello(@RequestParam(value = "name", defaultValue = "World") String name) { return String.format("Hello, %s! This is Spring Boot.", name); } } - 启动应用:找到
DemoApplication.java,右键点击,选择Run ‘DemoApplication’。IDEA 会启动内嵌的 Tomcat 服务器。 - 测试接口:观察控制台日志,看到类似
Tomcat started on port(s): 8080的信息后,打开浏览器或使用 Postman。- 访问:
http://localhost:8080/hello - 返回:
Hello, World! This is Spring Boot. - 带参数访问:
http://localhost:8080/hello?name=Spring - 返回:
Hello, Spring! This is Spring Boot.
- 访问:
恭喜!你的第一个 Spring Boot 应用已经成功运行并对外提供了 API 服务。整个过程没有配置任何 XML,没有部署 WAR 包,仅仅写了几行代码。
6. 连接数据库与数据操作
一个完整的应用离不开数据持久化。我们以 MySQL 和 Spring Data JPA 为例,演示如何集成数据库。
6.1 添加依赖与配置
- 修改
pom.xml:如果你创建项目时未选择 MySQL 和 JPA 依赖,需要手动添加。<!-- 在 <dependencies> 节点内添加 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> <!-- 运行时才需要 --> </dependency> - 配置数据库连接:打开
src/main/resources/application.properties文件,添加配置。
注意:请先在 MySQL 中创建名为# 服务器端口 server.port=8080 # 数据库连接配置 spring.datasource.url=jdbc:mysql://localhost:3306/springboot_demo?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai spring.datasource.username=root spring.datasource.password=your_password # 替换为你的数据库密码 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # JPA 配置 spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect spring.jpa.hibernate.ddl-auto=update # 启动时根据实体类自动更新表结构(仅用于开发) spring.jpa.show-sql=true # 在控制台显示执行的 SQL 语句,方便调试springboot_demo的数据库。
6.2 创建实体类与 Repository
- 创建实体类:对应数据库中的表。新建
entity包和User.java类。package com.example.demo.entity; import jakarta.persistence.*; import lombok.Data; @Data // Lombok 注解,自动生成 getter, setter, toString 等方法 @Entity // 标明这是一个 JPA 实体类 @Table(name = "user") // 指定对应的表名,默认为类名小写 public class User { @Id // 主键 @GeneratedValue(strategy = GenerationType.IDENTITY) // 主键自增 private Long id; @Column(nullable = false, unique = true) // 对应列,非空且唯一 private String username; @Column(nullable = false) private String password; private String email; } - 创建 Repository 接口:用于数据访问。新建
repository包和UserRepository.java接口。package com.example.demo.repository; import com.example.demo.entity.User; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository // 可省略,Spring 会自动识别 public interface UserRepository extends JpaRepository<User, Long> { // 无需实现任何方法,JpaRepository 已提供了基础的 CRUD 方法 // 可以根据方法名自动推导查询,例如: User findByUsername(String username); }JpaRepository<User, Long>提供了save(),findById(),findAll(),deleteById()等常用方法。
6.3 创建 Service 与 Controller
- 创建 Service 层:处理业务逻辑。新建
service包和UserService.java。package com.example.demo.service; import com.example.demo.entity.User; import com.example.demo.repository.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; import java.util.Optional; @Service public class UserService { @Autowired private UserRepository userRepository; public User saveUser(User user) { // 简单的保存逻辑,实际项目需增加校验、加密等 return userRepository.save(user); } public List<User> getAllUsers() { return userRepository.findAll(); } public Optional<User> getUserById(Long id) { return userRepository.findById(id); } public void deleteUser(Long id) { userRepository.deleteById(id); } } - 完善 Controller:新建或修改
UserController.java来暴露 REST API。package com.example.demo.controller; import com.example.demo.entity.User; import com.example.demo.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.Optional; @RestController @RequestMapping("/api/users") // 所有接口前缀为 /api/users public class UserController { @Autowired private UserService userService; @PostMapping // POST /api/users public User createUser(@RequestBody User user) { return userService.saveUser(user); } @GetMapping // GET /api/users public List<User> getAllUsers() { return userService.getAllUsers(); } @GetMapping("/{id}") // GET /api/users/1 public Optional<User> getUserById(@PathVariable Long id) { return userService.getUserById(id); } @DeleteMapping("/{id}") // DELETE /api/users/1 public String deleteUser(@PathVariable Long id) { userService.deleteUser(id); return "User deleted successfully."; } }
6.4 测试数据库操作
- 重启应用:由于修改了配置和代码,需要重启
DemoApplication。 - 观察日志:启动时,Hibernate 会根据
ddl-auto=update自动在springboot_demo数据库中创建user表。你可以在控制台看到create table user ...的 SQL 语句。 - 使用 Postman 测试 API:
- POST
http://localhost:8080/api/users- Body (raw JSON):
{"username": "testUser", "password": "123456", "email": "test@example.com"} - 应返回创建成功的用户信息(包含生成的 id)。
- Body (raw JSON):
- GET
http://localhost:8080/api/users- 应返回包含刚才创建用户的列表。
- GET
http://localhost:8080/api/users/1- 应返回 id 为 1 的用户信息。
- DELETE
http://localhost:8080/api/users/1- 应返回删除成功的消息,再次 GET 列表应为空。
- POST
至此,一个具备完整 CRUD 功能的 Spring Boot 后端服务已经搭建完成。
7. 集成 Thymeleaf 实现简单页面
虽然前后端分离是主流,但了解如何渲染页面也有其价值。我们使用 Thymeleaf 模板引擎快速实现一个页面。
- 添加依赖:在
pom.xml中添加 Thymeleaf 起步依赖。<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> - 创建页面控制器:新建
PageController.java。package com.example.demo.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @Controller // 注意这里是 @Controller,不是 @RestController public class PageController { @GetMapping("/") public String index(Model model) { model.addAttribute("message", "Welcome to Spring Boot with Thymeleaf!"); model.addAttribute("users", List.of("Alice", "Bob", "Charlie")); // 模拟数据 return "index"; // 对应 src/main/resources/templates/index.html } } - 创建 HTML 模板:在
src/main/resources/templates/目录下新建index.html。<!DOCTYPE html> <html xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Spring Boot Demo</title> </head> <body> <h1 th:text="${message}">Default Message</h1> <ul> <li th:each="user : ${users}" th:text="${user}">User Name</li> </ul> <p>Current Time: <span th:text="${#temporals.format(#temporals.createNow(), 'yyyy-MM-dd HH:mm:ss')}">2024-01-01 00:00:00</span></p> </body> </html> - 访问页面:重启应用,访问
http://localhost:8080/,你将看到一个渲染了动态数据的 HTML 页面。
8. 配置文件与多环境
Spring Boot 支持灵活的配置管理,这是生产就绪的重要特性。
- 配置文件优先级:Spring Boot 会按以下顺序加载配置,后加载的覆盖先加载的。
- 项目根目录
/config子目录下的application.properties - 项目根目录下的
application.properties classpath:/config/下的application.propertiesclasspath:/下的application.properties(即resources目录下)
- 项目根目录
- 多环境配置:可以创建
application-{profile}.properties文件来区分环境。application-dev.properties: 开发环境配置(如连接本地数据库)。application-prod.properties: 生产环境配置(如连接线上数据库)。- 在
application.properties中通过spring.profiles.active=dev来激活指定环境的配置。
- YAML 格式:除了
.properties,还可以使用更清晰的.yml或.yaml格式。# application.yml 示例 server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/demo username: root password: secret jpa: hibernate: ddl-auto: update show-sql: true custom: api: key: my-secret-key # 自定义配置 - 读取自定义配置:使用
@Value注解或@ConfigurationProperties。@Component public class MyConfig { @Value("${custom.api.key}") private String apiKey; // 或者使用类型安全的绑定 @ConfigurationProperties(prefix = "custom.api") @Data public static class ApiProperties { private String key; } }
9. 打包与部署
开发完成后,我们需要将应用打包并部署到服务器或容器中。
9.1 打包为可执行 JAR
Spring Boot 的 Maven 插件使得打包极其简单。
- 执行打包命令:在项目根目录(
pom.xml所在目录)打开终端,执行:mvn clean package - 找到 JAR 包:命令执行成功后,在
target/目录下会生成一个demo-0.0.1-SNAPSHOT.jar文件(名称取决于你的pom.xml中的artifactId和version)。这个 JAR 包是可执行的,因为它内嵌了 Tomcat 服务器和所有依赖。 - 运行 JAR 包:
应用会以与在 IDEA 中相同的方式启动。你可以通过java -jar target/demo-0.0.1-SNAPSHOT.jar--server.port=8081参数来覆盖配置文件中的端口。
9.2 使用 Docker 部署(可选)
Docker 能提供一致的环境。首先在项目根目录创建Dockerfile。
# 使用官方 Eclipse Temurin 17 JDK 镜像作为基础镜像 FROM eclipse-temurin:17-jre-alpine # 维护者信息 LABEL maintainer="your-email@example.com" # 在容器内创建一个应用目录 WORKDIR /app # 将构建好的 JAR 文件复制到容器内 COPY target/demo-0.0.1-SNAPSHOT.jar app.jar # 暴露应用运行的端口 EXPOSE 8080 # 指定容器启动时执行的命令 ENTRYPOINT ["java", "-jar", "app.jar"]然后构建镜像并运行容器:
# 1. 确保已打包好 JAR 文件 (mvn clean package) # 2. 构建 Docker 镜像 docker build -t springboot-demo . # 3. 运行容器,将宿主机的 8080 端口映射到容器的 8080 端口 docker run -d -p 8080:8080 --name demo-app springboot-demo访问http://localhost:8080即可访问容器中运行的应用。
10. 常见问题与排查方法
在学习和使用 Spring Boot 的过程中,你可能会遇到以下常见问题。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 启动失败,端口被占用 | 默认端口 8080 被其他程序占用。 | 查看日志Port 8080 was already in use. | 1. 在application.properties中修改server.port。2. 关闭占用端口的进程。 |
| 无法连接到数据库 | 数据库配置错误、服务未启动、网络不通。 | 查看启动日志中的数据库连接错误信息。 | 1. 检查spring.datasource.url,username,password。2. 确认 MySQL 服务已启动。 3. 检查防火墙和网络。 |
| JPA 实体类扫描不到 | 主启动类@SpringBootApplication所在的包层级不对。 | 实体类或 Repository 不在主类子包下。 | 1. 将实体类、Repository 等放在主类所在包或其子包下。 2. 使用 @EntityScan和@EnableJpaRepositories注解手动指定扫描路径。 |
| 依赖下载失败或冲突 | Maven 仓库网络问题,或依赖版本冲突。 | 查看 IDEA 的 Maven 面板或执行mvn dependency:tree。 | 1. 检查网络,更换 Maven 镜像源。 2. 使用 mvn dependency:tree分析依赖树,排除冲突依赖。 |
| 热部署不生效 | 未正确配置或 IDEA 未开启自动编译。 | 检查是否添加了spring-boot-devtools依赖。 | 1. 确认依赖已添加。 2. IDEA 中: Settings -> Build -> Compiler,勾选Build project automatically。3. Ctrl+Shift+Alt+/,选择Registry,勾选compiler.automake.allow.when.app.running。 |
| 打包后运行找不到主类 | 打包插件配置问题或主类路径错误。 | 检查pom.xml中spring-boot-maven-plugin配置。 | 确保pom.xml中使用了正确的打包插件:xml <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> |
| @Autowired 注入失败 | 被注入的类未被 Spring 管理(缺少注解),或存在多个同类型 Bean。 | 查看启动日志中的 Bean 创建和依赖注入错误。 | 1. 确保被注入的类上有@Component,@Service,@Repository等注解。2. 使用 @Qualifier指定 Bean 名称。 |
| 跨域请求被阻止 | 前端应用(如 Vue 运行在localhost:3000)访问后端 API 时触发浏览器同源策略。 | 浏览器控制台出现 CORS 错误。 | 在后端配置全局 CORS 规则:java @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("http://localhost:3000") .allowedMethods("*"); } } |
11. 最佳实践与进阶方向
掌握了基础之后,遵循一些最佳实践能让你的项目更健壮、更易维护。
- 分层架构:严格遵守 Controller -> Service -> Repository 的分层,每层职责单一。Controller 只负责参数校验和响应封装,Service 处理业务逻辑,Repository 负责数据访问。
- 统一响应封装:设计一个通用的响应类(如
Result<T>),包含状态码、消息和数据,让所有 API 返回格式统一。 - 全局异常处理:使用
@ControllerAdvice和@ExceptionHandler捕获并处理各类异常,返回友好的错误信息,而不是暴露堆栈跟踪。 - 参数校验:在接收参数的 DTO 类字段上使用
@NotNull,@Size,@Email等注解,并在 Controller 方法参数前加@Valid注解进行自动校验。 - 使用日志框架:使用 SLF4J 配合 Logback 或 Log4j2 记录日志,合理使用不同级别(DEBUG, INFO, WARN, ERROR),便于问题排查。
- 配置文件分离:将敏感信息(密码、密钥)从
application.properties中移出,使用环境变量或配置中心管理。 - 编写单元测试:为 Service 层和 Controller 层编写单元测试(使用 JUnit 和 Mockito)和集成测试,保证代码质量。
下一步可以探索的进阶主题:
- Spring Security: 为你的应用添加认证和授权功能。
- Spring Cloud: 如果你开始构建微服务,Spring Cloud 提供了服务发现、配置中心、网关等全套解决方案。
- Redis 缓存: 集成 Redis 提升应用性能。
- 消息队列: 集成 RabbitMQ 或 Kafka 进行异步处理和解耦。
- 定时任务: 使用
@Scheduled注解执行定时任务。 - API 文档: 集成 Swagger/OpenAPI 自动生成 API 文档。
- 监控与度量: 使用 Spring Boot Actuator 暴露应用健康指标,并集成 Prometheus 和 Grafana。
Spring Boot 的学习曲线前期非常平缓,能让你快速获得成就感。它的价值在于通过“约定大于配置”的理念,将开发者从繁琐的配置中解放出来,更专注于业务创新。从创建一个能响应的“Hello World”接口,到构建一个包含数据库操作、页面渲染、并最终能打包部署的完整应用,整个过程在几个小时内就能走通。关键在于动手实践,遇到问题多查阅官方文档和社区。当你熟悉了这套范式,开发效率的提升将是实实在在的。