使用 React 和 Patternfly 为您的 Quarkus 应用添加炫酷界面

对于容器化和分布式 Quarkus 应用来说,一个常见的模式是作为独立的后端应用程序提供高效且可扩展的后端。在 Kubernetes 世界中,前端应用程序可以是纯 Web 层 pod,例如 React、Angular 或 Vue.js,将所有 REST 调用委托给这些 Quarkus 服务层 pod。

frontend pod pattern

虽然这种方法具有独立的容器扩展和独立的生命周期的优点,但对于小型应用程序来说,有时可能会过度设计。

也许您只想创建一个小型独立的 CRUD 应用程序,而无需牺牲现代 Web GUI 技术?我们已经了解了如何使用 Angular 实现这一点,但对于 React 呢?根据 GitHub 关注度,React 在受欢迎程度方面至少已经超越了 Angular。这完全取决于您的选择,我将向您展示如何不仅集成 React,还可以使用一个名为 Patternfly 的 Web 组件框架。Patternfly 是用于创建丰富、一致且交互式 GUI 的模式、组件和样式的集合。

让我们创建一个 Quarkus 应用,其中包含一个 REST 端点,用于提供原子粒子对象,并在 React/Patternfly 表格中显示。最终应用程序的源代码可以在 此处找到。

步骤 1 - 生成 Quarkus 项目

要生成入门项目,请访问 https://code.quarkus.io。将“Maven Group”输入为“io.quarkus”,将“Artifact”输入为“quarkus-react”。在扩展列表中,选择 **RESTEasy JAX-RS** 和 **RESTEasy JSON-B**。然后生成并下载项目,将其解压缩到本地计算机,然后在您喜欢的 IDE 中打开项目文件夹。

步骤 2 - 添加 Quarkus REST 端点

在 Java 包文件夹 /src/main/java/io/quarkus 中,其中包含示例 **GreetingResource.java**,创建一个名为 **Particle.java** 的新 bean 类,内容如下:

package io.quarkus;

public class Particle {

    private String name;

    public void setName(String name)
    {
        this.name = name;
    }

    public String getName()
    {
        return this.name;
    }

}

现在创建一个名为 **ParticleResource.java** 的新 REST 资源类,我们在其中返回一些测试粒子(此处忽略任何原子物理影响)。

package io.quarkus;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Set;

import javax.ws.rs.GET;
import javax.ws.rs.Path;

@Path("/particles")
public class ParticleResource {

    @GET
    public Set<Particle> getUsers() {

        Set <Particle> particleList = Collections.newSetFromMap(Collections.synchronizedMap(new LinkedHashMap<>()));

        Particle particle = new Particle();
        particle.setName("Graviton");
        particleList.add(particle);

        Particle particle2 = new Particle();
        particle2.setName("Pentaquark");
        particleList.add(particle2);
        return particleList;
    }
}

通过在开发模式下启动 Quarkus 来测试一切是否正常

$ mvn quarkus:dev

在新的终端中调用端点以查看您的粒子响应

$ curl https://:8080/particles

[{"name":"Graviton"},{"name":"Pentaquark"}]

我们的 Quarkus 数据层现在已准备就绪,接下来让我们创建 React GUI。

步骤 3 - 生成 React 项目

请确保您已在系统上安装了 **Node.js** 和 **npm**。如果需要,请参阅 官方文档了解更多信息。

在您的项目 /src/main/**webapp** 中创建一个新文件夹,这将是您的 React 项目的基础文件夹。现在在此文件夹中打开另一个终端,运行 React 项目初始化程序,然后添加 Patternfly node 模块

$ npx create-react-app .
$ npm install @patternfly/patternfly --save
启动 React 应用时,它默认将在端口 3000 上运行。当我们尝试访问端口 8080 上的 Quarkus 端点时,浏览器会由于 CORS 安全策略而阻止此操作。在生产环境中,这无关紧要,因为编译后的静态 React 应用将从 Quarkus 通过端口 8080 提供服务,但在开发过程中这是一个问题。

幸运的是,React 有一个很棒的小功能叫做 **proxy**,它可以将所有未知端点的请求转发到另一个 URL。在 **/webapp** 文件夹中,打开 **package.json** 文件并添加代理行,将所有内容转发到我们 Quarkus 的 8080 端口

