Övning – Skapa ett Quarkus-program

Slutförd

I den här lektionen skapar du ett grundläggande Quarkus-program. Du använder Maven för att starta programmet och en integrerad utvecklingsmiljö (IDE) för att redigera koden. Använd valfri terminal för att köra koden. Du använder Docker för att starta en lokal PostgreSQL-databas så att du kan köra och testa programmet lokalt.

Generera Quarkus-programmet med hjälp av Maven

Det finns flera sätt att generera en Quarkus-projektstruktur. Du kan använda Quarkus-webbgränssnittet, ett IDE-plugin-program eller Quarkus Maven-plugin-programmet. Nu ska vi använda Plugin-programmet Maven för att generera projektstrukturen.

Du genererar ditt program med flera beroenden:

  • Det resteasy-beroendet för att exponera en REST-slutpunkt
  • Det jackson beroende för att serialisera och deserialisera JSON
  • Beroendet hibernate för att interagera med databasen
  • Det postgresql beroendet för att ansluta till PostgreSQL-databasen
  • Det docker beroendet för att skapa en Docker-avbildning

Du behöver inte ange Azure-beroenden eftersom du kör ditt program lokalt först och sedan distribuerar en containerbaserad version av det till Azure Container Apps.

Generera to-do-programmet vid en kommandorad:

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"

Det här kommandot skapar ett nytt Quarkus-projekt. Den genererar en Maven-katalogstruktur (src/main/java för källkod och src/test/java för tester). Det skapar vissa Java-klasser, vissa tester och vissa Dockerfiles. Den genererar också en pom.xml fil med alla nödvändiga beroenden (viloläge, RESTEasy, Jackson, PostgreSQL och 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>

Not

Alla beroenden i filen pom.xml definieras i Quarkus BOM (materialfaktura) io.quarkus.platform:quarkus-bom.

Koda programmet

Byt sedan namn på den genererade klassen MyEntity.java till Todo.java (finns i samma mapp som TodoResource.java-filen). Ersätt den befintliga koden med följande Java-kod. Den använder Java Persistence API (jakarta.persistence.*-paket) för att lagra och hämta data från Din PostgreSQL-server. Den använder också viloläges-ORM med Panache (ärver från io.quarkus.hibernate.orm.panache.PanacheEntity) för att förenkla beständighetsskiktet.

Du använder en JPA-entitet (@Entity) för att mappa Java-Todo-objektet direkt till tabellen PostgreSQL Todo. Den TodoResource REST-slutpunkten skapar sedan en ny Todo entitetsklass och bevarar den. Den här klassen är en domänmodell som mappas i tabellen Todo. Tabellen skapas automatiskt av JPA.

Om du utökar PanacheEntity får du ett antal metoder för att skapa, läsa, uppdatera och ta bort (CRUD) för din typ. Så du kan göra saker som att spara och ta bort Todo objekt på bara en rad med Java-kod.

Lägg till följande kod i den Todo entiteten:

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 +
                '}';
    }
}

Om du vill hantera den klassen uppdaterar du TodoResource så att den kan publicera REST-gränssnitt för att lagra och hämta data med hjälp av HTTP. Öppna klassen TodoResource och ersätt koden med följande:

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

Kör programmet

När du kör programmet i utvecklingsläge måste Docker köras. Det beror på att Quarkus upptäcker att du behöver en PostgreSQL-databas (på grund av PostgreSQL-beroendet quarkus-jdbc-postgresql deklarerat i filen pom.xml), laddar ned PostgreSQL Docker-avbildningen och startar en container med databasen. Den skapar sedan automatiskt tabellen Todo i databasen.

Kontrollera att Docker körs lokalt på datorn och kör det to-do programmet med hjälp av det här kommandot:

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

Quarkus-programmet bör starta och ansluta till databasen. Du bör se följande utdata:

[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>

Om du vill testa programmet kan du använda cURL.

I en separat terminal skapar du ett nytt to-do objekt i databasen med följande kommando. Du bör se loggen i Quarkus-konsolen:

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

Det här kommandot ska returnera det skapade objektet (med en identifierare):

{"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"}

Skapa en andra to-do med hjälp av följande cURL-kommando:

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

Hämta sedan data med hjälp av en ny cURL-begäran:

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

Det här kommandot returnerar listan över to-do objekt, inklusive de objekt som du skapade:

[ 
  {"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}
]

Testa programmet

Om du vill testa programmet kan du använda den befintliga TodoResourceTest-klassen. Den måste testa REST-slutpunkten. För att testa slutpunkten använder den RESTAssured. Ersätt koden i klassen TodoResourceTest med följande kod:

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

När du testar programmet måste Docker Desktop köras eftersom Quarkus identifierar att den behöver PostgreSQL-databasen för testning. Testa programmet med hjälp av det här kommandot:

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

Du bör se utdata som ser ut ungefär så här:

[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] ------------------------------------------------------------------------