2.4. 查看 Quickstart 示例


2.4.1. 探索 helloworld Quickstart

helloworld 快速入门演示了如何将简单的 Servlet 部署到 JBoss EAP。业务逻辑封装在服务中,该服务作为 Jakarta 上下文和依赖注入 Bjection Bjection Bean 提供,并注入到 Servlet 中。此快速入门是一个起点,可确保您已正确配置和启动服务器。

使用命令行构建和部署此快速启动的详细说明,请参见 helloworld 快速启动目录根目录下的 README.html 文件。本节介绍如何使用 Red Hat CodeReady Studio 运行 Quickstart,并假设您已安装红帽 CodeReady Studio、配置 Maven,并导入并成功运行 helloworld quickstart。

先决条件
检查目录结构

helloworld 快速启动的代码可以在 QUICKSTART_HOME/helloworld/ 目录中找到。helloworld 快速入门由一个 Servlet 以及 Jakarta 上下文和依赖注入 Bjection Ban 组成。它还包含应用的 WEB-INF/ 目录中的 beans.xml 文件,其版本号为 1.1,并且 bean-discovery-modeall。此标志文件将 WAR 识别为 bean 存档,并告知 JBoss EAP 在此应用中查找 bean,并激活 Jakarta 上下文和依赖注入。

src/main/webapp/ 目录包含快速启动的文件。本例的所有配置文件都位于 src/main/webapp/ 中的 WEB-INF/ 目录中, 包括 beans.xml 文件。src/main/webapp/ 目录还包括 index.html 文件,该文件使用简单的 meta refresh 将用户的浏览器重定向到 Servlet,它位于 http://localhost:8080/helloworld/HelloWorld。quickstart 不需要 web.xml 文件。

检查代码

软件包声明和导入已从这些列表中排除。Quickstart 源代码中提供了完整的列表。

  1. 查看 HelloWorldServlet 代码。

    HelloWorldServlet.java 文件位于 src/main/java/org/jboss/as/quickstarts/helloworld/ 目录中。此 servlet 将信息发送到浏览器。

    示例:HelloWorldServlet 类代码

    42 @SuppressWarnings("serial")
    43 @WebServlet("/HelloWorld")
    44 public class HelloWorldServlet extends HttpServlet {
    45
    46     static String PAGE_HEADER = "<html><head><title>helloworld</title></head><body>";
    47
    48     static String PAGE_FOOTER = "</body></html>";
    49
    50     @Inject
    51	   HelloService helloService;
    52
    53     @Override
    54     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    55         resp.setContentType("text/html");
    56         PrintWriter writer = resp.getWriter();
    57         writer.println(PAGE_HEADER);
    58         writer.println("<h1>" + helloService.createHelloMessage("World") + "</h1>");
    59         writer.println(PAGE_FOOTER);
    60         writer.close();
    61     }
    62
    63 }
    Copy to Clipboard Toggle word wrap

    Expand
    表 2.1. HelloWorldServlet Details
    备注

    43

    您只需要添加 @WebServlet 注释,并提供用于访问 servlet 的 URL 映射。

    46-48

    每个网页都需要正确构成 HTML。这个快速入门使用静态字符串来编写最小标头和页脚输出。

    50-51

    这些行注入 HelloService Jakarta Contexts 和 Dependency Injection bean,用于生成实际消息。只要我们不更改 HelloService 的 API,这种方法允许我们以后在不更改视图层的情况下更改 HelloService 的实施。

    58

    此行调用 服务以生成消息"Hello World",并将它写入到 HTTP 请求。

  2. 检查 HelloService 代码。

    HelloService.java 文件位于 src/main/java/org/jboss/as/quickstarts/helloworld/ 目录中。此服务只需返回一条消息。不需要 XML 或注解注册。

    示例:HelloService 类代码

    public class HelloService {
    
        String createHelloMessage(String name) {
            return "Hello " + name + "!";
        }
    }
    Copy to Clipboard Toggle word wrap

2.4.2. 探索 numberguess Quickstart

numberguess quickstart 演示了如何将简单的非持久性应用创建和部署至 JBoss EAP。信息通过 Jakarta Server Faces 视图显示,业务逻辑则封装在两个 Jakarta Contexts 和 Dependency Injection bean 中。在 numberguess 快速启动中,您有十次尝试猜测 1 到 100 之间的数字。在每次尝试后,您都会被告知您的猜测过高还是过低。

numberguess Quickstart 的代码可以在 QUICKSTART_HOME/numberguess/ 目录中找到,其中 QUICKSTART_HOME 是您下载并解压缩 JBoss EAP 快速入门的目录。numberguess quickstart 由多个 Bean、配置文件和 Facelets Jakarta Server Faces 视图组成,并打包为一个 WAR 模块。