{
  "name": "webapp",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.11.4",
    "@testing-library/react": "^11.1.0",
    "@testing-library/user-event": "^12.1.10",
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
    "react-scripts": "4.0.3",
    "web-vitals": "^1.0.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "proxy": "https://:8080/",
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

步骤 4 - 创建一个 Patternfly 表格组件来填充我们的数据

在 React 项目 **/webapp/src/index.js** 中导入 Patternfly CSS

...
import './index.css';
import '@patternfly/patternfly/patternfly.css';
import App from './App';
...

在 /webapp/src 中创建一个名为 **components** 的新文件夹,在其中创建一个名为 **particles.js** 的文件,并通过循环遍历粒子对象列表来生成 Patternfly 表格

import React from 'react'

const Particles = ({ particles }) => {
    return (
        <div>
            <center><h1>Particles List</h1></center>
            <table class="pf-c-table pf-m-grid-md" role="grid" aria-label="Supersonic Subatomic Particles" id="table-basic">
                <caption>Supersonic Subatomic Particles</caption>
                <thead>
                    <tr role="row">
                        <th role="columnheader" scope="col">Name</th>
                    </tr>
                </thead>
                {particles.map((particle) => (
                    <tbody role="rowgroup">
                        <tr role="row">
                            <td role="cell" data-label="Particle name">{particle.name}</td>
                        </tr>
                    </tbody>
                ))}
            </table>
        </div>

    )
};

export default Particles

接下来,调整 **/webapp/src/App.js** 以调用我们的 Quarkus 服务端点,并使用响应数据渲染我们的粒子组件

import React, {Component} from 'react';
import Particles from './components/particles'

class App extends Component {
  state = {
    particles: []
  }

  componentDidMount() {
    fetch('/particles')
    .then(res => res.json())
    .then((data) => {
      this.setState({ particles: data })
    })
    .catch(console.log)
  }

  render () {
    return (
      <Particles particles={this.state.particles} />
    );
  }
}

export default App;

现在我们已准备好在 React 开发模式下测试我们的 GUI。

请确保 Quarkus 仍在另一个终端中运行。

在 **/webapp** 文件夹中执行

$ npm start

浏览器将打开到 https://:3000。如果未打开,请导航到该 URL。您应该看到我们的表格已从您的 Quarkus 粒子后端动态填充。在浏览器的开发者工具中,您将看到数据实际上是从 https://:3000/particles 检索的。

patternfly table

我们现在处于双重开发模式。对 Java 或 Javascript 代码所做的任何更改都将立即应用。这难道不是开发者应得的幸福吗?

但您可能会问,容器化部署怎么办?好吧,一旦您闪亮的新 GUI 应用准备就绪,我们就需要进行一些最后的调整来构建可运行的 jar 和镜像。

步骤 5 - 为生产构建准备我们的项目

在 **/webapp/package.json** 中添加一个 prod 构建阶段

...
 "eject": "react-scripts eject",
 "prod": "react-scripts build --dest && rsync -a build/* ../resources/META-INF/resources"
  },
  "proxy": "https://:8080/",
...

这将对静态 React 资源执行生产构建,并将它们复制到 Quarkus 静态文件的默认目录中。

rsync 命令特定于 Linux。对于其他操作系统,请替换为等效命令。

最后一步,我们将优秀的 frontend-maven-plugin 添加到我们的 pom.xml 中,它将从普通的 maven 构建触发这些 React 构建阶段。调整 npm 和 node 版本以匹配您本地安装的版本。maven install 阶段实际上会安装这两个包,这对于 CI/CD 构建或开始使用此项目非常有用。

<build>
...
 <plugin>
  <groupId>com.github.eirslett</groupId>
  <artifactId>frontend-maven-plugin</artifactId>
  <version>1.11.2</version>
  <configuration>
    <workingDirectory>${project.basedir}/src/main/webapp</workingDirectory>
    <installDirectory>target</installDirectory>
  </configuration>
  <executions>
    <execution>
      <id>install node and npm</id>
      <goals>
        <goal>install-node-and-npm</goal>
      </goals>
      <configuration>
        <nodeVersion>v14.15.4</nodeVersion>
        <npmVersion>6.14.10</npmVersion>
      </configuration>
    </execution>
    <execution>
      <id>npm install</id>
      <goals>
        <goal>npm</goal>
      </goals>
      <configuration>
        <arguments>install</arguments>
      </configuration>
    </execution>
    <execution>
      <id>npm run build</id>
      <goals>
        <goal>npm</goal>
      </goals>
      <configuration>
        <arguments>run prod</arguments>
      </configuration>
    </execution>
  </executions>
</plugin>
</build>

现在让我们构建可运行的 jar

$ mvn clean package

停止所有其他正在运行的环境以释放端口并运行

$ java -jar target/quarkus-app/quarkus-run.jar

打开浏览器访问 https://:8080 再次查看您的表格,现在它从一个优化的 Quarkus jar 运行。

要点

就是这样。只需几个简单的步骤,您就可以利用 React 和 Patternfly 的强大功能为您的 Quarkus 应用添加精美、交互式的 GUI。

何不将此应用编译为 原生,然后部署一个极其轻量级的 Web 应用?或者您可能想查看一些其他 Patternfly 组件来创建更复杂的 Web 界面。无论哪种方式,只有您的创造力才能让您的 Quarkus 应用闪耀。