教程

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 概念来为不同环境配置不同的值。

Spring 和 CORS 跨域

如果你从事 web 应用开发,在前端使用异步请求(fetch/XMLHttpRequest)时,那你或多或少都应该在浏览器控制台见识过如下异常信息。 Access to fetch at 'http://localhost:8080/hello' from origin 'http://localhost:1313' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled. 是的,这就是在异步请求时跨域失败的异常信息。接下来本文将会先简单地介绍跨域的基础知识,再详细地介绍如何在 spring 应用中处理跨域。 简单了解跨域 跨域,全称为“跨域资源共享”(Cross-origin resource sharing),是浏览器的一种安全机制。只会在浏览器中,使用 AJAX (fetch/XMLHttpRequest)时发生。当你在一个 web 页面中,使用 ajax 对目标 URL 发起了请求,只要目标 URL 的 协议,主机,端口 和当前 web 页面的 协议,主机,端口 任意不一致,就会产生跨域。 例如,我在页面 http://localhost:1313 中,对如下 URL 发起 AJAX 请求,都会导致跨域:

Spring Boot 的测试教程

在前面的 Spring Boot 入门教程 中,我们学习了如何创建 Spring Boot 应用程序并构建一个简单的 REST API。 在本教程中,你将学习如何为 Spring Boot 应用程序编写单元测试、片段测试和集成测试。 测试 Spring Boot 应用 我们应该编写单元测试来验证特定单元(一个类、一个方法或一组类)的业务逻辑,而且它们不应该与任何外部服务(如数据库、队列或其他网络服务等)有联系。如果我们测试的单元依赖于任何外部服务,那么我们可以提供这些依赖关系的模拟(mock)实现,并验证单元的行为。 除了单元测试外,我们还应该编写集成测试,通过与实际服务和依赖的协作者(dependent collaborator)互动来检验子系统或组件的行为。 当我们生成 Spring Boot 应用程序时,会自动添加 spring-boot-starter-test 依赖项,它可以将 SpringTest、JUnit5、Mockito、Assertj、JsonPath、JsonAssert 等最常用的测试库作为测试依赖项添加到我们的应用程序中。 测试的类型 Unit Tests(单元测试): 这些测试用于验证单个单元的行为,最好不要依赖 Spring 或 Hibernate 等框架。 Slice Tests(片段测试): 这些测试用于验证应用程序的某个片段,如 Web 层或持久层等。Spring Boot 支持使用 @WebMvcTest、@DataJpaTest、@DataMongoTest 等测试应用程序的片段。 Integration Tests(集成测试): 这些测试以黑盒方式测试应用程序。我们传入一些输入,并期待特定的输出,但我们不知道也不关心内部是如何工作的。Spring Boot 支持使用 @SpringBootTest 编写集成测试。 使用 JUnit 5 和 Mockito 进行单元测试 我们将为之前的 Spring Boot 入门教程 中实现的 REST API 编写测试。 让我们从编写 GreetingService 的单元测试开始。我们将使用 JUnit 5 和 Mockito 来编写单元测试。

在 Spring Boot 应用中使用 Loki 记录日志

在本文中,你将学习如何收集 Spring Boot 应用程序日志并将其发送到 Grafana Loki。为此,我们将使用 Loki4j Logback appender 功能。Loki 是一个受 Prometheus 启发的可水平扩展、高度可用的日志聚合系统。我将逐步展示如何配置应用程序与 Loki 之间的集成。不过,你也可以使用我自动配置的用于记录 HTTP 请求和响应的库,它将为你完成所有这些步骤。 源码 如果你想自己尝试,可以克隆我的 GitHub 仓库。点击 此处 查看包含我的自定义 Spring Boot 日志库的源代码仓库。然后按照我的说明操作即可。 使用 Loki4j Logback Appender 为了使用 Loki4j Logback Appender,我们需要在 Maven pom.xml 中加入一个依赖。该库的当前版本为 1.4.1: <dependency> <groupId>com.github.loki4j</groupId> <artifactId>loki-logback-appender</artifactId> <version>1.4.1</version> </dependency> 然后,我们需要在 src/main/resources 目录下创建 logback-spring.xml 文件。我们的 Loki 实例在 http://localhost:3100 地址 (1) 下可用。Loki 不会索引日志内容,只会索引元数据标签。有一些静态标签,如应用程序名称、日志级别或主机名。我们可以在 format.label 字段 (2) 中设置它们。我们还将设置一些动态标签,因此要启用日志回溯标记功能 (3)。最后,我们将设置日志格式模式 (4)。为了简化 LogQL(Loki 查询语言)的潜在转换,我们将使用 JSON 符号。 <?xml version="1.0" encoding="UTF-8"?> <configuration> <springProperty name="name" source="spring.

