Spring Boot 3 中匹配以斜线结尾的 URL

1、概览 在本教程中,我们将学习 Spring Boot 3(Spring 6)在 URL 匹配方面引入的变化。 Spring Boot 使用 DispatcherServlet 处理 URL 映射,它会根据 URL 将请求转发到相应的 controller。DispatcherServlet 使用一组称为映射(mapping)的规则来确定使用哪个 controller 来处理请求。 2、Spring MVC 和 Webflux URL 匹配的更改 Spring Boot 3 对“尾斜线匹配”配置选项进行了重大修改。该选项决定是否将带尾斜线的 URL 与不带尾斜线的 URL 作相同处理。以前版本的 Spring Boot 默认将此选项设置为 true。这意味着 controller 默认会同时匹配 GET /some/greeting 和 GET /some/greeting/: @RestController public class GreetingsController { @GetMapping("/some/greeting") public String greeting { return "Hello"; } } 如上,如果我们尝试访问带有尾斜线的 URL,就会收到 404 错误。 让我们来探讨一下如何适应这种变化。 3、添加额外的路由 要处理这种问题,可以额外添加一个专门处理带尾斜线的路由: @RestController public class GreetingsController { @GetMapping("/some/greeting") public String greeting { return "Hello"; } @GetMapping("/some/greeting/") public String greeting { return "Hello"; } } 下面是一个使用 Webflux 的响应式 @RestController:

在 Spring Boot 应用中使用 Resilience4j

1、概览 Resilience4j 是一个轻量级的容错库,提供了诸如熔断、重试、限流、超时、隔板等功能,可以帮助应用程序在面对故障和不稳定条件时保持可用性和可靠性。 在本教程中,我们将学习如何在 Spring Boot 应用程序中使用 Resilience4j。 2、项目设置 2.1、Maven 依赖 首先,我们需要添加 spring-boot-starter-web starter 来创建一个简单的 web 应用: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> 接下来,我们需要 resilience4j-spring-boot2 和 spring-boot-starter-aop 依赖,以便在 Spring Boot 中通过注解使用 Resilience-4j 库的功能: <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-spring-boot2</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> 此外,我们还需要添加 spring-boot-starter-actuator 依赖,以便通过暴露一组端点来监控应用的当前状态: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> 最后,还要添加 wiremock-jre8 依赖,用于帮助我们使用 mock HTTP server 测试 REST API: <dependency> <groupId>com.github.tomakehurst</groupId> <artifactId>wiremock-jre8</artifactId> <scope>test</scope> </dependency> 2.2、RestController 和外部 API 调用 在使用 Resilience4j 库的不同功能时,我们的 web 应用需要与外部 API 进行交互。因此,我们需要添加一个 RestTemplate bean,用于 API 调用:

在 Spring Boot 中加载多个 YAML 配置文件

