59. 【Java】Spring Boot 入门:第一个 Web 应用

摘要: 本文是Spring Boot入门实战指南,从零开始手把手教你创建第一个Spring Boot应用。文章详细介绍了Spring Boot的核心概念、自动配置机制、起步依赖原理,并通过Hello World和用户管理API两个完整示例,展示如何快速构建RESTful Web服务。同时涵盖项目结构解析、运行测试方法、JDK 21虚拟线程支持等实用内容,帮助Java开发者快速掌握现代Spring Boot开发流程。

关键词: Spring Boot, Java Web开发, REST API, 自动配置, 起步依赖


在上一篇文章中,我们学习了 JDBC,你知道了如何用 Java 程序连接数据库、执行 SQL、处理结果集。你已经掌握了持久层的基本技能。

但是,你有没有发现:JDBC 的代码写起来有点"笨重"?每次都要手动获取连接、创建 PreparedStatement、处理 ResultSet、还要小心翼翼地关闭资源......这些代码和你的业务逻辑混在一起,让代码变得臃肿且难以维护。

而且,如果你要写一个真正的 Web 应用,光有 JDBC 是远远不够的。你还需要:

  • 一个 Web 服务器来处理 HTTP 请求和响应
  • 一个路由机制把不同的 URL 映射到不同的处理方法
  • 一个依赖注入容器来管理对象之间的依赖关系
  • 一套数据绑定机制把 HTTP 参数自动转换成 Java 对象
  • ......

如果这些都让你从头自己写,那工作量太大了。好消息是,Java 生态中有一个框架,几乎帮你做好了以上所有事情------Spring Boot

今天,我们就来学习 Spring Boot------这个让 Java Web 开发变得前所未有的简单的框架。


1. 什么是 Spring Boot?------ Spring 的"一键启动"版

在理解 Spring Boot 之前,我们先简单了解一下 Spring 框架

Spring 是 Java 企业级开发中最流行的框架。它提供了依赖注入(DI)面向切面编程(AOP)事务管理MVC Web 框架等核心功能。可以说,Spring 是 Java 后端开发的"基石"。

但是,传统的 Spring 项目配置相当繁琐。你需要写大量的 XML 配置文件(或者 Java 配置类),手动声明每个 Bean,配置数据源、事务管理器、视图解析器......一个简单的 Web 项目,光配置文件就可能上百行。这被称为"XML 地狱"。

Spring Boot 就是在 Spring 基础上构建的"一键启动"版本。它的核心理念是 "约定大于配置"(Convention over Configuration)------Spring Boot 为你提供了合理的默认配置,你只需要关注业务逻辑,不需要手动配置大部分基础设施。

打个比方:Spring 就像是一套高级的"乐高积木",零件很多、功能强大,但你需要自己看说明书把它们拼起来。Spring Boot 则是把这些零件提前拼好了一个"基础模型",你拿到手就能用,想改什么地方再微调就行了。

Spring Boot 的几个核心特点:

特点 说明
自动配置 根据你添加的依赖自动配置 Spring 和第三方库
起步依赖 一组预定义的依赖集合,一次引入就能获得某个功能的所有依赖
内嵌服务器 内置 Tomcat、Jetty 等 Web 服务器,无需部署 WAR 文件
生产就绪 提供健康检查、指标监控、外部化配置等生产级功能
零代码生成 不需要生成代码,也不需要 XML 配置

2. 准备工作:环境与工具

在开始写第一个 Spring Boot 应用之前,确保你的开发环境已经就绪。

  • JDK :Spring Boot 3.x 需要 JDK 17 或更高版本。我们一直使用 JDK 21,完全满足要求。
  • 构建工具Maven 3.8+ 或 Gradle 7.x。我们之前已经学过 Maven,就用它。
  • IDEIntelliJ IDEA(推荐,内置 Spring Initializr 支持)。

如果你用的是 IDEA 的 Ultimate 版本,新建项目时可以直接选择 Spring Boot。社区版也支持,但需要手动从 start.spring.io 导入。


3. 创建第一个 Spring Boot 项目

我们有三种方式创建 Spring Boot 项目。推荐前两种。

方式一:在 IDEA 中直接创建(最推荐)
  1. 打开 IntelliJ IDEA,点击 New Project
  2. 在左侧选择 Spring Boot (或 Spring Initializr)。
  3. 填写项目信息:
    • Name :项目名称,比如 demo-springboot
    • Group :比如 com.example
    • Artifact :比如 demo-springboot
    • JDK:选择 JDK 21
  4. 点击 Next ,在依赖列表中选择 Spring Web
  5. 点击 Create,IDEA 会自动生成项目并下载所有依赖。
方式二:通过 Spring Initializr 网站生成

