2.9 利用JSF的消息
对于MVC框架而言,系统处理过程总有一些额外的消息需要传递给浏览者,这些消息当然可以使用托管Bean的属性来维护。但对于JSF框架来说,使用JSF消息机制是更好的解决方法。
在JSF生命周期中,任何组件都可以创建一个JSF消息,JSF消息通常由FacesContext来添加,而且FacesContext会自动维护应用的消息队列。当JSF生命周期结束(进入生成响应阶段)时,视图页面只要使用简单的<h:messages.../>或<h:message.../>即可显示这些消息。
JSF一共支持4种级别的消息:
一般信息:由FacesMessage.SEVERITY_INFO常量代表。
警告消息:由FacesMessage.SEVERITY_WARNING常量代表。
错误消息:由FacesMessage.SEVERITY_ERROR常量代表。
致命错误:由FacesMessage.SEVERITY_FATAL常量代表。
当程序要使用JSF消息时,可以通过构造器创建一个FacesMessage对象,该对象就代表JSF消息。创建该对象时可传入3个参数:
severity:指定消息的严重级别,就是前面介绍的4种级别。
summary:指定消息的摘要信息。
detail:指定消息的详细信息。
一旦得到了FacesMessage对象之后,接下来就可使用FacesContext将该JSF消息添加到消息队列中。添加到消息队列中的消息可使用<h:messages.../>或<h:message.../>在生成响应阶段显示出来。
使用FacesContext添加JSF消息是通过调用FacesContext的如下方法来实现的:
addMessage(String clientId, FacesMessage message):该方法的第一个参数指定该消息关联到哪个页面组件,第二个参数指定添加到消息队列中的FacesMessage对象。
例如,如下简单的用户注册页面。
程序清单:codes\02\2.9\FacesMessage\regist.jsp
<f:view>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>JSF消息测试</title>
</head>
<body>
<h1><h:outputText value="用户注册"/></h1>
<h:form>
<!-- 将下面UI组件的值绑定到Bean属性 -->
用户名:<h:inputText value="#{userBean.name}"/><br/>
<!-- 将下面UI组件的值绑定到Bean属性 -->
年龄:<h:inputText id="age" value="#{userBean.age}"/><br/>
<h:commandButton value="注册" action="#{userBean.regist}"/><br/>
</h:form>
</body>
</html>
</f:view>
上面页面中有一行粗体字代码,这行粗体字代码将一个单行文本框绑定到userBean的age属性,该userBean是一个非常简单的托管Bean,它会在处理用户注册时对用户的年龄进行提醒:如果用户输入的年龄大于100或小于0,该托管Bean将会使用JSFMessage进行提醒。下面是该托管Bean的类代码。
程序清单:codes\02\2.9\FacesMessage\WEB-INF\src\org\crazyit\jsf\UserBean.java
public class UserBean
{
private String name;
private int age;
//无参数的构造器
public UserBean()
{
}
//初始化全部属性的构造器
public UserBean(String name, int age)
{
this.name = name;
this.age = age;
}
//省略name属性的setter和getter方法
...
//省略age属性的setter和getter方法
public void setAge(int age)
{
if (age > 100 || age < 0)
{
FacesContext.getCurrentInstance()
.addMessage("age"
, new FacesMessage(FacesMessage.SEVERITY_FATAL
, "年龄不对" , "年龄必须小于100,且大于0 ")); }
this.age = age;
}
public int getAge()
{
return this.age;
}
//简单的处理逻辑,直接返回“success”字符串
public String regist()
{
return "success";
}
}
上面程序中的粗体字代码判断当用户输入的age大于100或age小于0时,系统将会自动添加一个FacesMessage消息,该消息的summary为“年龄必须小于100,且大于0”。
在faces-config.xml文件中配置该托管Bean,并为该Bean配置导航规则,指定当该托管Bean返回“success”字符串时,应用将导航到show.jsp页面。show.jsp页面代码如下:
程序清单:codes\02\2.9\FacesMessage\show.jsp
<f:view>
<html>
...
<body>
<h:messages/>
<h1>注册结果</h1>
用户名:<h:outputText value="#{userBean.name}"/><br/>
年龄:<h:outputText value="#{userBean.age}" /><br/>
</body>
</html>
</f:view>
UserBean在setAge()方法中通过FacesContext添加了一条FacesMessage消息,该页面就可通过粗体字代码所示的<h:messages/>标签将它显示出来。关于<h:message.../>和<h:messages.../>标签的用法后面还会有介绍,此处不详述。
如果用户输入的age属性大于100,将可以看到如图2.32所示的页面。
图2.32 JSF的消息
从上面示例可以看出,当使用FacesContext添加JSF消息之后,这些JSF消息并不会改变JSF生命周期的推进。
应用对用户输入的age属性不只是简单地警告,而是强制要求age属性必须在0~100之间,否则系统直接退回regist.jsp,那我们可以在setAge()方法中显式抛出异常。代码如下所示:
程序清单:codes\02\2.9\FacesException\WEB-INF\src\org\crazyit\jsf\UserBean.java
public class UserBean
{
private String name;
private int age;
//无参数的构造器
public UserBean()
{
}
//初始化全部属性的构造器
public UserBean(String name, int age)
{
this.name = name;
this.age = age;
}
//省略name属性的setter和getter方法
...
//age属性的setter和getter方法
public void setAge(int age)
{
if (age > 100 || age < 0)
{
throw new RuntimeException("年龄必须小于100,且大于0!");
}
this.age = age;
}
public int getAge()
{
return this.age;
}
//简单的处理逻辑,直接返回“success”字符串
public String regist()
{
return "success";
}
}
从上面页面中可以看到,当用户输入的age不在0~100之内时,UserBean的setAge()方法将会抛出一个RuntimeException异常,这个异常信息是“年龄必须小于100,且大于0!”,JSF的<h:messages.../>标签和<h:message.../>标签都可输出这个异常信息。
为了在regist.jsp页面上输出setAge()方法中抛出的异常,可以将该页面代码改为如下形式:
程序清单:codes\02\2.9\FacesException\regist.jsp
<f:view> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>JSF消息测试</title> </head> <body> <h1><h:outputText value="用户注册"/></h1> <h:messages/> <h:form> <!-- 将下面UI组件的值绑定到Bean属性 --> 用户名:<h:inputText value="#{userBean.name}"/><br/> <!-- 将下面UI组件的值绑定到Bean属性 --> 年龄:<h:inputText id="age" value="#{userBean.age}"/> <!-- 输出age字段关联的异常信息 --> <h:message for="age"/><br/> <h:commandButton value="注册" action="#{userBean.regist}"/><br/> </h:form> </body> </html> </f:view>
上面页面代码中同时使用了<h:messages.../>和<h:message.../>两个标签,其中第一个标签可以输出所有组件上的异常信息;第二个标签需要指定一个for属性,for属性值指定输出哪个组件上的异常信息。
如果用户输入的age属性大于100,该应用将不会激发<h:commandButton.../>组件上的action属性绑定#{userBean.regist}方法,系统将退回regist.jsp,浏览者将看到如图2.33所示的页面。
图2.33 输出setAge()方法抛出的异常信息
通过上面两个示例可以看出,JSF提供的消息机制给实际开发带来了很大的便捷,开发者只要通过FacesContext将消息添加到消息队列中,接下来就可在生成响应阶段使用<h:messages.../>标签或<h:message.../>标签来输出消息内容了。
如果结合后面介绍的JSF国际化支持,应用程序还可添加具有国际化支持的消息。