SpringBoot 极速上手:从零到一构建Web应用 - Some-soda

SpringBoot 极速上手:从零到一构建Web应用

本文章为SpringBoot 极速上手:从零到一构建Web应用视频的整理稿件,略有修补。


SpringBoot 极速上手:从零到一构建Web应用

1. SpringBoot 简介与核心优势

1.1 什么是 SpringBoot?

SpringBoot 并非一个全新的框架,而是基于 Spring Framework 的基础上进行的一系列增强和自动化配置。其核心目标是简化 Spring 应用的初始搭建以及开发过程。 它通过“约定优于配置”(Convention over Configuration)的原则,大量减少了开发人员需要编写的样板代码和 XML 配置,从而大幅提升开发效率。 具体来说,SpringBoot 提供了以下关键特性:

  • 自动配置(Auto-Configuration): SpringBoot 根据项目依赖(如 classpath 中存在的 JAR 包)自动配置 Spring 应用,例如,如果检测到 spring-boot-starter-web 依赖,它会自动配置 Tomcat 和 Spring MVC。
  • 起步依赖(Starters): SpringBoot 提供了一系列“起步依赖”(Starters),这些依赖是一组预先配置好的依赖描述符,可以简化构建配置。例如,spring-boot-starter-data-jpa 包含了使用 JPA 进行数据访问所需的所有依赖。
  • 内嵌式容器(Embedded Servers): SpringBoot 默认内嵌了 Tomcat、Jetty 或 Undertow 等 Web 服务器,无需单独部署 WAR 文件。
  • Actuator: 提供生产级别的特性,例如健康检查、指标收集、外部化配置等。

1.2 SpringBoot 的优势

相比传统的 Spring 应用开发,SpringBoot 带来了显著的优势:

  • 简化配置: 大幅减少了 XML 配置和注解配置,大多数情况下,只需要使用默认配置即可。
  • 快速开发: 借助起步依赖和自动配置,可以快速搭建项目原型并进行业务逻辑开发。
  • 易于部署: 内嵌式容器使得应用可以打包成一个可执行的 JAR 文件,简化了部署流程。
  • 微服务友好: SpringBoot 的轻量级和快速启动特性非常适合构建微服务架构。
  • 提高生产力: 开发人员无需过多关注底层配置,可以专注于业务逻辑的实现,显著提高开发效率。
  • 强大的社区支持: Spring Framework 拥有庞大的社区和丰富的文档,SpringBoot 也因此受益。

1.3 SpringBoot 与 Spring 的关系

理解 SpringBoot 与 Spring 的关系至关重要。 SpringBoot 不是 Spring 的替代品,而是 Spring 的增强和扩展。 它构建在 Spring 的核心概念(如依赖注入、面向切面编程)之上,简化了 Spring 应用的开发和部署。 可以将 SpringBoot 视为一个“脚手架”,它预先搭建好了 Spring 应用的基础设施,让开发者可以更专注于业务逻辑的实现。 Spring 依然是核心,SpringBoot 只是提供了一种更加便捷的使用方式。

2. 快速搭建 SpringBoot 项目

2.1 环境准备

在开始之前,确保已安装以下软件:

  • Java Development Kit (JDK): JDK 23 。
  • Maven 或 Gradle: 作为项目构建工具,我推荐使用 Maven(Gradle太难用了)。
  • IDE (集成开发环境): IntelliJ IDEA 或 Vscode。

2.2 使用 Spring Initializr 创建项目

Spring Initializr 是一个 Web 应用程序,可以帮助我们快速生成 SpringBoot 项目的基础结构。 访问 https://start.spring.io/

  1. Project: 选择 “Maven Project”。
  2. Language: 选择 “Java”。
  3. Spring Boot: 选择一个稳定的 SpringBoot 版本。
  4. Group: 输入你的组织或项目的 Group ID(默认,com.example)。
  5. Artifact: 输入你的项目名称(默认,demo)。
  6. Packaging: 选择 “Jar”。
  7. Java: 选择你的 JDK 版本(23)。
  8. Dependencies: 点击 “Add Dependencies” 按钮,添加所需的依赖。 对于一个简单的 Web 应用,添加 “Spring Web” 依赖。 如果需要使用数据库,可以添加 “Spring Data JPA” 和相应的数据库驱动(例如,“H2 Database” 用于内存数据库)。

