Spring-Boot

在 Spring Boot 开发模式中使用 Testcontainers 和 Docker

在本文中,你将学习如何使用 Spring Boot 内置的 Testcontainers 和 Docker Compose 支持,在开发模式下运行外部服务。Spring Boot 在当前的最新版本 3.1 中引入了这些功能,你已经可以在 Spring Boot 应用的测试中利用 Testcontainers。在应用程序启动时运行外部数据库、message broker 或其他外部服务的功能是我一直期待的。尤其是竞争框架 Quarkus 已经提供了名为 Dev Services 的类似功能,这在我的开发过程中非常有用。此外,还有另一个令人兴奋的功能 - 与 Docker Compose 集成。 源代码 如果你想自己尝试,可以查看我的源代码。因为我经常使用 Testcontainers,所以你可以在我的多个仓库中找到示例。下面是我们今天要使用的仓库列表: https://github.com/piomin/sample-spring-boot-on-kubernetes.git https://github.com/piomin/sample-spring-microservices-advanced.git https://github.com/piomin/sample-spring-kafka-microservices.git 你可以克隆它们,然后按照指导查看如何在开发模式下使用 Spring Boot 内置的 Testcontainers 和 Docker Compose 支持。 在测试中使用 Testcontainers 让我们从标准使用示例开始。第一个仓库中有一个连接 Mongo 数据库的 Spring Boot 应用程序。为了构建自动测试,我们必须包含以下 Maven 依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.testcontainers</groupId> <artifactId>mongodb</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.testcontainers</groupId> <artifactId>junit-jupiter</artifactId> <scope>test</scope> </dependency> 现在,我们可以创建测试了。我们需要用 @Testcontainers 来注解我们的测试类。然后,我们必须声明 MongoDBContainer Bean。在 Spring Boot 3.

Spring Boot 中内置的测试容器(Testcontainers)

