Spring Boot + jOOQ 教程 - 5:多对多关系检索

上一教程 介绍了如何使用 jOOQ 检索一对多关系的记录。本文将带你了解如何使用 jOOQ 检索多对多关系的记录。 你可以通过 Github 获取到完整的源码。 在示例数据库中,有 bookmarks(书签)表和 tags(标签)表。每个书签可以关联多个标签,反之亦然,因此 bookmarks 表和 tags 表之间存在多对多的关系。 让我们看看如何获取书签列表以及与之关联的标签 首先,创建 BookmarkWithTags record。 package com.sivalabs.bookmarks.models; import java.util.List; public record BookmarkWithTags(Long id, String title, String url, List<TagInfo> tags) { public record TagInfo (Long id, String name){} } 使用 MULTISET Value 构造器获取多对多关系 使用 jOOQ 的 MULTISET Value Constructor 来获取书签列表和标签。 实现获取书签和标签,如下: package com.sivalabs.bookmarks.repositories; import com.sivalabs.bookmarks.models.BookmarkWithTags; import org.jooq.DSLContext; import org.springframework.stereotype.Repository; import java.util.List; import static com.sivalabs.bookmarks.jooq.Tables.BOOKMARK_TAG; import static com.

Spring Boot + jOOQ 教程 - 4:一对多关系检索

上一教程 中介绍了如何使用 jOOQ 检索一对一(*One-to-One)关系的记录。本文将带你了解如何使用 jOOQ 检索一对多(One-to-Many)关系的记录。 你可以在 Github 获取完整的源码。 在示例数据库中,有 users(用户)表和 bookmarks(书签)表。每个用户可以创建多个书签,因此 users 表和 bookmarks 表之间是一对多的关系。 让我们看看如何获取用户详细信息以及用户创建的书签。 首先,创建 UserWithBookmarks Record。 package com.sivalabs.bookmarks.models; import java.util.List; public record UserWithBookmarks(Long id, String name, String email, List<BookmarkInfo> bookmarks) { public record BookmarkInfo (Long id, String title, String url){} } 使用 MULTISET Value 构造器获取一对多关系 使用 jOOQ 的 MULTISET Value 构造函数来获取用户创建的书签列表。有关 MULTISET Value 构造函数的更多详情,请访问:https://www.jooq.org/doc/latest/manual/sql-building/column-expressions/multiset-value-constructor/。 此外,强烈推荐你阅读《jOOQ 3.15 的新 Multiset Operator 将如何改变你对 SQL 的看法》一文。 实现获取用户详细信息以及该用户创建的书签。 @Repository public class UserRepository { .

Spring Boot + jOOQ 教程 - 3:一对一关系检索

上一教程 介绍了如何使用 jOOQ 实现基本的 CRUD 操作。本文将带你了解如何使用 jOOQ 检索一对一(One-to-One)关系的记录。 你可以在 Github 上找到完整的源码。 一般来说,在显示记录列表时,只会显示记录的最基本的信息,当点击记录时,才会显示记录的完整信息。 在本示例应用中,用户列表只显示 id、name 和 email 基本信息。当点击详情时,才显示包含用户偏好(Preferences)的完整信息。 更新 findUserById() 方法,以获取用户偏好设置。 首先,创建 UserPreferences record。 public record UserPreferences(Long id, String theme, String language) { } 更新 User 类,使其包含 UserPreferences。 package com.sivalabs.bookmarks.models; public record User ( Long id, String name, String email, String password, UserPreferences preferences ) { public User(Long id, String name, String email, String password) { this(id, name, email, password, null); } public static User create(Long id, String name, String email, String password) { return new User(id, name, email, password, null); } } 在 SQL 中,可以使用 LEFT OUTER JOIN 查询获取关联数据,如下所示:

Spring Boot + jOOQ 教程 - 2:实现 CRUD 操作

在 上一教程 中,介绍了如何使用 testcontainers-jooq-codegen-maven-plugin 生成 jOOQ 代码,以及如何使用 jOOQ DSL 执行 SQL 查询。 本文将带你了解如何使用 jOOQ 对 USERS 表执行基本的 CRUD(创建、读取、更新、删除)操作。 你可以在 Github 上获取到完整的源码。 findAllUsers() 首先,从 USERS 表中获取所有用户。假设只检索 USERS 表中的 id、name、email 和 password 列。 创建 User record,如下: package com.sivalabs.bookmarks.models; public record User(Long id, String name, String email, String password) { } 在 UserRepository 类中实现 findAllUsers() 方法,如下: package com.sivalabs.bookmarks.repositories; import com.sivalabs.bookmarks.models.User; import org.jooq.DSLContext; import org.jooq.impl.SQLDataType; import org.springframework.stereotype.Repository; import java.util.List; import static com.sivalabs.bookmarks.jooq.tables.Users.USERS; import static org.

