Spring

Linux 与 Spring 中 Cron 的区别

1、概览 通过 Cron 表达式,我们可以安排任务在特定日期和时间定期运行。Cron 表达式在 Unix 中推出后,其他基于 Unix 的操作系统和软件库(包括 Spring)都采用了它的任务调度方法。 本文将带你了解基于 Unix 操作系统的 Cron 表达式与 Spring Cron 之间的区别。 2、Unix Cron 在大多数基于 Unix 的系统中,Cron 有五个字段:分钟(0-59)、小时(0-23)、月日(1-31)、月份(1-12 或名称)和星期(0-7 或名称)。 可以在每个字段中添加一些特殊值,如星号(*): 5 0 * * * 任务将在每天午夜后 5 分钟执行。也可以使用数值范围: 5 0-5 * * * 如上,调度器将在午夜 12 点后 5 分钟执行任务,并在每天 1 点、2 点、3 点、4 点和 5 点后 5 分钟执行任务。 或者,可以使用一个值列表: 5 0,3 * * * 现在,调度器会在每天午夜 12 点后 5 分钟和下午 3 点后 5 分钟执行作业。原始 Cron 表达式提供的功能远不止这些。

如果 @PathVariable 包含点(.),会被截断

1、概览 使用 Spring 的 @PathVariable 和 @RequestMapping 来映射包含点的请求时,最后一个 URI 路径变量的值被会截断。 2、原因 具体来说,Spring 认为最后一个点后面的任何内容都是文件扩展名,如 .json 或 .xml,因此,它会截断值以检索路径变量。 来看一个使用路径变量的例子: @RestController public class CustomController { @GetMapping("/example/{firstValue}/{secondValue}") public void example(@PathVariable("firstValue") String firstValue, @PathVariable("secondValue") String secondValue) { // ... } } 如上,考虑以下请求 URL 以及 firstValue 和 secondValue 变量的值: example/gallery/link:firstValue = "gallery",secondValue = "link"。 example/gallery.df/link.ar URL:firstValue = "gallery.df ",secondValue = "link" example/gallery.df/link.com.ar:firstValue = "gallery.df",secondValue = "link.com" 可以看到,第一个变量不受影响,但第二个带点(.)的变量总是被截断。 3、解决办法 解决这种不便的方法之一是修改 @PathVariable 定义,添加一个 regex(正则)映射。这样,任何点(包括最后一个点)都将被视为参数的一部分: @GetMapping("/example/{firstValue}/{secondValue:.+}") public void example( @PathVariable("firstValue") String firstValue, @PathVariable("secondValue") String secondValue) { //.

Spring 中的 @PathVariable 注解

1、概览 本文将带你了解 Spring 中 @PathVariable 注解的作用和用法。 简单地说,@PathVariable 注解可用于处理请求 URI 映射中的模板变量,并将其绑定到 Controller 方法参数。 2、示例映射 @PathVariable 注解的一个简单用例是用于标识具有 ID 的实体的端点: @GetMapping("/api/employees/{id}") @ResponseBody public String getEmployeesById(@PathVariable String id) { return "ID: " + id; } 在本例中,使用 @PathVariable 注解来提取 URI 的模板部分,该部分由变量 {id} 表示。 调用示例如下: http://localhost:8080/api/employees/111 ---- ID: 111 3、指定 PATH (路径)变量名 在上一个示例中,由于方法参数和路径变量的名称相同,可以不用主动设置模板路径变量的名称。 如果路径变量名不同,可以在 @PathVariable 注解的参数中指定: @GetMapping("/api/employeeswithvariable/{id}") @ResponseBody public String getEmployeesByIdWithVariableName(@PathVariable("id") String employeeId) { return "ID: " + employeeId; } 测试如下: http://localhost:8080/api/employeeswithvariable/1 ---- ID: 1 为了清晰起见,还可以将路径变量名定义为 @PathVariable(value="id"),而不是 PathVariable("id")。

Spring MVC Async 和 WebFlux

1、概览 本文将带你了解 Spring Async 和 Spring WebFlux 之间的区别。 2、场景 本文分别用 Spring Async 和 Spring WebFlux 来实现一个简单的 Web 应用。 Web 请求会通过一个延迟时间为 200 毫秒的 Filter,然后 Controller 需要 500 毫秒来计算并返回结果。 最后使用 Apache ab 分别进行负载测试,并使用 JConsole 监控应用的行为。 3、Spring MVC Async Spring 3.0 引入了 @Async 注解。@Async 的目标是允许应用在单独的线程上运行重负载的任务。此外,调用方可以等待结果(如果感兴趣)。因此,返回类型不能是void,而可以是 Future、CompletableFuture 或 ListenableFuture 之一。 Spring 3.2 引入了 org.springframework.web.context.request.async 包,它与 Servlet 3.0 一起为 Web 层带来了异步的支持。因此,自 Spring 3.2 起,@Async 可以在 @Controller 或 @RestController 类中使用。 当客户端发起请求时,请求会经过过滤器链(filter chain)中所有匹配的过滤器(filter),直到到达 DispatcherServlet 实例。 然后,Servlet 会对请求进行异步调度。它通过调用 AsyncWebRequest#startAsync 将请求标记为已启动,将请求处理转移到 WebSyncManager 的实例,然后在不提交响应的情况下完成其工作。过滤器链也按相反的方向遍历执行到根节点。

Spring 中的 @ConditionalOnProperty 注解

1、概览 本文将带你了解 Spring 中 @ConditionalOnProperty 注解的作用和用法。 2、@ConditionalOnProperty 的作用 通常,在开发基于 Spring 的应用时,需要根据配置属性是否存在,或者配置属性有指定的值来有条件地创建一些 Bean。 例如,我们需要注册一个 DataSource Bean,并且要根据属性值设置为 prod 还是 test 来创建生产数据库或测试数据库。 这正是 @ConditionalOnProperty 注解的用武之地。 简而言之,@ConditionalOnProperty 只有在环境属性存在且具有指定值的情况下才会启用 Bean 注册。默认情况下,指定的属性必须已定义且等于指定的值。 熟悉了 @ConditionalOnProperty 注解的用途后,接着来深入了解一下如何使用。 3、@ConditionalOnProperty 注解实践 开发一个基本的电子邮件通知系统来示范 @ConditionalOnProperty 的使用。 首先,创建一个简单的服务来发送通知消息。 定义 NotificationSender 接口: public interface NotificationSender { String send(String message); } 接下来,提供一个 NotificationSender 接口的实现来发送电子邮件: public class EmailNotification implements NotificationSender { @Override public String send(String message) { return "Email Notification: " + message; } } 现在,来看看如何使用 @ConditionalOnProperty 注解。

Spring 中的 @DynamicPropertySource 注解

1、概览 当代应用通常需要连接到各种外部服务,如 PostgreSQL、Apache Kafka、Cassandra、Redis 和其他外部 API。 本文将带你了解 Spring 如何通过引入动态属性(@DynamicPropertySource)来帮助测试此类应用。 2、问题:动态属性 假设我们正在开发一个使用 PostgreSQL 作为数据库的应用。 创建 JPA 实体: @Entity @Table(name = "articles") public class Article { @Id @GeneratedValue(strategy = IDENTITY) private Long id; private String title; private String content; // get、set 省略 } 我们需要编写测试来确保应用按预期运行,由于该测试需要与真实数据库创建连接,我们应该事先建立一个 PostgreSQL 实例。 在测试执行过程中,有不同的方法来设置此类基础工具。事实上,这类解决方案主要有三类: 专门为测试设置一个单独的数据库服务器 使用一些轻量级的、测试专用的替代品,如 H2 让测试本身管理数据库的生命周期 由于未区分测试环境和生产环境,与使用 H2 等测试替身相比,有更好的选择。第三个选项不仅可以与真实数据库一起使用,还可以为测试提供更好的隔离性。此外,借助 Docker 和 Testcontainers 等技术,实现第三个选项非常容易。 如果使用 Testcontainers 等技术,测试流程如下: 在所有测试前设置 PostgreSQL 等组件。通常,这些组件会监听随机端口。 运行测试。 卸载组件。 如果 PostgreSQL 容器每次都监听随机端口,那么我们就应该以某种方式动态设置和更改 spring.datasource.url 配置属性。基本上,每个测试都应该有自己的配置属性版本。 当配置是静态的时候,可以使用 Spring Boot 的配置管理工具轻松地对其进行管理。但是,当我们面对的是动态配置时,同样的任务就会变得比较麻烦。

Spring 中的事件(Event)机制

1、Spring 事件机制 有的人可能会觉得 Spring 中的事件机制很神奇,一个地方发消息,另一个地方收消息,跟 MQ 一样。其实,Spring 中的事件本质上就是观察者模式的应用。事件有其便利的一面,但是用多了也容易导致混乱,所以在实际项目中,我们还是要谨慎选择是否使用 Spring 事件。 2、简单实践 先用一个简单的案例,来让大家了解一下 Spring 中事件的应用。 事件发布流程中,有三个核心概念,它们之间的关系如下图: 事件源(ApplicationEvent):这个就是你要发布的事件对象。 事件发布器(ApplicationEventPublisher):这是事件的发布工具。 事件监听器(ApplicationListener):这个相当于是事件的消费者。 以上三个要素,事件源和事件监听器都可以有多个,事件发布器(通常是由容器来扮演)一般来说只有一个。 接下来,让我们通过一个简单的案例来演示一下 Spring 中事件的用法。 首先,我们需要自定义一个事件对象,自定义的事件继承自 ApplicationEvent 类,如下: public class MyEvent extends ApplicationEvent { private String name; public MyEvent(Object source, String name) { super(source); this.name = name; } @Override public String toString() { return "MyEvent{" + "name='" + name + '\'' + "} " + super.toString(); } } 这里只额外定义了一个 name 属性,如果大家在事件发送的时候需要传递的数据比较多,那么就可以在这里定义更多的属性。 在具体实践中,事件源并非一定要继承自 ApplicationEvent,事件源也可以是一个普通的 Java 类,如果是普通的 Java 类,系统会自动将之封装为一个 PayloadApplicationEvent 对象去发送。

Spring 中 @Valid 和 @Validated 注解的区别

1、概览 本文将带你了解 Spring 中 @Valid 和 @Validated 注解的用法和它们之间的区别。 在大多数应用中,验证用户输入是常见的功能。在 Java 生态系统中,一般使用 Java Standard Bean Validation API 来支持这一点,从 Spring 4.0 版本开始,它就与 Spring 完美集成。@Valid 和 @Validated 注解就源自于这个 Standard Bean API。 2、@Valid 和 @Validated 注解 在 Spring 中,通常使用 JSR-303 的 @Valid 注解进行方法级验证,以及用于标记成员属性以进行验证。不过,该注解不支持分组验证。 分组(Group)可以帮助限制在验证过程中应用的约束条件。一个特定的使用案例是 UI 引导(UI wizards)。在第一步中,可能会有一组特定的字段。在后续步骤中,可能还有同一个 Bean 的另一组字段。因此,需要在每个步骤中对这些有限的字段应用约束条件,但是 @Valid 无法支持这样的功能。 对于分组级(Group-Level)验证,必须使用 Spring 的 @Validated,它是 JSR-303 的 @Valid 的变体,用于方法级。对于成员属性的标记,继续使用 @Valid 注解就行。 3、示例 使用 Spring Boot 开发一个简单的用户注册表单。 首先,只有 name 和 password 属性: public class UserAccount { @NotNull @Size(min = 4, max = 15) private String password; @NotBlank private String name; // 构造函数、Get、Set 省略 } 接下来是 Controller。在 saveBasicInfo 方法参数上使用 @Valid 注解来验证用户输入:

Spring MVC 处理 JSON 参数

1、概览 本文将带你了解如何在 Spring MVC 中处理 POST 和 GET 请求中发送 JSON 参数。 2、Spring MVC 中的 JSON 参数 使用 JSON 发送或接收数据是 Web 开发人员的常见做法。JSON 字符串的分层结构为 HTTP 请求参数提供了一种更紧凑、更易于人类阅读的表示方式。 默认情况下,Spring MVC 通过了一系列内置的底层 Property Editor 为 String 等简单数据类型提供开箱即用的数据绑定。 但是,在实际项目中,可能需要绑定更复杂的数据类型。例如:将 JSON 参数映射到 Model Object。 3、使用 POST 请求发送 JSON Spring 提供了一种简单的方式来处理 POST 请求发送 JSON 数据。内置的 @RequestBody 注解可以自动将请求体中的 JSON 数据反序列化为特定的 Model 对象。 通常情况下,无需自己解析请求体,Spring MVC 会使用 Jackson 库来完成所有的工作。 首先,创建一个 Model 对象来表示传递的 JSON 数据。例如 Product 类: public class Product { private int id; private String name; private double price; // 构造函数、get、set 方法省略 } 其次,定义一个接受 POST 请求的 Spring Handler 方法:

以 String 形式读取 HTTP 响应体

1、简介 本文介绍了以字符串形式读取 HTTP 响应体的几种方式。 2、HttpClient Java 11 中添加了 HttpClient,用于访问 Web 资源。与 HttpURLConnection 不同的是,HttpClient 除了支持 HTTP/1.1 和 HTTP/2 外,它还提供同步和异步请求类型。 HttpClient 提供了一个现代化的 API,具有很大的灵活性和强大的功能。该 API 由三个核心类组成:HttpClient、HttpRequest 和 HttpResponse。 HttpResponse 描述了 HttpRequest 调用的结果。HttpResponse 并非直接创建,而是在完全接收到正文(Body)后才可用。 首先创建 HttpClient 和 HttpRequest 对象: HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(DUMMY_URL)) .build(); 然后,使用 BodyHandlers 并调用 ofString() 方法返回 String 响应: HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); 3、HttpURLConnection HttpURLConnection 是一个轻量级 HTTP 客户端,用于通过 HTTP 或 HTTPS 协议访问资源,它允许创建一个 InputStream。获得 InputStream 后,就可以像读取普通本地文件一样读取它。 在 Java 中,可以用来访问互联网的主要类是 java.