Java在最近几年逐渐升温随着Java SE 和Java SE 的推出Java的未来更显得无比辉煌但以Java为基础的JSP在Java SE 推出之前却一直抬不起头来这最重要的原因就是JSP虽然功能十分强大但最大的优点也是它的最大缺点功能强大就意味着复杂尤其是设计前端界面的可视化工具不多也不够强大因此设计JSP页面就变得十分复杂和繁琐不过在Java SE 推出的同时Sun为了简化JSP的开发难度推出了新的JavaServer Faces(简称JSF)规范从而使JSP走上了康庄大道
一什么是JSF
JSF和JSP是一对新的搭档JSP是用于后台的逻辑处理的技术而JSF恰恰相反是使开发人员能够快速的开发基于 Java 的 Web 应用程序的技术是一种表现层技术目前JSF已经正式作为一个标准加入了Java EE 中
作为一种高度组件化的技术开发人员可以在一些开发工具的支持下实现拖拉式编辑操作用户只需要简单的将 JSF 组件拖到页面上就可以很容易的进行 Web 开发了这是其作为一种组件化的技术所具有的最大好处我们能用的组件不光是一些比较简单的输入框之类还有更多复杂的组件可以使用的比如 DataTable 这样的表格组件 Tree 这样的树形组件等等
作为一种标准的技术JSF还得到了相当多工具提供商的支持同时我们也会有很多很好的免费开发工具可以使用前不久 Sun Java Studio Creator 和 Oracle JDeveloper g 作为免费的支持 JSF 的开发工具发布给 JSF 带来了不小的生气另外我们也有一些很优秀的商业开发工具可共选择BEA Workshop (原 M NitroX)ExadelMyEclipse 这样的基于 Eclipse 的插件开发工具为现在广大的 Eclipse 用户带来了不小的便利IBM 的 Rational Application Developer 和 Borland 的 JBuilder 也是很不错的支持 JSF 可视化开发的商业开发工具
JSF和传统的Web技术有着本质上的差别在传统的Web技术需要用户自己对浏览器请求进行捕捉保存客户端状态并且手工控制着页面的转向等等而JSF的出现无疑给我们带来了巨大的便利JSF 提供了事件驱动的页面导航模型该模型使应用程序开发人员能够设计应用程序的页面流与 Struts 的方式向类似的是所有的页面流信息都定义在 JSF 配置 XML 文件 (facesconfigxml) 中而非硬编码在应用程序中这很大程度简化了开发人员开发难度简化了应用程序的开发
同时JSF也是一种遵循模型视图-控制器 (MVC) 模式的框架实现了视图代码(View)与应用逻辑(Model)的完全分离使得使用 JSF 技术的应用程序能够很好的实现页面与代码的分离所有对 JSF 页面的请求都会通过一个前端控制器 (FacesServlet) 处理系统自动处理用户的请求并将结果返回给用户这和传统的 MVC 框架并没有太大的区别
在JSF中不仅使用了 POJO 技术而且还使用了类似 Spring 的控制反转(IoC) (或称为依赖注入DI) 技术在 JSF 的 Backing Bean 中我们可以把视图所需要的数据和操作放进一个 Backing Bean 中同时得益于 JSF 使用的 DI 技术我们可以在配置文件中初始化 Managed Bean同时我们也可以通过这样的技术很方便的和使用类似技术的 Spring 进行整合
二如何在JSP中使用JSF
JSF只有通过和JSP相结合才能充分发挥它的功效JSF是通过标签库和JSP进行集成的标签库就相当于ASPNET的服务端组件JSF提供了非常丰富的标签库通过这些标签库可以生成各种客户端模型如HTMLWMLXML以及JavaScript等通过这些标签你可以很容易建立大规模的客户端模型并由这些标签自动处理客户端请求
接下来让我们来看一个如何使JSF和JSP在一起工作的例子在JSF中有两个库第一个叫做内核库在这个库中包含了各种主要的标签如配置组件管理事件验证输入信息等第二个库的主要功能是将HTML和JSF的各种标签相对应每一个JSF标签都会对应一个HTML组件如UIInput标签对应了HTML中的文本框或密码框
在JSF标签中文本输入框叫做inputText而密码输入库叫inputSecret下面是一个简单的JSF和JSP结合的用户接口程序
<%@ taglib uri="%>
<%@ taglib uri="%>
<html>
<head>
<meta HTTPEQUIV="ContentType" CONTENT="text/html;CHARSET=GB">
<title>第一个JSF程序</title>
</head>
<body>
<f:view>
<h:form id="simpleForm">
<h:outputText id="favoriteLabel" value="请输入一个数字"/>
<h:inputText id="favoriteValue" value="#{simplelongValue}">
<f:validateLongrange maximum="" minimum=""/>
</h:inputText>
<p/>
<h:commandButton id="submit" value="提交" action="#{simplesimpleActionMethod}"/>
</h:form>
</f:view>
</body>
</html>
在上面的代码中我们可以了解到JSF是如何同JSP集成的我们首先可以看到一个内核标签view然后是几个JSF组件如formoutputTextinputText以及commandButton这几个组件被放到form中从而开成了form中的一部分在程序的最开始必须使用import导入两个标签库代码如下
<%@ taglib uri="%>
<%@ taglib uri="%>
上面行代码声明了JSP中要使用哪一个JSF标签库内核库使用前缀(prefix)f声明而HTML库使用前缀(prefix)h声明这两个前缀并不是必须要使用而只是一个建议在程序中内核库必须要使用因为view在所有的JSF页中必须使用而HTML标签在运行时将JSF标签转化为HTML组件这个h前缀并不是必须的而是JSF规范推荐使用的这样我们使我们的JSF程序更易读
在声明后是几行标准的HTML语句本文不再详述从<f:view>开始是一段JSF语句这段代码如下所示
<f:view>
<h:form id="simpleForm">
<h:outputText id="favoriteLabel" value="请输入一个数字"/>
<h:inputText id="favoriteValue" value="#{simplelongValue}">
<f:validateLongrange maximum="" minimum=""/>
</h:inputText>
<p/>
<h:commandButton id="submit" value="提交"
action="#{simplesimpleActionMethod}"/>
</h:form>
</f:view>
</f:view>标签预示着JSF的开始而它的下一个标签form将建立一个HTML Form而outputText标签相当于HTML中的label组件inputText标签相当于HTML中的textField组件而commandButton标签相当于HTML中的submit按钮运行这个JSP程序将得到如图所显示效果
图 第一个JSF程序的运行结果
三JSP如何响应JSF的请求
从上面的例子我们已经知道如何在JSP中使用JSF了在这一部分让我们来看看在JSF是如何处理请求的
首先让我们来看一个例子这个例子是将华氏度转换为摄氏度当用户点击提交按钮时程序将进行转换
<%@ taglib uri="%>
<%@ taglib uri="%>
<html>
<head>
<meta HTTPEQUIV="ContentType" CONTENT="text/html;CHARSET=GB">
<title>温度转换程序</title>
</head>
<body>
<f:view>
<h:form>
<div>
<h:outputText id="fahrenheitLabel" value="请输入华氏温度"/>
<span>
<h:inputText id="temperature" value="#{tcfahrenheitTemp}">
<f:validateDoublerange minimum="" maximum=""/>
<f:valuechangeListener type="tempconvpageTCChangedListener"/>
</h:inputText>
</span>
</div>
<div>
<h:outputText id="celsiusLabel" value="摄氏温度"/>
<span>
<h:outputText id="celsiusValue" value="#{tccelsiusTemp}">
<f:convertNumber maxFractionDigits="" type="number"/>
</h:outputText>
</span>
</div>
<div>
<h:commandButton value="转换" action="#{tcconvert}">
</h:commandButton>
</div>
</h:form>
</f:view>
</body>
</html>
在程序的前两行是导入JSF核心库和HTML库这个在前面已经讨论过在这里不再详述
下面让我们来看看JSF标签是如何同后端进行交互的由于我们是在JSP中使用JSF因此这个和正常的JSP没有什么区别JSP实际上就是Servlet在JSP第一次运行时由JSP编译器将JSP文件编译成Servlet后再由Servlet调用然后由Servlet来接收客户端传过来的数据流但和一般的JSP程序不同的是JSF标签是由JSF API负责调用的(这样可以做到逻辑层和表现层分离)除此之外它们和一般的JSP标签没有任何区别
当UIComponent标签收到doStartTag方法时JSF将使用这些属性来设置标签的值如本例中的inputText标签将按它的属性值来设置下面是JSF的代码片段
<h:inputText id="temperature" value="#{tcfahrenheitTemp}">
<f:validateDoublerange minimum="" maximum=""/>
<f:valuechangeListener type="tempconvpageTCChangedListener"/>
</h:inputText>
inputText标签根据相应的值设置了id和value的属性在JSF中是通过setAttribute(String name Object value)设置每一个属性值的但我们需要注意的是JSF标签可以指定相应的默认值这有些类似java中的系统属性如果你给了一个属性名子那系统将返回这个属性的值如果指定它的默认值并且这个属性不存在的话将返回这个默认值
接下来让我们来看看上面程序的最重要的部分也就是UIInput组件的事件处理
<f:valuechangeListener type="tempconvpageTCChangedListener"/>
在JSF中事件处理是由valuechangeListener标签完成的这个标签所表示的事件在文本框的值发生变化时引发事件但有意思的是这个事件并不马上提交而是要等到用户点击"提交"按钮后这个事件连同相应的数据才提交给后端因此这个事件请求也叫做预提交最后让我们看看UICommand的代码实现
<div>
<h:commandButton value="转换" action="#{tcconvert}">
</h:commandButton>
</div>
上面的代码将convert()方法和UICommand连接了起来也就是说点击"提交"按钮后将执行convert()方法在遇到view标签后JSF程序结果JSFAPI最后调用doEnd方法来结束JSF程序JSF引擎在解析这段程序后将相应的JSF标签转换为HTML组件
最后让我们来看看JSP是如何响应JSF事件的下面是一段响应JSF事件的Java代码
public class TCChangedListener implements ValueChangeListener
{
public TCChangedListener()
{
super();
}
// 事件处理
public void processValueChange(ValueChangeEvent event)
throws AbortProcessingException
{
UIComponent comp = eventgetComponent();
Object value = eventgetNewValue();
if (null != value)
{
float curVal = ((Number) value)floatValue();
Map values = compgetAttributes();
if (curVal < )
{
valuesput("styleClass" "red");
}
else
{
valuesput("styleClass" "black");
}
}
}
要想响应JSF事件必须要实现JSF库中的ValueChangeListener接口上面的程序要注意的是最后根据输入的值来设置相应的颜色这些值并不依赖JSP当然你也可以将它们设置成null而由JSP 标签来设置它们的颜色