1.5 Hello, world! 解剖 -JSF实战 -hxzon -jsf学习笔记

来源:互联网 发布:淘宝网有没有香港卖家 编辑:程序博客网 时间:2024/06/02 04:26

 

1.5 Hello, world! 解剖 -JSF实战 -hxzon -jsf学习笔记

既然已经对JSF能够解决什么问题有了初步理解,我们来开始开发一个简单的应用。本节假定你已熟悉Java Web应用和JSP(关于这些技术的信息,参考1.2节)。下面来解剖一个简单的基于HTML的Web应用,该应用有两个页面:hello.jsp 和 goodbye.jsp。

hello.jsp页面做以下工作:

l    显示文本“Welcome to JSF!”;

l    有一个表单,其中有个文本框,要求输入1 到 500 的整数;

l    在名为numControls 的JavaBean 属性中存储提交的文本值;

l    文本框下面有个表格;

l    有一个标签为Redisplay的按钮,点击它时,将添加一个numControls 输出UI组件到表格中(清除先前已经有了的UI组件);

l    有一个标签为Goodbye的按钮,点击它将显示goodbye.jsp 页面。

goodbye.jsp 页面做以下工作:

l    显示文本“Goodbye!”;

l    显示JavaBean 属性numControls的值。

JSF执行Hello, world!应用程序的大部分工作,但是除了JSP 页面之外,还有一些其他要求:

l    HelloBean后台bean类;

l    Faces配置文件;

l    正确配置的部署描述符。

某些工具可以简化部分或者全部需求的创建工作,但在本节,我们将详细讨论这些原始文件。

在涉足细节之前,先看看Hello, world!在Web浏览器中怎样显示。应用以hello.jsp开始,如图1-7所示。页面中的文本框与HelloBean类中的一个JavaBean属性相关联;当用户在此文本框中输入一个值,属性将自动更新(如果值有效)。

图1-7 数据提交之前的Hello, world!应用程序

如果在文本框中输入数字64,点击Redisplay 按钮,页面将重新显示,如图1-8,共有64个UI输出组件显示在表格中。如果清除文本框,然后点击Redisplay按钮,将会得到一个验证错误,如图1-9所示。如果输入数字99999,然后点击Redisplay按钮,也会得到验证错误,如图1-10。

图1-8 输入“64”并且点击Redisplay按钮后的Hello,world!应用程序。表格内组装了64个UI输出组件

图1-9 对必须填写的字段提交空值,并且点击Redisplay按钮后的Hello,world!应用程序。因为发生了验证错误,相关JavaBean属性的值未被修改

不要担心错误信息,你完全可以在自己的应用中定制它们。重点在于,在这两种情况下,表单提交时,相关的 JavaBean属性未被修改。

如果点击Goodbye 按钮,你将看到goodbye.jsp页面,如图1-11。虽然这是完全不同的页面,JavaBean 属性的值也会显示。JSF组件可以引用应用作用域中的JavaBean。

Hello, world! 示例是一个标准的Java Web应用,它使用标准的Servlet API(虽然它要求标准的Faces 库)。这五个图都是由两个JSP产生的。接下来详细讨论一下。

1.5.1 解剖hello.jsp

主页面hello.jsp提供了图1-7~图1-10的界面。JSF 通过使用定制标签库与JSP集成。JSF 定制标签允许JSP使用Faces UI组件。某些工具使你可以通过从面板拖放JSF组件来设计JSP页面。事实上,图1-1~图1-3就是在不同的IDE中设计hello.jsp 的屏幕截图。这些IDE最终都产生与代码清单1-1类似的代码(当然,也可以手工编写JSF页面)。

图1-10 在文本框内输入"99999",然后点击Redisplay后的Hello, world!应用程序。字段仅接受1~500之间的数值,所以产生如图所示的验证错误。因为发生了验证错误,相关的JavaBean属性的值未被修改

图1-11 点击Goodbye按钮后的Hello, world!应用程序。注意JavaBean 属性,它与第一个页面中的文本字段保持同步,也显示在此页面中

代码清单1-1 hello.jsp: Hello,world! 应用程序的起始页面(浏览器输出如图1-7~图1-10所示)

首先,导入核心JSF标签库。该库提供诸如验证和事件处理之类的基本任务的定制标签。接着,导入基本HTML标签库,它提供诸如文本框、输出标签和表单之类的UI组件(前缀f和h是建议的,非必要)。

<f:view>标签必须将所有其他Faces相关的标签包围起来(包括来自于核心标签和基本HTML标签库中的标签)。