使用命令行构建和部署此快速启动的详细说明,请参阅 numberguess quickstart 目录的 README.html 文件。以下示例使用 Red Hat CodeReady Studio 运行 Quickstart。

先决条件
检查配置文件

本例的所有配置文件都位于 QUICKSTART_HOME/numberguess/src/main/webapp/WEB-INF/ 目录中。

  1. 检查 face-config.xml 文件。

    此快速入门使用 Jakarta Server Faces 2.2 版本的 face-config.xml 文件名。Facelet 的标准化版本是 Jakarta Server Faces 2.2 中的默认视图处理程序,因此不需要配置。此文件仅包含 root 元素,只是指示应用中应启用 JSF 的标志文件。

    <faces-config version="2.2"
       xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
          http://xmlns.jcp.org/xml/ns/javaee
          http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd">
    
    </faces-config>
    Copy to Clipboard Toggle word wrap
  2. 检查 beans.xml 文件。

    beans.xml 文件包含版本号 1.1,并且 bean-discovery-mode 包含 all。此文件是一个标志文件,将 WAR 识别为 Bean 存档,并告知 JBoss EAP 在此应用中查找 bean,并激活 Jakarta 上下文和依赖注入。

    <beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="
          http://xmlns.jcp.org/xml/ns/javaee
          http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
        bean-discovery-mode="all">
    </beans>
    Copy to Clipboard Toggle word wrap
注意

此快速入门不需要 web.xml 文件。

2.4.2.1. 检查 Jakarta 服务器 Faces 代码

Jakarta Server Faces 将 .xhtml 文件扩展用于源文件,但通过 .jsf 扩展提供渲染的视图。home.xhtml 文件位于 src/main/webapp/ 目录中。

示例:Jakarta Server Faces 源代码

19<html xmlns="http://www.w3.org/1999/xhtml"
20	xmlns:ui="http://java.sun.com/jsf/facelets"
21	xmlns:h="http://java.sun.com/jsf/html"
22	xmlns:f="http://java.sun.com/jsf/core">
23
24	<head>
25	<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
26	<title>Numberguess</title>
27	</head>
28
29	<body>
30	<div id="content">
31		<h1>Guess a number...</h1>
32		<h:form id="numberGuess">
33
34		<!-- Feedback for the user on their guess -->
35	<div style="color: red">
36		<h:messages id="messages" globalOnly="false" />
37		<h:outputText id="Higher" value="Higher!"
38 		  rendered="#{game.number gt game.guess and game.guess ne 0}" />
39		<h:outputText id="Lower" value="Lower!"
40		   rendered="#{game.number lt game.guess and game.guess ne 0}" />
41	</div>
42
43	<!-- Instructions for the user -->
44	<div>
45	I'm thinking of a number between <span
46	id="numberGuess:smallest">#{game.smallest}</span> and <span
47	id="numberGuess:biggest">#{game.biggest}</span>. You have
48	#{game.remainingGuesses} guesses remaining.
49	</div>
50
51	<!-- Input box for the users guess, plus a button to submit, and reset -->
52	<!-- These are bound using EL to our Jakarta Contexts and Dependency Injection beans -->
53	<div>
54	Your guess:
55	<h:inputText id="inputGuess" value="#{game.guess}"
56		required="true" size="3"
57		disabled="#{game.number eq game.guess}"
58		validator="#{game.validateNumberRange}" />
59		<h:commandButton id="guessButton" value="Guess"
60			action="#{game.check}"
61			disabled="#{game.number eq game.guess}" />
62	</div>
63	<div>
64	<h:commandButton id="restartButton" value="Reset"
65	action="#{game.reset}" immediate="true" />
66	</div>
67	</h:form>
68
69	</div>
70
71	<br style="clear: both" />
72
73	</body>
74</html>
Copy to Clipboard Toggle word wrap

以下行号与在 Red Hat CodeReady Studio 中查看文件时看到的行号对应。

Expand
表 2.2. Jakarta Server Faces 详情
备注

36-40

这些消息可以发送给用户:"Higher!"和"Lower!"。

45-48

用户猜测,可以猜到的数字范围会较小。这一句子会改变,确保他们知道有效猜测的范围。

55-58

此输入字段绑定至使用值表达式的 bean 属性。

58

验证器绑定用于确保用户不会意外输入他们可能猜到的范围之外的数字。如果验证器不在此处,用户可能会对不限号使用一个猜测。

59-61

必须有办法让用户将其猜测发送到服务器。在这里,我们绑定了 Bean 的操作方法。

2.4.2.2. 检查类文件