1、概览 在本教程中,我们将讨论 Spring Boot 3.1 中引入的增强型 Testcontainers 支持。 这个更新提供了一种更简化的配置容器的方法,并允许我们启动它们进行本地开发。因此,使用 Testcontainers 进行开发和运行测试变得更加无缝和高效。 2、SpringBoot 3.1 之前的 Testcontainers 在测试阶段,我们可以使用 Testcontainers 创建一个类似生产的环境。这样,我们就不需要模拟,就能写出与实现细节无关的高质量自动测试。 在本文的代码示例中,我们将使用一个简单的 Web 应用程序,其中包含一个 MongoDB 数据库作为持久层,并具有一个小型的 REST 接口。 @RestController @RequestMapping("characters") public class MiddleEarthCharactersController { private final MiddleEarthCharactersRepository repository; // constructor not shown @GetMapping public List<MiddleEarthCharacter> findByRace(@RequestParam String race) { return repository.findAllByRace(race); } @PostMapping public MiddleEarthCharacter save(@RequestBody MiddleEarthCharacter character) { return repository.save(character); } } 在集成测试期间,我们将启动一个包含数据库服务器的 Docker 容器。由于容器暴露的数据库端口将动态分配,我们无法在 properties 文件中定义数据库 URL。因此,对于版本早于 3.1 的 Spring Boot 应用程序,我们需要使用 @DynamicPropertySource 注解才能将这些属性添加到 DynamicPropertyRegistry 中:

在 Spring Boot 中使用 Logback 和 Log4j2 记录日志

日志系统对应用程序的重要性不言而喻。Spring Boot 为应用程序的日志记录提供了强大的支持,并提供了各种自定义选项。在本教程中,你将学习如何在 Spring Boot 应用程序中使用 Logback 和 Log4j2 实现日志记录 Spring Boot 中默认的的日志支持 当你创建一个添加了任何 starter 的 Spring Boot 应用程序时,它们都依赖于 spring-boot-starter,而 spring-boot-starter 又依赖于 spring-boot-starter-logging,这就为日志记录添加了 logback 依赖。 Spring Boot 默认日志配置已在 spring-boot-starter 中通过 CONSOLE appender 进行了配置。你可以在 org/springframework/boot/logging/logback 包下查看打包在 spring-boot.jar 中的默认配置文件(defaults.xml、base.xml、console-appender.xml、file-appender.xml)。 因此,默认情况下,Spring Boot 配置了 Slf4j 和 Logback 来记录日志,你可以在应用程序中按如下方式记录日志: import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Service class CustomerService { private static final Logger log = LoggerFactory.getLogger(CustomerService.class); public Customer findById(Long id) { log.info("Fetching customer by id: {}", id); .

在 Spring Boot 中自定义 Date/LocalDateTime/LocalDate 的序列化、反序列化格式

Spring Boot 中默认使用的 JSON 框架是 jackson,它负责把 JSON 请求体反序列化为 Java 对象,并把响应给客户端的 Java 对象序列化为 JSON 字符串。 本文将会详细介绍如何在 Spring Boot 应用中自定义 jackson 对 Date、LocalDateTime、LocalDate 等日期对象的序列化、反序列化格式。 Jackson 对 Date/LocalDateTime/LocalDate 的默认处理方式 为了处理 java.time 类型的日期类,你还需要在项目中添加 com.fasterxml.jackson.datatype:jackson-datatype-jsr310 模块。 <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> </dependency> 默认情况下,Jackson 将 Date 对象序列化为时间戳。对于 LocalDateTime 和 LocalDate 对象,jackson 会序列化为一个 long[],其中,从第一个元素开始分别表示日期的:年、月、日、时、分、秒、毫秒。 示例: package cn.springdoc.test; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.Date; import java.util.HashMap; import java.util.Map; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; public class JacksonTest { public static void main(String[] args) throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); // 注册 JavaTime 模块 objectMapper.

使用 Spring Doc 为 Spring REST API 生成 OpenAPI 3.0 文档

1、概览 文档是构建 REST API 的重要组成部分。在本教程中,我们将介绍 Spring Doc,它可简化 API 文档的生成和维护,这些文档基于 OpenAPI 3 规范,适用于 Spring Boot 3.x 应用程序。 2、设置 springdoc-openapi Spring Boot 3.x 要求使用 springdoc-openapi version 2: <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <version>2.1.0</version> </dependency> 2.1、 OpenAPI 描述的路径 正确设置依赖后,我们就可以运行应用程序,并在 /v3/api-docs 路径访问 OpenAPI 描述,这是默认路径: http://localhost:8080/v3/api-docs 此外,我们还可以使用 springdoc.api-docs 属性在 application.properties 中自定义描述的路径。例如,我们可以将路径设置为 /api-docs: springdoc.api-docs.path=/api-docs 然后,我们就可以通过以下网址访问文档描述: http://localhost:8080/api-docs OpenAPI 描述定义默认为 JSON 格式。对于 yaml 格式,我们可以从以下网址获取定义: http://localhost:8080/api-docs.yaml 3、整合 Swagger UI 除了生成 OpenAPI 3 规范之外,我们还可以将 springdoc-openapi 与 Swagger UI 集成,以与我们的 API 规范进行交互并测试端点。 Springdoc-openapi 依赖项中已经包含了 Swagger UI,因此我们可以通过如下路径访问 API 文档:

在 Spring Boot 应用中使用 Grpc 进行通信

在本文中,你将学习如何在 Spring Boot 应用程序中实现使用 gRPC 进行通信。gRPC 是一个现代的开源远程过程调用(RPC)框架,可以在任何环境中运行。默认情况下,它使用 Google 的 Protocol Buffer 来对结构化数据进行序列化和反序列化。当然,我们也可以切换到其他数据格式,比如 JSON。为了简化我们在 gRPC 和 Spring Boot 中的使用体验,我们将使用一个专门的 starter。由于没有官方支持的 gRPC 和 Spring Boot 集成的 starter,我们将选择较流行的第三方项目 - grpc-spring-boot-starter。该项目在 GitHub 上有大约 3.1k 个星星。你可以在 这里 找到关于其功能的详细文档。 源码 如果你想亲自尝试,你可以克隆我的 GitHub 仓库。它包含四个应用程序。其中 account-service 和 customer-service 与我之前的文章相关,介绍了 Java 中的 Protocol Buffers。对于这篇文章,请参考另外两个应用 account-service-grpc 和 customer-service-grpc。它们与对应的前2个应用非常相似,但使用了我们的第三方 Spring Boot 和 gRPC 通信,而不是 REST。此外,它们需要使用 Spring Boot 2,因为我们的第三方 starter 还不支持 Spring Boot 3。无论如何,克隆了仓库后,只需按照我的说明进行操作即可。 生成 gRPC 的 Model 类和 service 第一步,我们将使用 .proto 文件生成 model 类和 gRPC service。我们需要加入一些额外的 Protobuf schema,以便使用 google.

Spring Boot 整合 MyBatis

MyBatis 是一个流行的 Java 持久层框架,它简化了与关系型数据库的交互。通过将 SQL 语句与 Java 代码进行映射,MyBatis 提供了一种方便、灵活的方式来执行数据库操作。它支持动态SQL、缓存机制和插件扩展,使得开发人员能够更高效地编写和管理数据库访问代码。作为一种轻量级框架,MyBatis 在 Java 开发中被广泛应用于构建可靠的持久化解决方案。 本文将会指导你如何在 Spring Boot 中整合 MyBatis。 框架版本: Spring Boot:3.1.3 MyBatis:3.5.13 创建 Spring Boot 项目 通过 start.springboot.io 创建工程(你可以直接点击 这个链接 快速创建)。 选择 MySQL Driver、Spring Web、MyBatis Framework 基本依赖,点击 “GENERATE” 下载到本地后,导入到IDEA中。 本文将在示例中使用 MySQL 数据库,如果你使用其他类型的数据库,需要把 MySQL Driver 替换为对应的依赖。 配置项目 定义 mapper 接口 创建专门存放 mapper 接口的包: cn.springdoc.mapper,并在其中定义一个 FooMapper,如下: package cn.springdoc.mapper; import java.time.LocalDateTime; import org.apache.ibatis.annotations.Mapper; @Mapper // 使用 Mapper 注解 public interface FooMapper { /** * 获取数据库的当前时间 * @return */ LocalDateTime now(); } 该 Mapper 简单定义了一个 now 用于从数据库获取到当前时间。

在 Spring 应用中处理 CORS 跨域

1、概览 在任何现代浏览器中,随着通过 REST API 获取数据的 HTML5 和 JS 客户端的出现,跨源资源共享 (CORS) 已成为一种相关规范。 通常,提供 JS 的主机(如 example.com)与提供数据的主机(如 api.example.com)不同。在这种情况下,CORS 可以实现跨域通信。 Spring 为 CORS 提供了一流的 支持,为在任何 Spring 或 Spring Boot Web 应用中配置 CORS 提供了简单而强大的方法。 2、Controller 方法级的 CORS 配置 启用 CORS 非常简单,只需添加注解 @CrossOrigin。 我们可以通过几种不同的方式来实现。 2.1、在 @RequestMapping 方法上注解 @CrossOrigin @RestController @RequestMapping("/account") public class AccountController { @CrossOrigin @RequestMapping(method = RequestMethod.GET, path = "/{id}") public Account retrieve(@PathVariable Long id) { // ... } @RequestMapping(method = RequestMethod.DELETE, path = "/{id}") public void remove(@PathVariable Long id) { // .

在 Spring Boot 应用中把上传的图片编码为 WEBP 格式

WebP 是一种现代的图像格式,由 Google 开发。它采用了无损和有损的压缩算法,可以显著减小图像文件的大小,同时保持较高的视觉质量。WebP 图像通常比 JPEG 和 PNG 格式的图像更小,并且具有更快的加载速度,这对于 Web 应用程序和网页的性能优化非常有益。此外,WebP 还支持透明度和动画,使其成为一个多功能的图像格式。它已经得到了广泛的支持,包括主流的 Web 浏览器和图像处理软件。 简单理解就是:Webp编码格式的图片,体积更小,质量不减(肉眼很难看出质量差异),主流浏览器都支持。 据说使用 webp 编码的图片,有利于搜索引擎 SEO。 参考资料: Webp 官网 浏览器兼容情况 在 Java 中编码 Webp 图片 WEBP 官方开放了源码,以及编译后的可执行文件(可以通过命令行的形式对图片文件进行编码,解码处理),官方并未提供 Java 的 SDK。 我翻遍了互联网,在网上找到了一个开源的 webp 编码库:https://github.com/sejda-pdf/webp-imageio <!-- https://mvnrepository.com/artifact/org.sejda.imageio/webp-imageio --> <dependency> <groupId>org.sejda.imageio</groupId> <artifactId>webp-imageio</artifactId> <version>0.1.6</version> </dependency> 它貌似采用了 JNI 技术来调用 webp 的动态库来实现的编码。使用方式及其简单,如下: import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.io.InputStream; import javax.imageio.IIOImage; import javax.imageio.ImageIO; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.stream.FileImageOutputStream; import com.luciad.imageio.webp.WebPWriteParam; public class Webp { /** * 编码为WEBP * * @param in 输入文件 * @param file 输出文件 * @throws IOException */ public void encode(InputStream in, File file) throws IOException { // 读取图片文件 BufferedImage image = ImageIO.

Spring Boot 配置教程

在上一篇 Spring Boot 测试教程 中,我们学习了如何为 Spring Boot 应用编写单元测试、片段测试和集成测试。 在本教程中,你将学习如何使用 properties 和 YAML 文件配置 Spring Boot 应用程序,以便在不同环境中运行应用。 外部化 Spring Boot 的配置 大多数应用程序都会有一些配置项目,你希望这些项目是可以灵活配置的,而不是在程序代码中硬编码这些值。 Spring Boot 提供了许多 配置 application properties 的方法,其中我们最有可能使用的只有以下方法: 默认 src/main/resources/application.{properties/yml} 中的属性值。 特定 profile src/main/resources/application-{profile}.{properties/yml} 中的属性值。 使用环境变量(Environment Variables)或系统属性(System Properties)覆盖默认配置。 在我们的应用程序中,通常会有两种配置属性: Spring Boot 定义了用于配置 DataSource、Kafka 等服务的属性。例如:spring.datasource.url、spring.datasource.username、spring.datasource.password 等。 应用特定的配置属性。 配置默认属性 Spring Boot 默认从 src/main/resources/application.{properties/yml} 中加载属性。例如,我们可以使用 application.properties 文件配置应用属性,如下所示: spring.datasource.url=jdbc:postgresql://localhost:5432/postgres spring.datasource.username=postgres spring.datasource.password=secret123 ftp.host=ftpsrv001 ftp.port=21 ftp.username=appuser1 ftp.password=secret321 同样的配置值也可以使用 application.yml 文件进行配置,如下所示: spring: datasource: url: jdbc:postgresql://localhost:5432/postgres username: postgres password: secret123 ftp: host: ftpsrv001 port: 21 username: appuser1 password: secret321 配置特定于 Profile 的属性 我们的应用可能会在不同的环境中运行,如本地、开发、QA、暂存和生产环境。我们可能希望为不同的环境配置不同的值。在这种情况下,我们可以使用 Spring 的 profile 概念来为不同环境配置不同的值。