JSF 转换器

Sang Shin, sang.shin@sun.com, Sun Microsystems, www.javapassion.cn



在本实验室中,您首先将了解如何使用内嵌式 JSF 转换器。您也将了解如何编译和使用定制转换器。本实验室使用的一些示例应用程序来自 Core JSF 一书(David Geary 和 Cay Horstmann 著)发布的源代码



预计时间:90 分钟(不包括课外练习)


前提条件

本动手实验室假定您拥有以下技术的基本知识或者具备相关编程经验:


软件需求

开始之前,需要在您的计算机中安装以下软件。


可以使用的操作系统平台

变更记录



实验室练习


练习 1:编译和运行 "core-converter" 示例应用程序

学习要点:


(1.1)打开、编译和运行 "core-converter" 示例应用程序

0. 启动 NetBeans IDE。
1. 打开 core-converter NetBeans 项目。

2. 编译和运行 core-converter 项目。








(1.2)深入了解  "core-converter" 示例应用程序


1.  index.jsp

<html>
    <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
    <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
    <f:view>
        <head>
            <link href="styles.css" rel="stylesheet" type="text/css"/>
            <title><h:outputText value="#{msgs.title}"/></title>
        </head>
        <body>
            <h:form>
                <h1><h:outputText value="#{msgs.enterPayment}"/></h1>
                <h:panelGrid columns="3">
                    <h:outputText value="#{msgs.amount}"/>
                    <h:inputText id="amount" label="#{msgs.amount}"
                                 value="#{payment.amount}">
                        <f:convertNumber minFractionDigits="2"/>
                    </h:inputText>
                    <h:message for="amount" styleClass="errorMessage"/>
                   
                    <h:outputText value="#{msgs.creditCard}"/>
                    <h:inputText id="card" label="#{msgs.creditCard}"
                                 value="#{payment.card}"/>
                    <h:panelGroup/>
                   
                    <h:outputText value="#{msgs.expirationDate}"/>
                    <h:inputText id="date" label="#{msgs.expirationDate}"
                                 value="#{payment.date}">               
                        <f:convertDateTime pattern="MM/yyyy"/>
                    </h:inputText>
                    <h:message for="date" styleClass="errorMessage"/>
                </h:panelGrid>
                <h:commandButton value="#{msgs.process}" action="process"/>
            </h:form>
        </body>
    </f:view>
</html>


2.  response.jsp

<html>
    <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
    <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
    <f:view>
        <head>
            <link href="styles.css" rel="stylesheet" type="text/css"/>
            <title><h:outputText value="#{msgs.title}"/></title>
        </head>
        <body>
            <h:form>
                <h1><h:outputText value="#{msgs.paymentInformation}"/></h1>
                <h:panelGrid columns="2">
                    <h:outputText value="#{msgs.amount}"/>
                    <h:outputText value="#{payment.amount}">
                        <f:convertNumber type="currency"/>
                    </h:outputText>
                   
                    <h:outputText value="#{msgs.creditCard}"/>
                    <h:outputText value="#{payment.card}"/>
                   
                    <h:outputText value="#{msgs.expirationDate}"/>
                    <h:outputText value="#{payment.date}">
                        <f:convertDateTime pattern="MM/yyyy"/>
                    </h:outputText>
                </h:panelGrid>
                <h:commandButton value="Back" action="back"/>
            </h:form>
        </body>
    </f:view>
</html>


结束语

在本练习中, 您编译和运行了一个现成的 "core-converter" 示例应用程序,从而对该应用程序的运行机制有所感触。

                                                                                                                        返回顶部



练习 2:编译和运行 "core-converter2" 示例应用程序


学习要点:

(2.1)打开、编译和运行"core-converter2" 示例应用程序

1. 打开 core-converter2 NetBeans 项目。

2. 编译和运行 core-converter2 项目。







(2.2)深入了解  "core-converter2" 示例应用程序


1. index.jsp

<html>
   <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
   <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
   <f:view>
      <head>
         <link href="styles.css" rel="stylesheet" type="text/css"/>
         <title><h:outputText value="#{msgs.title}"/></title>
      </head>
      <body>
         <h:form>
            <h1><h:outputText value="#{msgs.enterPayment}"/></h1>
            <h:panelGrid columns="3">
               <h:outputText value="#{msgs.amount}"/>
               <h:inputText id="amount" label="#{msgs.amount}"
                     value="#{payment.amount}">
                  <f:convertNumber minFractionDigits="2"/>
               </h:inputText>
               <h:message for="amount" styleClass="errorMessage"/>

               <h:outputText value="#{msgs.creditCard}"/>
               <h:inputText id="card" label="#{msgs.creditCard}"
                     value="#{payment.card}">
                  <f:converter converterId="com.corejsf.CreditCard"/>
               </h:inputText>
               <h:message for="card" styleClass="errorMessage"/>

               <h:outputText value="#{msgs.expirationDate}"/>
               <h:inputText id="date" label="#{msgs.expirationDate}"
                     value="#{payment.date}">
                  <f:convertDateTime pattern="MM/yyyy"/>
               </h:inputText>
               <h:message for="date" styleClass="errorMessage"/>
            </h:panelGrid>
            <h:commandButton value="Process" action="process"/>
         </h:form>
      </body>
   </f:view>
