练习 - 创建 Quarkus 应用程序

已完成

在本单元中,你将创建一个基本的 Quarkus 应用程序。 使用 Maven 启动应用程序,并使用你选择的集成开发环境 (IDE) 编辑代码。 使用自己所选的终端来运行代码。 使用 Docker 启动本地 PostgreSQL 数据库,以便在本地运行和测试应用程序。

使用 Maven 生成 Quarkus 应用程序

可通过几种方法生成 Quarkus 项目结构。 可使用 Quarkus Web 界面、IDE 插件或 Quarkus Maven 插件。 接下来使用 Maven 插件生成项目结构。

生成具有多个依赖项的应用程序:

  • 用于公开 REST 终结点的 resteasy 依赖项
  • 用于对 JSON 进行序列化和反序列化的 jackson 依赖项
  • 用于与数据库交互的 hibernate 依赖项
  • 用于连接 PostgreSQL 数据库的 postgresql 依赖项
  • 用于生成 Docker 映像的 docker 依赖项

无需指定 Azure 依赖项,因为首先在本地运行应用程序,然后将应用程序的容器化版本部署到 Azure 容器应用。

在命令提示符处,生成待办事项应用程序:

mvn -U io.quarkus:quarkus-maven-plugin:3.7.3:create \
    -DplatformVersion=3.7.3 \
    -DprojectGroupId=com.example.demo \
    -DprojectArtifactId=todo \
    -DclassName="com.example.demo.TodoResource" \
    -Dpath="/api/todos" \
    -DjavaVersion=17 \
    -Dextensions="resteasy-jackson, hibernate-orm-panache, jdbc-postgresql, docker"

此命令创建新的 Quarkus 项目。 它生成 Maven 目录结构(源代码为 src/main/java,测试为 src/test/java)。 它创建一些 Java 类、一些测试和一些 Dockerfile。 它还生成一个 pom.xml 文件,其中包含所需的所有依赖项(Hibernate、RESTEasy、Jackson、PostgreSQL 和 Docker)

  <dependencies>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-hibernate-orm-panache</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-resteasy-jackson</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-jdbc-postgresql</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-container-image-docker</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-arc</artifactId>
    </dependency>
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-hibernate-orm</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-resteasy</artifactId>
    </dependency>
    <dependency>
      <groupId>io.quarkus</groupId>
      <artifactId>quarkus-junit5</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.rest-assured</groupId>
      <artifactId>rest-assured</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>

注意

pom.xml 文件中的所有依赖项都在 Quarkus BOM(物料清单)io.quarkus.platform:quarkus-bom 中定义

编写应用程序代码

接下来,将生成的 MyEntity.java 类重命名为 Todo.java(与 TodoResource.java 文件位于同一文件夹中)。 将现有代码替换为以下 Java 代码。 它使用 Java 持久性 API(jakarta.persistence.* 包)存储和检索 PostgreSQL 服务器中的数据。 它还使用 Hibernate ORM with Panache(继承自 io.quarkus.hibernate.orm.panache.PanacheEntity)简化持久性层。

使用 JPA 实体 (@Entity) 将 Java Todo 对象直接映射到 PostgreSQL Todo 表。 然后,TodoResource REST 终结点新建一个 Todo 实体类并将其持久保留。 此类是映射到 Todo 表上的域模型。 JPA 将自动创建一个表。

通过扩展 PanacheEntity,你可获得一些针对你的类型的通用 create、read、update 和 delete (CRUD) 方法。 因此,只需一行 Java 代码即可完成保存和删除 Todo 对象等操作。

将以下代码添加到 Todo 实体:

package com.example.demo;

import io.quarkus.hibernate.orm.panache.PanacheEntity;

import jakarta.persistence.Entity;
import java.time.Instant;

@Entity
public class Todo extends PanacheEntity {

    public String description;

    public String details;

    public boolean done;

    public Instant createdAt = Instant.now();

    @Override
    public String toString() {
        return "Todo{" +
                "id=" + id + '\'' +
                ", description='" + description + '\'' +
                ", details='" + details + '\'' +
                ", done=" + done +
                ", createdAt=" + createdAt +
                '}';
    }
}

要管理该类,请更新 TodoResource,使其可发布 REST 接口以使用 HTTP 存储和检索数据。 打开 TodoResource 类并将代码替换为以下代码:

package com.example.demo;

import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriBuilder;
import jakarta.ws.rs.core.UriInfo;
import org.jboss.logging.Logger;

import java.util.List;

@Path("/api/todos")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
public class TodoResource {

    @Inject
    Logger logger;

    @Inject
    UriInfo uriInfo;

    @POST
    @Transactional
    public Response createTodo(Todo todo) {
        logger.info("Creating todo: " + todo);
        Todo.persist(todo);
        UriBuilder uriBuilder = uriInfo.getAbsolutePathBuilder().path(todo.id.toString());
        return Response.created(uriBuilder.build()).entity(todo).build();
    }

    @GET
    public List<Todo> getTodos() {
        logger.info("Getting all todos");
        return Todo.listAll();
    }
}

运行应用程序