访问 https://start.spring.io

  1. 填写 Group、Artifact、Dependencies(勾选 Spring Web)。
  2. 点击 Generate 下载 ZIP 包。
  3. 解压后,在 IDEA 中选择 File → New → Project from Existing Sources 导入。
方式三:手动创建 Maven 项目 + 添加依赖

如果你更习惯手动操作,可以创建一个普通的 Maven 项目,然后在 pom.xml 中添加 Spring Boot 的父依赖和起步依赖。


4. 项目结构 ------ 长什么样?

Spring Boot 项目生成后,你会看到这样的目录结构:

复制代码
demo-springboot/
├── pom.xml                          ← Maven 配置文件
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/example/demo/
│   │   │       └── DemoApplication.java   ← 启动类(最重要的文件!)
│   │   └── resources/
│   │       ├── application.properties     ← 配置文件(可选)
│   │       └── static/                    ← 静态资源(CSS、JS、图片)
│   └── test/
│       └── java/
│           └── com/example/demo/
│               └── DemoApplicationTests.java  ← 测试类

其中最核心的是 DemoApplication.java,它是整个应用的"入口"。


5. 编写第一个 REST API ------ Hello World

让我们打开 DemoApplication.java,看看里面的内容:

java 复制代码
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication      // ① 标记这是一个 Spring Boot 应用
@RestController            // ② 标记这是一个 REST 控制器
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);  // ③ 启动应用!
    }

    @GetMapping("/hello")   // ④ 处理 GET 请求,路径为 /hello
    public String hello(@RequestParam(value = "name", defaultValue = "World") String name) {
        return String.format("Hello %s!", name);  // ⑤ 返回响应
    }
}

逐行解读:

  • @SpringBootApplication :这是一个组合注解,它包含了 @Configuration@EnableAutoConfiguration@ComponentScan。简单说,它告诉 Spring Boot:"这是一个 Spring Boot 应用,请自动配置一切"。
  • @RestController:标记这个类是一个 REST 风格的 Web 控制器,它的每个方法返回值会直接作为 HTTP 响应体返回(而不是跳转到一个页面)。
  • SpringApplication.run(...):启动 Spring Boot 应用。它会启动内嵌的 Tomcat 服务器,扫描所有 Bean,完成自动配置。
  • @GetMapping("/hello") :将 hello() 方法映射到 /hello 路径的 GET 请求。
  • @RequestParam :从 HTTP 请求参数中获取 name 的值。如果没传,默认是 "World"

就这么几行代码,我们就有了一个完整的 Web 服务!没有配置 web.xml,没有配置 Spring 容器,没有部署 WAR 文件------全部"开箱即用"。


6. 运行与测试

在 IDEA 中,点击 DemoApplication 类中的绿色三角形 ▶,或者右键 → Run 'DemoApplication'

你会看到类似这样的启动日志:

复制代码
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.4.0)

2026-07-01T14:30:45.123Z  INFO 12345 --- [main] com.example.demo.DemoApplication
...
Tomcat started on port 8080 (http) with context path '/'
Started DemoApplication in 2.5 seconds

最后一行提示 Tomcat started on port 8080------Spring Boot 内嵌的 Tomcat 服务器已经启动,正在监听 8080 端口。

打开浏览器,访问 http://localhost:8080/hello,你会看到:

复制代码
Hello World!

再试试 http://localhost:8080/hello?name=张三

复制代码
Hello 张三!

恭喜你!你已经用 Spring Boot 成功构建了一个 Web 服务。


7. 自动配置 ------ Spring Boot 的"魔法"是什么?

你可能会好奇:我们明明没有配置 Tomcat,为什么它能启动?我们没有配置 Spring MVC,为什么 @GetMapping 能工作?

这就是 Spring Boot 的自动配置(Auto-configuration) 在起作用。

自动配置的核心思想是 "开箱即用" 。Spring Boot 会根据你项目中的依赖来"猜"你需要什么配置:

  • 当 Spring Boot 检测到 spring-web 依赖,它会自动配置 Spring MVC内嵌 Tomcat
  • 当它检测到 spring-data-jpa 依赖,它会自动配置 数据源JPA
  • 当它检测到 spring-security 依赖,它会自动配置 安全过滤器链

自动配置的背后是 条件注解(Condition Annotations) 。Spring Boot 中大量的 @ConditionalOnClass@ConditionalOnMissingBean 等注解,会在启动时判断"某个类是否存在"、"某个 Bean 是否已经定义",然后决定是否应用某个自动配置。

你可以在 application.propertiesapplication.yml 中覆盖这些默认配置。比如,如果你想修改服务器端口:

properties 复制代码
# application.properties
server.port=9090