</html>


2. result.jsp

<html>
    <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
    <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
    <f:view>
        <head>
            <link href="styles.css" rel="stylesheet" type="text/css"/>
            <title><h:outputText value="#{msgs.title}"/></title>
        </head>
        <body>
            <h:form>
                <h1><h:outputText value="#{msgs.paymentInformation}"/></h1>
                <h:panelGrid columns="2">
                    <h:outputText value="#{msgs.amount}"/>
                    <h:outputText value="#{payment.amount}">
                        <f:convertNumber type="currency"/>
                    </h:outputText>
                   
                    <h:outputText value="#{msgs.creditCard}"/>
                    <h:outputText value="#{payment.card}"
                                  converter="com.corejsf.CreditCard"/>
                   
                    <h:outputText value="#{msgs.expirationDate}"/>
                    <h:outputText value="#{payment.date}">
                        <f:convertDateTime pattern="MM/yyyy"/>
                    </h:outputText>
                </h:panelGrid>
                <h:commandButton value="Back" action="back"/>
            </h:form>
        </body>
    </f:view>
</html>


3. faces-config.xml

<?xml version="1.0"?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
              http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
              version="1.2">
    <application>
        <message-bundle>com.corejsf.messages</message-bundle>
    </application>
   
    <navigation-rule>
        <from-view-id>/index.jsp</from-view-id>
        <navigation-case>
            <from-outcome>process</from-outcome>
            <to-view-id>/result.jsp</to-view-id>
        </navigation-case>
    </navigation-rule>
   
    <navigation-rule>
        <from-view-id>/result.jsp</from-view-id>
        <navigation-case>
            <from-outcome>back</from-outcome>
            <to-view-id>/index.jsp</to-view-id>
        </navigation-case>
    </navigation-rule>
   
    <converter>
        <converter-id>com.corejsf.CreditCard</converter-id>
        <converter-class>com.corejsf.CreditCardConverter</converter-class>
    </converter>
   
    <managed-bean>
        <managed-bean-name>payment</managed-bean-name>
        <managed-bean-class>com.corejsf.PaymentBean</managed-bean-class>
        <managed-bean-scope>session</managed-bean-scope>
    </managed-bean>
   
    <application>
        <resource-bundle>
            <base-name>com.corejsf.messages</base-name>
            <var>msgs</var>
        </resource-bundle>
    </application>
</faces-config>


4. CreditCardConverter.java

package com.corejsf;

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;

public class CreditCardConverter implements Converter {
    public Object getAsObject(FacesContext context, UIComponent component,
            String newValue) throws ConverterException {
        StringBuilder builder = new StringBuilder(newValue);
        boolean foundInvalidCharacter = false;
        char invalidCharacter = '\0';
        int i = 0;
        while (i < builder.length() && !foundInvalidCharacter) {
            char ch = builder.charAt(i);
            if (Character.isDigit(ch))
                i++;
            else if (Character.isWhitespace(ch))
                builder.deleteCharAt(i);
            else {
                foundInvalidCharacter = true;
                invalidCharacter = ch;
            }
        }
       
        if (foundInvalidCharacter) {
            FacesMessage message = com.corejsf.util.Messages.getMessage(
                    "com.corejsf.messages", "badCreditCardCharacter",
                    new Object[]{ new Character(invalidCharacter) });
            message.setSeverity(FacesMessage.SEVERITY_ERROR);
            throw new ConverterException(message);
        }
       
        return new CreditCard(builder.toString());
    }
   
    public String getAsString(FacesContext context, UIComponent component,
            Object value) throws ConverterException {
        // length 13: xxxx xxx xxx xxx
        // length 14: xxxxx xxxx xxxxx
        // length 15: xxxx xxxxxx xxxxx
        // length 16: xxxx xxxx xxxx xxxx
        // length 22: xxxxxx xxxxxxxx xxxxxxxx
        String v = value.toString();
        int[] boundaries = null;
        int length = v.length();
        if (length == 13)
            boundaries = new int[]{ 4, 7, 10 };
        else if (length == 14)
            boundaries = new int[]{ 5, 9 };
        else if (length == 15)
            boundaries = new int[]{ 4, 10 };
        else if (length == 16)
            boundaries = new int[]{ 4, 8, 12 };
        else if (length == 22)
            boundaries = new int[]{ 6, 14 };
        else
            return v;
        StringBuilder result = new StringBuilder();
        int start = 0;
        for (int i = 0; i < boundaries.length; i++) {
            int end = boundaries[i];
            result.append(v.substring(start, end));
            result.append(" ");
            start = end;
        }
        result.append(v.substring(start));
        return result.toString();
    }
}


