视图和控件

视图是JSF中的核心概念,它允许开发人员使用组件化的方式构建Web用户界面。前面章节我们已经编写过很多视图了,这篇笔记我们继续学习JSF视图的开发。

XHTML视图

一个典型的XHTML视图页面通常包含以下内容。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<h:head>
    <title>JSF Demo</title>
</h:head>
<h:body>
</h:body>
</html>

我们这里主要关注引入的XML命名空间,其中h是JSF的HTML控件标签,f是JSF的核心标签,ui则是Facelets标签。核心标签库用于设置AJAX、设置属性监听器等核心功能;HTML标签则对应于输入框、按钮等控件,用于构建Web界面;Facelets标签则包含了模板嵌套、循环渲染逻辑等标签,它使得JSF视图成为一个完整的模板引擎。

HTML控件标签

JSF提供了大量的HTML控件标签并封装了很多实用的功能,我们这里不能逐一介绍,具体可以参考相关文档。我们这里主要展示一些例子,以帮助大家理解这些标签的基本使用方法。

面板控件

面板控件类似于布局容器,它们常用于将一些控件分组管理,这样便于控制这一组控件的位置、显示与隐藏等,此外还方便控制内部控件的布局,常用的有<h:panelGrid><h:panelGroup>等。

<h:form>
    <h:panelGrid columns="2">
        <h:outputLabel for="username" value="用户名"/>
        <h:inputText id="username"/>
        <h:outputLabel for="password" value="密码"/>
        <h:inputSecret id="password"/>
    </h:panelGrid>
</h:form>

上面代码我们使用了<h:panelGrid>,它指定了布局样式为2列,显示效果如下图。

<h:panelGroup rendered="#{demo.renderFlag}">
    <h:outputText value="Hello JSF!"/>
    <h:outputText value="Hello JSF!"/>
    <h:outputText value="Hello JSF!"/>
</h:panelGroup>

上面代码我们使用了<h:panelGroup>,其rendered属性用于控制该面板是否显示。

输入输出控件

输入控件包括文本输入框、密码输入框、单选框、复选框等,输出控件包括文本输出框、图片输出框等。下面例子展示了文本输出控件和文本框控件。

<h:outputText value="#{demo.text}" escape="true"/>
<h:form>
    <h:inputText id="username" value="#{demo.username}"/>
</h:form>

代码中,对于<h:outputText>我们设置了escape属性为true,表示转义特殊字符,这对于防止XSS有重要意义,不过如果是在诸如富文本显示等场景,则可能需要将其设置为false。此外,我们还设置了value属性将它和托管Bean中的字段相关联。对于<h:inputText>文本输出框,其value属性将它和托管Bean中的字段相关联,我们通常都需要使用<h:form>表单控件将其包裹,否则JSF会抛出一个警告信息。

实际上,如果不需要太多复杂的设置,仅仅需要展示一些文本,我们更习惯于在XHTML中直接像如下方式编写输出文本:

#{demo.text}

对于日期等需要格式化展示的内容,我们可以使用转换器标签。

<h:outputText value="#{demo.pageTime}">
    <f:convertDateTime pattern="yyyy-MM-dd HH:mm:ss" />
</h:outputText>

对于输入控件类是类似的,例如时间类型,我们同样可以使用转换器标签,将其转换为字符串提交。

操作控件

操作控件用于接收用户的输入或触发特定的操作,这些控件允许用户与应用程序进行交互,例如提交表单数据、执行动作等。典型的操作控件包括按钮、命令链接(类似按钮,但渲染为超链接)等。

<h:form>
    <h:panelGrid columns="2">
        <h:outputLabel for="username" value="用户名"/>
        <h:inputText id="username" value="#{demo.username}"/>
        <h:outputLabel for="password" value="密码"/>
        <h:inputSecret id="password" value="#{demo.password}"/>
    </h:panelGrid>
    <h:commandButton value="登录" action="#{demo.login()}" />
    <h:commandButton type="reset" value="重置" />
</h:form>

上面代码中我们设置了两个按钮,一个通过触发demo.login()方法提交表单信息,另一个则用于重置表单。

数据表格控件

在各种管理系统中数据表格非常常用,它用于按行列展示数据,JSF对表格做了一些封装,下面是一个例子。

