1、概览 本文将带你了解从 Kafka 命令行(CLI)发送 Key/Value 消息的两种方法。
在处理金融交易、预订、在线购物等实时事件驱动系统中,确保特定 Topic 上消息的有序性是一个常见需求。在这种情况下,我们应该为发送到这些 Topic 的事件使用 Kafka Message Key。
2、先决条件 首先,需要一个正在运行的 Kafka 实例。如果没有,可以使用 Kafka Docker 或根据 Kafka 快速入门指南 建立一个环境。下面的章节将假定我们已经有一个运行中的 Kafka 实例,且可以通过 kafka-server:9092 访问。
接下来,假设我们开发的是一个 “支付系统”,而且需要从命令行发送消息。
以下是对应的 Model 类:
// 支付事件 public class PaymentEvent { private String reference; private BigDecimal amount; private Currency currency; // 标准的 Getter / Setter 方法 } 另一个前提条件是要有访问 Kafka CLI 工具的权限,这很简单。首先,下载 Kafka 发行版,然后解压下载的文件,并进入解压后的文件夹中。在 bin 文件夹下就可以找到 Kafka CLI 工具。
本文后面内容中的所有 CLI 命令,都假设是在 Kafka 解码文件夹下执行的。
Spring AI 现在支持 NVIDIA®(英伟达™)的 大型语言模型 API,可与各种 模型 集成。通过利用 NVIDIA 的 OpenAI 兼容 API,Spring AI 允许开发人员通过熟悉的 Spring AI API 使用 NVIDIA LLM。
本文将带你了解如何配置和使用 Spring AI OpenAI 聊天客户端来连接 NVIDIA LLM API。
完整的示例代码可从 nvidia-llm GitHub 仓库获取。 SpringAI / NVIDIA 整合文档。 先决条件 创建 NVIDIA 帐户并获得足够的积分。 从 NVIDIA 提供的 LLM 模型 中选择自己喜欢的模型。如下面截图中的 meta/llama-3.1-70b-instruct。 从模型页面获取所选模型的 API Key。 依赖 首先,将 Spring AI OpenAI Starter 添加到 Maven pom.xml 中:
<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-openai-spring-boot-starter</artifactId> </dependency> 对于 Gradle 来说,需要在 build.gradle 添加如下依赖:
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 的查询。
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.
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,以优化批处理操作,减少序列检索所需的数据库调用次数。
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:
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.
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.
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.
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.