或者用 YAML 格式:

yaml 复制代码
# application.yml
server:
  port: 9090

重启应用,访问 http://localhost:9090/hello 就能看到效果。


8. Spring Boot 的"起步依赖"

pom.xml 中,你会看到这样的依赖:

xml 复制代码
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.4.0</version>
</parent>

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

spring-boot-starter-web 就是一个"起步依赖"(Starter)。它不是一个单一的 JAR,而是一个依赖集合------它包含了:

  • spring-webspring-webmvc(Spring MVC 框架)
  • spring-boot-starter-tomcat(内嵌 Tomcat)
  • jackson-databind(JSON 序列化/反序列化)
  • 以及其他一些辅助库

你只需要引入这一个依赖,所有构建 Web 应用所需的核心库就全部到位了。

Spring Boot 提供了几十个起步依赖,覆盖了绝大多数常见场景:

Starter 用途
spring-boot-starter-web 构建 Web 应用(REST API)
spring-boot-starter-data-jpa 使用 JPA 访问数据库
spring-boot-starter-security 集成 Spring Security
spring-boot-starter-test 测试(JUnit、Mockito 等)
spring-boot-starter-actuator 生产监控(健康检查、指标)

9. 一个更"真实"的 REST API 示例

让我们写一个更贴近实际的项目:一个简单的"用户管理"REST API。

java 复制代码
package com.example.demo;

import jakarta.annotation.PostConstruct;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

@SpringBootApplication
@RestController
@RequestMapping("/api/users")   // ① 所有方法的路由前缀
public class DemoApplication {

    // 模拟数据库:用 Map 存储用户
    private final ConcurrentHashMap<Long, User> userStore = new ConcurrentHashMap<>();
    private final AtomicLong idGenerator = new AtomicLong(1);

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }


    /** 应用启动后自动插入默认数据 */
    @PostConstruct
    public void initDefaultUsers() {
        addUser("Alice", "alice@example.com", 28);
        addUser("Bob", "bob@example.com", 34);
        addUser("Charlie", "charlie@example.com", 22);
        System.out.println(">>> 默认用户已加载,当前共 " + userStore.size() + " 条");
    }

    /** 辅助方法:创建用户并返回 ID */
    private long addUser(String name, String email, int age) {
        long id = idGenerator.getAndIncrement();
        User user = new User();
        user.setId(id);
        user.setName(name);
        user.setEmail(email);
        user.setAge(age);
        userStore.put(id, user);
        return id;
    }

    // ② GET /api/users ------ 获取所有用户
    @GetMapping
    public List<User> listUsers() {
        return new ArrayList<>(userStore.values());
    }

    // ③ GET /api/users/{id} ------ 根据 ID 获取用户
    @GetMapping("/{id}")
    public User getUser(@PathVariable Long id) {
        User user = userStore.get(id);
        if (user == null) {
            throw new RuntimeException("用户不存在: " + id);  // 实际项目应使用自定义异常
        }
        return user;
    }

    // ④ POST /api/users ------ 创建用户
    @PostMapping
    public User createUser(@RequestBody User user) {
        long id = idGenerator.getAndIncrement();
        user.setId(id);
        userStore.put(id, user);
        return user;
    }

    // ⑤ PUT /api/users/{id} ------ 更新用户
    @PutMapping("/{id}")
    public User updateUser(@PathVariable Long id, @RequestBody User user) {
        if (!userStore.containsKey(id)) {
            throw new RuntimeException("用户不存在: " + id);
        }
        user.setId(id);
        userStore.put(id, user);
        return user;
    }

    // ⑥ DELETE /api/users/{id} ------ 删除用户
    @DeleteMapping("/{id}")
    public String deleteUser(@PathVariable Long id) {
        if (userStore.remove(id) == null) {
            throw new RuntimeException("用户不存在: " + id);
        }
        return "用户 " + id + " 已删除";
    }

    // ---- 内部数据类 ----
    public static class User {
        private Long id;
        private String name;
        private String email;
        private Integer age;

        // getter / setter(省略,实际用 Lombok 简化)
        public Long getId() { return id; }
        public void setId(Long id) { this.id = id; }
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public String getEmail() { return email; }
        public void setEmail(String email) { this.email = email; }
        public Integer getAge() { return age; }
        public void setAge(Integer age) { this.age = age; }
    }
}

代码中用到的注解:

注解 作用
@RequestMapping("/api/users") 类级别的路由前缀
@GetMapping 处理 GET 请求
@PostMapping 处理 POST 请求
@PutMapping 处理 PUT 请求
@DeleteMapping 处理 DELETE 请求
@PathVariable 从 URL 路径中提取参数
@RequestBody 把 HTTP 请求体(JSON)自动绑定到 Java 对象