<h:dataTable value="#{student.studentList}" var="s">
    <h:column>
        <f:facet name="header">姓名</f:facet>
        #{s.name}
    </h:column>
    <h:column>
        <f:facet name="header">年级</f:facet>
        #{s.grade}
    </h:column>
    <h:column>
        <f:facet name="header">分数</f:facet>
        #{s.score}
    </h:column>
</h:dataTable>

代码中student.studentList是包含一组实体类的列表,它绑定到了表格<h:dataTable>上,<h:column>则用于定义每一列的显示内容,其中包括表头和具体的数据字段。

实际开发中,表格的处理可能非常复杂,涉及分页、排序、筛选、行或列锁定等诸多功能,原生HTML的表格控件通常是难以满足的,这一般需要使用组件库来实现。

实现循环渲染

前面我们介绍过,条件渲染通常使用控件标签的rendered属性控制,循环渲染则需要使用<ui:repeat>标签。

<ui:repeat value="#{student.studentList}" var="s">
    #{s.name} #{s.grade} #{s.score}
</ui:repeat>

我们可以看到,循环渲染的使用方式有些类似数据表格<h:dataTable>,其中value属性用于指定循环渲染的数据源,var属性用于指定循环渲染的变量名。

Facelets模板

Facelets提供了一种模板机制,使得我们能够更好的复用视图。Facelets主要包括以下标签:

  • <ui:insert>:用于插入由<ui:define>定义的子视图。
  • <ui:define>:用于定义子视图。
  • <ui:include>:类似JSP的<jsp:include>,用于引入其他视图。
  • <ui:composition>:用于定义模板页面或一组用于填充模板的子视图。

我们这里直接看一个例子。

page.xhtml

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
                xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
    <html xmlns="http://www.w3.org/1999/xhtml"
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
    <head>
        <title><ui:insert name="title">Default Title</ui:insert></title>
    </head>
    <body>
    <ui:insert name="content">Default Content</ui:insert>
    </body>
    </html>
</ui:composition>

template.xhtml

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
                xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
                template="/page.xhtml">
    <ui:define name="title">Page Title</ui:define>
    <ui:define name="content">
        <h1>Welcome to My Page</h1>
    </ui:define>
</ui:composition>

上面代码中,template.xhtml中使用了<ui:composition>和一系列的<ui:define>定义了一组模板,这些模板被逐一在page.xhtml中使用<ui:insert>引入。

资源库 ResourcesLibrary

视图的CSS、JavaScript、图片等在JSF中被统一视为资源,JSF在此基础上还提供了资源库的概念,这样我们的视图就可以在不同的资源库之间切换,实现换肤效果。我们的资源库需要遵循如下目录结构,resources文件夹必须放置在webapp下。

|_ webapp
    |_ resources       # 包含所有资源库的文件夹
        |_ mytheme     # 资源库,文件夹名就是资源库名
            |_ app.css # 资源库内容
    |_ WEB-INF
<h:outputStylesheet library="mytheme" name="app.css" />

代码中,我们使用<h:outputStylesheet>引入资源库中的CSS文件,library为资源库名,name为资源库中的文件名,引入文件时的相对路径起始点是资源库文件夹。类似的,我们也可以使用<h:outputScript>引入资源库的JavaScript文件。

使用组件库

上面我们介绍的组件都是HTML标准组件,这些标准组件对于实际项目来说是远远不够用的,实际开发中我们通常需要用到组件库。PrimeFaces是当前比较流行的一个JSF组件库,功能强大而且组件极为丰富(媲美Antd),而且它是基于MIT协议开源的。

引入Maven依赖如下。

<dependency>
    <groupId>org.primefaces</groupId>
    <artifactId>primefaces</artifactId>
    <version>12.0.0</version>
</dependency>

编写测试页面,我们这里需要引入PrimeFaces的XML命名空间。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<h:head>
    <title>JSF Demo</title>
</h:head>
<h:body>
    <p:button value="提交" />
</h:body>
</html>

如果一切正常,我们可以看到一个默认的蓝色按钮。相比于那些搭建工程就繁琐到炸裂的前端项目,JSF的组件库使用实在是太方便了。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。
Copyright © 2017-2024 Gacfox All Rights Reserved.
Build with NextJS | Sitemap