<h:form>标签表示HtmlForm组件,它是其他组件的容器,并将信息提交给服务器。在一个页面内可以有多个HtmlForm,但输入组件必须嵌入<h:form>标签中。

<h:outputText>标签创建HtmlOutputText 组件,该组件只是在屏幕上显示只读数据。此标签有一个id属性和一个value 属性。id 属性对每个组件是可选的,不是必需属性,除非你想要在其他地方引用该组件(组件可以使用客户端技术(如JavaScript)引用或者在Java 代码中引用)。Value属性的值是需要显示的文本。

<h:message>标签表示HtmlMessage 组件,它显示特定组件的验证和转换错误信息。for 属性告诉它需要显示针对标识符为helloInput的组件的错误信息。helloInput是页面中*处的文本框的标识符。如果没有错误则什么都不显示。

<h:outputLabel>标签创建新的HtmlOutputLabel组件,它用作输入控件的标注。for属性将它与该输入控件相联系,即 helloInput 文本框。HtmlOutputLabel不显示内容,所以还需要下属HtmlOutputText(由嵌套的<h:outputText> 标签创建)来显示标注的文本。

* <h:inputText>标签用于创建HtmlInputText 组件,该组件接收用户的文本输入。注意,该组件的value 属性是"#{helloBean.numControls}",这是JSF表达式语言(EL)写成的表达式,引用了后台bean中的numControls 属性,该bean名为HelloBean(JSF EL 基于JSP 2.0引入的表达式语言)。

Faces将自动在不同的上下文(请求、会话、应用)中查询特定的后台bean。这样,它将在应用会话中找到在关键字helloBean下保存的后台bean。组件的value属性和helloBean的numControls 属性是同步的,其中一个变化了,另一个也要修改(除非HtmlInputText 组件中的文本无效)。

输入组件有个required 属性,它决定该字段是否必须有一个值。这样,如果required 属性被设置为true,则组件只能接受非空输入。如果用户输入空值,页面将重新显示,而HtmlMessage()将显示错误信息,如图1-9所示。

JSF也支持验证器,它负责确保用户的输入是可接受的值。每个输入控件都可以与一个或者多个验证器相关联。<f:validateLongRange>标签注册LongRange验证器到HtmlInputText 组件。验证器检查输入值以确保用户输入是在预设的0~500之间的一个数(包含端点)。如果用户输入一个超出此范围的值,验证器将拒绝该输入,页面重新显示,并且HtmlMessage()组件显示错误信息,如图1-10所示。

当用户输入被拒绝时,HtmlInputText组件引用的对象的value 属性不会更新。

HtmlPanelGrid 组件用<h:panelGrid> 标签来表示。HtmlPanelGrid表现为其他组件的可配置容器,将显示为HTML表格。

许多JSF 组件都可以通过其JSP标签的binding属性直接与后台bean相联系(某些工具能够自动使页面上的所有组件与后台bean相联系)。此标签的binding属性被设置为"#{helloBean.controlPanel}"。这也是JSF EL表达式,它引用了helloBean的controlPanel属性,这是HtmlPanelGrid类型的属性。这样确保helloBean 总是能够访问页面上的HtmlPanelGrid 组件。

<h:commandButton>表示HtmlCommandButton 组件,它显示为HTML表单按钮。HtmlCommandButton在被用户点击后会发送动作事件(Action Event)到服务器中的应用。可通过actionListener属性直接引用事件监听器(执行事件响应的方法)。第一个HtmlCommandButton的actionListener属性设置为"#{helloBean.addControls}"。这仍是JSF EL表达式,它告诉JSF去查找helloBean 对象,然后调用其addControls 方法来处理事件。一旦方法执行完毕,页面将重新显示。

第2个HtmlCommandButton按钮设置action属性而不是actionListener属性。该属性的值为"#{helloBean.goodbye}",这个表达式引用一个特定的处理导航的事件监听器。这也是为什么点击这个按钮将显示goodbye.jsp页面,而不是重新显示hello.jsp页面的原因。这个按钮还有个immediate 属性设置为true,这告诉JSF在验证和更新发生前就执行相关的监听器。这样,即使输入不正确,点击此按钮也可以工作。这就是整个hello.jsp。

代码清单1-2列出了验证出错后的HTML输出(浏览器的视图显示效果示于图1-10)。

代码清单1-2 hello.jsp的HTML输出(此代码是图1-10的源代码)