在开发模式下运行应用程序时,需要运行 Docker。 这是因为 Quarkus 检测到需要 PostgreSQL 数据库(由于 pom.xml 文件中声明的 PostgreSQL 依赖项 quarkus-jdbc-postgresql),下载 PostgreSQL Docker 映像,并启动包含该数据库的容器。 然后,它会自动在数据库中创建 Todo 表。

确保 Docker 在计算机上本地运行,并使用以下命令运行待办事项应用程序:

cd todo
./mvnw quarkus:dev    # On Mac or Linux
mvnw.cmd quarkus:dev  # On Windows

Quarkus 应用程序应启动并连接到数据库。 应会看到以下输出:

[io.qua.dat.dep.dev.DevServicesDatasourceProcessor] Dev Services for the default datasource (postgresql) started.
[io.qua.hib.orm.dep.HibernateOrmProcessor] Setting quarkus.hibernate-orm.database.generation=drop-and-create to initialize Dev Services managed database
__  ____  __  _____   ___  __ ____  ______ 
 --/ __ \/ / / / _ | / _ \/ //_/ / / / __/ 
 -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \   
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/   
[org.hib.eng.jdb.spi.SqlExceptionHelper] (JPA Startup Thread) SQL Warning Code: 0, SQLState: 00000

[org.hib.eng.jdb.spi.SqlExceptionHelper] (JPA Startup Thread) table "todo" does not exist, skipping
[org.hib.eng.jdb.spi.SqlExceptionHelper] (JPA Startup Thread) SQL Warning Code: 0, SQLState: 00000
[org.hib.eng.jdb.spi.SqlExceptionHelper] (JPA Startup Thread) sequence "hibernate_sequence" does not exist, skipping
[io.quarkus] (Quarkus Main Thread) todo 1.0.0-SNAPSHOT on JVM (powered by Quarkus) started in 4.381s. Listening on: http://localhost:8080
[io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
[io.quarkus] (Quarkus Main Thread) Installed features: [agroal, cdi, hibernate-orm, hibernate-orm-panache, jdbc-postgresql, narayana-jta, resteasy, resteasy-jackson, smallrye-context-propagation, vertx]

--
Tests paused
Press [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options>

若要测试应用程序,可使用 cURL。

在单独的终端中,使用以下命令在数据库中新建一个待办事项。 应在 Quarkus 控制台中看到日志:

curl --header "Content-Type: application/json" \
    --request POST \
    --data '{"description":"Take Quarkus MS Learn","details":"Take the MS Learn on deploying Quarkus to Azure Container Apps","done": "true"}' \
    http://127.0.0.1:8080/api/todos

此命令应返回已创建的项(带有标识符):

{"id":1,"description":"Take Quarkus MS Learn","details":"Take the MS Learn on deploying Quarkus to Azure Container Apps","done":true,"createdAt":"2022-12-30T15:17:20.280203Z"}

使用以下 cURL 命令创建另一个待办事项:

curl --header "Content-Type: application/json" \
    --request POST \
    --data '{"description":"Take Azure Container Apps MS Learn","details":"Take the ACA Learn module","done": "false"}' \
    http://127.0.0.1:8080/api/todos

接下来,使用新的 cURL 请求检索数据:

curl http://127.0.0.1:8080/api/todos

此命令返回待办事项列表,包括已创建的项:

[ 
  {"id":1,"description":"Take Quarkus MS Learn","details":"Take the MS Learn on deploying Quarkus to Azure Container Apps","done":true},
  {"id":2,"description":"Take Azure Container Apps MS Learn","details":"Take the ACA Learn module","done":false}
]

测试应用程序

要测试应用程序,可使用现有的 TodoResourceTest 类。 它需要测试 REST 终结点。 它使用 RESTAssured 测试终结点。 将 TodoResourceTest 类中的代码替换为以下代码:

package com.example.demo;

import io.quarkus.test.junit.QuarkusTest;
import static io.restassured.RestAssured.given;
import static jakarta.ws.rs.core.HttpHeaders.CONTENT_TYPE;
import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;
import org.junit.jupiter.api.Test;

@QuarkusTest
class TodoResourceTest {

    @Test
    void shouldGetAllTodos() {
        given()
                .when().get("/api/todos")
                .then()
                .statusCode(200);
    }

    @Test
    void shouldCreateATodo() {
        Todo todo = new Todo();
        todo.description = "Take Quarkus MS Learn";
        todo.details = "Take the MS Learn on deploying Quarkus to Azure Container Apps";
        todo.done = true;

        given().body(todo)
                .header(CONTENT_TYPE, APPLICATION_JSON)
                .when().post("/api/todos")
                .then()
                .statusCode(201);
    }
}

测试应用程序时,需要运行 Docker Desktop,因为 Quarkus 检测到需要 PostgreSQL 数据库进行测试。 使用以下命令测试应用程序:

./mvnw clean test    # On Mac or Linux
mvnw.cmd clean test  # On Windows

应看到与以下内容类似的输出:

[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.example.demo.TodoResourceTest
[INFO] 
[INFO] Results:
[INFO] 
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------