1、概览 在设计 Spring Boot 应用程序时,我们通常希望使用外部配置来定义 application properties。这样,我们就可以在不同的环境中使用相同的代码。在某些情况下,即使是同一个环境,我们可能希望将属性定义在多个 YAML 配置文件中。 在本教程中,我们将学习在 Spring Boot 应用中加载多个 YAML 配置文件的两种方法。 2、使用 Spring Profiles 在应用程序中包含多个 YAML 配置文件的一种方法是使用 Spring profiles。 这种方法利用了 “Spring 自动加载与 profiles 相关联的 YAML 配置文件” 的功能。 接下来,让我们以两个 .yml 文件为例进行说明。 2.1、YAML 配置 我们的第一个文件列出了 student 列表。我们将其命名为 application-students.yml,并将其放在 ./src/main/resources 目录中: students: - Jane - Michael 我们将第二个文件命名为 application-teachers.yml,并放置在相同的 ./src/main/resources 目录中: teachers: - Margo - Javier 2.2. Application 现在,让我们来设置我们的示例应用。我们将在应用中使用 CommandLineRunner 来查看属性加载情况: @SpringBootApplication public class MultipleYamlApplication implements CommandLineRunner { @Autowired private MultipleYamlConfiguration config; public static void main(String[] args) { SpringApplication springApp = new SpringApplication(MultipleYamlApplication.

在 Spring Cache 中获取 Caffeine 缓存的所有 KEY

1、概览 在本文中,我们将学习如何在使用 Spring Cache 时获取 Caffeine 缓存中的所有缓存 KEY。 2、Spring Cache 缓存(Cache)是 Spring Framework 不可分割的一部分。从 3.1 版本开始,它就是 Spring 生态系统的一部分。因此,它拥有一套定义明确、久经考验的接口。 让我们来看看其中两个主要接口: CacheManager 和 Cache: interface CacheManager { Cache getCache(String name); Collection<String> getCacheNames(); } public interface Cache { String getName(); Object getNativeCache(); ValueWrapper get(Object key); <T> T get(Object key, @Nullable Class<T> type); <T> T get(Object key, Callable<T> valueLoader); void put(Object key, @Nullable Object value); ValueWrapper putIfAbsent(Object key, @Nullable Object value); void evict(Object key); void clear(); } 我们可以看到,CacheManager 是应用程序中可用缓存的注册中心。而 Cache 对象则是缓存内的一组键值对。

JUnit 5 根据激活的 Profile 进行测试

1、概览 我们经常需要为开发和部署过程中的不同阶段创建不同的配置。在 Spring Boot 应用中,我们可以为每个不同的阶段定义一个 Spring Profile 并为其创建专门的测试。 在本教程中,我们将介绍如何使用 JUnit 5 基于激活的 Spring Profile 来进行测试。 2、项目设置 首先,在我们的项目中添加 spring-boot-starter-web 依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> 现在,让我们创建一个简单的 Spring Boot 应用: @SpringBootApplication public class ActiveProfileApplication { public static void main (String [] args){ SpringApplication.run(Application.class); } } 最后,创建 application.yaml 配置文件。 3、Spring Profile Spring Profile 提供了一种方法,通过对每个环境的特定配置进行分组,来定义和管理不同的环境。 通过激活特定的 Profile,我们可以在不同的配置之间轻松切换。 3.1、在 Properties 中激活 Profile 我们可以在 application.yaml 文件中指定要激活的 profile: spring: profiles: active: dev 现在 Spring 将检索激活的 profile 的所有属性,并将所有专用 Bean 加载到 application context 中。

在 Spring Boot 应用中同时上传文件、JSON和表单数据

一般我们会使用 multipart/form-data 请求来上传文件。multipart/form-data 请求可以有多个子请求体,每个子请求体都可以有自己的 header 和 body。 本文将带你了解如何在 Spring Boot 应用中使用 multipart/form-data 请求同时上传文件、JSON、表单数据。 服务端 Controller 定义文件上传 controller。 package cn.springdoc.demo.controller; import java.io.IOException; import java.io.InputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.MediaType; import org.springframework.util.StreamUtils; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import cn.springdoc.demo.model.Meta; @RestController @RequestMapping("/upload") public class UploadController { private static final Logger log = LoggerFactory.getLogger(UploadController.class); /** * 文件上传 * @param file * @param response * @return * @throws IOException */ @PostMapping(consumes = MediaType.

Thymeleaf 中 th:text 和 th:value 之间的区别

1、概览 Thymeleaf 是一种流行的 Java 模板引擎,它允许我们创建动态网页。它提供了多种属性,用于将数据从模型绑定到视图。 在本教程中,我们将了解 Thymeleaf 中 th:text 和 th:value 属性之间的主要区别。 2、th:text 属性 Thymeleaf 中的 th:text 属性用于设置元素的文本内容。 它还取代了标准的 HTML text 属性。因此,我们可以把它放在任何支持文本内容的 HTML 元素中,如标题、段落、标签等。 我们还可以使用该属性来显示动态文本内容,例如网页上的标题。 假设我们想在 HTML 页面上显示 controller 提供的 title 属性。 首先,让我们创建一个 controller 类和一个指定模型属性的方法: @GetMapping public String show(Model model) { model.addAttribute("title", "Baeldung"); return "attributes/index"; } 接下来,我们将在标题元素中显示值: <h1 th:text="${title}"/> 在这里,Thymeleaf 会计算表达式 ${title},并将该值插入标题元素。 我们将得到的 HTML 如下: <h1>Baeldung</h1> 此外,与标准 HTML text 属性不同,th:text 属性支持表达式。除了变量,这些表达式还可能包括运算符和函数。 例如,让我们在没有提供 title 属性的情况下指定默认值: <h1 th:text="${title} ?: 'Default title'"/> 3、th:value 属性 另一方面,th:value 属性用于设置通常需要用户输入的元素的值。输入框、复选框、单选按钮和下拉按钮等元素都属于此类。

在 Spring Boot 中使用 OpenAI ChatGPT API

1、概览 在本教程中,我们将学习如何在 Spring Boot 中调用 OpenAI ChatGPT API。我们将创建一个 Spring Boot 应用程序,通过调用 OpenAI ChatGPT API 来生成对提示的回复。 2、OpenAI ChatGPT API 在开始本教程之前,让我们先了解一下本教程中将使用的 OpenAI ChatGPT API。我们将调用 create chat completion API 来生成对提示的回复。 2.1、API 参数和认证 让我们来看看 API 强制的请求参数: model - 是我们将向其发送请求的模型版本。该模型有几个版本。我们将使用 gpt-3.5-turbo 模型,它是 该模型的最新公开版本。 messages - 发送给模型的提示。每条 message 都需要两个字段:role 和 content。role 字段指定信息的发送者。在请求中是 user,在回复中是 assistant。content 字段是实际的消息。 API 调用需要认证,我们需要生成一个 OpenAI API key。在调用 API 时在 Authorization 头中设置该 key。 cURL 格式的请求示例如下: $ curl https://api.openai.com/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $OPENAI_API_KEY" \ -d '{ "model": "gpt-3.

在 Spring 6 中使用虚拟线程(Virtual Threads)

1、简介 在这个简短的教程中,我们将了解如何在 Spring Boot 中使用虚拟线程(Virtual Threads)。 虚拟线程是 Java 19 的 预览特性,这意味着它们将在未来 12 个月内被纳入 JDK 的正式版本中。虚拟线程最初是由 Loom 项目引入的,在 Spring 6 中,开发人员可以一睹为快了。 首先,我们将了解 “平台线程” 与 “虚拟线程” 的主要区别。接下来,我们将使用虚拟线程从头开始构建一个 Spring-Boot 应用。最后,我们会进行一个测试,测试 web 应用的吞吐量提升了多少。 2、虚拟线程和平台线程 主要区别在于,虚拟线程在运行周期内不依赖操作系统线程:它们与硬件脱钩,因此被称为 “虚拟”。这种解耦是由 JVM 提供的抽象层赋予的。 虚拟线程的运行成本远低于平台线程。它们消耗的内存要少得多。这就是为什么我们可以创建数百万个虚拟线程而不会出现内存不足的问题,而标准平台(或内核)线程只能创建数百个。 从理论上讲,这赋予了开发人员一种超级能力:无需依赖异步代码即可管理高度可扩展的应用程序。 3、在 Spring 6 中使用虚拟线程 从 Spring Framework 6(和 Spring Boot 3)开始,虚拟线程功能正式全面可用,但虚拟线程是 Java 19 的预览特性。这意味着我们需要告诉 JVM 我们想在应用程序中启用虚拟线程。由于我们使用 Maven 构建应用程序,因此要确保在 pom.xml 中包含以下代码: <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>19</source> <target>19</target> <compilerArgs> --enable-preview </compilerArgs> </configuration> </plugin> </plugins> </build> 从 Java 的角度来看,要使用 Apache Tomcat 和虚拟线程,我们需要一个简单的配置类和几个 Bean:

Spring Boot 应用中的事务处理

在 Spring 应用中,无论使用 JdbcTemplate 还是 JPA/Hibernate 或 Spring Data JPA,都需要处理数据库事务。 数据库事务是一个事务单元,它要么全部完成,要么都不完成,并使数据库处于一致状态。在实现数据库事务时,需要考虑到 ACID(原子性、一致性、隔离性、持久性)属性。 让我们了解一下如何在 Spring Boot 应用中处理数据库事务。 使用 JDBC 进行事务处理 首先,让我们快速了解一下我们通常是如何在普通 JDBC 中处理数据库事务的。 class UserService { void register(User user) { String sql = "..."; Connection conn = dataSource.getConnection(); // <1> try(conn) { // <6> conn.setAutoCommit(false); // <2> PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, user.getEmail()); pstmt.setString(2, user.getPassword()); pstmt.executeUpdate(); // <3> conn.commit(); // <4> } catch(SQLException e) { conn.rollback(); // <5> } } } 在上述代码片段中: