自订转换, 验证标签

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