结束语

在本练习中, 您编译和运行了一个现成的 "core-converter2" 示例应用程序,从而对该应用程序的运行机制有所感触。

                                                                                                                        返回顶部


练习 3:编译和运行 "core-custom-converter" 示例应用程序


学习要点:

(3.1)打开、编译和运行"core-custom-converter" 示例应用程序

1. 打开 core-custom-converter NetBeans 项目。

2. 编译和运行 core-custom-converter 项目。





(3.2)深入了解  "core-custom-converter" 示例应用程序


1. result.jsp

<html>
    <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
    <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
    <%@ taglib uri="http://corejsf.com/converter" prefix="corejsf" %>
    <f:view>
        <head>
            <link href="styles.css" rel="stylesheet" type="text/css"/>
            <title><h:outputText value="#{msgs.title}"/></title>
        </head>
        <body>
            <h:form>
                <h1><h:outputText value="#{msgs.paymentInformation}"/></h1>
                <h:panelGrid columns="2">
                    <h:outputText value="#{msgs.amount}"/>
                    <h:outputText value="#{payment.amount}">
                        <f:convertNumber type="currency"/>
                    </h:outputText>
                   
                    <h:outputText value="#{msgs.creditCard}"/>
                    <h:outputText value="#{payment.card}">
                        <corejsf:convertCreditcard separator="-"/>
                    </h:outputText>
                   
                    <h:outputText value="#{msgs.expirationDate}"/>
                    <h:outputText value="#{payment.date}">
                        <f:convertDateTime pattern="MM/yyyy"/>
                    </h:outputText>
                </h:panelGrid>
                <h:commandButton value="#{msgs.back}" action="back"/>
            </h:form>
        </body>
    </f:view>
</html>

2. converter.tld

<?xml version="1.0" encoding="UTF-8"?>
<taglib xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
        http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
        version="2.1">
    <tlib-version>1.1</tlib-version>
    <tlib-version>1.1</tlib-version>
    <short-name>converter</short-name>
    <uri>http://corejsf.com/converter</uri>
   
    <tag>
        <name>convertCreditcard</name>
        <tag-class>com.corejsf.CreditCardConverterTag</tag-class>
        <body-content>empty</body-content>
        <attribute>
            <name>separator</name>
            <deferred-value>
                <type>java.lang.String</type>
            </deferred-value>
        </attribute>
    </tag>
</taglib>

3.  CreditCardConverterTag.java

package com.corejsf;

import javax.el.ELContext;
import javax.el.ValueExpression;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.webapp.ConverterELTag;
import javax.servlet.jsp.JspException;

public class CreditCardConverterTag extends ConverterELTag {
    private ValueExpression separator;
   
    public void setSeparator(ValueExpression newValue) {
        separator = newValue;
    }
   
    public Converter createConverter() throws JspException {
        CreditCardConverter converter = new CreditCardConverter();
        ELContext elContext = FacesContext.getCurrentInstance().getELContext();
        converter.setSeparator((String) separator.getValue(elContext));
        return converter;
    }
   
    public void release() {
        separator = null;
    }
}

4. CreditCardConverter.java

package com.corejsf;

import java.io.Serializable;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;

public class CreditCardConverter implements Converter, Serializable {
    private String separator;
   
    // PROPERTY: separator
    public void setSeparator(String newValue) { separator = newValue; }
   
    public Object getAsObject(
            FacesContext context,
            UIComponent component,
            String newValue)
            throws ConverterException {
        StringBuilder builder = new StringBuilder(newValue);
        int i = 0;
        while (i < builder.length()) {
            if (Character.isDigit(builder.charAt(i)))
                i++;
            else
                builder.deleteCharAt(i);
        }
        return new CreditCard(builder.toString());
    }
   
    public String getAsString(
            FacesContext context,
            UIComponent component,
            Object value)
            throws ConverterException {
        // length 13: xxxx xxx xxx xxx
        // length 14: xxxxx xxxx xxxxx
        // length 15: xxxx xxxxxx xxxxx
        // length 16: xxxx xxxx xxxx xxxx
        // length 22: xxxxxx xxxxxxxx xxxxxxxx
        if (!(value instanceof CreditCard))
            throw new ConverterException();
        String v = ((CreditCard) value).toString();
        String sep = separator;
        if (sep == null) sep = " ";
        int[] boundaries = null;
        int length = v.length();
        if (length == 13)
            boundaries = new int[] { 4, 7, 10 };
        else if (length == 14)
            boundaries = new int[] { 5, 9 };
        else if (length == 15)
            boundaries = new int[] { 4, 10 };
        else if (length == 16)
            boundaries = new int[] { 4, 8, 12 };
        else if (length == 22)
            boundaries = new int[] { 6, 14 };
        else
            return v;
        StringBuilder result = new StringBuilder();
        int start = 0;
        for (int i = 0; i < boundaries.length; i++) {
            int end = boundaries[i];
            result.append(v.substring(start, end));
            result.append(sep);
            start = end;
        }
        result.append(v.substring(start));
        return result.toString();
    }
}

