教程

Quarkus 整合 Elasticsearch

1、概览 Quarkus 是一个现代框架,它能让你轻松高效地地构建高性能应用。 本文将带你了解如何在 Quarkus 中整合 Elasticsearch,一个著名的全文搜索引擎和 NoSQL 数据库。 2、依赖和配置 首先,你需要在本地主机上运行 Elasticsearch 实例(推荐用 Docker 的方式)。 然后,在 Quarkus 应用中添加依赖: <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-elasticsearch-rest-client</artifactId> <version>${quarkus.version}</version> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-elasticsearch-java-client</artifactId> <version>${quarkus.version}</version> </dependency> quarkus-elasticsearch-rest-client 依赖提供了底层的 Elasticsearch REST 客户端。 quarkus-elasticsearch-java-client 依赖提供了高级的 Elasticsearch Java 客户端。 在我们的应用中,可以根据需要选择使用合适的客户端。 接下来,将 Elasticsearch HOST 添加到 application.properties 文件中: quarkus.elasticsearch.hosts=localhost:9200 现在,我们可以开始在 Quarkus 应用中使用 Elasticsearch 了。ElasticsearchRestClientProducer 和 ElasticsearchJavaClientProducer 会自动创建所有必要的 Bean。 3、Elasticsearch 低级 REST 客户端 我们可以使用 Elasticsearch 低级 REST 客户端 将应用与 Elasticsearch 集成。这使得我们可以完全控制序列化和反序列化过程,并允许我们使用 JSON 构建 Elasticsearch 的查询。

在 Spring Boot 中使用 SendGrid 发送电子邮件

