Quarkus 和 Web UI 开发

在本篇博文中,我们将利用 Quarkus 和 Angular CLI各自的开发模式,并展示如何开发一个以 Quarkus RESTful API 为后端的零停顿 Web 应用程序。虽然我使用的是 Angular,但这些概念也适用于其他现代 Web 应用程序框架。

本篇博文的源代码可以在 https://github.com/kabir/blog-quarkus-ui-development 找到。它包含一个 README,详细解释了应用程序的设置方式以及我们如何实现每个步骤,并解决了我们遇到的问题。

您需要在系统上安装 NodeYarnAngular CLI,并假定您熟悉 Angular 和 Quarkus。

克隆 项目,然后进入其文件夹。首先运行

$mvn -Dui.deps compile

这会下载构建我们的 Web 应用程序所需的所有依赖项。然后运行

$mvn package -Dui.dev -Dui.proxy quarkus:dev

-Dui 系统属性启用了用于构建 Web 应用程序的 Maven profile。Web 应用程序的输出目录 webapp/dist/webapp 会被打包到 Quarkus 应用程序中。稍后我们将讨论 -Dui.proxy

在浏览器中访问 https://:8080,看看我们的示例应用程序。它包含几个不同的页面。转到名为 Rest 的页面,它会进行 REST 调用。我们可以更改 SampleServlet.hello() 方法的返回值。如果您刷新页面,您将看到所做的更改自动反映出来!

有了我们目前所拥有的,如果我们想在 Web 应用程序中更改用户界面,我们就需要停止 Quarkus 并再次运行上述命令来构建 Web 应用程序,然后重新启动 Quarkus。这不是我们想要的,所以我们利用 Angular 的 代理ReactVue 也有类似的功能。

在另一个终端窗口中,进入克隆项目的 webapp/ 文件夹,然后运行

$yarn proxy

这将在端口 4200 上以代理模式启动 Angular 开发服务器。在浏览器中访问 https://:4200,您将看到与之前在端口 8080 上看到的相同的应用程序,但由 Angular 开发服务器提供服务,同时从正在运行的 Quarkus 应用程序访问 REST 端点。如果您对 app.component.ts 中设置的任何 Angular 组件进行了任何更改,您将看到更改得到反映。

太棒了!!!现在我们可以非常高效地同时更改前端和后端,并立即看到更改,而无需重新构建、重新打包和重新启动我们的应用程序!

调整总结

示例项目已经进行了必要的调整,以便在打包应用程序和开发模式下都能正常工作。以下是主要的调整:

  1. 在 UI 中处理 Angular 路由,而不是在后端处理。这对于打包版本(在端口 8080 上运行)很重要。

  2. 启用 Angular 代理,允许 UI 调用 Quarkus 提供的 REST 端点。

    1. 向后端指示前端正在代理模式下运行,即不由我们提供服务。如果后端需要重定向到前端的某个页面,这一点很重要。

我们将重点关注使此工作正常运行所需的更改,而不深入探讨应用程序的设置细节。

处理 Angular 路由

添加一个过滤器,AngularRouteFilter。其 doFilter() 方法的精髓是

chain.doFilter(request, response);

if (response.getStatus() == 404) {
    String path = request.getRequestURI().substring(
            request.getContextPath().length()).replaceAll("[/]+$", "");
    if (!FILE_NAME_PATTERN.matcher(path).matches()) {
        // We could not find the resource, i.e. it is not anything known to the server (i.e. it is not a REST
        // endpoint or a servlet), and does not look like a file so try handling it in the front-end routes.
        request.getRequestDispatcher("/").forward(request, response);
    }
}

此过滤器仅在 Quarkus 打包的应用程序(端口 8080)运行时需要。在连接到 Angular 应用程序(端口 4200)运行时则不需要。它的目的是让我们能够为应用程序中的页面添加书签。服务器知道的只有诸如

  • REST 端点

  • 已部署的 Servlet

  • 应用程序 META-INF/resources/ 文件夹中的资源