你可以看到,在JSP中定义的每一个组件都在HTML页面中有一个对应的显示。注意,<h:form>标签(),它表示HtmlForm组件,有一个action属性,它指向调用此页面的JSP,但是有一个前缀faces。这是Faces servlet的一个别名,是在应用的部署描述符中定义的。重新显示调用页面是默认行为,但Faces应用也可以导航到其他页面(这发生在用户点击Goodbye按钮后)。

HtmlMessage组件()的输出是文本“Validation Error: Specified attribute is not between the expected values of 1 and 500。”正如你所想,此消息是由注册到页面中的LongRange 验证器产生的。当验证器拒绝提交输入不正确值的尝试时,它也产生错误信息,而框架则避免更新相关的JavaBean的属性值。

对应于JSF组件的每个HTML元素都有个继承自JSP中指定的id值的id属性(如果没有指定,将自动创建一个)。这就是客户端标识符(client identifier),它是JSF用来将输入值映射到服务器组件的标识。某些组件也使用name属性作为客户端标识符。

HtmlPanelGrid组件()的输出是HTML表格。注意,JSP中的border 和cellspacing 属性直接传递到HTML(大多数标准HTML组件都会暴露一些直接传递到浏览器的HTML特定属性)。表格中的每个单元格都输出一个HtmlOutputText组件,它是通过Java代码在响应用户点击Redisplay按钮后添加到其中的(在实际的HTML中,有64 个单元格,因为这是用户在文本框中输入的数字。我们省略了部分代码,否则将会浪费大量的篇幅!)。

我们很快就会研究Java代码,但现在先来看看goodbye.jsp。

1.5.2 解剖goodbye.jsp

goodbye.jsp页面的效果如图1-11所示,用户点击Goodbye按钮后显示。页面代码(代码清单1-3)包含了一些与hello.jsp 页面中的组件相同的组件:导入JSF标签库、一个HtmlForm组件、HtmlOutputText组件。其中一个HtmlOutputText组件引用与前一个页面中相同的helloBean 对象。这运行得很好,因为对象在应用的会话中,可以在页面请求间存活。

代码清单1-3 goodbye.jsp: Hello, world!应用程序的结束页面(浏览器输出示于图1-11)

此页面产生的HTML和前一节相比无特别需要说明之处,因此就不再浪费时间。重要的是可以创建有功能的应用了,包括验证和导航,尽管仅有两个页面(如果不打算展示导航,第一个页面就已足够了)。

现在,我们来看页面背后的代码。

1.5.3 检视HelloBean

hello.jsp和goodbye.jsp都包含了通过JSF EL表达式引用名为helloBean的后台bean的JSF组件。这个JavaBean包含了此应用所需的所有内容:两个属性和两个方法。其代码如代码清单1-4所示。

代码清单1-4 HelloBean.java: Hello, world!应用程序的简单后台bean

被Goodbye HtmlCommandButton执行

与其他很多框架不同,JSF后台bean并不是非要继承自特定的类。它们只需要简单地遵循普通的JavaBean约定,在事件处理方法中使用特定的方法签名暴露其属性即可。

numControls属性被hello.jsp的HtmlInputText组件和goodbye.jsp中的HtmlOutputText组件所引用。无论何时用户改变 HtmlInputText 组件的值,此属性的值都要相应改变(如果输入有效)。

controlPanel属性的类型是HtmlPanelGrid,后者是在hello.jsp中使用<h:panelGrid>标签创建的实际的Java类。该标签的binding属性与由controlPanel属性的标签创建的组件相关。这样使HelloBean能够操作实际的代码,即在处执行的任务。

addControls是用来处理action 事件的方法(即动作监听器方法);你能辨别,因为它接受ActionEvent作为其唯一的参数。在hello.jsp中,Redisplay按钮HtmlCommandButton通过其actionListener属性引用这个方法。这就告诉JSF,在处理用户点击Redisplay按钮时产生的动作事件时,调用这个方法(如果你习惯使用Swing之类的框架,将组件和事件监听器相联系会显得有些奇怪,因为它们通常需要一个单独的事件监听器接口。JSF也支持接口风格的监听器,但是最好的方法还是使用监听器方法,因为它缓解了后台bean中对适配器类的需求)。

此方法被执行时,它添加新的HtmlOutputText组件到controlPanel中,并执行numControls次(首先清零)。所以,如果numControls的值是64,如例中所述,代码将创建并添加64个HtmlOutputText实例到controlPanel中。每个实例的值被设置为其顺序号,从0开始直到63。最后,每个实例的style属性都设置为"color: blue"。

