Using the Redis Client
本指南演示了 Quarkus 应用程序如何使用 Redis 客户端扩展连接到 Redis 服务器。 :iokays-category: quarkus :iokays-path: modules/ROOT/pages/_includes/extension-status.adoc :keywords: Quarkus, 中文文档, 编程技术
该技术被认为是 {extension-status}。 有关可能状态的完整列表,请查看我们的 FAQ entry. |
- Prerequisites
- Architecture
- Solution
- Creating the Maven Project
- Creating the Increment POJO
- Creating the Increment Service
- Creating the Increment Resource
- Creating the test class
- Get it running
- Interacting with the application
- Configuring for production
- Packaging and running in JVM mode
- Running Native
- Going further
Architecture
在本指南中,我们将公开一个简单的 Rest API 来使用 INCRBY
命令递增数字。同时,我们将了解如何使用其他 Redis 命令,如 GET
、SET
(来自字符串组)、DEL
和 KEYS
(来自键组)。
我们将使用 Quarkus Redis 扩展来连接和与 Redis 交互。
Solution
我们建议您遵循接下来的部分中的说明,按部就班地创建应用程序。然而,您可以直接跳到完成的示例。
克隆 Git 存储库: git clone $${quickstarts-base-url}.git
,或下载 $${quickstarts-base-url}/archive/main.zip[存档]。
解决方案位于 redis-quickstart
directory 中。
Creating the Maven Project
首先,我们需要一个新项目。使用以下命令创建一个新项目:
quarkus create app {create-app-group-id}:{create-app-artifact-id} \
--no-code
cd {create-app-artifact-id}
要创建一个 Gradle 项目,添加 --gradle
或 --gradle-kotlin-dsl
选项。
有关如何安装和使用 Quarkus CLI 的详细信息,请参见 Quarkus CLI 指南。
mvn {quarkus-platform-groupid}:quarkus-maven-plugin:{quarkus-version}:create \
-DprojectGroupId={create-app-group-id} \
-DprojectArtifactId={create-app-artifact-id} \
-DnoCode
cd {create-app-artifact-id}
要创建一个 Gradle 项目,添加 -DbuildTool=gradle
或 -DbuildTool=gradle-kotlin-dsl
选项。
适用于 Windows 用户:
-
如果使用 cmd,(不要使用反斜杠
\
,并将所有内容放在同一行上) -
如果使用 Powershell,将
-D
参数用双引号引起来,例如"-DprojectArtifactId={create-app-artifact-id}"
此命令会生成一个新项目,导入 Redis 扩展。
如果您已经配置了您的 Quarkus 项目,则可以通过在项目的根目录中运行以下命令将 @"1" 扩展添加到您的项目:
quarkus extension add {add-extension-extensions}
./mvnw quarkus:add-extension -Dextensions='{add-extension-extensions}'
./gradlew addExtension --extensions='{add-extension-extensions}'
这会将以下内容添加到构建文件中:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-redis-client</artifactId>
</dependency>
implementation("io.quarkus:quarkus-redis-client")
Creating the Increment POJO
我们将使用 @"2" POJO 来建模我们的增量。创建 @"3" 文件,内容如下:
package org.acme.redis;
public class Increment {
public String key; (1)
public long value; (2)
public Increment(String key, long value) {
this.key = key;
this.value = value;
}
public Increment() {
}
}
1 | 用作 Redis 密钥的密钥 |
2 | Redis 密钥保存的值 |
Creating the Increment Service
我们将创建一个 @"4" 类,其将发挥 Redis客户端的作用。有了这个类,我们将能够执行 @"5"、@"6"、@"7"、@"8" 和 @"9" Redis 命令。
创建 @"10" 文件,内容如下:
package org.acme.redis;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import io.quarkus.redis.datasource.ReactiveRedisDataSource;
import io.quarkus.redis.datasource.RedisDataSource;
import io.quarkus.redis.datasource.keys.KeyCommands;
import io.quarkus.redis.datasource.keys.ReactiveKeyCommands;
import io.quarkus.redis.datasource.string.StringCommands;
import io.smallrye.mutiny.Uni;
@ApplicationScoped
public class IncrementService {
// This quickstart demonstrates both the imperative
// and reactive Redis data sources
// Regular applications will pick one of them.
private ReactiveKeyCommands<String> keyCommands; (1)
private ValueCommands<String, Long> countCommands; (2)
public IncrementService(RedisDataSource ds, ReactiveRedisDataSource reactive) { (3)
countCommands = ds.value(Long.class); (4)
keyCommands = reactive.key(); (5)
}
long get(String key) {
Long value = countCommands.get(key); (6)
if (value == null) {
return 0L;
}
return value;
}
void set(String key, Long value) {
countCommands.set(key, value); (7)
}
void increment(String key, Long incrementBy) {
countCommands.incrby(key, incrementBy); (8)
}
Uni<Void> del(String key) {
return keyCommands.del(key) (9)
.replaceWithVoid();
}
Uni<List<String>> keys() {
return keyCommands.keys("*"); (10)
}
}
1 | 用于操作密钥的字段 |
2 | 用于操作计数器的字段 |
3 | 注入命令式和响应式数据源 |
4 | 检索用于操作计数器的命令 |
5 | 检索用于操作密钥的命令 |
6 | 检索与给定密钥相关的值。 如果 @"11",则返回 0。 |
7 | 设置与给定密钥相关的值 |
8 | 递增与给定密钥相关的值 |
9 | 删除密钥(及其相关值) |
10 | List all the keys |
Creating the Increment Resource
创建 @"12" 文件,内容如下:
package org.acme.redis;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.DELETE;
import java.util.List;
import io.smallrye.mutiny.Uni;
@Path("/increments")
public class IncrementResource {
@Inject
IncrementService service;
@GET
public Uni<List<String>> keys() {
return service.keys();
}
@POST
public Increment create(Increment increment) {
service.set(increment.key, increment.value);
return increment;
}
@GET
@Path("/{key}")
public Increment get(String key) {
return new Increment(key, service.get(key));
}
@PUT
@Path("/{key}")
public void increment(String key, long value) {
service.increment(key, value);
}
@DELETE
@Path("/{key}")
public Uni<Void> delete(String key) {
return service.del(key);
}
}
Creating the test class
编辑 pom.xml
文件以添加以下依赖项:
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
创建 @"13" 文件,内容如下:
package org.acme.redis;
import static org.hamcrest.Matchers.is;
import org.junit.jupiter.api.Test;
import io.quarkus.test.junit.QuarkusTest;
import static io.restassured.RestAssured.given;
import io.restassured.http.ContentType;
@QuarkusTest
public class IncrementResourceTest {
@Test
public void testRedisOperations() {
// verify that we have nothing
given()
.accept(ContentType.JSON)
.when()
.get("/increments")
.then()
.statusCode(200)
.body("size()", is(0));
// create a first increment key with an initial value of 0
given()
.contentType(ContentType.JSON)
.accept(ContentType.JSON)
.body("{\"key\":\"first-key\",\"value\":0}")
.when()
.post("/increments")
.then()
.statusCode(200)
.body("key", is("first-key"))
.body("value", is(0));
// create a second increment key with an initial value of 10
given()
.contentType(ContentType.JSON)
.accept(ContentType.JSON)
.body("{\"key\":\"second-key\",\"value\":10}")
.when()
.post("/increments")
.then()
.statusCode(200)
.body("key", is("second-key"))
.body("value", is(10));
// increment first key by 1
given()
.contentType(ContentType.JSON)
.body("1")
.when()
.put("/increments/first-key")
.then()
.statusCode(204);
// verify that key has been incremented
given()
.accept(ContentType.JSON)
.when()
.get("/increments/first-key")
.then()
.statusCode(200)
.body("key", is("first-key"))
.body("value", is(1));
// increment second key by 1000
given()
.contentType(ContentType.JSON)
.body("1000")
.when()
.put("/increments/second-key")
.then()
.statusCode(204);
// verify that key has been incremented
given()
.accept(ContentType.JSON)
.when()
.get("/increments/second-key")
.then()
.statusCode(200)
.body("key", is("second-key"))
.body("value", is(1010));
// verify that we have two keys in registered
given()
.accept(ContentType.JSON)
.when()
.get("/increments")
.then()
.statusCode(200)
.body("size()", is(2));
// delete first key
given()
.accept(ContentType.JSON)
.when()
.delete("/increments/first-key")
.then()
.statusCode(204);
// verify that we have one key left after deletion
given()
.accept(ContentType.JSON)
.when()
.get("/increments")
.then()
.statusCode(200)
.body("size()", is(1));
// delete second key
given()
.accept(ContentType.JSON)
.when()
.delete("/increments/second-key")
.then()
.statusCode(204);
// verify that there is no key left
given()
.accept(ContentType.JSON)
.when()
.get("/increments")
.then()
.statusCode(200)
.body("size()", is(0));
}
}
Get it running
如果您按照说明进行操作,则您应该已运行 Redis 服务器。 然后,您只需使用以下命令运行该应用程序:
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
打开另一个终端并运行 @"14" 命令。
Interacting with the application
正如我们在上面看到的,API 暴露了五个 Rest 端点。在本部分中,我们将了解如何初始化自增值、查看当前自增值列表、增量给定键的值、检索自增值的当前值,最后删除键。
Creating a new increment
curl -X POST -H "Content-Type: application/json" -d '{"key":"first","value":10}' http://localhost:8080/increments 1
1 | 我们用键 `first`和初始值 `10`创建第一个自增值。 |
运行以上命令应返回以下结果:
{
"key": "first",
"value": 10
}
See current increments keys
若要查看当前自增值键列表,请运行以下命令:
curl http://localhost:8080/increments
以上命令应该返回 ["first"]
,表明到目前为止,我们只有一个自增值。
Retrieve a new increment
若要使用其键检索一个自增值,我们将不得不运行以下命令:
curl http://localhost:8080/increments/first 1
1 | 运行此命令,应返回以下结果: |
{
"key": "first",
"value": 10
}
Increment a value given its key
若要增量一个值,请运行以下命令:
curl -X PUT -H "Content-Type: application/json" -d '27' http://localhost:8080/increments/first 1
1 | 将 `first`的值增加 27。 |
现在,运行命令 `curl [role="bare"]http://localhost:8080/increments/first`应返回以下结果:
{
"key": "first",
"value": 37 1
}
1 | 我们看到 first`键的值现在是 `37 ,这正是 10 + 27 的结果,快速数学。 |
Deleting a key
使用以下命令,根据其键删除一个自增值。
curl -X DELETE http://localhost:8080/increments/first 1
1 | Delete the first increment. |
现在,运行命令 curl [role="bare"]http://localhost:8080/increments`应返回一个空列表 `[]
Configuring for production
此时,Quarkus 使用 Redis Dev Service 来运行 Redis 服务器并配置应用程序。然而,在实际生产环境中,您将运行自己的 Redis(或使用云服务)。
让我们使用以下命令在端口 6379 上启动一个 Redis 服务器:
docker run --ulimit memlock=-1:-1 -it --rm=true --memory-swappiness=0 --name redis_quarkus_test -p 6379:6379 redis:5.0.6
然后,打开 src/main/resources/application.properties
文件并添加:
%prod.quarkus.redis.hosts=redis://localhost:6379
Packaging and running in JVM mode
您可以将应用程序作为常规 jar 文件运行。
首先,我们需要对其进行打包:
quarkus build
./mvnw install
./gradlew build
此命令将启动一个 Redis 实例来执行测试。 |
然后运行它:
java -jar target/quarkus-app/quarkus-run.jar
Running Native
您还可以从此应用程序创建本机可执行程序,而无需进行任何源代码更改。本机可执行程序消除了对 JVM 的依赖:在本机可执行程序中包含了在目标平台上运行应用程序所需的一切,从而允许应用程序以最小的资源开销运行。
编译本机可执行程序需要花费更长时间,因为 GraalVM 会执行额外的步骤来删除不必要的代码路径。使用 native
配置文件来编译本机可执行程序:
quarkus build --native
./mvnw install -Dnative
./gradlew build -Dquarkus.native.enabled=true
构建完成后,您可以使用以下命令运行可执行程序:
./target/redis-quickstart-1.0.0-SNAPSHOT-runner
Going further
若要了解有关 Quarkus Redis 扩展的更多信息,请查看 the Redis extension reference guide。