教程

使用 WebClient 获取 JSON 对象集合

1、概览 从 Spring 5 开始,可以使用 WebClient 以响应式、非阻塞的方式执行服务之间的 REST 通信。WebClient 是新的 WebFlux 框架的一部分,构建于 Project Reactor 之上。它使用 Fluent 风格的响应式 API,底层实现使用 HTTP 协议。 当发起 Web 请求时,数据通常会以 JSON 格式返回,本文将带你了解如何使用 WebClient 将响应的 JSON 数组转换为 Java Object 数组、POJO 数组和 POJO 集合。 2、依赖 在 pom.xml 中添加如下依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> <groupId>org.projectreactor</groupId> <artifactId>reactor-spring</artifactId> <version>1.0.1.RELEASE</version> </dependency> 3、JSON、POJO 和 Service 从端点 http://localhost:8080/readers 开始,它以 JSON 数组的形式返回读者最喜欢的书籍列表: [{ "id": 1, "name": "reader1", "favouriteBook": { "author": "Milan Kundera", "title": "The Unbearable Lightness of Being" } }, { "id": 2, "name": "reader2" "favouriteBook": { "author": "Douglas Adams", "title": "The Hitchhiker's Guide to the Galaxy" } }] 还需要相应的 Reader 和 Book 类来处理数据:

Spring RestTemplate 异常:“Not enough variables available to expand”

1、概览 本文将带你了解 Spring RestTemplate 抛出 IllegalArgumentException: Not enough variables available to expand 异常的原因以及解决办法。 2、原因 简而言之,当试图在 GET 请求参数中发送 JSON 数据时,通常会导致这个异常。 RestTemplate 提供了 getForObject 方法,通过在指定的 URL 上发出 GET 请求来获取表示对象。 出现异常的主要原因是 RestTemplate 将大括号中封装的 JSON 数据视为 URI 变量的占位符。 由于没有为预期的 URI 变量提供任何值,getForObject 方法就会抛出异常。 例如,尝试发送 {"name": "HP EliteBook"} 作为查询参数: String url = "http://products.api.com/get?key=a123456789z&criterion={\"name\":\"HP EliteBook\"}"; Product product = restTemplate.getForObject(url, Product.class); 将导致 RestTemplate 抛出异常: java.lang.IllegalArgumentException: Not enough variable values available to expand 'name' 3、示例应用 创建一个只有一个 GET 端点的基本 REST API 示例,来复现 RestTemplate 抛出 IllegalArgumentException 异常的情况。

Java 使用 RSA 进行加密、解密、签名和验签