点击 “Generate” 按钮,下载生成的 ZIP 文件,解压并导入到你的 IDE 中。

2.3 项目结构

生成的项目结构通常如下:

demo/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/
│   │   │       └── example/
│   │   │           └── demo/
│   │   │               └── DemoApplication.java  // 主程序入口
│   │   └── resources/
│   │       └── application.properties     // 配置文件
│   └── test/
│       └── java/
│           └── com/
│               └── example/
│                   └── demo/
│                       └── DemoApplicationTests.java // 测试类
├── pom.xml       // Maven 项目描述文件
└── mvnw          // Maven Wrapper (可选)
└── mvnw.cmd      // Maven Wrapper (可选)
  • DemoApplication.java: 包含 main 方法,是 SpringBoot 应用的启动入口。它通常包含 @SpringBootApplication 注解。
  • application.properties: 用于配置应用的属性,例如数据库连接、服务器端口等。也可以使用 application.yml 文件(YAML 格式)。
  • pom.xml: Maven 项目的配置文件,包含了项目的依赖、插件等信息。

2.4 @SpringBootApplication 注解

@SpringBootApplication 是一个组合注解,它等同于同时使用 @Configuration@EnableAutoConfiguration@ComponentScan

  • @Configuration: 表明该类是一个配置类,可以包含 @Bean 注解的方法来定义 Spring Beans。
  • @EnableAutoConfiguration: 启用 SpringBoot 的自动配置机制。
  • @ComponentScan: 告诉 Spring 扫描当前包及其子包中的组件(例如,@Controller@Service@Repository 等)。

3. 创建一个简单的 RESTful API

3.1 创建 Controller

com.example.demo 包下创建一个名为 HelloController 的类:

package com.example.demo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello, Spring Boot!";
    }
}
  • @RestController: 一个组合注解,等同于 @Controller@ResponseBody。它表明该类是一个 RESTful 控制器,其方法的返回值将直接作为 HTTP 响应体。
  • @GetMapping("/hello"): 将 HTTP GET 请求映射到 /hello 路径。

3.2 运行应用

在 IDE 中运行 DemoApplication 类的 main 方法,或者在项目根目录下执行 Maven 命令:

mvn spring-boot:run

应用启动后,默认会在 8080 端口监听请求。 在浏览器中访问 http://localhost:8080/hello,你将看到 “Hello, Spring Boot!"。

3.3 添加请求参数

我们可以通过 @RequestParam 注解获取请求参数:

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
public class HelloController {

    @GetMapping("/hello")
    public String hello(@RequestParam(value = "name", defaultValue = "World") String name) {
        return "Hello, " + name + "!";
    }
}
  • @RequestParam(value = "name", defaultValue = "World"): 获取名为 name 的请求参数。如果请求中没有提供 name 参数,则使用默认值 “World”。

现在访问 http://localhost:8080/hello?name=SpringBoot,你将看到 “Hello, SpringBoot!"。

3.4 使用 @PathVariable 获取路径变量

除了使用@RequestParam获取请求参数,还可以使用@PathVariable来获取URL路径中的变量。

package com.example.demo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello(@RequestParam(value = "name", defaultValue = "World") String name) {
        return "Hello, " + name + "!";
    }
	
	@GetMapping("/greet/{username}")
    public String greet(@PathVariable("username") String username) {
        return "Greetings, " + username + "!";
    }
}
  • @PathVariable("username"): 将 URL 路径中的 {username} 部分映射到 username 参数。