在我们的例子中,META-INF/resources/ 包含应用程序的 index.html 和转译后的资源。

没有这个过滤器,如果您直接访问 Angular 路由(例如,如果您在 https://:8080/rest 上刷新,这是我们之前看到的 Rest 页面),Quarkus 会认为它是一个文件、一个 REST 端点或一个 Servlet。由于 Quarkus 对任何名为 /rest 的东西一无所知,您最终会得到一个 404(未找到)状态。过滤器在调用 chain.doFilter() 后检查请求的状态码。如果状态码是 404 并且看起来不是一个文件,我们会将此请求转发到 /,然后由 / 提供 index.html 文件。通过转发,请求的路径和参数得以保留。然后 Angular 会识别出 /rest 是其已知路由之一,并显示应用程序的相应页面。一旦 Web 应用程序在浏览器中加载,Angular 就会接管并处理所有到 Web 应用程序中其他路由的内部链接(例如,如果您在 https://:8080 上,然后单击将您带到 https://:8080/other 的链接,则不会与服务器进行往返)。

您也可以通过其他方式处理此问题,例如,将路径与一组需要由后端处理的硬编码的已知路径进行比较,但对我而言,上述方法效果很好。关键是调用

request.getRequestDispatcher("/").forward(request, response);

如果它是应该由 Angular 处理的内容。

设置 Angular 代理

代理在 proxy.conf.json 中配置。所有指向 /api 下的 REST 调用都将被传递到在端口 8080 上运行的后端。为了使用此配置运行 Angular 开发服务器,我们在 package.jsonscripts 部分添加了一个 proxy 配置。

在我们的例子中,有一个 Servlet 需要重定向回前端(我在主项目中实现 OAuth 时发现需要实现这个功能)。它有一个检查,用于检查我们之前在处理 SampleServlet/callback 路径时看到的 -Dui.proxy 系统属性。如果设置了此属性,我们会将 https://:4200(Angular 代理的地址)前缀添加到重定向 URL,如果我们发现代理正在端口 4200 上运行。

最后,app.component.ts 中的 DefaultComponent 直接链接到后端运行的 Servlet。它有一个检查,用于查看 Web 应用程序是否在代理中运行(即其端口是否为 4200),如果是这种情况,它会将 URL 从 /servlet/make-external-call 调整为指向在端口 8080 上运行的 Quarkus 后端。

最后的话

我们已经看到了,只需少量的配置,就可以让我们的应用程序的后端和前端分别在 Quarkus 和 Angular 的开发模式下运行。在开发过程中,这消除了在更改某项内容时重新构建应用程序的需要。您可以直接编码,然后在刷新浏览器时看到更改。这是通过启动 Quarkus 来实现的:

$mvn package -Dui.dev -Dui.proxy quarkus:dev

并从 webapp/ 文件夹启动 Angular 应用程序:

$yarn proxy

开发打包

如果您想偶尔重新构建以打包应用程序并在 Quarkus 中运行,请执行

$mvn package -Dui.dev quarkus:dev

通过不传递 -Dui.proxy,我们禁用了对前端是否在代理中运行的检查。-Dui.dev 会构建 Web 应用程序,使其成为 Quarkus 应用程序的一部分。

生产打包

要打包生产应用程序,请使用

$mvn package -Dui

-Dui 会像 -Dui.dev 一样构建 Web 应用程序,但它会为生产进行更多优化。这些优化需要一些时间。

云原生打包

最后,要构建原生镜像,请确保您已按照 此处 的说明设置了 GraalVM。然后构建应用程序以生成原生可执行文件。

$mvn package -Dui -Pnative

运行此命令,我们将看到 Quarkus 在原生模式下提供的超快速启动时间

$./target/blog-quarkus-ui-development-0.1.0-runner
2019-06-06 10:57:02,254 INFO  [io.quarkus] (main) Quarkus 0.15.0 started in 0.005s. Listening on: http://[::]:8080
2019-06-06 10:57:02,464 INFO  [io.quarkus] (main) Installed features: [cdi, resteasy, resteasy-jsonb]