Spring Boot + jOOQ 教程 - 1:入门

jOOQ 是一个 Java 持久库,提供用于编写类型安全 SQL 查询的 SQL DSL。它支持大多数流行的数据库,如 MySQL、PostgreSQL、Oracle、SQL Server 等。 本文将带你了解如何在 Spring Boot 中使用 jOOQ 实现持久层。JOOQ 也可以在 Kotlin、Scala 等其他基于 JVM 的语言中使用。 本系列教程中,将带你学习如何在 Spring Boot 中使用 JOOQ 实现: 基本的 CRUD 操作 一对一关系检索 一对多关系检索 多对多关系检索 你可以在 Github 获取完整的源码。 前提条件 安装 JDK 17 或更高版本 安装任何容器运行时,如 Docker Desktop、OrbStack 等。 注意:jOOQ 不需要 Docker。只是使用 Testcontainers 进行 jOOQ 代码生成和测试需要一个容器运行时。 示例数据库 本教程使用下列示例数据库。 创建 Spring Boot 应用 使用 Spring Initializr 创建一个 Spring Boot 项目。选择 JOOQ Access Layer、Flyway Migration、PostgreSQL Driver 和 Testcontainers。

在 Spring Boot 微服务中使用 JWT Token 进行认证

Spring Boot 微服务需要对用户进行身份认证,其中一种方式是使用 JSON Web Token (JWT)。JWT 是一种开放标准(RFC 7519),它定义了一种紧凑的机制,用于在各方之间安全地传输信息。 本文将会带你了解如何在 Spring Boot 微服务项目中使用 JWT 进行身份认证。 JWT Token 概览 JWT 的体积相对较小。因此,它可以通过 URL 发送: POST 参数 HTTP 请求头 通过 HTTP Header 发送 Token 是最常见的方式。 JWT Token 包含一个实体(可以是用户或服务)的所有必要信息。 下图显示了使用 JWT 进行身份认证的典型用例。 示例应用 创建两个服务: AuthenticatorService:负责验证用户名和密码。验证成功后,该服务会生成并返回一个 JWT Token。 BlogService:受保护的服务。该服务包含一个 Filter,用于验证客户端发送的 JWT Token。验证成功后,该服务会返回业务数据。 下图显示了客户端与上述服务之间的交互。 AuthenticatorService Maven 依赖 添加 jjwt 依赖,用于生成 JWT Token。 <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> <!-- 其他依赖忽略 --> 实体 AuthenticatorService 包含一个 User 实体,用于表示用户凭证。如下: package com.

在 Spring 应用中使用 Fastjson2

Fastjson2 是 Fastjson 的一个重大升级版本。 以下摘自官方的介绍: FASTJSON 2是一个性能极致并且简单易用的Java JSON库。 FASTJSON 2是FASTJSON项目的重要升级,和FASTJSON 1相比,性能有非常大的提升,解决了autoType功能因为兼容和白名单的安全性问题。 性能极致,性能远超过其他流行 JSON 库,包括 jackson/gson/org.json,性能数据: https://github.com/alibaba/fastjson2/wiki/fastjson_benchmark 支持JDK新特性,包括JDK 11/JDK 17,针对compact string优化,支持Record,支持GraalVM Native-Image 完善的JSONPath支持,支持 SQL:2016 的 JSONPath 语法 支持Android 8+,客户端和服务器一套 API 支持Kotlin https://alibaba.github.io/fastjson2/kotlin_cn 支持JSON Schema https://alibaba.github.io/fastjson2/json_schema_cn 新增加支持二进制格式 JSONB https://alibaba.github.io/fastjson2/jsonb_format_cn 总得来说,提高了性能(拳打 Gson,脚踢 Jackson)和饱解决了饱受诟病的安全问题(因为 Fastjson 屡次爆出反序列化安全问题,在国内被戏称为 Bugjson)。 Fastjson2 确实一个款性能很高的 Json 库,API 也设计得比较简单、易用。本文将带你了解如何在 Spring 中使用 Fastjson2。 1、依赖 Fastjson2 采用 多模块 的结构设计,对 Spring 等框架的支持现独立在 extension 包中。 2.0.23 版本之后为了兼容 Spring 5.x / 6.x,将不同的版本独立出来了。 使用 Maven: <!-- Sring 5 --> <dependency> <groupId>com.

Spring Security 中的 RequestRejectedException