controlPanel是HtmlPanelGrid 实例,它将在HTML表格中显示其所有的子控件,每个HtmlOutputText 组件将在一个单独的表格单元中显示。图1-8显示方法执行后controlPanel的样子。

与addControls方法类似,goodbye方法也是事件监听器。然而,它与JSF的导航系统相关联,所以其职责是返回一个字符串,或者是一个逻辑结果,于是导航系统使用这个结果来决定下一步将载入哪个页面。这种类型的方法称为动作方法(action method)。hxzon:方法无参数,返回一个字符串,决定导航,对应action属性。而之前addControls带有一个ActionEvent参数,无返回值,处理事件。对应actionListener属性。

goodbye方法通过hello.jsp中的“Goodbye”按钮HtmlCommandButton的action属性与该按钮相关联。所以用户点击Goodbye按钮时,goodbye方法被执行。在这里,goodbye 并不执行决定逻辑结果的工作,它只是直接返回"success"。这一结果在Faces 配置文件中与特定的页面相关联,我们将在下面提及。

因为goodbye方法不执行任何处理( 在实际应用中也可能如此),我们可以在按钮的action属性中通过硬编码"success"来达到同样的效果。这是因为导航系统可以使用HtmlCommandButton的action属性,也可以使用action 方法的结果(如果该属性引用了动作方法)。

1.5.4 通过faces-config.xml进行配置

类似于大部分框架,Faces 也有一个配置文件;它名为faces-config.xml(技术上说,JSF支持多个配置文件,但是现在先保持简化)。这一配置文件允许你定义导航规则、初始化JavaBean、注册自己的JSF组件和验证器(validator)以及配置JSF应用的其他部分。这里的简单应用只需配置bean初始化和导航。具体的配置文件如代码清单1-5所示。

代码清单1-5 faces-config.xml : Hello world! 应用程序的Faces配置

首先,JSF配置文件是XML文档,根节点是<faces-config>()。

在此文件中,可以声明一个或者多个在应用中使用的JavaBean。可以给它们分别设置一个名字(该名称可通过JSF EL表达式引用)、一个说明、一个范围,甚至可以初始化它们的属性。在配置文件中声明的对象称为受管bean(managed bean)。在代码清单中,我们声明了在整个Hello, world!应用程序中使用的helloBean对象()。请注意,对象的名称是"helloBean",这与在两个JSP中的JSF EL表达式中使用的名称是一样的。其实现类是org.jia.hello.HelloBean,这是在前一节所讲的后台bean类的名称。受管bean 的名称和对象的类名称不一定相同。

声明导航和声明受管bean一样简单。每个JSF 应用可以有一个或者多个导航规则。一个导航规则定义了从特定页面出发的可能路由。每种路由称为一个导航案例(navigation case)。配置文件清单显示了Hello, world!应用程序的hello.jsp页面的导航规则()。hello.jsp有个Goodbye 按钮,该按钮用于载入另一个页面,所以这里只有一个单一导航案例:如果结果是"success",则显示goodbye.jsp。这个结果是由helloBean的 goodbye 方法返回的,该方法在用户单击Goodbye按钮时被执行。

值得指出的是JSF 配置的某些方面,特别是导航,可以使用工具进行可视化处理。现在,来看看应用程序在Web应用的层面是如何配置的。

1.5.5 配置web.xml

所有的J2EE Web应用都通过web.xml 部署描述符来进行配置,Faces应用也不例外。然而,JSF 应用要求你必须指定FacesServlet,而这通常是应用的主servlet。另外,请求必须被映射到这个servlet。我们的Hello, world!应用程序的部署描述符如代码清单1-6所示。你可以使用一些工具来产生Faces应用所需要的元素。

代码清单1-6 web.xml:Hello world!应用程序的部署描述符

到此,我们剖析完了Hello world!。你可以看到,JSF做了大部分的工作——验证、事件处理、导航及UI组件管理等等。随着更加深入地探讨JSF的各个方面,你将获得对其所提供的各种服务的更深的理解,从而可以将它应用在你的应用程序中,而避免一些令人抱怨的繁琐工作。

hxzon:faces-config.xml中,配置托管bean,导航规则。托管bean既是model也是action。
导航规则from-view-id表示触发的页面,from-outcome表示前进页面的逻辑名(由导航方法返回),to-view-id表示前进的页面位置。一个managed-bean配置一个托管bean,一个navigation-rule配置一个页面的导航规则(前进规则)。

http://hi.baidu.com/hxzon/blog/item/498cc9fc33ee878ab801a0c8.html

 

 

原创粉丝点击