为什么 JPA Entity 类需要有默认的无参构造函数?

1、概览 在本教程中,我们将学习在 JPA 中,为什么实体类必须要有默认无参数构造函数? 为了理解无参数构造函数的意义,我们将使用一个简单的 Employee 实体示例。我们将观察缺少默认构造函数是如何导致编译时错误的。我们将深入探讨 JPA 在实体实例化中对 Reflection 的使用。此外,我们还将简要介绍这些类中可能需要该构造函数的其他原因。 2、示例 让我们举一个简单的例子,建立一个名为 Employee 的实体类,其中包含 name、department 和自动生成的 id。让我们定义一个包含所有三个字段的构造函数: @Entity public class Employee { @Id private Long id; private String name; private int age; public Employee(Long id, String name, int age) { this.id = id; this.name = name; this.age = age; } // get 和 set } 不过,此时我们会发现 Employee 类无法编译:Class'Employee' should have [public, protected] no-arg constructor。 显然,在这里我们可以看到,我们定义了一个带有全参构造函数的 Entity 类,但却没有无参数构造函数。在这种情况下,会出现一个编译时错误,提示我们除了现有的构造函数外,还需要一个无参数构造函数。 在接下来的两节中,我们将围绕 Entity 类中的构造函数了解 JPA 规范。我们将了解如何修复错误,以及 JPA 施加这些约束的根本原因。

Spring Data JPA 中 findBy 和 findOneBy 的区别

1、概览 Spring Data Repository 提供了大量可简化数据访问逻辑实现的方法。然而,选择合适的方法并不总是像我们想象的那么容易。 以 findBy 和 findOneBy 为前缀的方法就是一个例子。尽管从名称上看,它们似乎做着同样的事情,但其实还是有一些区别的。 2、Spring Data 中的派生查询方法 Spring Data JPA 的派生查询方法功能经常受到称赞。这些方法提供了一种从方法名称派生特定查询的方法。例如,如果我们想通过 foo 属性检索数据,只需写 findByFoo() 即可。 通常,我们可以使用多个前缀来构建派生查询方法。这些前缀包括 findBy 和 findOneBy。下面,我们就来看看它们的实际应用。 3、实例 首先,我们来看看 Person 实体类: @Entity public class Person { @Id private int id; private String firstName; private String lastName; // 标准的 get 和 set 方法 } 在这里,我们将使用 H2 作为数据库。让我们使用一个基本的 SQL 脚本为数据库添加数据: INSERT INTO person (id, first_name, last_name) VALUES(1, 'Azhrioun', 'Abderrahim'); INSERT INTO person (id, first_name, last_name) VALUES(2, 'Brian', 'Wheeler'); INSERT INTO person (id, first_name, last_name) VALUES(3, 'Stella', 'Anderson'); INSERT INTO person (id, first_name, last_name) VALUES(4, 'Stella', 'Wheeler'); 最后,让我们创建一个 JPA repository 来管理我们的 Person 实体:

使用 Webflux R2dbc 和 Postgres 构建响应式 Spring Boot 应用

在本文中,你将学习如何使用 Spring WebFlux、R2DBC 和 Postgres 数据库实现和测试响应式(Reactive) Spring Boot 应用程序。我们将使用最新版本的 Spring Boot 3 创建两个用 Kotlin 编写的简单应用程序。我们的应用程序通过 HTTP 公开一些 REST 端点。为了测试它们之间的通信以及与 Postgres 数据库的集成,我们将使用 Testcontainers 和 Netty Mock Server。 源码 你可以可以克隆我的 GitHub repository。它包含 employee-service 和 organization-service 两个应用程序。之后,你只需按照我的说明操作即可。 依赖 第一步,我们将添加几个与 Kotlin 相关的依赖。除了标准库,我们还可以加入 Kotlin 对 Jackson(JSON 序列化/反序列化)的支持: <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-stdlib</artifactId> </dependency> <dependency> <groupId>com.fasterxml.jackson.module</groupId> <artifactId>jackson-module-kotlin</artifactId> </dependency> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-reflect</artifactId> </dependency> 我们还需要包含两个 Spring Boot Starter。为了创建响应式 Spring @Controller,我们需要使用 Spring WebFlux 模块。有了 Spring Boot Data R2DBC Starter,我们就能以响应方式使用 Spring Data Repository。最后,我们还需要加入 R2DBC 提供的 Postgres 驱动程序。