访问 http://localhost:8080/greet/User,你将看到 “Greetings, User!"。

4. 数据库集成 (以 H2 为例)

4.1 添加依赖

pom.xml 文件中添加 Spring Data JPA 和 H2 Database 的依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

4.2 配置数据源

application.properties 文件中配置 H2 数据库:

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create-drop
  • spring.datasource.url: 指定 H2 数据库的连接 URL。jdbc:h2:mem:testdb 表示使用内存数据库,数据库名为 testdb
  • spring.jpa.hibernate.ddl-auto=create-drop: 表示在应用启动时创建数据库表,在应用关闭时删除数据库表。 在生产环境中,通常使用 updatevalidate

4.3 创建实体类

创建一个 User 实体类:

package com.example.demo;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity(name = "users") 
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;

    // Getters and setters
    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;
    }
}
  • @Entity: 表明该类是一个 JPA 实体,对应数据库中的一张表。
  • @Id: 表明该字段是主键。
  • @GeneratedValue: 指定主键的生成策略。

Oracle将Java EE(Java Enterprise Edition)交给了Eclipse基金会管理,Eclipse基于Apache 2.0协议开发了新的版本,并将其重命名为Jakarta,以避免与Oracle的商标冲突,javax更名为jakarta。

在JPA中,如果实体类的属性或字段名是SQL保留字(如user),会引发问题。

4.4 创建 Repository

创建一个 UserRepository 接口,继承 JpaRepository

package com.example.demo;

import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
}

JpaRepository 提供了许多常用的数据库操作方法,例如 save(), findById(), findAll(), delete() 等。 我们无需编写任何实现代码,SpringBoot 会自动生成实现。

4.5 在 Controller 中使用 Repository

修改 HelloController,注入 UserRepository 并使用它来操作数据库:

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class HelloController {

    @Autowired
    private UserRepository userRepository;

    @GetMapping("/hello")
    public String hello(@RequestParam(value = "name", defaultValue = "World") String name) {
        User user = new User();
        user.setName(name);
        userRepository.save(user);
        return "Hello, " + name + "!";
    }

    @GetMapping("/users")
    public List<User> listUsers() {
        return userRepository.findAll();
    }
    @GetMapping("/greet/{username}")
    public String greet(@PathVariable("username") String username) {
        return "Greetings, " + username + "!";
    }
}
  • @Autowired: 自动注入 UserRepository 的实例。

现在访问 http://localhost:8080/hello?name=TestUser,会将一个名为 “TestUser” 的用户保存到数据库中。

访问 http://localhost:8080/users,将返回所有用户的列表。

5. 测试

5.1 单元测试

SpringBoot 提供了强大的测试支持。 spring-boot-starter-test 依赖包含了 JUnit、Spring Test、AssertJ、Hamcrest 等测试框架。

src/test/java 目录下,DemoApplicationTests.java 已经包含了一个基本的测试类:

package com.example.demo;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class DemoApplicationTests {

    @Test
    void contextLoads() {
    }

}
  • @SpringBootTest: 表明这是一个 SpringBoot 测试类,它会加载 Spring 应用上下文。

我们可以添加更多的测试方法来测试我们的 Controller、Service、Repository 等组件。

5.2 集成测试

集成测试用于测试多个组件之间的协作。我们可以使用@SpringBootTest@AutoConfigureMockMvc来模拟HTTP请求。

package com.example.demo;

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 static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@AutoConfigureMockMvc
class DemoApplicationTests {

    @Autowired
    private MockMvc mockMvc;

    @Test
    void contextLoads() {
    }