所有 numberguess 快速启动源文件都可在 QUICKSTART_HOME/numberguess/src/main/java/org/jboss/as/quickstarts/numberguess/ 目录中找到。软件包声明和导入已从这些列表中排除。Quickstart 源代码中提供了完整的列表。

  1. 查看 Random.java Qualifier Code

    限定符用于消除两个 Bean 之间的不确定性,两者都有资格根据其类型注入。如需有关限定符的更多信息,请参阅 JBoss EAP 开发指南中的使用限定符解决 Ambiguous Injection@Random 限定符用于注入随机数字。

    @Target({ TYPE, METHOD, PARAMETER, FIELD })
    @Retention(RUNTIME)
    @Documented
    @Qualifier
    public @interface Random {
    
    }
    Copy to Clipboard Toggle word wrap
  2. 查看 MaxNumber.java Qualifier Code

    @MaxNumber qualifier 用于注入允许的最大数量。

    @Target({ TYPE, METHOD, PARAMETER, FIELD })
    @Retention(RUNTIME)
    @Documented
    @Qualifier
    public @interface MaxNumber {
    }
    Copy to Clipboard Toggle word wrap
  3. 查看 Generator.java Code

    Generator 类通过制作者方法创建随机数,并通过相同方式公开可能的最大数量。此类为应用范围,因此每次都不会出现不同的随机值。

    @SuppressWarnings("serial")
    @ApplicationScoped
    public class Generator implements Serializable {
    
        private java.util.Random random = new java.util.Random(System.currentTimeMillis());
    
        private int maxNumber = 100;
    
        java.util.Random getRandom() {
            return random;
        }
    
        @Produces
        @Random
        int next() {
            // a number between 1 and 100
            return getRandom().nextInt(maxNumber - 1) + 1;
        }
    
        @Produces
        @MaxNumber
        int getMaxNumber() {
            return maxNumber;
        }
    }
    Copy to Clipboard Toggle word wrap
  4. 查看 Game.java 代码

    会话范围的 Game 类是应用的主要入口点。它负责设置或重置游戏,捕获和验证用户的猜测,并通过 FacesMessage 向用户提供反馈。它使用构建后生命周期方法从 @Random Instance<Integer> bean 检索随机数来初始化游戏。

    注意类中的 @Named 注释。只有在您想要使用 Jakarta Expression Language(本例中为 #{game} )使 bean 可访问 Jakarta Server Faces 视图时,才需要此注解。

    @SuppressWarnings("serial")
    @Named
    @SessionScoped
    public class Game implements Serializable {
    
        /**
         * The number that the user needs to guess
         */
        private int number;
    
        /**
         * The users latest guess
         */
        private int guess;
    
        /**
         * The smallest number guessed so far (so we can track the valid guess range).
         */
        private int smallest;
    
        /**
         * The largest number guessed so far
         */
        private int biggest;
    
        /**
         * The number of guesses remaining
         */
        private int remainingGuesses;
    
        /**
         * The maximum number we should ask them to guess
         */
        @Inject
        @MaxNumber
        private int maxNumber;
    
        /**
         * The random number to guess
         */
        @Inject
        @Random
        Instance<Integer> randomNumber;
    
        public Game() {
        }
    
        public int getNumber() {
            return number;
        }
    
        public int getGuess() {
            return guess;
        }
    
        public void setGuess(int guess) {
            this.guess = guess;
        }
    
        public int getSmallest() {
            return smallest;
        }
    
        public int getBiggest() {
            return biggest;
        }
    
        public int getRemainingGuesses() {
            return remainingGuesses;
        }
    
        /**
         * Check whether the current guess is correct, and update the biggest/smallest guesses as needed. Give feedback to the user
         * if they are correct.
         */
        public void check() {
            if (guess > number) {
                biggest = guess - 1;
            } else if (guess < number) {
                smallest = guess + 1;
            } else if (guess == number) {
                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Correct!"));
            }
            remainingGuesses--;
        }
    
        /**
         * Reset the game, by putting all values back to their defaults, and getting a new random number. We also call this method
         * when the user starts playing for the first time using {@linkplain PostConstruct @PostConstruct} to set the initial
         * values.
         */
        @PostConstruct
        public void reset() {
            this.smallest = 0;
            this.guess = 0;
            this.remainingGuesses = 10;
            this.biggest = maxNumber;
            this.number = randomNumber.get();
        }
    
        /**
         * A Jakarta Server Faces validation method which checks whether the guess is valid. It might not be valid because there are no guesses left,
         * or because the guess is not in range.
         *
         */
        public void validateNumberRange(FacesContext context, UIComponent toValidate, Object value) {
            if (remainingGuesses <= 0) {
                FacesMessage message = new FacesMessage("No guesses left!");
                context.addMessage(toValidate.getClientId(context), message);
                ((UIInput) toValidate).setValid(false);
                return;
            }
            int input = (Integer) value;
    
            if (input < smallest || input > biggest) {
                ((UIInput) toValidate).setValid(false);
    
                FacesMessage message = new FacesMessage("Invalid guess");
                context.addMessage(toValidate.getClientId(context), message);
            }
        }
    }
    Copy to Clipboard Toggle word wrap
返回顶部
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2025 Red Hat