1、简介 Spring 5.0 至 5.0.4、4.3 至 4.3.14 以及其他旧版本在 Windows 系统上存在目录或路径遍历安全漏洞。 静态资源配置错误会导致恶意用户访问服务器的文件系统。例如,在 Windows 上使用 file: 协议配置静态资源,可能导致用户非法访问文件系统。 Spring 承认存在该 漏洞,并在后续版本中对其进行了修复。 此修复可防止应用遭受路径遍历攻击。不过,在修复后,一些之前的 URL 现在会抛出 org.springframework.security.web.firewall.RequestRejectedException 异常。 本文先带你了解什么是 “路径遍历攻击”,在这个知识背景下再带你了解 org.springframework.security.web.firewall.RequestRejectedException 和 StrictHttpFirewall 的相关知识。 2、路径遍历漏洞 路径遍历或目录遍历漏洞可非法访问 Web 文档根目录以外的内容。例如,篡改 URL 可对文档根目录以外的文件进行未经授权的访问。 虽然大多数最新和流行的 Web 服务器都能抵消大部分攻击,但攻击者仍可使用特殊字符(如 ./、../)的 URL 编码来规避 Web 服务器的安全设置并获取非法访问权限。 OWASP 介绍了路径遍历漏洞和解决方法。 3、Spring 的漏洞 先尝试复现这个漏洞,然后再介绍如何进行修复。 首先,克隆 Spring Framework MVC 示例。然后,修改 pom.xml,用一个易受攻击的版本替换现有的 Spring Framework 版本。 克隆仓库: git clone git@github.com:spring-projects/spring-mvc-showcase.git 在克隆目录中,编辑 pom.xml,修改 Spring Framework 的版本为 5.0.0.RELEASE: <org.springframework-version>5.0.0.RELEASE</org.springframework-version> 接下来,编辑 Web 配置类 WebMvcConfig,修改 addResourceHandlers 方法,使用 file: 将资源映射到本地文件目录:

在 Spring Boot 中设置环境变量前缀

1、概览 本文将带你了解 Spring Boot 2.5 中的一个新特性:为系统环境变量指定前缀。通过该特性,就可以在同一环境中运行多个不同的 Spring Boot 应用,只要所有属性都使用带前缀的版本。 2、环境变量前缀 有时,我们可能需要在同一个环境中运行多个 Spring Boot 应用,并且经常会面临环境变量名称分配的问题。现在,我们可以在应用级别设置一个 “前缀”,不同应用加载不同前缀的环境变量即可。 以一个简单的 Spring Boot 应用为例,通过设置前缀来修改应用属性,例如 tomcat 服务器端口。 关于 Spring Boot 中属性属性的优先级,你可以参阅 中文文档。 2.1、Spring Boot 应用示例 创建一个 Spring Boot 应用。 首先,为应用设置一个前缀。为了简单起见,称之为 prefix: @SpringBootApplication public class PrefixApplication { public static void main(String[] args) { SpringApplication application = new SpringApplication(PrefixApplication.class); // 设置环境变量前缀 application.setEnvironmentPrefix("prefix"); application.run(args); } } 不能使用已经包含下划线字符(_)的单词作为前缀。否则,抛出异常。 再创建一个 API 端点,返回应用正在监听的端口: @Controller public class PrefixController { @Autowired private Environment environment; @GetMapping("/prefix") public String getServerPortInfo(final Model model) { model.

覆盖 Spring Boot 依赖的版本号

1、简介 Spring Boot 为大多数常用的依赖、第三方库都定义好了最兼容的版本号(如 JPA、MySQL 驱动、Redis 客户端)。得益于此,我们可以快速地创建一个新应用。 但,有时出于特殊原因,我们需要修改这些预定义的依赖版本号。 2、Spring Boot 依赖清单(BOM) Spring Boot 使用 Bill of Materials (BOM) 来定义依赖和版本。 大多数 Spring Boot 项目都继承自 spring-boot-starter-parent,而 spring-boot-starter-parent 本身又继承自 spring-boot-dependencies 。后者就是 Spring Boot BOM,它只是一个 Maven POM 文件,其中有一个很大的 ependencyManagement 节点: <dependencyManagement> <dependencies> <dependency> ... </dependency> <dependency> ... </dependency> </dependencies> </dependencyManagement> 通过使用 Maven 的 dependencyManagement,BOM 可以指定依赖的默认版本(如果应用使用了这个依赖)。 Spring Boot BOM 中的一个依赖如下: <dependency> <groupId>org.apache.activemq</groupId> <artifactId>activemq-amqp</artifactId> <version>${activemq.version}</version> </dependency> 这意味着,在项目中依赖了 ActiveMQ,就会使用这个默认的版本。 另外,注意。版本是使用属性占位符指定的。这是 Spring Boot BOM 中的常见做法,它在自己的 properties 部分中提供了该属性和其他属性的值。 3、覆盖 Spring Boot 管理的依赖版本 既然已经了解了 Spring Boot 如何管理依赖版本,那就来看看如何覆盖它们。