3. 数据转换与验证
转换器(Converter)协助模型与视图之间的数据转换,验证器(Validator)
协助进行语意检验(Semantic Validation)。
3.1 标准转换器
Web应用程序与浏览器之间是使用HTTP进行沟通,所有传送的数据基本上
都是字符串文字,而Java应用程序本身基本上则是对象,所以对象数据必须经由
转换传送给浏览器,而浏览器送来的数据也必须转换为对象才能使用。
JSF定义了一系列标准的转换器(Converter),对于基本数据类型(primitive
type)或是其Wrapper类,JSF会使用javax.faces.Boolean、javax.faces.Byte、
javax.faces.Character、javax.faces.Double、javax.faces.Float、 javax.faces.Integer、
javax.faces.Long、javax.faces.Short等自动进行转换,对于 BigDecimal、BigInteger,
则会使用javax.faces.BigDecimal、javax.faces.BigInteger自动进行转换。
至于DateTime、Number,我们可以使用<f:convertDateTime>、
<f:convertNumber>标签进行转换,它们各自提供有一些简单的属性,可以让我们
在转换时指定一些转换的格式细节。
来看个简单的例子,首先我们定义一个简单的Bean:
•UserBean.java
package onlyfun.caterpillar;
import java.util.Date;
public class UserBean {
private Date date = new Date();
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
这个Bean的属性接受Date类型的参数,按理来说,接收到HTTP传来的数据
中若有相关的日期信息,我们必须剖析这个信息,再转换为Date对象,然而我们
可以使用JSF的标准转换器来协助这项工作,例如:
•index.jsp
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@page contentType="text/html;charset=GB2312"%>
<f:view>
<html>
<head>
<title>转换器示范</title>
</head>
<body>
设定的日期是:
<b>
<h:outputText value="#{user.date}">
<f:convertDateTime pattern="dd/MM/yyyy"/>
</h:outputText>
</b>
<h:form>
<h:inputText id="dateField" value="#{user.date}">
<f:convertDateTime pattern="dd/MM/yyyy"/>
</h:inputText>
<h:message for="dateField" style="color:red"/>
<br>
<h:commandButton value="送出" action="show"/>
</h:form>
</body>
</html>
</f:view>
在<f:convertDateTime>中,我们使用pattern指定日期的样式为dd/MM/yyyy,
即「日/月/公元」格式,如果转换错误,则<h:message>可以显示错误信息,for
属性参考至<h:inputText> 的id属性,表示将有关dateField的错误信息显示出来。
假设faces-config.xml是这样定义的:
•faces-config.xml
<?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>/*</from-view-id>
<navigation-case>
<from-outcome>show</from-outcome>
<to-view-id>/pages/index.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>
首次连上页面时显示的画面如下:
如您所看到的,转换器自动依pattern设定的样式将Date对象格式化了,当您
依格式输入数据并提交后,转换器也会自动将您输入的数据转换为Date对象,如
果转换时发生错误,则会出现以下的信息:
<f:convertDateTime>标签还有几个可用的属性,您可以参考 Tag Library
Documentation 的说明,而依照类似的方式,您也可以使用<f:convertNumber>来
转换数值。
您还可以参考 Using the Standard Converters 这篇文章中有关于标准转换器
的说明。
3.2自定义转换器
除了使用标准的转换器之外,您还可以自行定制您的转换器,您可以实现
javax.faces.convert.Converter接口,这个接口有两个要实现的方法:
public Object getAsObject(FacesContext context, UIComponent component, String
str);
public String getAsString(FacesContext context, UIComponent component, Object
obj);
简单的说,第一个方法会接收从客户端经由HTTP传来的字符串数据,您在
第一个方法中将之转换为您的自定义对象,这个自定义对象将会自动设定给您指
定的Bean对象;第二个方法就是将从您的Bean对象得到的对象转换为字符串,
如此才能由HTTP传回给客户端。
直接以一个简单的例子来作说明,假设您有一个User类:
•User.java
package onlyfun.caterpillar;
public class User {
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
这个User类是我们转换器的目标对象,而您有一个GuestBean类:
•GuestBean.java
package onlyfun.caterpillar;
public class GuestBean {
private User user;
public void setUser(User user) {
this.user = user;
}
public User getUser() {
return user;
}
}
这个Bean上的属性直接传回或接受User类型的参数,我们来实现一个简单的
转换器,为HTTP字符串与User对象进行转换:
•UserConverter.java
package onlyfun.caterpillar;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
public class UserConverter implements Converter {
public Object getAsObject(FacesContext context, UIComponent component,
String str) throws ConverterException {
String[] strs = str.split(",");
User user = new User();
try {
user.setFirstName(strs[0]);
user.setLastName(strs[1]);
} catch(Exception e) {
// 转换错误,简单的丢出例外
throw new ConverterException();
}
return user;
}
public String getAsString(FacesContext context, UIComponent component,
Object obj) throws ConverterException {
String firstName = ((User) obj).getFirstName();
String lastName = ((User) obj).getLastName();
return firstName + "," + lastName;
}
}
实现完成这个转换器,我们要告诉JSF这件事,这是在faces-config.xml中完成注
册:
•faces-config.xml
<?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>/*</from-view-id>
<navigation-case>
<from-outcome>show</from-outcome>
<to-view-id>/pages/index.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<converter>
<converter-id>onlyfun.caterpillar.User</converter-id>
<converter-class>
onlyfun.caterpillar.UserConverter
</converter-class>
</converter>
<managed-bean>
<managed-bean-name>guest</managed-bean-name>
<managed-bean-class>
onlyfun.caterpillar.GuestBean
</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
</faces-config>
注册转换器时,需提供转换器标识(Converter ID)与转换器类,接下来要
在JSF页面中使用转换器的话,就是指定所要使用的转换器标识,例如:
•index.jsp
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@page contentType="text/html;charset=GB2312"%>
<f:view>
<html>
<head>
<title>自定义转换器</title>
</head>
<body>
Guest名称是:<b>
<h:outputText value="#{guest.user}" converter="onlyfun.caterpillar.User"/>
</b>
<h:form>
<h:inputText id="userField" value="#{guest.user}"
converter="onlyfun.caterpillar.User"/>
<h:message for="userField" style="color:red"/>
<br>
<h:commandButton value="送出" action="show"/>
</h:form>
</body>
</html>
</f:view>
您也可以用<f:converter>标签并使用converterId属性来指定转换器,例如:
<h:inputText id="userField" value="#{guest.user}">
<f:converter converterId="onlyfun.caterpillar.User"/>
</h:inputText>
除了向JSF注册转换器之外,还有一个方式可以不用注册,就是直接在Bean
上提供一个取得转换器的方法,例如:
•GuestBean.java
package onlyfun.caterpillar;
import javax.faces.convert.Converter;
public class GuestBean {
private User user;
private Converter converter = new UserConverter();
public void setUser(User user) {
this.user = user;
}
public User getUser() {
return user;
}
public Converter getConverter() {
return converter;
}
}
之后可以直接结合 JSF Expression Language 来指定转换器:
<h:inputText id="userField" value="#{guest.user}"
converter="#{guest.converter}"/>
3.3标准验证器
当应用程序要求使用者输入数据时,必然考虑到使用者输入数据的正确性,
对于使用者的输入必须进行检验,检验必要的两种验证是语法检验(Synatic
Validation)与语意检验(Semantic Validation)。
语法检验是要检查使用者输入的数据是否合乎我们所要求的格式,最基本的
就是检查使用者是否填入了栏目值,或是栏目值的长度、大小值等等是否符合要
求。语意检验是在语法检验之后,在格式符合需求之后,我们进一步验证使用者
输入的数据语意上是否正确,例如检查使用者的名称与密码是否匹配。
在1.3简单的导航 (Navigation) 中,我们对使用者名称与密码检查是否匹配,
这是语意检验,我们可以使用JSF所提供的标准验证器,为其加入语法检验,例
如:
•index.jsp
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@page contentType="text/html;charset=GB2312"%>
<html>
<head>
<title>验证器示范</title>
</head>
<body>
<f:view>
<h:messages layout="table" style="color:red"/>
<h:form>
<h3>请输入您的名称</h3>
<h:outputText value="#{user.errMessage}"/><p>
名称: <h:inputText value="#{user.name}" required="true"/><p>
密码: <h:inputSecret value="#{user.password}" required="true">
<f:validateLength minimum="6"/>
</h:inputSecret><p>
<h:commandButton value="送出" action="#{user.verify}"/>
</h:form>
</f:view>
</body>
</html>
在<h:inputText>、</h:inputSecret>中,我们设定了required属性为true,这表
示这个栏目一定要输入值,我们也在</h:inputSecret>设定了<f: validateLength>,
并设定其minimum属性为6,这表示这个栏目最少需要6个字符。
这一次在错误信息的显示上,我们使用<h:messages>标签,当有验证错误发
生时,相关的错误信息会收集起来,使用<h:messages>标签可以一次将所有的错
误信息显示出来。
下面是一个验证错误的信息显示:
JSF提供了三种标准验证器:<f:validateDoubleRange>、<f:validateLongRange>、
<f:validateLength>,您可以分别查询它们的 Tag Library Documentation,了解他
们有哪些属性可以使用,或者是参考 Using the Standard Validators 这篇文章中有
关于标准验证器的说明。
3.4自定义验证器
您可以自定义自己的验证器,所需要的是实现javax.faces.validator.Validator
接口,例如我们实现一个简单的密码验证器,检查字符长度,以及密码中是否包
括字符与数字:
•PasswordValidator.java
package onlyfun.caterpillar;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
public class PasswordValidator implements Validator {
public void validate(FacesContext context, UIComponent component,
Object obj) throws ValidatorException {
String password = (String) obj;
if(password.length() < 6) {
FacesMessage message = new FacesMessage(
FacesMessage.SEVERITY_ERROR,
"字符长度小于6",
"字符长度不得小于6");
throw new ValidatorException(message);
}
if(!password.matches(".+[0-9]+")) {
FacesMessage message = new FacesMessage(
FacesMessage.SEVERITY_ERROR,
"密码必须包括字符与数字",
"密码必须是字符加数字所组成");
throw new ValidatorException(message);
}
}
}
您要实现javax.faces.validator.Validator接口中的validate()方法,如果验证错
误,则丢出一个ValidatorException,它接受一个FacesMessage对象,这个对象接
受三个参数,分别表示信息的严重程度(INFO、 WARN、ERROR、FATAL)、
信息概述与详细信息内容,这些信息将可以使用<h:messages>或<h: message>标
签显示在页面上。
接下来要在faces-config.xml中注册验证器的标识(Validater ID),要加入以
下的内容:
•faces-config.xml
<?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>
....
<validator>
<validator-id>
onlyfun.caterpillar.Password
</validator-id>
<validator-class>
onlyfun.caterpillar.PasswordValidator
</validator-class>
</validator>
....
</faces-config>
要使用自定义的验证器,我们可以使用<f:validator>标签并设定validatorId属
性,例如:
....
<h:inputSecret value="#{user.password}" required="true">
<f:validator validatorId="onlyfun.caterpillar.Password"/>
</h:inputSecret><p>
....
您也可以让Bean自行负责验证的工作,可以在Bean上提供一个验证方法,
这个方法没有传回值,并可以接收FacesContext、UIComponent、Object三个参数,
例如:
•UserBean.java
package onlyfun.caterpillar;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.ValidatorException;
public class UserBean {
....
public void validate(FacesContext context, UIComponent component,
Object obj) throws ValidatorException {
String password = (String) obj;
if(password.length() < 6) {
FacesMessage message = new FacesMessage(
FacesMessage.SEVERITY_ERROR,
"字符长度小于6",
"字符长度不得小于6");
throw new ValidatorException(message);
}
if(!password.matches(".+[0-9]+")) {
FacesMessage message = new FacesMessage(
FacesMessage.SEVERITY_ERROR,
"密码必须包括字符与数字",
"密码必须是字符加数字所组成");
throw new ValidatorException(message);
}
}
}
接着可以在页面下如下使用验证器:
.....
<h:inputSecret value="#{user.password}"
required="true"
validator="#{user.validate}"/>
....
3.5错误信息处理
在使用标准转换器或验证器时,当发生错误时,会有一些预定义的错误信息
显示,这些信息可以使用<h:messages>或<h:message>标签来显示出来,而这些预
定义的错误信息也是可以修改的,您所要作的是提供一个信息资源文件,例如:
•messages.properties
javax.faces.component.UIInput.CONVERSION=Format Error.
javax.faces.component.UIInput.REQUIRED=Please input your data.
....
javax.faces.component.UIInput.CONVERSION是用来设定当转换器发现错误
时显示的信息,而javax.faces.component.UIInput.REQUIRED是在标签设定了
required为true,而使用者没有在栏目输入时显示的错误信息。
您要在faces-config.xml中告诉JSF您使用的信息文件名称,例如:
•faces-config.xml
<?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>
<application>
<local-config>
<default-locale>en</default-locale>
<supported-locale>zh_TW</supported-locale>
</local-config>
<message-bundle>messages</message-bundle>
</application>
.....
</faces-config>
在这边我们设定了信息文件的名称为messages_xx_YY.properties,其中
xx_YY是根据您的Locale来决定,转换器或验证器的错误信息如果有设定的话,
就使用设定值,如果没有设定的话,就使用预定义值。
验证器错误信息,除了上面的javax.faces.component.UIInput.REQUIRED之
外,还有以下的几个:
信息标识 预定义信息 用于
javax.faces.validator.
NOT_IN_RANGE
Validation Error:
Specified attribute is not
between the expected
values of {0} and {1}.
DoubleRangeValidator与
LongRangeValidator,{0}
与{1}分別代表minimum与
maximum所设定的属性
javax.faces.validator.
DoubleRangeValidator.
MAXIMUM、
javax.faces.validator.
LongRangeValidator.
MAXIMUM
Validation Error: Value is
greater than allowable
maximum of '{0}'.
DoubleRangeValidator或
LongRangeValidator,{0}
表示maximum属性
javax.faces.validator.
DoubleRangeValidator.
MINIMUM、
javax.faces.validator.
LongRangeValidator.
MINIMUM
Validation Error: Value is
less than allowable
minimum of '{0}'.
DoubleRangeValidator或
LongRangeValidator,{0}
代表minimum属性
javax.faces.validator.
DoubleRangeValidator.
TYPE、
javax.faces.validator.
LongRangeValidator.
TYPE
Validation Error: Value is
not of the correct type.
DoubleRangeValidator或
LongRangeValidator
javax.faces.validator.
LengthValidator.
MAXIMUM
Validation Error: Value is
greater than allowable
maximum of ''{0}''.
LengthValidator,{0}代表
maximum属性
javax.faces.validator.
LengthValidator.
MINIMUM
Validation Error: Value is
less than allowable
minimum of ''{0}''.
LengthValidator,{0}代表
minimum属性
在您提供自定义信息的时候,也可以提供{0}或{1}来设定显示相对的属性
值,以提供详细正确的错误提示信息。
信息的显示有概述信息与详述信息,如果是详述信息,则在标识上加上
"_detail",例如:
javax.faces.component.UIInput.CONVERSION=Error.
javax.faces.component.UIInput.CONVERSION_detail= Detail Error.
....
除了在信息资源文件中提供信息,您也可以在程序中使用FacesMessage来提
供信息,例如在3.4自定义验证器中我们就这么用过:
....
if(password.length() < 6) {
FacesMessage message = new FacesMessage(
FacesMessage.SEVERITY_ERROR,
"字符长度小于6",
"字符长度不得小于6");
throw new ValidatorException(message);
}
....
最好的方法是在信息资源文件中提供信息,这么一来如果我们要修改信息,
就只要修改信息资源文件的内容,而不用修改程序,来看一个简单的例子,假设
我们的信息资源文件中有以下的内容:
onlyfun.caterpillar.message1=This is message1.
onlyfun.caterpillar.message2=This is message2 with \{0} and \{1}.
则我们可以在程序中取得信息资源文件的内容,例如:
package onlyfun.caterpillar;
import java.util.Locale;
import java.util.ResourceBundle;
import javax.faces.context.FacesContext;
improt javax.faces.component.UIComponent;
import javax.faces.application.Application;
import javax.faces.application.FacesMessage;
....
public void xxxMethod(FacesContext context,
UIComponent component,
Object obj) {
// 取得应用程序代表对象
Application application = context.getApplication();
// 取得信息文件主名称
String messageFileName = application.getMessageBundle();
// 取得当前 Locale 对象
Locale locale = context.getViewRoot().getLocale();
// 取得信息绑定 ResourceBundle 对象
ResourceBundle rsBundle = ResourceBundle.
getBundle(messageFileName, locale);
String message = rsBundle.getString( "onlyfun.caterpillar.message1");
FacesMessage facesMessage = new FacesMessage(
FacesMessage.SEVERITY_FATAL,
message,
message);
....
}
....
....
接下来您可以将FacesMessage对象填入ValidatorException或
ConverterException后再丢出,FacesMessage建构时所使用的三个参数是严重程
度、概述信息与详述信息,严重程度有SEVERITY_FATAL、SEVERITY_ERROR、
SEVERITY_WARN与SEVERITY_INFO四种。
如果需要在信息资源文件中设定{0}、{1}等参数,则可以如下:
....
String message = rsBundle.getString( "onlyfun.caterpillar.message2");
Object[] params = {"param1", "param2"};
message = java.text.MessageFormat.format(message, params);
FacesMessage facesMessage = new FacesMessage(
FacesMessage.SEVERITY_FATAL,
message, message);
....
如此一来,在显示信息时,onlyfun.caterpillar.message2的{0}与{1}的位置就
会被"param1"与"param2"所取代。
3.6 自定义转换, 验证标签
在自定义验证器中,我们的验证器只能验证一种pattern(.+[0-9]+),我们
希望可以在JSF页面上自定义匹配的pattern,然而由于我们使用<f: validator>这个
通用的验证器标签,为了要能提供pattern属性,我们可以使用<f:attribute>标签来
设置,例如:
....
<h:inputSecret value="#{user.password}" required="true">
<f:validator validatorId="onlyfun.caterpillar.Password"/>
<f:attribute name="pattern" value=".+[0-9]+"/>
</h:inputSecret><p>
....
使用<f:attribute>标签来设定属性,接着我们可以如下取得所设定的属性:
....
public void validate(FacesContext context,
UIComponent component,
Object obj) throws ValidatorException {
....
String pattern = (String)
component.getAttributes().get("pattern");
....
}
....
您也可以开发自己的一组验证标签,并提供相关属性设定,这需要了解JSP
Tag Library的编写,所以请您先参考 JSP/Servlet 中有关于JSP Tag Library的介
绍。
要开发验证器转用标签,您可以直接继承javax.faces.webapp.ValidatorTag,
这个类可以帮您处理大部份的细节,您所需要的,就是重新定义它的
createValidator()方法,我们以改写自定义验证器中的PasswordValidator为例:
•PasswordValidator.java
package onlyfun.caterpillar;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
public class PasswordValidator implements Validator {
private String pattern;
public void setPattern(String pattern) {
this.pattern = pattern;
}
public void validate(FacesContext context,
UIComponent component,
Object obj) throws ValidatorException {
String password = (String) obj;
if(password.length() < 6) {
FacesMessage message = new FacesMessage(
FacesMessage.SEVERITY_ERROR,
"字符长度小于6",
"字符长度不得小于6");
throw new ValidatorException(message);
}
if(pattern != null && !password.matches(pattern)) {
FacesMessage message = new FacesMessage(
FacesMessage.SEVERITY_ERROR,
"密码必须包括字符与数字",
"密码必须是字符加数字所组成");
throw new ValidatorException(message);
}
}
}
主要的差别是我们提供了pattern属性,在validate()方法中进行验证时,是根
据我们所设定的pattern属性,接着我们继承javax.faces.webapp.ValidatorTag来编
写自己的验证标签:
•PasswordValidatorTag.java
package onlyfun.caterpillar;
import javax.faces.application.Application;
import javax.faces.context.FacesContext;
import javax.faces.validator.Validator;
import javax.faces.webapp.ValidatorTag;
public class PasswordValidatorTag extends ValidatorTag {
private String pattern;
public void setPattern(String pattern) {
this.pattern = pattern;
}
protected Validator createValidator() {
Application application = FacesContext.getCurrentInstance(). getApplication();
PasswordValidator validator = (PasswordValidator) application.createValidator(
"onlyfun.caterpillar.Password");
validator.setPattern(pattern);
return validator;
}
}
application.createValidator()方法建立验证器对象时,是根据在faces-config.xml中
注册验证器的标识(Validater ID):
•faces-config.xml
<?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>
....
<validator>
<validator-id>
onlyfun.caterpillar.Password
</validator-id>
<validator-class>
onlyfun.caterpillar.PasswordValidator
</validator-class>
</validator>
....
</faces-config>
剩下来的工作,就是布署tld描述文件了,我们简单的定义一下:
•taglib.tld
<?xml version="1.0" encoding="UTF-8" ?>
<taglib 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
web-jsptaglibrary_2_0.xsd"
version="2.0">
<description>PasswordValidator Tag</description>
<tlib-version>1.0</tlib-version>
<jsp-version>2.0</jsp-version>
<short-name>co</short-name>
<uri>http://caterpillar.onlyfun.net</uri>
<tag>
<description>PasswordValidator</description>
<name>passwordValidator</name>
<tag-class>
onlyfun.caterpillar.PasswordValidatorTag
</tag-class>
<body-content>empty</body-content>
<attribute>
<name>pattern</name>
<required>true</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
</taglib>
而我们的index.jsp改写如下:
•index.jsp
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="/WEB-INF/taglib.tld" prefix="co" %>
<%@page contentType="text/html;charset=GB2312"%>
<html>
<head>
<title>验证器示范</title>
</head>
<body>
<f:view>
<h:messages layout="table" style="color:red"/>
<h:form>
<h3>请输入您的名称</h3>
<h:outputText value="#{user.errMessage}"/>
<p>名称: <h:inputText value="#{user.name}" required="true"/>
<p>密码: <h:inputSecret value="#{user.password}" required="true">
<co:passwordValidator pattern=".+[0-9]+"/>
</h:inputSecret> <p>
<h:commandButton value="送出" action="#{user.verify}"/>
</h:form>
</f:view>
</body>
</html>
主要的差别是,我们使用了自己的验证器标签:
<co:passwordValidator pattern=".+[0-9]+"/>
如果要自定义转换器标签,方法也是类似,您要作的是继承
javax.faces.webapp.ConverterTag,并重新定义其createConverter()方法。