JdbcClient 是 Spring 6.1 引入的一个 Jdbc 客户端工具类,提供了 Fluent 链式调用风格的查询和更新方法,支持 JDBC 风格的位置参数和 Spring 风格的命名参数绑定。
本文将带你了解,如何在使用 JdbcClient 执行 insert 操作时返回自增 ID。
关于 JdbcClient 更多详细的用法可以参阅 “Spring 6 JdbcClient API 指南” 和 “Spring Boot 中的新 JDBC 客户端: JdbcClient”
创建数据表 在本地 MYSQL 数据库 demo 中创建一张简单的 t_user 表,如下:
CREATE TABLE `t_user` ( `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', `create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `enabled` tinyint unsigned NOT NULL COMMENT '是否启用。0:禁用,1:启用', `name` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '名字', PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`) ) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户'; 其中, id 列是自增列。
1、概览 本文将带你了解给 Spring REST API 设置请求超时的几种方法。
当资源耗时过长时,请求超时机制可以避免糟糕的用户体验。当然也可以使用断路器模式(Circuit Breaker pattern)来实现,本文不细说。
2、@Transactional 超时 在数据库调用中实现请求超时的一种方法是利用 Spring 的 @Transactional 注解。它有一个 timeout 属性可以设置。该属性的默认值是 -1,相当于没有任何超时。
例如,假设将超时设置为 30 秒。如果注解方法的执行时间超过这个秒数,就会抛出异常。这对于回滚长时间运行的数据库查询可能很有用。
编写一个非常简单的 JPA Repository,它代表一个外部服务,该服务需要太长时间才能完成并导致超时。
这个 Repository 中有一个耗时的方法:
public interface BookRepository extends JpaRepository<Book, String> { default int wasteTime() { Stopwatch watch = Stopwatch.createStarted(); // 延迟 2 秒 while (watch.elapsed(SECONDS) < 2) { int i = Integer.MIN_VALUE; while (i < Integer.MAX_VALUE) { i++; } } } } 如果在超时时间为 1 秒的事务中调用 wasteTime() 方法,超时时间将在方法执行完毕之前结束:
1、简介 本文将带你了解如何使用 Spring AOP Aspect 获取 Advise 方法的签名、参数、注解以及其他的额外信息。
2、Maven 依赖 首先,在 pom.xml 中添加 spring-boot-starter-aop Starter 依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> 3、创建 Pointcut 注解 创建一个 AccountOperation 注解,作为切面中的切点:
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AccountOperation { String operation(); } 注意,切点(Pointcut)不一定非要使用注解定义。也可以使用 Spring AOP 提供的 Pointcut 定义语言定义其他 Pointcut 类型,如类中的某些方法、以某些前缀开头的方法等。
4、创建示例 Service 4.1、Account 类 创建一个 Account POJO,带有 accountNumber 和 balance 属性。
在 service 方法中使用它作为方法参数:
public class Account { private String accountNumber; private double balance; // get/set toString方法省略 } 4.
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 类来处理数据:
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 异常的情况。
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 相同的功能。
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.
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 功能。
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 注解。
1、概览 本文将带你了解如何获取 Spring Boot 应用中的所有 REST 端点。
2、映射端点 在 Spring Boot 应用中,通过在 Controller 类中使用 @RequestMapping 注解来暴露 REST API 端点。要获取这些端点,有三种选择:事件监听器、Spring Boot Actuator 或 SpringDoc。
3、事件监听器 在 Controller 中使用 @RestController 和 @RequestMapping 创建 REST API 服务。这些类在 Spring Application Context 中注册为 Spring Bean。因此,当 Application Context 在启动时准备就绪,就可以使用事件监听器获取端点。定义监听器有两种方法。可以实现 ApplicationListener 接口,或者使用 @EventListener 注解。
3.1、ApplicationListener 接口 在实现 ApplicationListener 时,必须定义 onApplicationEvent() 方法:
@Override public void onApplicationEvent(ContextRefreshedEvent event) { ApplicationContext applicationContext = event.getApplicationContext(); RequestMappingHandlerMapping requestMappingHandlerMapping = applicationContext .getBean("requestMappingHandlerMapping", RequestMappingHandlerMapping.class); Map<RequestMappingInfo, HandlerMethod> map = requestMappingHandlerMapping .