    @Test
    void testHelloEndpoint() throws Exception {
        mockMvc.perform(get("/hello"))
                .andExpect(status().isOk())
                .andExpect(content().string("Hello, World!"));
    }
		@Test
    void testGreetEndpoint() throws Exception {
        mockMvc.perform(get("/greet/TestUser"))
                .andExpect(status().isOk())
                .andExpect(content().string("Greetings, TestUser!"));
    }
}
  • @AutoConfigureMockMvc: 自动配置MockMvc实例,MockMvc可以模拟HTTP请求。
  • mockMvc.perform(get("/hello")): 模拟发送一个GET请求到/hello
  • .andExpect(status().isOk()): 期望HTTP状态码为200 OK。
  • .andExpect(content().string("Hello, World!")): 期望响应内容为"Hello, World!"。

运行mvn test进行测试。

小结

今天介绍了 SpringBoot 的基本概念、核心优势以及如何快速搭建一个 SpringBoot 应用,并集成了 H2 数据库和进行了简单的测试。 SpringBoot 的强大之处在于其自动化配置、起步依赖和内嵌式容器,这些特性极大地简化了 Spring 应用的开发和部署。

未来,可以进一步探索 SpringBoot 的高级特性:

  • Spring Security: 用于实现应用的安全性。
  • Spring Cloud: 用于构建分布式系统和微服务。
  • Spring Boot Actuator: 用于监控和管理应用。
  • 使用不同的数据库: 例如 MySQL、PostgreSQL、MongoDB 等。
  • 异步处理: 使用 @Async 注解和 CompletableFuture
  • 缓存: 使用 @Cacheable@CachePut@CacheEvict 等注解。

SpringBoot 是一个非常强大且灵活的框架,值得深入学习和掌握,虽然我不喜欢。

接下来进行一些美化工作,麻雀虽小五脏俱全。

为了让 SpringBoot 返回一个包含 CSS 和 JavaScript 的网页,我们需要做以下几处修改:

  1. 静态资源处理: SpringBoot 默认会将 /src/main/resources/static 目录下的文件作为静态资源(如 CSS、JavaScript、图片等)提供。
  2. Thymeleaf 模板引擎): 为了更方便地构建动态 HTML 页面,我们可以使用 Thymeleaf 模板引擎。当然,也可以直接返回静态 HTML 文件。
  3. Controller 修改: 修改 Controller,让其返回一个视图名称(View Name),而不是直接返回字符串。 SpringBoot 会根据视图名称查找对应的模板文件(如果使用了模板引擎)或静态 HTML 文件。
  4. 创建HTML,CSS,JS文件/src/main/resources/static目录下分别创建。

使用 Thymeleaf 模板引擎):

1. 添加 Thymeleaf 依赖 (pom.xml):

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

2. 修改 HelloController:

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller; // 注意:这里改为 @Controller
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

@Controller // 使用 @Controller,而不是 @RestController
public class HelloController {

    @Autowired
    private UserRepository userRepository;

    @GetMapping("/hello")
    public String hello(@RequestParam(value = "name", defaultValue = "World") String name, Model model) {
        User user = new User();
        user.setName(name);
        userRepository.save(user);
        model.addAttribute("name", name); // 将 name 属性添加到 Model 中
        return "hello"; // 返回视图名称 "hello"
    }

    @GetMapping("/users")
    public String listUsers(Model model) {
        List<User> users = userRepository.findAll();
        model.addAttribute("users", users);
        return "users"; // 返回视图名称 "users"
    }
    
    @GetMapping("/greet/{username}")
    public String greet(@PathVariable("username") String username, Model model) {
        model.addAttribute("username", username);
        return "greet"; //返回视图名称 "greet"
    }
}
  • @Controller: 使用 @Controller 注解,表明该类是一个控制器,用于处理 Web 请求并返回视图。
  • Model: Model 对象用于将数据传递给视图。
  • return "hello";: 返回视图名称 “hello”。 Thymeleaf 会在 /src/main/resources/templates 目录下查找名为 hello.html 的模板文件。

3. 创建 Thymeleaf 模板文件 (hello.html):

/src/main/resources/templates 目录下创建 hello.html 文件:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Hello, Spring Boot!</title>
    <link rel="stylesheet" type="text/css" th:href="@{/css/style.css}">
