Web应用程序的开发与传统的单机程序开发在本质上存在着太多的差异,Web应用程序开发人员至今不可避免的必须处理HTTP的细节,而HTTP无状态的(stateless)本质,与传统应用程序必须维持程序运行过程中的信息有明显的违背,再则Web应用程序面对网站上不同的使用者同时的存取,其线程安全问题以及数据验证、转换处理等问题,又是复杂且难以解决的。
另一方面,本质上是静态的HTML与本质上是动态的应用程序又是一项违背,这造成不可避免的,处理网页设计的美术人员与程序设计人员,必须被彼此加入至视图组件中的逻辑互相干扰,即便一些视图呈现逻辑以Tag的方式呈现,试图展现对网页设计美术人员的亲切,但它终究必须牵涉到相关的流程逻辑。
有很多方案试着解决种种的困境,而各自的着眼点各不相同,有的从程序设计人员的角度来解决,有的从网页设计人员的角度来解决,各种的框架被提出,所造成的是各种不统一的标签与框架,为了促进产能的整合开发环境(IDE)难以整合这些标签与框架,另一方面,开发人员的学习负担也不断的加重,他们必须一人了解多个角色的工作。
JavaServer Faces 的提出在试图解决这个问题,它试图在不同的角度上提供网页设计人员、应用程序设计人员、组件开发人员解决方案,让不同技术的人员可以彼此合作又不互相干扰,它综合了各家厂商现有的技术特点,由Java Community Process(JCP)团队研拟出来的一套标准,并在2004年三月发表了JavaServer Faces 1.0实作成果。
从网页设计人员的角度来看,JavaServer Faces提供了一套像是新版本的HTML标签,但它不是静态的,而是动态的,可以与后端的动态程序结合,但网页设计人员不需要理会后端的动态部份,网页设计人员甚至不太需要接触JSTL这类的Tag,也可以动态的展现数据(像是动态的查询表格内容),JavaServer Faces提供标准的标签,这可以与网页编辑程序结合在一起,另一方面,JavaServer Faces也允许您自订标签。
从应用程序设计人员的角度来看,JavaServer Faces提供一个与传统应用程序开发相类似的模型(当然因某些本质上的差异,模型还是稍有不同),他们可以基于事件驱动来开发程序,不必关切HTTP的处理细节,如果必须处理一些视觉组件的属性的话,他们也可以直接在整合开发环境上拖拉这些组件,点选设定组件的属性,JavaServer Faces甚至还为应用程序设计人员处理了对象与字符串(HTTP传送本质上就是字符串)间不匹配的转换问题。
从UI组件开发人员的角度来看,他们可以设计通用的UI组件,让应用程序的开发产能提高,就如同在设计Swing组件等,UI开发人员可以独立开发,只要定义好相关的属性选项来调整细节,而不用受到网页设计人员或应用程序设计人员的干扰。
三个角色的知识领域原则上可以互不干扰,根据您的角色,您只要了解其中一个知识领域,就可以运用JavaServer Faces,其它角色的知识领域您可以不用了解太多细节。
要使用JSF,首先您要先取得JavaServer Faces参考实作(JavaServer Faces Reference Implementation),在将来,JSF会与Container整合在一起,届时您只要下载支持的Container,就可以使用JSF的功能。
请至 JSF 官方网站的 下载区 下载参考实作,在下载压缩档并解压缩之后,将其 lib 目录下的 jar 档案复制至您的Web应用程序的/WEB-INF/lib目录下,另外您还需要 jstl.jar 与 standard.jar 档案,这些档案您可以在 sample 目录下,解压缩当中的一个范例,在它的/WEB-INF/lib目录下找到,将之一并复制至您的Web应用程序的/WEB-INF/lib目录下,您总共需要以下的档案:
* jsf-impl.jar
* jsf-api.jar
* commons-digester.jar
* commons-collections.jar
* commons-beanutils.jar
* jstl.jar
* standard.jar
Web应用程序的web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<description>
JSF Demo
</description>
<display-name>JSF Demo</display-name>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>
javax.faces.webapp.FacesServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.faces</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
在上面的定义中,我们将所有.faces的请求交由FaceServlet来处理,FaceServlet会唤起相对的.jsp网页,例如请求是/index.faces的话,则实际上会唤起/index.jsp网页。
JSF的实现思想来源于.NET平台的ASP.NET,组件化的设计以及事件驱动模型是它们的特点,对于开发人员,我们可以想象Swing or SWT的开发。即JSP是UI的展现,那么UI的控制代码则交给后台的一个UI Bean进行处理,在这个UI Bean中包含了页面组件的事件(一个button的click事件等等)以及其它的控制部分。
一个简单的示例
index.jsp
<%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<html>
<head>
<title>第一个JSF </title>
</head>
<body>
<f:view>
<h:form>
<h3>请输入您的名称</h3>
名称: <h:inputText value="#{user.name}"/><p>
<h:commandButton value="确定" action="login"/>
</h:form>
</f:view>
</body>
</html>
JSP中的f、h两组标签库是JSF的标准标签库,分别代表JSF HTML 和 JSF CORE,注意#{user.name},#代表JSF的表达式语言,而user.name表示,user是UI Bean(managed bean),name是这个bean的一个属性,由提供的get方法获取值。我们可以从下面的代码看到,UI Bean是一个POJO的,而不象Struts需要继承Struts本身的父类。
package onlyfun.caterpillar;
public class UserBean {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public String login() //按下页面上的“确定”时执行
{
….
}
}
所有的managed bean需要通过config文件进行管理
<?xml version="1.0"?>
<!DOCTYPE faces-config PUBLIC
"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN"
"http://java.sun.com/dtd/web-facesconfig_1_0.dtd">
<faces-config>
<navigation-rule>
<from-view-id>/pages/index.jsp</from-view-id>
<navigation-case>
<from-outcome>login</from-outcome>
<to-view-id>/pages/welcome.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<managed-bean>
<managed-bean-name>user</managed-bean-name>
<managed-bean-class>
onlyfun.caterpillar.UserBean
</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
</faces-config>
通过这个例子我们可以看到,JSF的事件驱动与开发Swing程序是很相似的,页面上的UI组件可以触发到UI Bean的某个method或者与UI Bean的某个属性值进行绑定,这样的封装方式使开发者无需关心HTML的具体细节,让开发者将精力尽可能的投入到业务逻辑上去
一个datatable的例子
将数据库查询到的记录以table的形式呈现出来,这是在WEB应用开发的一个常用的表现方法,JSF Html标签库中提供了<h:datatable/>以方便的实现这一功能
Index.jsp
<h:form>
<h:dataTable value="#{bb.customerList}" var="customers">
<%-- nitrox:varType="com.entity.Customer" --%>
<h:column>
<f:facet name="header">
<h:outputText value="Company Name"/>
</f:facet>
<h:outputText value="#{customers.companyName}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="City"/>
</f:facet>
<h:outputText value="#{customers.city}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Address"/>
</f:facet>
<h:outputText value="#{customers.address}"/>
</h:column>
</h:dataTable>
</h:form>
managed bean
faces-config.xml
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE faces-config PUBLIC
"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
"http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<!-- =========== FULL CONFIGURATION FILE ================================== -->
<faces-config>
<application>
<message-bundle>resources.application</message-bundle>
<locale-config>
<default-locale>en</default-locale>
</locale-config>
</application>
<managed-bean>
<managed-bean-name>bb</managed-bean-name>
<managed-bean-class>com.corejsf.BackingBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
</faces-config>
我们将customerList绑定给datatable,并且在datatable中指定显示的columns,这样我们会很方便的得到table的呈现
除了使用JSF提供的标准标签库,我们也可以象Swing一样制作自己的标签组件,具体请参考SUN 网站上针对JSF的document.
另外,JSF已经是JCP的标准,也就是说,其他的开源组织以及厂商也可以在这个标准上开发自己的JSF组件以对JSF的功能库进行扩展,目前开源组织Apache的MyFaces以及Oracle 的ADF都得到了很好的应用
另一方面,本质上是静态的HTML与本质上是动态的应用程序又是一项违背,这造成不可避免的,处理网页设计的美术人员与程序设计人员,必须被彼此加入至视图组件中的逻辑互相干扰,即便一些视图呈现逻辑以Tag的方式呈现,试图展现对网页设计美术人员的亲切,但它终究必须牵涉到相关的流程逻辑。
有很多方案试着解决种种的困境,而各自的着眼点各不相同,有的从程序设计人员的角度来解决,有的从网页设计人员的角度来解决,各种的框架被提出,所造成的是各种不统一的标签与框架,为了促进产能的整合开发环境(IDE)难以整合这些标签与框架,另一方面,开发人员的学习负担也不断的加重,他们必须一人了解多个角色的工作。
JavaServer Faces 的提出在试图解决这个问题,它试图在不同的角度上提供网页设计人员、应用程序设计人员、组件开发人员解决方案,让不同技术的人员可以彼此合作又不互相干扰,它综合了各家厂商现有的技术特点,由Java Community Process(JCP)团队研拟出来的一套标准,并在2004年三月发表了JavaServer Faces 1.0实作成果。
从网页设计人员的角度来看,JavaServer Faces提供了一套像是新版本的HTML标签,但它不是静态的,而是动态的,可以与后端的动态程序结合,但网页设计人员不需要理会后端的动态部份,网页设计人员甚至不太需要接触JSTL这类的Tag,也可以动态的展现数据(像是动态的查询表格内容),JavaServer Faces提供标准的标签,这可以与网页编辑程序结合在一起,另一方面,JavaServer Faces也允许您自订标签。
从应用程序设计人员的角度来看,JavaServer Faces提供一个与传统应用程序开发相类似的模型(当然因某些本质上的差异,模型还是稍有不同),他们可以基于事件驱动来开发程序,不必关切HTTP的处理细节,如果必须处理一些视觉组件的属性的话,他们也可以直接在整合开发环境上拖拉这些组件,点选设定组件的属性,JavaServer Faces甚至还为应用程序设计人员处理了对象与字符串(HTTP传送本质上就是字符串)间不匹配的转换问题。
从UI组件开发人员的角度来看,他们可以设计通用的UI组件,让应用程序的开发产能提高,就如同在设计Swing组件等,UI开发人员可以独立开发,只要定义好相关的属性选项来调整细节,而不用受到网页设计人员或应用程序设计人员的干扰。
三个角色的知识领域原则上可以互不干扰,根据您的角色,您只要了解其中一个知识领域,就可以运用JavaServer Faces,其它角色的知识领域您可以不用了解太多细节。
要使用JSF,首先您要先取得JavaServer Faces参考实作(JavaServer Faces Reference Implementation),在将来,JSF会与Container整合在一起,届时您只要下载支持的Container,就可以使用JSF的功能。
请至 JSF 官方网站的 下载区 下载参考实作,在下载压缩档并解压缩之后,将其 lib 目录下的 jar 档案复制至您的Web应用程序的/WEB-INF/lib目录下,另外您还需要 jstl.jar 与 standard.jar 档案,这些档案您可以在 sample 目录下,解压缩当中的一个范例,在它的/WEB-INF/lib目录下找到,将之一并复制至您的Web应用程序的/WEB-INF/lib目录下,您总共需要以下的档案:
* jsf-impl.jar
* jsf-api.jar
* commons-digester.jar
* commons-collections.jar
* commons-beanutils.jar
* jstl.jar
* standard.jar
Web应用程序的web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<description>
JSF Demo
</description>
<display-name>JSF Demo</display-name>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>
javax.faces.webapp.FacesServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.faces</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
在上面的定义中,我们将所有.faces的请求交由FaceServlet来处理,FaceServlet会唤起相对的.jsp网页,例如请求是/index.faces的话,则实际上会唤起/index.jsp网页。
JSF的实现思想来源于.NET平台的ASP.NET,组件化的设计以及事件驱动模型是它们的特点,对于开发人员,我们可以想象Swing or SWT的开发。即JSP是UI的展现,那么UI的控制代码则交给后台的一个UI Bean进行处理,在这个UI Bean中包含了页面组件的事件(一个button的click事件等等)以及其它的控制部分。
一个简单的示例
index.jsp
<%@taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<html>
<head>
<title>第一个JSF </title>
</head>
<body>
<f:view>
<h:form>
<h3>请输入您的名称</h3>
名称: <h:inputText value="#{user.name}"/><p>
<h:commandButton value="确定" action="login"/>
</h:form>
</f:view>
</body>
</html>
JSP中的f、h两组标签库是JSF的标准标签库,分别代表JSF HTML 和 JSF CORE,注意#{user.name},#代表JSF的表达式语言,而user.name表示,user是UI Bean(managed bean),name是这个bean的一个属性,由提供的get方法获取值。我们可以从下面的代码看到,UI Bean是一个POJO的,而不象Struts需要继承Struts本身的父类。
package onlyfun.caterpillar;
public class UserBean {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public String login() //按下页面上的“确定”时执行
{
….
}
}
所有的managed bean需要通过config文件进行管理
<?xml version="1.0"?>
<!DOCTYPE faces-config PUBLIC
"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN"
"http://java.sun.com/dtd/web-facesconfig_1_0.dtd">
<faces-config>
<navigation-rule>
<from-view-id>/pages/index.jsp</from-view-id>
<navigation-case>
<from-outcome>login</from-outcome>
<to-view-id>/pages/welcome.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<managed-bean>
<managed-bean-name>user</managed-bean-name>
<managed-bean-class>
onlyfun.caterpillar.UserBean
</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
</faces-config>
通过这个例子我们可以看到,JSF的事件驱动与开发Swing程序是很相似的,页面上的UI组件可以触发到UI Bean的某个method或者与UI Bean的某个属性值进行绑定,这样的封装方式使开发者无需关心HTML的具体细节,让开发者将精力尽可能的投入到业务逻辑上去
一个datatable的例子
将数据库查询到的记录以table的形式呈现出来,这是在WEB应用开发的一个常用的表现方法,JSF Html标签库中提供了<h:datatable/>以方便的实现这一功能
Index.jsp
<h:form>
<h:dataTable value="#{bb.customerList}" var="customers">
<%-- nitrox:varType="com.entity.Customer" --%>
<h:column>
<f:facet name="header">
<h:outputText value="Company Name"/>
</f:facet>
<h:outputText value="#{customers.companyName}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="City"/>
</f:facet>
<h:outputText value="#{customers.city}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="Address"/>
</f:facet>
<h:outputText value="#{customers.address}"/>
</h:column>
</h:dataTable>
</h:form>
managed bean
faces-config.xml
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE faces-config PUBLIC
"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.1//EN"
"http://java.sun.com/dtd/web-facesconfig_1_1.dtd">
<!-- =========== FULL CONFIGURATION FILE ================================== -->
<faces-config>
<application>
<message-bundle>resources.application</message-bundle>
<locale-config>
<default-locale>en</default-locale>
</locale-config>
</application>
<managed-bean>
<managed-bean-name>bb</managed-bean-name>
<managed-bean-class>com.corejsf.BackingBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
</faces-config>
我们将customerList绑定给datatable,并且在datatable中指定显示的columns,这样我们会很方便的得到table的呈现
除了使用JSF提供的标准标签库,我们也可以象Swing一样制作自己的标签组件,具体请参考SUN 网站上针对JSF的document.
另外,JSF已经是JCP的标准,也就是说,其他的开源组织以及厂商也可以在这个标准上开发自己的JSF组件以对JSF的功能库进行扩展,目前开源组织Apache的MyFaces以及Oracle 的ADF都得到了很好的应用