您的位置:首页 > Web前端 > JavaScript

JSF2自定义组件

2016-06-17 10:25 453 查看


1.     
序言

JSF2.0标准被JCP通过并正式发布已有一年多(2009年6月份通过的),其标准实现jsf-api-2.0.3.jar也一再更新版本,各种开源社区对应的版本也相继发布,如:IceFace、OpenFaces、PrimeFaces等,IceFace也发布了netbean和eclipse3.6的可视化插件,JSF2.0生机勃勃,呈现出一片繁荣景象。
Composite Component JSF2(复合组件)提供了Composite
Component的创建方法,避免了通过Java代码生成html标记的繁琐,只需要基于现有的JSF tag进行组合即可。IceFace、OpenFaces、PrimeFaces提供了各种的炫酷UI
Components,但JSF的开源社区都忙于商业支持,而很少对free的用户进行友好及时的支持。 
<>一书提到如果有别人已经造好的车轮子,就没有必要自己造车轮。但是为了学习JSF的内部机制,还是很有必要编写传统的Non Composite Component,同时在我们很难获得开源社区的支持的现实下,自己制造车轮子,一方面为了自己用,另一方面也是为了更好的理解JSF和其他开源库,第三方的JSF库有问题自己能够解决,而不必依赖别人,Non
Composite Component的基本结构如下图所示:
 

图1‑1 
Non Composite Component的基本结构

本文所有代码采用技术:eclipse3.6+jdk6+tomcat6,JSF选用标准实现Mojarra
2.0.3-b03。
本文的所有的源代码可以从http://dazen.sourceforge.net/下载。
本文从易到难,先后介绍4个Non Composite Component。

2.     
简单的Noncomposite Component

学习新事物,我们自然想到Hello world,本文也不例外,我们从hello world开始,首先开发一个最为简单的输出hello
world的Non Composite Component:HtmlHelloWorld。UI component包括两部分:
1、一个HtmlHelloWorld.java类文件,这个类提供组件的核心功能,包括在html中的展现信息和呈现方式等。
2、一个配置文件:helloworld-taglib.xml,即组件的Facelet
tag library descriptor (TLD)。
在eclipse中创建dynamic web project,或者下载源代码后直接导入工程即可,工程名称为jsfdemo。
创建HtmlHelloWorld.java类文件,代码如下:
package com.dazen.components.component;
 
import java.io.IOException;
import javax.faces.component.FacesComponent;
import javax.faces.component.UIComponentBase;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
 
@FacesComponent(value = "HtmlHelloWorld")
public class HtmlHelloWorld extends UIComponentBase {
      
@Override
      
public String getFamily() {
             
return null;
      
}
 
      
@Override
      
public void encodeAll(FacesContext context) throws IOException {
             
ResponseWriter writer = context.getResponseWriter();
             
writer.startElement("div", this);
             
writer.writeAttribute("style", "color : red", null);
             
writer.writeText("HelloWorld! today is: " + new java.util.Date(), null);
             
writer.endElement("div");
      
}
}
在代码中才采用注解的方式进行了组件注册:@FacesComponent(value = "HtmlHelloWorld"),否则需要在faces-config.xml中进行如下配置:

 <component>

   
 <component-type>HtmlHelloWorldcomponent-type>

     <component-class>

       com.dazen.components.component.HtmlHelloWorld

component-class>
component>
在WEB-INF目录下创建文件:Facelet tag library descriptor (TLD):helloworld.taglib.xml,文件内容如下:

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

<facelet-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-facelettaglibrary_2_0.xsd"
    version="2.0">

    <namespace>http://dazen.com/examplenamespace>

    <tag>

       <tag-name>helloworldtag-name>

       <component>

           <component-type>HtmlHelloWorldcomponent-type>

       component>

    tag>

facelet-taglib>

至此,第一个Non Composite Component开发完毕,下面写一个xhtml文件:component.xhtml来调用该组件:

DOCTYPE
html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html
xmlns="http://www.w3.org/1999/xhtml"

    xmlns:h="http://java.sun.com/jsf/html"

    xmlns:vt="http://dazen.com/example">

<h:head>

    <title>A Simple JavaServer Faces 2.0 Viewtitle>

h:head>

<h:body>

    <h:form>

       <p><vt:helloworld
/>p>

    h:form>

h:body>

html>

 

IE中显示效果:

图2‑1 
组件调用效果

3.     
能接受参数的Noncomposite Component

一个组件一般要接受在调用时传递过来的参数。首先创建类文件:ParamHelloWorld.java,代码如下:

package com.dazen.components.component;

 

import java.io.IOException;

import javax.faces.component.FacesComponent;

import javax.faces.component.UIComponentBase;

import javax.faces.context.FacesContext;

import javax.faces.context.ResponseWriter;

 

@FacesComponent(value =
"ParamHelloWorld")

public
class ParamHelloWorld
extends UIComponentBase {

    @Override

    public String getFamily() {

       return
null;

    }

    @Override

    public
void encodeAll(FacesContext context)
throws IOException {

       ResponseWriter writer = context.getResponseWriter();

       writer.startElement("div",
this);

       writer.writeAttribute("style",
"color : red",
null);

       String message = (String)
this.getAttributes().get("hellomsg");

       if (null == message) {

           writer.writeText("HelloWorld! today is: " +
new java.util.Date(),

                  null);

       } else {

           writer.writeText(message,
null);

       }

       writer.endElement("div");

    }

}

这个组件可以接受参数名为: hellomsg的参数。

然后在helloworld.taglib.xml中添加如下代码来注册该组件:

<tag>

       <tag-name>paramhelloworldtag-name>

       <component>

           <component-type>ParamHelloWorldcomponent-type>

       component>

tag>

最后创建调用该组件的页面文件:param_component.xhtml,代码如下:

DOCTYPE
html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html
xmlns="http://www.w3.org/1999/xhtml"

    xmlns:h="http://java.sun.com/jsf/html"

    xmlns:vt="http://dazen.com/example">

<h:head>

    <title>A Simple JavaServer Faces 2.0 Viewtitle>

h:head>

<h:body>

    <h:form>

       <vt:paramhelloworld
hellomsg="Hello JSF! "/>

    h:form>

h:body>

html>

执行效果如下图所示:

图3‑1 
可传参数的组件

4.     
能与页面交互的Noncomposite Component

首先创建类文件:InputHelloWorld.java,代码如下:

package com.dazen.components.component;

 

import java.io.IOException;

import java.util.Map;

 

import javax.faces.component.FacesComponent;

import javax.faces.component.UIInput;

import javax.faces.component.UINamingContainer;

import javax.faces.context.FacesContext;

import javax.faces.context.ResponseWriter;

 

@FacesComponent(value =
"InputHelloWorld")

public
class InputHelloWorld
extends UIInput {

    public InputHelloWorld() {

       setRendererType(null);
// this component renders itself

    }

 

    @Override

    public
void encodeEnd(FacesContext context)
throws IOException {

       String clientId = getClientId(context);

       char sep = UINamingContainer.getSeparatorChar(context);

       encodeInputField(context, clientId + sep +
"inputfield");

       encodeSubmitButton(context, clientId + sep +
"submit");

       encodeOutputField(context);

    }

 

    private
void encodeInputField(FacesContext context, String clientId)

          
throws IOException {

       // Render a standard HTML input field

       ResponseWriter writer = context.getResponseWriter();

       writer.startElement("input",
this);

       writer.writeAttribute("type",
"text",
null);

       writer.writeAttribute("name", clientId,
"dazen_Id");

       Object value = getValue();

       if (value !=
null) {

           writer.writeAttribute("value", value.toString(),
"value");

       }

       writer.writeAttribute("size",
"6",
null);

       writer.endElement("input");

    }

 

    private
void encodeSubmitButton(FacesContext context, String clientId)

           throws IOException {

       // render a submit button

       ResponseWriter writer = context.getResponseWriter();

       writer.startElement("input",
this);

       writer.writeAttribute("type",
"Submit",
null);

       writer.writeAttribute("name", clientId,
"dazen_Id");

       writer.writeAttribute("value",
"Click Me!",
null);

       writer.endElement("input");

    }

 

    private
void encodeOutputField(FacesContext context)
throws IOException {

       ResponseWriter writer = context.getResponseWriter();

       String hellomsg = (String) getAttributes().get("value");

       writer.startElement("p",
this);

       writer.writeText("You entered: " + hellomsg,
null);

       writer.endElement("p");

    }

 

 

    @Override

    public
void decode(FacesContext context) {

       Map requestMap = context.getExternalContext().getRequestParameterMap();

       String clientId = getClientId(context);

       char sep = UINamingContainer.getSeparatorChar(context);

       String submitted_hello_msg = ((String) requestMap.get(clientId + sep

              + "inputfield"));

       setSubmittedValue(submitted_hello_msg);

    }

}

这个组件可以由用户输入信息并反馈给用户。 基本流程是,用户在页面上输入数据,点击按钮后,一般采用PostBack的方法将数据传递到JSF的
Serverlet,在后台的Renderer的decode方法内部通过 FacesContext.getExternalContext().getRequestParameterMap()获取Map对象,然后通过
key去查找用户的输入数据。

然后在helloworld.taglib.xml中添加如下代码来注册该组件:

    <tag>

       <tag-name>inputhelloworldtag-name>

       <component>

           <component-type>InputHelloWorldcomponent-type>

       component>

tag>

 

最后创建调用该组件的页面文件:input_component.xhtml,代码如下:

DOCTYPE
html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html
xmlns="http://www.w3.org/1999/xhtml"

    xmlns:h="http://java.sun.com/jsf/html"

    xmlns:vt="http://dazen.com/example">

<h:head>

    <title>A Simple JavaServer Faces 2.0 Viewtitle>

h:head>

<h:body>

    <h:form>

       <vt:inputhelloworld/>

    h:form>

h:body>

html>

执行效果如下图所示:

图4‑1 
可交互的组件


 

5.     
能与页面交互的Noncomposite Component

通常一个UI Component包含了两个部分:Behavior和Renderer.两者一般都分别实现,UIComponent类用来实现Behavior,比如处理事件,通过EL绑定属性等等。专门实现一个Renderer类来负责Encoding和Decoding。Encoding指的是生成可以在客户端显示的标记语言,比如html等,Decoding用来将客户端传来的请求(通常以某种标记语言风格)转换成Java变量。

首先创建Renderer类文件:HtmlInputRenderer.java,代码如下:

package com.dazen.components.renderer;

 

import java.io.IOException;

import java.util.Map;

 

import javax.faces.component.UIComponent;

import javax.faces.component.UINamingContainer;

import javax.faces.context.FacesContext;

import javax.faces.context.ResponseWriter;

import javax.faces.render.FacesRenderer;

import javax.faces.render.Renderer;

 

import com.dazen.components.component.HtmlInput;

@FacesRenderer(componentFamily="javax.faces.Input",

       rendererType="HtmlInputRenderer")

public
class
HtmlInputRenderer extends Renderer {

 

    public
void decode(FacesContext context, UIComponent component) {

       Map requestMap = context.getExternalContext().getRequestParameterMap();

       String clientId = component.getClientId(context);

       char sep = UINamingContainer.getSeparatorChar(context);

       String symbol = ((String) requestMap.get(clientId + sep +
"inputfield"));

       HtmlInput myComponent = (HtmlInput) component;

       myComponent.setSubmittedValue(symbol);

    }

 

    @Override

    public
void encodeEnd(FacesContext context, UIComponent component)

           throws IOException {

       String clientId = component.getClientId(context);

       char sep = UINamingContainer.getSeparatorChar(context);

       encodeInputField(context, clientId + sep +
"inputfield", component);

       encodeSubmitButton(context, clientId + sep +
"submit", component);

       encodeOutputField(context, component);

    }

 

    private
void encodeInputField(FacesContext context, String clientId,

           UIComponent component)
throws IOException {

       ResponseWriter writer = context.getResponseWriter();

       writer.startElement("input", component);

       writer.writeAttribute("type",
"text",
null);

       writer.writeAttribute("name", clientId,
"dazenId");

       HtmlInput myComponent = (HtmlInput) component;

       String value = (String) myComponent.getSubmittedValue();

       if (value !=
null) {

           writer.writeAttribute("value", value,
"value");

       }

       writer.writeAttribute("size",
"6",
null);

       writer.endElement("input");

    }

 

    private
void encodeSubmitButton(FacesContext context, String clientId,

           UIComponent component)
throws IOException {

       ResponseWriter writer = context.getResponseWriter();

       writer.startElement("input", component);

       writer.writeAttribute("type",
"Submit",
null);

       writer.writeAttribute("name", clientId,
"dazenId");

       writer.writeAttribute("value",
"Click Me!",
null);

       writer.endElement("input");

    }

 

    private
void encodeOutputField(FacesContext context, UIComponent component)

           throws IOException {

       ResponseWriter writer = context.getResponseWriter();

       String hellomsg = (String) component.getAttributes().get("value");

       writer.startElement("p", component);

       writer.writeText("You entered: " + hellomsg,
null);

       writer.endElement("p");

    }

}

       然后创建Behavior类文件:HtmlInput.java,

package com.dazen.components.component;

 

import javax.faces.component.FacesComponent;

import javax.faces.component.UIInput;

 

@FacesComponent(value =
"HtmlInput")

public
class
HtmlInput extends UIInput {

 

}

因为HtmlInput类继承了UIInput类,所以自然拥有了getFamily,get/setSubmittedValue等方法的实现。

然后在helloworld.taglib.xml中添加如下代码来注册该组件:

    <tag>

       <tag-name>htmlinputtag-name>

       <component>

           <component-type>HtmlInputcomponent-type>

           <renderer-type>HtmlInputRendererrenderer-type>

       component>

tag>

最后创建调用该组件的页面文件:renderer_component.xhtml,代码如下:

DOCTYPE
html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"

"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html
xmlns="http://www.w3.org/1999/xhtml"

    xmlns:h="http://java.sun.com/jsf/html"

    xmlns:vt="http://dazen.com/example">

<h:head>

    <title>A Simple JavaServer Faces 2.0 Viewtitle>

h:head>

<h:body>

    <h:form>

       <vt:htmlinput/>

    h:form>

h:body>

html>

执行效果如下图所示:

原创地址:http://blog.itpub.net/25341012/viewspace-687031/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  jsf 自定义组件