第一个应用

应用结构

端点 -> 资源 -> 服务

依赖结构

Quarkus BOM的导入,允许省略不同Quarkus依赖的版本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>${quarkus.platform.group-id}</groupId>
            <artifactId>${quarkus.platform.artifact-id}</artifactId>
            <version>${quarkus.platform.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

看到 quarkus-maven-plugin ,负责应用程序的打包,也提供开发模式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20

<build>
    <plugins>
        <plugin>
            <groupId>${quarkus.platform.group-id}</groupId>
            <artifactId>quarkus-maven-plugin</artifactId>
            <version>${quarkus.platform.version}</version>
            <extensions>true</extensions>
            <executions>
                <execution>
                    <goals>
                        <goal>build</goal>
                        <goal>generate-code</goal>
                        <goal>generate-code-tests</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Gradle同理

Platform引入QuarkusBOM

1
2
3
4
5
6
7
val quarkusPlatformGroupId: String by project
val quarkusPlatformArtifactId: String by project
val quarkusPlatformVersion: String by project

dependencies {
    implementation(enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}"))
}

Quarkus插件

1
2
3
plugins {
    id("io.quarkus")
}

Rest依赖

1
2
3
4
5

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-rest</artifactId>
</dependency>
1
implementation("io.quarkus:quarkus-rest")

代码结构

使用Quarkus,不需要创建一个 Application 类。它支持这么做,但不是必须的。此外,只有一个资源的实例被创建,而不是每个请求一个。你可以使用不同的 *Scoped 注解( ApplicationScoped , RequestScoped , 等等)来配置。

Resource

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package org.acme.getting.started;

import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/hello")
public class GreetingResource {

    @Inject
    GreetingService service;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @Path("/greeting/{name}")
    public String greeting(String name) {
        return service.greeting(name);
    }

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "hello";
    }
}

Service/Bean

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package org.acme.getting.started;

import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class GreetingService {

    public String greeting(String name) {
        return "hello " + name;
    }
}

运行Quarkus

1
2
3
4
5
6
7
8
#CLI
quarkus dev

#MAVEN
./mvnw quarkus:dev

#GRADLE
./gradlew --console=plain quarkusDev

依赖注入

创建Bean

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package org.acme;

import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped//声明Bean
public class GreetingService {

    public String greeting(String name) {
        return "hello " + name;
    }
}

注入Bean

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package org.acme;

import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/hello")
public class GreetingResource {

    @Inject//注入Bean
    GreetingService service;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @Path("/greeting/{name}")
    public String greeting(String name) {
        return service.greeting(name);
    }

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "Hello from Quarkus REST";
    }
}

测试

测试依赖

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13

<dependencys>
    <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>
</dependencys>

maven还需要额外配置插件

1
2
3
4
5

<plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>${surefire-plugin.version}</version>
</plugin>

maven还需要额外设置Surefire Maven Plugin 的版本,因为默认版本不支持JUnit 5:

1
2
3
4
5

<plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>${surefire-plugin.version}</version>
</plugin>
1
2
testImplementation("io.quarkus:quarkus-junit5")
testImplementation("io.rest-assured:rest-assured")

测试代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import io.quarkus.test.junit.QuarkusTest;
import org.junit.jupiter.api.Test;

import java.util.UUID;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;

@QuarkusTest
public class GreetingResourceTest {

    @Test
    public void testHelloEndpoint() {
        given()
                .when().get("/hello")
                .then()
                .statusCode(200)
                .body(is("Hello from Quarkus REST"));
    }

    @Test
    public void testGreetingEndpoint() {
        String uuid = UUID.randomUUID().toString();
        given()
                .pathParam("name", uuid)
                .when().get("/hello/greeting/{name}")
                .then()
                .statusCode(200)
                .body(is("hello " + uuid));
    }
}

可以直接使用test命令运行测试

默认情况下,测试将在端口 8081 上运行,以便不与正在运行的应用程序冲突。我们自动将RestAssured配置为使用该端口。如果你想使用不同的客户端,你应该使用 @TestHTTPResource 注释,直接将测试应用程序的URL注入到测试类的一个字段中。这个字段的类型可以是 String , URL 或 URI 。这个注解也可以给测试路径一个值。例如,如果我想测试一个映射到 /myservlet 的Servlet,只需在测试中添加以下内容:

1
2
3

@TestHTTPResource("/myservlet")
URL testUrl;

测试端口可以通过 quarkus.http.test-port 配置属性来控制。Quarkus还创建了一个名为 test.url 的系统属性,在不能使用注入的情况下被设置为基本测试URL。

打包

1
2
3
4
5
6
#CLI
quarkus build
#Maven
./mvnw install
#Gradle
./gradlew build

getting-started-1.0.0-SNAPSHOT.jar - 它只包含项目的类和资源,是Maven构建时产生的常规组件——它是不可运行的jar。

quarkus-app 目录,其中包含 quarkus-run.jar jar文件是一个可执行的 jar 。请注意,它不是 über-jar ,因为依赖项目被复制到 quarkus-app/lib/ 的子目录中。

使用以下方式运行该应用程序。 java -jar target/quarkus-app/quarkus-run.jar

如果你想把你的应用程序部署到某个地方(通常是在一个容器中),你需要部署整个 quarkus-app 目录。

配置Banner

默认情况下,当Quarkus应用程序启动时(在常规或开发模式下),它将显示ASCII艺术横幅。可以通过在 application.properties 中设置 quarkus.banner.enabled=false 、设置 -Dquarkus.banner.enabled=false Java系统属性或将 QUARKUS_BANNER_ENABLED 环境变量设置为 false 来禁用横幅。此外,用户可以通过将横幅文件放在 src/main/resources 中并在 application.properties 中配置 quarkus.banner.path=name-of-file 来提供自定义横幅。

基础知识

基本注解

quarkus注解spring注解说明注解位置
@GET/@POST/@PUT/@DELETE@GetMapping/@PostMapping/@PutMapping/@DeleteMapping注明请求方式方法注解
@HEAD@RequestMethod(method = RequestMethod.HEAD)请求一个与Get相同的请求,但没有响应体方法注解
@OPTIONS@RequestMethod(method = RequestMethod.OPTIONS)描述目标资源的通信选项方法注解
@Path@RequestMapping类/方法中处理方法的URL的基本路径类/方法注解
@Produces@RequsetMapping的生产属性资源生成输出类型类/方法注解
@Consumes@RequsetMapping的消费属性资源使用的媒体类型类/方法注解
@PathParam@PathVariableURL路径变量方法参数
@QueryParam@RequestParam查询参数方法参数
@FormParam@RequestParamForm参数方法参数
@HeadParam@RequestHeaderHead值方法参数
@CookieParam@CookieValueCookie值方法参数
@MatrixParam@MatrixVariableMatrix参数方法参数
@RequsetBody请求体对象方法参数
@Context无(直接在参数中写入对象即可)注入上下文信息方法参数
@ApplicationScope@Component指定容器管理Bean,设置为应用级别单例类注解
@Inject@Autowired注入Bean属性注解
@ConfigProperty@Value配置属性注入属性注解
@QuarkusMain@Application程序入口点类注解