你可以用 curl 或 Postman 测试这些接口:

bash 复制代码
# 创建用户
curl -X POST http://localhost:8080/api/users \
  -H "Content-Type: application/json" \
  -d '{"name":"张三","email":"zhangsan@example.com","age":25}'

# 获取所有用户
curl http://localhost:8080/api/users

# 获取 ID=1 的用户
curl http://localhost:8080/api/users/1

# 更新用户
curl -X PUT http://localhost:8080/api/users/1 \
  -H "Content-Type: application/json" \
  -d '{"name":"张三丰","email":"zhangsanfeng@example.com","age":30}'

# 删除用户
curl -X DELETE http://localhost:8080/api/users/1

Spring Boot 自动集成了 Jackson,会自动把 JSON 请求体转换成 Java 对象,也会把 Java 对象自动序列化成 JSON 响应。你完全不需要手动处理 JSON 的序列化和反序列化。


10. 关于 JDK 21 与 Spring Boot

Spring Boot 3.x 对 JDK 21 有完整的支持。在 Spring Boot 3.2+ 中,你还可以开启虚拟线程支持,让 Web 应用处理高并发请求的能力大幅提升。

application.yml 中只需一行配置:

yaml 复制代码
spring:
  threads:
    virtual:
      enabled: true

开启后,Tomcat 处理每个请求的线程池会从"平台线程"切换为"虚拟线程"。在 I/O 密集型的 Web 应用中,这可以显著提升吞吐量。


11. 今天的总结

今天我们迈入了 Spring Boot 的大门:

  • Spring Boot 是什么:基于 Spring 框架的"一键启动"版本,核心理念是"约定大于配置"。
  • 核心特性:自动配置、起步依赖、内嵌服务器、生产就绪。
  • 第一个应用:通过 Spring Initializr 创建项目,一个类 + 几行注解,就完成了一个 Web 服务。
  • 自动配置原理:根据 classpath 中的依赖自动配置组件。
  • 起步依赖spring-boot-starter-* 是一组预定义的依赖集合。
  • REST API 开发@RestController@GetMapping@PostMapping@RequestBody@PathVariable 等注解。
  • JDK 21 支持:Spring Boot 3.x 完全支持 JDK 21,且可以开启虚拟线程支持。

Spring Boot 让 Java Web 开发从一个"繁琐的配置过程"变成了一件"愉快的事情"。你不再需要花大量时间在配置文件上,而是可以专注于写业务逻辑。


动手试试

  1. 在 IDEA 中创建一个 Spring Boot 项目,运行 DemoApplication,在浏览器中访问 http://localhost:8080/hello,确认服务正常启动。

  2. application.propertiesapplication.yml 中把端口改成 9090,重启应用,验证端口变化。

  3. 在上面的用户管理 API 示例中,添加一个 @GetMapping("/search") 方法,接收 name 参数,返回名字包含该关键词的用户列表。

  4. 在 IDEA 中,打开 pom.xml,找到 spring-boot-starter-web 依赖,查看它传递引入了哪些其他的依赖(在 IDEA 的 Maven 面板中查看依赖树)。

  5. (挑战)结合上一篇文章的 JDBC 知识,把用户管理 API 的数据存储从内存 Map 改为 MySQL 数据库(提示:在 pom.xml 中添加 spring-boot-starter-data-jpamysql-connector-j,配置数据源,创建一个 UserRepository 接口)。

下一篇文章,我们将从零到一构建一个完整的个人博客项目,把 Spring Boot、数据库、模板引擎等知识全部串联起来。

我们下一篇见。😃

📌 获取本系列示例代码请访问 GitCode

相关推荐
lilian2331 小时前
Harmony os 技术实战|拼豆制图43:压缩字符矩阵上线前如何拦住错位图纸
开发语言·前端·华为·矩阵·harmonyos
进击ing小白1 小时前
Qt 无边框窗口进阶指南
开发语言·qt
点我头像干啥2 小时前
004:多个PDF文件合并
开发语言·pdf·php
En^_^Joy2 小时前
Cadence Skill脚本语言快速入门指南
开发语言
10mAh2 小时前
【Java】HashMap 的 put 到底做了什么?——冲突、扩容与树化实测
java·开发语言·hash
我命由我123452 小时前
人脸识别 - 勒克斯(光线照射到物体表面上的明亮程度)
android·java·学习·java-ee·人脸识别·学习方法·android runtime
TechLee3 小时前
跨语言加解密总对不上?这个纯 Go 神库让 AES/RSA 与 PHP、Java 100% 互通
java·后端·算法
LINgZone23 小时前
系统架构与分支规范
java·数据库·架构