资料转换与验证(3)

来源:互联网 发布:office2010 mac 编辑:程序博客网 时间:2024/05/16 05:14

 1.JSF Gossip: 标准转换器

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=Big5"%>

<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  这篇文章中有关于标准转换器的说明。

2.JSF Gossip: 自订转换器

除了使用标准的转换器之外,您还可以自行定制您的转换器,您可以实作 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类别:

  • GuestBook.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=Big5"%>

<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.JSF Gossip: 标准验证器

当应用程式要求使用者输入资料时,必然考虑到使用者输入资料之正确性,对于使用者的输入必须进行检验,检验必要的两种验证是语法检验(Synatic Validation)与语意检验(Semantic Validation)。

语法检验是要检查使用者输入的资料是否合乎我们所要求的格式,最基本的就是检查使用者是否填入了栏位值,或是栏位值的长度、大小值等等是否符合要求。语意检验是在语法检验之后,在格式符合需求之后,我们进一步验证使用者输入的资料语意上是否正确,例如检查使用者的名称与密码是否匹配。

简单的导航(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=Big5"%>
<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  这篇文章中有关于标准验证器的说明。
4.JSF Gossip: 自订验证器

您可以自订自己的验证器,所需要的是实作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}"/>
 ....


5.JSF Gossip: 错误讯息处理

在使用标准转换器或验证器时,当发生错误时,会有一些预设的错误讯息显示,这些讯息可以使用<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来提供讯息,例如在 自订验证器 中我们就这么用过:

 ....
         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"所取代。


6.JSF Gossip: 自订转换、验证标签

自订验证器 中,我们的验证器只能验证一种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=Big5"%>
<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()方法。