RSA(Rivest-Shamir-Adleman)算法是一种非对称加密算法,广泛用于数据加密和数字签名领域。它是由 Ron Rivest、Adi Shamir 和 Leonard Adleman 于 1977 年共同提出的。 RSA 算法常用于如下场景: 公钥加密,私钥解密 私钥加密,公钥解密(不推荐) 私钥签名,公钥验签 生成密钥对 通过 Java java.security 包下的工具类可以生成 RSA 公钥和私钥。 package cn.springdoc.demo.test; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.util.Base64; /** * @author springdoc.cn * 生成 RSA 密钥对 */ public class Main { public static void main(String[] args) throws Exception { // 初始化 Key 生成器,指定算法类型为 RSA KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); // 密钥长度为 2048 位 keyPairGenerator.initialize(2048); // 生成密钥对 KeyPair keyPair = keyPairGenerator.

在 Spring 应用中防止跨站脚本(XSS)攻击

1、概览 在构建 Spring Web 应用时,关注安全性非常重要。跨站脚本 (XSS) 是对 Web 安全威胁最大的攻击之一。 在 Spring 应用中,防止 XSS 攻击是一项挑战。Spring 提供了内置的帮助来实现全面的保护。 本文将带你了解如何通过 Spring Security 使用 X-XSS-Protection 和 Content-Security-Policy 机制来防止 XSS 攻击。 2、什么是跨站脚本(XSS)攻击? 2.1、问题的定义 XSS 是一种常见的注入式攻击。在 XSS 中,攻击者试图在 Web 应用程序中执行恶意代码。他们通过 Web 浏览器或 HTTP 客户端工具(如 Postman)与应用交互。 XSS 攻击有两种类型: 反射性或非持久性 XSS 存储型或持久型 XSS 在反射型或非持久型 XSS 中,不受信任的用户数据被提交到 Web 应用,并立即在响应中返回,从而在页面中添加了不可信的内容。Web 浏览器会认为代码来自 Web 服务器并执行它。这可能会让黑客向你发送一个链接,当你点击该链接时,浏览器会从你使用的网站上获取你的私人数据,然后让你的浏览器将这些数据转发到黑客的服务器上。 在存储型或持久型 XSS 中,Web 服务器会存储攻击者的输入。随后,任何后来的访问者都可能执行该恶意代码。 2.2、防御攻击 防止 XSS 攻击的主要策略是清理用户输入。 在 Spring Web 应用中,用户的输入是 HTTP 请求。为防止攻击,应检查 HTTP 请求的内容,并删除可能可在服务器或浏览器中执行的任何内容。 对于通过 Web 浏览器访问的普通 Web 应用,可以使用 Spring Security 的内置功能(反射性 XSS)。

OpenFeign 上传文件

1、概览 Feign 是微服务中通过 REST API 以声明方式与其他微服务通信的强大工具,本文将带你了解如何使用 Open Feign 上传文件。 2、先决条件 假设如下 RESTful Web 服务用于文件上传: POST http://localhost:8081/upload-file 该 Web 服务端点定义如下: @PostMapping(value = "/upload-file") public String handleFileUpload(@RequestPart(value = "file") MultipartFile file) { // 文件上传逻辑 } 3、依赖 为了支持文件上传的 application/x-www-form-urlencoded 和 multipart/form-data 编码类型,需要添加 feign-core、 feign-form 和 feign-form-spring 模块。 在 Maven 中添加以下依赖: <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-core</artifactId> <version>10.12</version> </dependency> <dependency> <groupId>io.github.openfeign.form</groupId> <artifactId>feign-form</artifactId> <version>3.8.0</version> </dependency> <dependency> <groupId>io.github.openfeign.form</groupId> <artifactId>feign-form-spring</artifactId> <version>3.8.0</version> </dependency> 还可以直接使用 spring-cloud-starter-openfeign 依赖,它已经包含了 feign-core: <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>3.1.0</version> </dependency> 4、配置 在 main 类中添加 @EnableFeignClients:

Spring 中的 @Component 注解

1、概览 本文将带你全面了解 Spring @Component 注解及相关领域。 2、Spring ApplicationContext 在了解 @Component 之前,首先需要了解一下 Spring ApplicationContext。 Spring ApplicationContext 是 Spring 保存对象实例的地方,Spring 已确定这些实例将被自动管理和分发。这些实例被称为 Bean。 Spring 的一些主要功能包括 Bean 管理和依赖注入。 利用控制反转(Inversion of Control),Spring 可以从应用中收集 Bean 实例,并在适当的时候使用它们。可以在 Spring 中定义 Bean 依赖,而无需处理这些对象的设置和实例化。 使用 @Autowired 等注解将 Spring 管理的 Bean 注入应用的能力是在 Spring 中创建功能强大且可扩展代码的驱动力。 那么,如何让 Spring 来管理的 Bean 呢?可以利用 Spring 的自动 Bean 检测功能,通过在类中使用元注解(Stereotype Annotation)来实现。 3、@Component @Component 是一个注解,它允许 Spring 自动检测自定义 Bean。 换句话说,无需编写任何明确的代码,Spring 就能做到: 扫描应用,查找注解为 @Component 的类 将它们实例化,并注入任何指定的依赖 在需要的地方注入 不过,大多数时候应该使用更专业的元(Stereotype)注解来实现这一功能。 3.1、Spring 元注解 Spring 提供了一些专门的元注解:@Controller、@Service 和 @Repository。它们都提供了与 @Component 相同的功能。

HttpMessageNotWritableException: "No converter found for return value of type"

1、概览 本文将带你了解 Spring 中出现 HttpMessageNotWritableException: "No converter found for return value of type" 异常的原因以及解决办法。 2、原因 通常,当 Spring 无法获取返回对象的属性时,就会出现这种异常。 导致这种异常的最典型原因通常是返回对象的属性没有任何 public getter 方法。 默认情况下,Spring Boot 依赖于 Jackson 库来完成序列化/反序列化请求和响应对象的所有工作。 因此,导致异常的另一个常见原因可能是 缺少或使用了错误的 Jackson 依赖。 简而言之,这种异常情况的一般准则是检查是否存在以下情况: 默认构造器 Getter 方法 Jackson 依赖 注意,异常类型 已从 java.lang.IllegalArgumentException 变为 org.springframework.http.converter.HttpMessageNotWritableException。 3、实例 现在,来看看一个会产生 org.springframework.http.converter.HttpMessageNotWritableException: "No converter found for return value of type" 异常的示例 使用 Spring Boot 构建一个基本的 REST API。 首先,创建 Student Model 类,并假装忘记生成 Getter 方法: public class Student { private int id; private String firstName; private String lastName; private String grade; public Student() { } public Student(int id, String firstName, String lastName, String grade) { this.

REST API:JAX-RS 与 Spring

1、概览 本文将带你了解 JAX-RS 和 Spring MVC 在 REST API 开发方面的区别。 2、Jakarta RESTful Web 服务 要成为 Jakarta EE 世界的一部分,一项功能必须具备规范、兼容的实现和 TCK(技术兼容套件)。JAX-RS 就是一套用于构建 REST 服务的规范。其最著名的参考实现是 RESTEasy 和 Jersey。 现在,通过实现一个简单的 Controller 来熟悉一下 Jersey: @Path("/hello") public class HelloController { @GET @Path("/{name}") @Produces(MediaType.TEXT_PLAIN) public Response hello(@PathParam("name") String name) { return Response.ok("Hello, " + name).build(); } } 上面的代码中,端点返回一个简单的 “text/plain” 响应,这是由 @Produces 注解指定的。具体来说,暴露了一个名为 hello 的 HTTP 资源,它接受一个名为 name 的参数,使用了两个 @Path 注解进行路径的定义。还使用 @GET 注解指定它是一个 GET 请求。 3、使用 Spring MVC 实现 REST Spring MVC 是 Spring Framework 的一个模块,用于创建 Web 应用程序。它为 Spring Framework 添加了 REST 功能。

Spring 中的 @EntityScan 和 @ComponentScan 注解

1、概览 在 Spring 应用中,我们通常使用 @EntityScan 来指定实体类所在的包,使用 @ComponentScan 来指定 Bean 组件所在的包。 组件是带有 @Controller、@Service、@Repository、@Component、@Bean 等注解的类。实体则是带有 @Entity 注解的类。 本文将带你了解 @EntityScan 和 @ComponentScan 注解在 Spring 中的用法和区别。 2、@EntityScan 注解 在 Spring 中,有 2 种方式放置 @Entity 实体类: 在 main 包或者其子包下 在完全不同的 root 包中 在第一种情况下,可以使用 @EnableAutoConfiguration 来启用 Spring 自动配置 Application Context。 在第二种情况下,需要用 @EntityScan 来告诉 Spring 实体所在的包,如下。 @Configuration @EntityScan("com.baeldung.demopackage") public class EntityScanDemo { // ... } 注意,使用 @EntityScan 会禁用 Spring Boot 对实体的自动扫描配置。 3、@ComponentScan 注解 与 @EntityScan 和实体类似,如果我们希望 Spring 只使用一组特定的 Bean 类,可以使用 @ComponentScan 注解。

Spring Boot 3.2 中开箱即用的虚拟线程和 GraalVM

Spring Boot 3.2 前几天 发布 了,让我们用 Java 21、GraalVM 和 Virtual Threads(虚拟线程)来快速体验一下。 Spring Boot 3.2 支持: Java 21 虚拟线程 原生镜像(自 2022 年 11 月 Spring Boot 3.0 发布以来,Spring Boot 已在生产中支持 GraalVM 原生镜像) Java 21 2023 年 9 月 19 日 Java 21 发布。 正如宣布的那样,Java 21 在性能、稳定性和安全性方面进行了数千项改进,包括平台增强功能,这有助于开发人员提高生产力,推动整个组织的创新和发展。 Project Loom 其中一个比较重要的更新是虚拟线程(Virtual Thread),这是 Project Loom 提供的功能。具体细节这里就不多说了,你可以参考官方的 JEP:https://openjdk.org/jeps/444。 GraalVM 和 Native image GraalVM 是一款高性能 JDK,可使用另一种即时(JIT)编译器提高 Java 和基于 JVM 的应用程序的性能。 原生镜像(Native image)是一种将 Java 代码提前编译成独立可执行文件(称为原生镜像)的技术。该可执行文件包括应用程序类、其依赖项中的类、运行时库类以及 JDK 中静态链接的本地代码。