Quarkus 和 Web UI 开发
在本篇博文中,我们将利用 Quarkus 和 Angular CLI各自的开发模式,并展示如何开发一个以 Quarkus RESTful API 为后端的零停顿 Web 应用程序。虽然我使用的是 Angular,但这些概念也适用于其他现代 Web 应用程序框架。
本篇博文的源代码可以在 https://github.com/kabir/blog-quarkus-ui-development 找到。它包含一个 README,详细解释了应用程序的设置方式以及我们如何实现每个步骤,并解决了我们遇到的问题。
您需要在系统上安装 Node、Yarn 和 Angular 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 的 代理。 React 和 Vue 也有类似的功能。
在另一个终端窗口中,进入克隆项目的 webapp/
文件夹,然后运行
$yarn proxy
这将在端口 4200 上以代理模式启动 Angular 开发服务器。在浏览器中访问 https://:4200,您将看到与之前在端口 8080 上看到的相同的应用程序,但由 Angular 开发服务器提供服务,同时从正在运行的 Quarkus 应用程序访问 REST 端点。如果您对 app.component.ts
中设置的任何 Angular 组件进行了任何更改,您将看到更改得到反映。
太棒了!!!现在我们可以非常高效地同时更改前端和后端,并立即看到更改,而无需重新构建、重新打包和重新启动我们的应用程序!
调整总结
示例项目已经进行了必要的调整,以便在打包应用程序和开发模式下都能正常工作。以下是主要的调整:
-
在 UI 中处理 Angular 路由,而不是在后端处理。这对于打包版本(在端口 8080 上运行)很重要。
-
启用 Angular 代理,允许 UI 调用 Quarkus 提供的 REST 端点。
-
向后端指示前端正在代理模式下运行,即不由我们提供服务。如果后端需要重定向到前端的某个页面,这一点很重要。
-
我们将重点关注使此工作正常运行所需的更改,而不深入探讨应用程序的设置细节。
处理 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.json
的 scripts
部分添加了一个 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 应用程序的一部分。
云原生打包
最后,要构建原生镜像,请确保您已按照 此处 的说明设置了 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]