1、概览 无论是用户注册、密码重置还是促销活动,发送电子邮件都是现代 Web 应用的一项重要功能。 本文将带你了解如何在 Spring Boot 应用中使用 SendGrid 发送电子邮件。 2、SendGrid 设置 在开始之前,我们首先需要一个 SendGrid 账户。SendGrid 提供了免费套餐,允许我们每天发送多达 100 封电子邮件,这对于演示来说已经足够了。 注册完成后,需要创建一个 API Key 来对我们发送到 SendGrid 服务的请求进行 身份认证。 3、项目设置 在开始使用 SendGrid 发送电子邮件之前,需要添加 SDK 依赖并配置应用。 3.1、依赖 首先,在项目的 pom.xml 文件中添加 SendGrid SDK 依赖: <dependency> <groupId>com.sendgrid</groupId> <artifactId>sendgrid-java</artifactId> <version>4.10.2</version> </dependency> 该依赖为我们提供了与 SendGrid 服务交互和从应用发送电子邮件所需的类。 3.2、定义 SendGrid 配置属性 现在,为了与 SendGrid 服务交互并向用户发送电子邮件,我们需要配置 API Key 以验证 API 请求。我们还需要配置发件人姓名和电子邮件地址,它们应与我们在 SendGrid 账户中设置的发件人身份相匹配。 我们在项目的 application.yaml 文件中配置这些属性,并使用 @ConfigurationProperties 将这些值映射到 POJO,Service 层在与 SendGrid 交互时会引用配置的 POJO: @Validated @ConfigurationProperties(prefix = "com.

Hibernate 6 中序列的命名策略

1、简介 本文将带你了解如何为数据库序列(Sequences)配置 Hibernate 6 的隐式 命名策略。Hibernate 6 引入了几种新的命名策略,这些策略会影响序列的命名和使用方式。 2、标准命名策略 默认情况下,Hibernate 6 使用标准命名策略。它根据实体名称和列名称生成序列名称。假如,我们有一个带有 id 列的实体 Person,那么序列名称就是 person_seq。 要修改命名策略,需要在 application.properties 中为不同的命名策略添加必要的配置。 # 使用标准命名策略 spring.jpa.properties.hibernate.id.db_structure_naming_strategy=standard 下面介绍如何为每种命名策略设置配置。 来看一个基本的 Person 实体类: @Entity public class Person { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) private Long id; private String name; // Getter / Setter 省略 } 在本例中,由于我们使用的是标准策略,因此在建表的同时,Hibernate 会自动生成一个名为 person_seq 的序列: Hibernate: create table person ( id bigint not null, name varchar(255), primary key (id) ) Hibernate: create sequence person_seq start with 1 increment by 50 标准策略的一个关键点是其默认增量(increment)值。Hibernate 会分配一个较大的值,如 50,以优化批处理操作,减少序列检索所需的数据库调用次数。

MyBatis Plus 简介

1、简介 MyBatis 是一个流行的开源持久性框架,提供了 JDBC 和 Hibernate 的替代方案。 本文将带你了解 MyBatis 的一个扩展,名为 MyBatis-Plus,它具有许多方便的功能,可以大大地提高我们的开发效率。 2、MyBatis-Plus 整合 2.1、Maven 依赖 首先,在 pom.xml 中添加以下 Maven 依赖。 <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-spring-boot3-starter</artifactId> <version>3.5.7</version> </dependency> 最新版本的 Maven 依赖可在 此处 找到。由于这是基于 Spring Boot 3 的 Maven 依赖,我们还需要在 pom.xml 中添加 spring-boot-starter 依赖。 如果使用的是 Spring Boot 2,则需要添加以下依赖: <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.7</version> </dependency> 接着,在 pom.xml 中添加 H2 内存数据库依赖,用于验证 MyBatis-Plus 的特性和功能。 <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>2.3.230</version> </dependency> 同样,H2 的最新版本可以在 这里 找到。除了 H2 外,我们还可以使用 MySQL 等其他关系型数据库。 2.2、Client 依赖添加完毕后,创建 Client 实体,其中包含一些属性,如 id、firstName、lastName 和 email:

Spring AI 拥抱 OpenAI 的结构化输出:增强 JSON 响应的可靠性

OpenAI 最近 推出了 一项名为 “结构化输出”(Structured Outputs)的强大功能,可确保 AI 生成的响应严格遵守预定义的 JSON Schema。这一功能大大提高了 AI 生成的内容在实际应用中的可靠性和可用性。 Spring AI(1.0.0-SNAPSHOT) 已 完全集成 了对 OpenAI 的结构化输出的支持,以一种无缝的 Spring 原生方式为 Java 开发人员带来了这一功能。 下图显示了新的结构化输出功能如何扩展 OpenAI Chat API: 注:Spring AI 已经提供了 功能强大、与模型无关的结构化输出 工具,可用于包括 OpenAI 在内的各种 AI 模型。OpenAI 结构化输出功能提供了一个额外的、一致的、但针对特定模型的解决方案,目前仅适用于 gpt-4o、gpt-4o-mini 和更高版本的模型。 OpenAI 结构化输出功能可确保 AI 模型生成的响应符合所提供的 JSON Schema。这解决了 AI 驱动的应用程序中的几个常见难题: 类型安全:不再担心缺少必填 KEY 或枚举值无效; 明确拒绝:基于安全性的模型拒绝变得可以通过编程检测到; 简化的提示:实现一致的格式化,而无需使用过于具体的 Prompt(提示)。 Spring AI 允许开发人员以最少的配置利用这一功能。接下来看看如何在 Spring 应用中使用它。 编程式配置 你可以使用 OpenAiChatOptions Builder 以编程式设置响应格式,如下所示: String jsonSchema = """ { "type": "object", "properties": { "steps": { "type": "array", "items": { "type": "object", "properties": { "explanation": { "type": "string" }, "output": { "type": "string" } }, "required": ["explanation", "output"], "additionalProperties": false } }, "final_answer": { "type": "string" } }, "required": ["steps", "final_answer"], "additionalProperties": false } """; Prompt prompt = new Prompt("how can I solve 8x + 7 = -23", OpenAiChatOptions.

包含所有 HTTP 状态码的 Java 枚举

1、简介 Enum(枚举)提供了一种在 Java 编程语言中定义一组命名常量的强大方法。这些常量可用于表示相关值的固定集合,例如 HTTP 状态码。总所周知,互联网上的所有 Web 服务器都会响应 HTTP 状态码作为标准响应码。 本文将带你了解如何创建一个包含所有 HTTP 状态码的 Java 枚举。 2、了解 HTTP 状态码 HTTP 状态码在 Wweb 通信中起着至关重要的作用,它能告知客户端其请求的结果。这些代码分为五类,每一类在 HTTP 协议中都有特定的功能。 3、HTTP 状态码使用枚举的好处 在 Java 中枚举 HTTP 状态码有几个优点,包括: 类型安全:使用 Enum 枚举可确保类型安全,使代码更具可读性和可维护性 分组常量:Enum 枚举将相关常量组合在一起,以清晰和结构化的方式处理固定值集合 避免硬编码:将 HTTP 状态码定义为枚举,有助于防止硬编码字符串或整数造成的错误 增强清晰度和可维护性:这种方法通过增强清晰度、减少错误和提高代码的可维护性,促进软件开发的最佳实践 4、基本做法 为了在 Java 应用中有效管理 HTTP 状态码,我们可以定义一个枚举来封装所有标准 HTTP 状态码及其描述。 这种方法可以让我们充分利用枚举类型安全和代码清晰的优势。 定义 HttpStatus 枚举: public enum HttpStatus { CONTINUE(100, "Continue"), SWITCHING_PROTOCOLS(101, "Switching Protocols"), OK(200, "OK"), CREATED(201, "Created"), ACCEPTED(202, "Accepted"), MULTIPLE_CHOICES(300, "Multiple Choices"), MOVED_PERMANENTLY(301, "Moved Permanently"), FOUND(302, "Found"), BAD_REQUEST(400, "Bad Request"), UNAUTHORIZED(401, "Unauthorized"), FORBIDDEN(403, "Forbidden"), NOT_FOUND(404, "Not Found"), INTERNAL_SERVER_ERROR(500, "Internal Server Error"), NOT_IMPLEMENTED(501, "Not Implemented"), BAD_GATEWAY(502, "Bad Gateway"), UNKNOWN(-1, "Unknown Status"); private final int code; private final String description; HttpStatus(int code, String description) { this.

删除 Spring Security 中的 ROLE_ 前缀

1、概览 在配置应用的安全设置时,用户的详细信息可能未包括 Spring Security 预期的 ROLE_ 前缀。这种情况下会导致 “Forbidden” 授权错误,无法访问受保护端点。 本文将带你了解如何配置 Spring Security,以允许使用不带 ROLE_ 前缀的角色。 2、Spring Security 默认行为 首先来看看 Spring Security 角色检查机制的默认行为。 添加一个 InMemoryUserDetailsManager,其中包含一个具有 ADMIN 角色的用户: @Configuration public class UserDetailsConfig { @Bean public InMemoryUserDetailsManager userDetailsService() { UserDetails admin = User.withUsername("admin") .password(encoder().encode("password")) .authorities(singletonList(new SimpleGrantedAuthority("ADMIN"))) .build(); return new InMemoryUserDetailsManager(admin); } @Bean public PasswordEncoder encoder() { return new BCryptPasswordEncoder(); } } 如上,创建 UserDetailsConfig 配置类,该类配置了一个 InMemoryUserDetailsManager Bean。在工厂方法内部,使用 PasswordEncoder 来处理用户详细信息的密码。 接着,添加要调用的端点: @RestController public class TestSecuredController { @GetMapping("/test-resource") public ResponseEntity<String> testAdmin() { return ResponseEntity.

Java 中的 Class.cast() 方法和 Cast(转换)操作符

1、简介 Java 中的转换(“Cast”)是一个基本概念,它允许将一种数据类型转换为另一种数据类型。它是在程序中有效操作对象和变量的关键过程。在现实世界中,“Cast” 类似于将一种单位的度量值转换为另一种单位的度量值,例如将英寸转换为厘米。 在 Java 的多态(Polymorphism)中,当超类引用子类的对象时,经常会使用到转换。例如,我们需要访问子类的特定方法或属性,就需要依靠转换来实现。这一点非常重要,因为 Java 是一种强类型语言,变量具有特定的数据类型。 本文将带你了解 Java Class.cast() 方法和 Cast(强转)操作符两个选项用法和差别,以及每个选项的最佳实践。 2、定义用例 以一个视频游戏角色的层次结构为例。 创建一个包含了超类 Character(角色)和子类 Warrior(战士)、Commander(指挥官)的示例。 该用例涉及创建 Warrior 和 Commander 的实例。这些实例存储在 Character 对象类型的集合中。之后,它们会被检索并转换回各自的特定类型。这种转换允许调用特定子类的方法。 3、定义 Model 类 首先,定义第一个继承自 Character 的子类,即实现了 obeyCommand() 方法的 Warrior: public class Warrior extends Character { public void obeyCommand(String command) { logger.info("Warrior {} obeys a command {}", this.getName(), command); } } 然后,创建 Character 的第二个子类,即 Commander。这个子类实现了一个 issueCommand() 方法,可以向战士们发布命令: public class Commander extends Character { public void issueCommand(String command) { log.

调整 JDBC 连接池大小的最佳实践

1、简介 本文将带你了解调整 JDBC 连接池大小的最佳策略。 2、什么是 JDBC 连接池,为什么要使用它? JDBC 连接池是一种用于有效管理数据库连接的机制。创建数据库连接需要几个耗时的步骤,如 打开数据库连接 验证用户身份 创建用于通信的 TCP Sokcet 套接字 通过套接字收发数据 关闭连接和 TCP Sokcet 套接字 为每个用户请求重复这些步骤的效率可能会很低,尤其是对于有许多用户的应用。JDBC 连接池通过提前创建一个可重复使用的连接池来解决这个问题。当应用程序启动时,它会在池中创建并维护数据库连接。池连接管理器负责管理这些连接并处理其生命周期。 当客户端请求连接时,连接池管理器会从连接池中提供一个连接,而不是创建一个新的连接。一旦客户端完成操作,连接就会返回池中重复使用,而不是关闭。这种连接的重复使用节省了时间和资源,大大提高了应用程序的性能。 3、为什么 JDBC 连接池的大小对应用来说很重要? 确定 JDBC 连接池的最佳大小对于平衡性能和资源利用率至关重要。较小的连接池可能会加快连接访问速度,但如果没有足够的连接来满足所有请求,则可能导致延迟。相反,较大的连接池可确保有更多连接可用,减少在队列中花费的时间,但可能会降低连接表的访问速度。 “连接表” 通常指的是管理和跟踪数据库连接的内部数据结构。它记录了当前连接的状态(如空闲、使用中等)以及相关的元数据,以便有效地分配和管理连接。这个“表”并不是数据库中的实际表,而是连接池实现中的一个逻辑概念。 下表总结了在确定连接池大小时需要考虑的利弊: 连接池大小 优点 缺点 较小的连接池 更快地访问连接表 可能需要更多连接来满足请求。请求在队列中停留的时间可能会更长 较大的连接池 有更多连接来满足请求。请求在队列中花费的时间减少(或没有) 降低访问连接表的速度 4、确定 JDBC 连接池大小时应考虑的要点 在确定池大小时,需要考虑几个因素。首先,应该评估平均事务响应时间和花费在数据库查询上的时间。负载测试可以帮助确定这些时间,建议在计算连接池大小时再增加 25% 的容量,以应对意外负载。其次,连接池应能根据实际需要进行增减。我们可以使用日志或 JMX 监视来监控系统,从而动态调整池的大小。 此外,还应考虑每次页面加载执行多少次查询以及每次查询的持续时间。为了获得最佳性能,我们可以从少量连接开始,然后逐渐增加。每个节点 8 到 16 个连接的池通常是最佳的。我们还可以根据监控统计数据调整空闲超时(Idle Timeout)和池大小调整数量(Pool Resize Quantity)值。 5、JDBC 连接池的基本控制设置 这些基本设置可控制池的大小: 连接池属性 说明 初始和最少连接数 池创建时的大小及其允许的最小连接数量 池最大连接数 连接池可维护的最大连接数量 池大小调整数量 空闲超时时要移除的连接数。闲置时间超过超时的连接将被移除,一旦连接池达到初始和最小连接池大小,就会停止移除。 最大空闲连接数 池中允许的最大闲置连接数。如果闲置连接数超过此限制,多余的连接将被关闭,从而释放资源 最小空闲连接数 在连接池中保留的空闲连接的最小数量 最大等待时间 应用等待连接可用的最长时间 验证查询 用于验证连接的 SQL 查询,然后再将其交给应用 6、调整 JDBC 连接池大小的最佳实践 以下是调整 JDBC 连接池以确保与数据库实例之间健康连接的一些最佳实践。

在 Spring Boot 中使用 ProblemDetail 返回错误

1、简介 本文将带你了解如何在 Spring Boot 应用中使用 ProblemDetail 响应错误信息,无论我们处理的是 REST API 还是 Reactive Stream(响应式流),它都提供了一种向客户端传达错误的标准化方式。 2、为什么要关注 ProblemDetail? 使用 ProblemDetail 来标准化错误响应对任何 API 都至关重要。 它可以帮助客户理解和处理错误,提高 API 的可用性和可调试性。这将带来更好的开发体验和更强大的应用。 采用它还有助于提供更翔实的错误信息,这对维护我们的服务和排除故障至关重要。 3、传统的错误处理方式 在 ProblemDetail 之前,我们经常在 Spring Boot 中实现自定义 ExceptionHandler 和 ResponseEntity 来处理错误。我们会创建自定义的错误响应结构。这导致了不同 API 之间的不一致性。 这种方式不仅需要大量的模板代码。而且,缺乏表示错误的标准化方式,因此客户端很难统一解析和理解错误信息。 4、ProblemDetail 规范 ProblemDetail 规范是 RFC 7807 标准的一部分。它为错误响应定义了一致的结构,包括诸如类型(type)、标题(title)、状态(status)、详情(detail)和实例(instance)等字段。这种标准化提供了一个通用的错误信息格式,有助于 API 开发人员和使用者。 实现 ProblemDetail 可确保我们的错误响应具有可预测性并易于理解。这反过来提高了我们的 API 和其客户端之间的整体沟通效果。 5、在 Spring Boot 中实现 ProblemDetail 在 Spring Boot 中有多种方法可以实现 ProblemDetail。 5.1、通过配置属性启用 ProblemDetail 我们可以添加一个配置属性来启用它。对于 RESTful 服务,在 application.properties 中添加以下属性: spring.mvc.problemdetails.enabled=true 此属性可使 ProblemDetail 自动用于基于 MVC(servlet 栈)的应用中的错误处理。