使用Quarkus和Redis创建一个简单的应用程序

简而言之

我最近了解到了一个叫Quarkus的Java框架。

Quarkus 是一个全栈 Kubernetes 原生 Java 框架,专为 Java 虚拟机(JVM)和本地编译而创建,将 Java 优化为容器化,并可在无服务器、云和 Kubernetes 环境中作为高效的平台使用。
https://www.redhat.com/ja/topics/cloud-native-apps/what-is-quarkus

听说是这样的。

只需要一个选项,在中国进行本地化改写:
随着微服务越来越流行,我个人认为Kubernetes原生的Java框架在未来是有潜力的。关于其特点和详细使用方法,我将交由其他人处理。

在这篇文章中,我总结了使用Quarkus网站介绍的redis-client创建示例应用程序的方法。这是一个与Redis连接并进行CRUD操作的RESTful API应用程序。

以下是我进行了一些修改的页面内容:
https://quarkus.io/guides/redis

操作步骤

创建Maven项目

如果您想要快速创建一个新的Quarkus项目,只需要执行以下命令。
您可以根据个人喜好更改-DprojectGroupId和-DprojectArtifactId参数。

mvn io.quarkus:quarkus-maven-plugin:1.13.4.Final:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=redis-quickstart \
    -Dextensions="redis-client,resteasy-jackson,resteasy-mutiny" \
    -DnoExamples
cd redis-quickstart

在Quarkus版本1.13.4中,需要使用3.6.2或更高版本的maven。

-Dextensions中指定了实现Quarkus+Redis应用程序所需的库。

    • redis-client: Redisのクライアントライブラリです。

 

    resteasy-jackson, resteasy-mutiny: REST APIを作るのに必要なライブラリです。

如果你想给已经创建的Maven项目添加库,可以执行以下命令:

./mvnw quarkus:add-extension -Dextensions="redis-client"

请在pom.xml文件中添加以下内容。

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-redis-client</artifactId>
</dependency>

准备Redis服务器。

如果您没有准备Redis服务器,那就使用Docker来准备Redis容器吧。

docker run --ulimit memlock=-1:-1 -it --rm=true --memory-swappiness=0 --name redis_quarkus_test -p 6379:6379 redis:5.0.6

创建应用程序

从这里开始修改源码。
请预先使用以下命令创建必要的目录。

# redis-quickstart配下で
mkdir -p src/{main,test}/java/org/acme/redis/

application.properties

在application.properties文件中记录Redis服务器的URL。

quarkus.redis.hosts=redis://localhost:6379

POJO的中文含义是:普通的Java对象。

当有时间时,我会解释源代码(并没有说不会做… 没有说!)

package org.acme.redis;

public class Increment {
    public String key; 
    public int value; 

    public Increment(String key, int value) {
        this.key = key;
        this.value = value;
    }

    public Increment() {
    }
}

服务

package org.acme.redis;

import io.quarkus.redis.client.RedisClient;
import io.quarkus.redis.client.reactive.ReactiveRedisClient;
import io.smallrye.mutiny.Uni;

import io.vertx.mutiny.redis.client.Response;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.inject.Inject;
import javax.inject.Singleton;

@Singleton
class IncrementService {

    @Inject
    RedisClient redisClient; 

    @Inject
    ReactiveRedisClient reactiveRedisClient; 

    Uni<Void> del(String key) {
        return reactiveRedisClient.del(Arrays.asList(key))
                .map(response -> null);
    }

    String get(String key) {
        return redisClient.get(key).toString();
    }

    void set(String key, Integer value) {
        redisClient.set(Arrays.asList(key, value.toString()));
    }

    void increment(String key, Integer incrementBy) {
        redisClient.incrby(key, incrementBy.toString());
    }

    Uni<List<String>> keys() {
        return reactiveRedisClient
                .keys("*")
                .map(response -> {
                    List<String> result = new ArrayList<>();
                    for (Response r : response) {
                        result.add(r.toString());
                    }
                    return result;
                });
    }
}

资源

package org.acme.redis;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.PathParam;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.POST;
import javax.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(@PathParam("key") String key) {
        return new Increment(key, Integer.valueOf(service.get(key)));
    }

    @PUT
    @Path("/{key}")
    public void increment(@PathParam("key") String key, Integer value) {
        service.increment(key, value);
    }

    @DELETE
    @Path("/{key}")
    public Uni<Void> delete(@PathParam("key") String key) {
        return service.del(key);
    }
}

测试

这是一个可选项。

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));
    }
}

按照步骤進行時,我在我的情况下找不到io.hamcrest和io.restassured库,导致出现了错误。
如果出现错误,请在pom.xml中加入以下内容。

    <dependency>
      <groupId>org.hamcrest</groupId>
      <artifactId>hamcrest</artifactId>
      <version>2.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.rest-assured</groupId>
      <artifactId>rest-assured</artifactId>
      <version>3.0.0</version>
      <scope>test</scope>
    <dependency>

源代码的编辑到此为止。

试试运行应用程序。

让我们尝试使用下面的命令来运行应用程序。

./mvnw quarkus:dev
image.png

让我们尝试一下刚刚创建的应用程序。

一旦启动完成后,将监听8080端口,让我们尝试使用curl命令对/increments进行POST请求。

curl -X POST -H "Content-Type: application/json" -d '{"key":"first","value":10}' http://localhost:8080/increments 
# -> {"key":"first","value":10}

当您使用GET请求增量时,将返回已注册键的列表。

curl http://localhost:8080/increments
# -> ["first"]

如果指定了键并进行GET操作,将以JSON格式返回键-值对。

curl http://localhost:8080/increments/first
# -> {"key":"first","value":10}

为了确认,我将尝试访问Redis服务器并检查记录。

docker exec -it redis_quarkus_test redis-cli 
127.0.0.1:6379> keys *
# -> 1) "first"
127.0.0.1:6379> get first
# -> "10"

你已经正确注册了。

执行PUT操作时,将指定键的值增加指定的数量。

curl -X PUT -H "Content-Type: application/json" -d '27' http://localhost:8080/increments/first
curl http://localhost:8080/increments/first
# -> {"key":"first","value":37}

当执行DELETE操作时,会从Redis中删除记录。

curl -X DELETE  http://localhost:8080/increments/first
curl http://localhost:8080/increments
# -> []

由于没有对 Redis 服务器中不存在的键进行错误处理,所以如果键的指定错误,将会引发异常。

curl http://localhost:8080/increments/second
# -> java.lang.NullPointerException: Cannot invoke "io.vertx.redis.client.Response.toString()" because the return value of "io.quarkus.redis.client.RedisClient.get(String)" is null

mvn打包和执行

如果在JVM上运行

# パッケージング
./mvnw package

# 起動
java -jar target/quarkus-app/quarkus-run.jar

如果要在本地运行

使用Quarkus的一个优点是能够进行本地编译并启动的方式。根据这种方法进行打包可能需要一些时间(大约2分30秒在Intel Core i7-10710u上。我的电脑变得非常热)。

# パッケージング
./mvnw package -Pnative

# 起動
./target/redis-quickstart-1.0.0-SNAPSHOT-runner

其他操作

在这个页面上,除了上述的步骤之外,还列出了以下的步骤。

    • コネクションのヘルスチェック

 

    複数Redisクライアント

配置

施工进行中

广告
将在 10 秒后关闭
bannerAds