</head>
<body>
    <h1 th:text="'Hello, ' + ${name} + '!'"></h1>
    <p>This is a beautiful webpage powered by Spring Boot, Thymeleaf, CSS, and JavaScript.</p>
    <button onclick="showAlert()">Click Me!</button>

    <script th:src="@{/js/script.js}"></script>
</body>
</html>
  • xmlns:th="http://www.thymeleaf.org": 声明 Thymeleaf 命名空间。
  • th:href="@{/css/style.css}": 使用 Thymeleaf 的 th:href 属性和 @ 语法来引用静态资源。SpringBoot 会自动处理 /css/style.css 路径。
  • th:text="'Hello, ' + ${name} + '!'" : 使用 Thymeleaf 的 th:text 属性来显示动态内容。${name} 会被替换为 Model 中 name 属性的值。
  • <script th:src="@{/js/script.js}"></script>: 引用外部JavaScript文件。

4. 创建 CSS 文件 (style.css):

/src/main/resources/static/css 目录下创建 style.css 文件:

body {
    font-family: sans-serif;
    background-color: #f0f0f0;
    text-align: center;
    padding: 50px;
}

h1 {
    color: #333;
}

button {
    background-color: #4CAF50;
    border: none;
    color: white;
    padding: 15px 32px;
    text-align: center;
    text-decoration: none;
    display: inline-block;
    font-size: 16px;
    margin: 4px 2px;
    cursor: pointer;
}

5. 创建 JavaScript 文件 (script.js):

/src/main/resources/static/js 目录下创建 script.js 文件:

function showAlert() {
    alert("Hello from JavaScript!");
}

6. 创建 users.html (用于 /users 路径):/src/main/resources/templates 目录下创建 users.html:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>User List</title>
    <link rel="stylesheet" type="text/css" th:href="@{/css/style.css}">
</head>
<body>
    <h1>User List</h1>
    <table>
        <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
            </tr>
        </thead>
        <tbody>
            <tr th:each="user : ${users}">
                <td th:text="${user.id}"></td>
                <td th:text="${user.name}"></td>
            </tr>
        </tbody>
    </table>
     <script th:src="@{/js/script.js}"></script>
</body>
</html>
  • th:each="user : ${users}": Thymeleaf 的循环指令,用于遍历 users 列表。
  • th:text="${user.id}" 和**th:text="${user.name}"**: 显示用户的id和name。

7. 创建 greet.html (用于 /greet/{username} 路径):/src/main/resources/templates 目录下创建 greet.html:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Greetings</title>
    <link rel="stylesheet" type="text/css" th:href="@{/css/style.css}">
</head>
<body>
    <h1 th:text="'Greetings, ' + ${username} + '!'"></h1>
     <script th:src="@{/js/script.js}"></script>
</body>
</html>

8. 运行和测试:

运行 DemoApplication,然后在浏览器中访问:

  • http://localhost:8080/hello
  • http://localhost:8080/hello?name=DNG
  • http://localhost:8080/users
  • http://localhost:8080/greet/TestUser

现在,你应该能看到一个包含 CSS 样式和 JavaScript 功能的精美网页。

点击 “Click Me!” 按钮会弹出一个 JavaScript 警告框。

小结

  • 静态资源: 将 CSS、JavaScript 和图片等静态资源放在 /src/main/resources/static 目录下。
  • Thymeleaf (可选): 使用 Thymeleaf 模板引擎可以更方便地构建动态 HTML 页面,并使用 @ 语法引用静态资源。
  • @Controller: 使用 @Controller 注解处理 Web 请求并返回视图。
  • Model: 使用 Model 对象将数据传递给视图。
  • 视图名称: Controller 方法返回视图名称,SpringBoot 会根据视图名称查找对应的模板文件或静态 HTML 文件。
  • 文件结构: 确保文件结构符合SpringBoot的规范。/src/main/resources/static用于静态资源,/src/main/resources/templates用于Thymeleaf模板。