5. faces-config.xml

<?xml version="1.0"?>
<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
        http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"
    version="1.2">
   <navigation-rule>
      <from-view-id>/index.jsp</from-view-id>
      <navigation-case>
         <from-outcome>process</from-outcome>
         <to-view-id>/result.jsp</to-view-id>
      </navigation-case>
   </navigation-rule>

   <navigation-rule>
      <from-view-id>/result.jsp</from-view-id>
      <navigation-case>
         <from-outcome>back</from-outcome>
         <to-view-id>/index.jsp</to-view-id>
      </navigation-case>
   </navigation-rule>
  
   <converter>
      <converter-id>com.corejsf.CreditCard</converter-id>
      <converter-class>com.corejsf.CreditCardConverter</converter-class>
   </converter>

   <managed-bean>
      <managed-bean-name>payment</managed-bean-name>
      <managed-bean-class>com.corejsf.PaymentBean</managed-bean-class>
      <managed-bean-scope>session</managed-bean-scope>
   </managed-bean>

   <application>
      <resource-bundle>
         <base-name>com.corejsf.messages</base-name>
         <var>msgs</var>
      </resource-bundle>
   </application>
</faces-config>


练习 4:编译和运行 "custom-converter2" 示例应用程序



(4.1)打开、编译和运行"custom-converter2" 示例应用程序

1. 打开 custom-converter2 NetBeans 项目。

2. 编译和运行 custom-converter2 项目。




(4.2)深入了解  "custom-converter2" 示例应用程序


1. faces-config.xml

<?xml version='1.0' encoding='UTF-8'?>

<!--
 Copyright 2004 Sun Microsystems, Inc. All rights reserved.
 SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
-->

<!DOCTYPE faces-config PUBLIC
"-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN"
"http://java.sun.com/dtd/web-facesconfig_1_0.dtd">

<!-- =========== FULL CONFIGURATION FILE ================================== -->

<faces-config>
   
    <application>
        <message-bundle>creditcard.bundles.Messages</message-bundle>
        <locale-config>
            <default-locale>en</default-locale>
            <supported-locale>de</supported-locale>
            <supported-locale>fr</supported-locale>
            <supported-locale>es</supported-locale>
        </locale-config>
    </application>
   
    <!-- Validator -->
    <validator>
        <description>
            Registers the concrete Validator implementation,
            creditcard.FormatValidator with the validator
            identifier, FormatValidator.
        </description>
        <validator-id>FormatValidator</validator-id>
        <validator-class>creditcard.FormatValidator</validator-class>
        <attribute>
            <description>
                List of format patterns separated by '|'.  The validator
                compares these patterns against the data entered in a
                component that has this validator registered on it.
            </description>
            <attribute-name>formatPatterns</attribute-name>
            <attribute-class>java.lang.String</attribute-class>
        </attribute>
    </validator>
   
    <!-- converter -->
    <converter>
        <description>
            Registers the concrete Converter implementation,
            creditcard.CreditCardConverter using the ID,
            creditCardConverter.
        </description>
        <converter-id>creditCardConverter</converter-id>
        <converter-class>creditcard.CreditCardConverter</converter-class>
    </converter>
   
    <!-- navigation rules -->
    <navigation-rule>
        <from-view-id>/creditcardInfo.jsp</from-view-id>
        <navigation-case>
            <description>
                Any action that returns "finish" on customerInfo.jsp should
                cause navigation to finish.jsp
            </description>
            <from-outcome>finish</from-outcome>
            <to-view-id>/finish.jsp</to-view-id>
        </navigation-case>
    </navigation-rule>
   
</faces-config>


课外练习(针对 Sang Shin“Java EE 编程在线课程”的学习者)


1.课外练习是根据以下要求修改 core-converter2 项目。为防止您没有 core-converter2 项目,可使用动手实验室压缩文件中的 <LAB_UNZIPPED_DIRECTORY>/jsfconverter/samples/core-converter2(可以通过复制 core-converter2项目创建一个新项目。您可以任意方式为课外练习项目命名,但此处我将称其为 Mycore-converter2。)
2. 将以下文件J2EEHomework-jsfconverter 作为 发送主题 发送至 j2eehomeworks@sun.com

                                                                                                                    返回顶部





原文链接: http://www.javapassion.com/handsonlabs/jsfconverter/