一个带有Ajax功能的JSF组件的完整详细开发过程

一个带有Ajax功能的JSF组件的完整详细开发过程

    文章有点长,写得比较详细,有兴趣与耐心开发JSF组件的就往下看吧,下面将详细介绍一个标准JSF组件的制作过程,并且后面将使用QFaces将它升级为Ajax方式的组件(如果要升级为Ajax组件,请先安装QFaces增强框架).如果你发现有任何问题或错漏,请给予批评指正,相关的完整代码在QFaces的Demo示例中,可以自行下载查看:

    QFaces相关完整示例下载

    现在先来看一下一个JSF标准组件所需要用到的一些文件:

1.UIComponent ― 组件的主类,用于组件渲染,状态的保存及一些行为的处理等.

2.UIComponentTag - 组件的jsp标签处理类,主要进行值绑定及方法绑定等.

3.tld - 标签库描述符文件,主要用于注册组件的可用属性等.

4.faces-config.xml - 配置文件,主要用于注册你的组件.

注意的是,我们这里所介绍的环境是JSF1.2JSP视图的组件, 如果你使用了facelets视图技术,则可以省去UIComponentTagtld文件,制作组件的方法基本相同,但注册及方法绑定稍有不同.

现在我们来一步一步创建一个组件吧,暂且把这个组件的名字取为:Hello

步骤1.创建UIComponent – HtmlHello.java

 

public   class  HtmlHello  extends  UIComponentBase  implements  Ajax{

    @Override
    
public  String getFamily() {
        
return   null ;
    }

    
public   void  ajaxInvokeOnPost(Map < String, String >  params, FacesContext fc) {
        
throw   new  UnsupportedOperationException( " Not supported yet. " );
    }

    
public   void  ajaxInvokeOnGet(Map < String, String >  params, FacesContext fc) {
        
//  后面我们将实现这个方法
    }

}

    为了简单起见,我们继承了比较基础的UIComponentBase 同时实现QFaces中的Ajax接口,Ajax接口需要实现两个方法:ajaxInvokeOnPost ajaxInvokeOnPost 分别处理postget请求,可以选择实现,后面我们将实现ajaxInvokeOnGet这个方法,因为这对性能很好,如果你只需要一个标准JSF组件,可以不实现这个接口.在这里我们需要先进行一些其它方面的工作:渲染组件

为了渲染组件,我们需要覆盖encodeBegin方法:

public   class  HtmlHello  extends  UIComponentBase  implements  Ajax{

    @Override
    
public  String getFamily() {
        
return   null ;
    }

    
public   void  ajaxInvokeOnPost(Map < String, String >  params, FacesContext fc) {
        
throw   new  UnsupportedOperationException( " Not supported yet. " );
    }

    
public   void  ajaxInvokeOnGet(Map < String, String >  params, FacesContext fc) {
        
// 我们将实现这个方法
    }

    @Override
    
public void encodeBegin(FacesContext fc) throws IOException {
        String clientId 
= this.getClientId(fc); // 获得组件的客户端ID
        ResponseWriter rw = fc.getResponseWriter();
        rw.startElement(
"input"this);
        rw.writeAttribute(
"id", clientId, null);
        rw.writeAttribute(
"name", clientId, null);
        rw.writeAttribute(
"type""text"null);
        rw.endElement(
"input"
);
    }


}

你可以看到我们实现的encodeBegin方法,实际上只是在客户端渲染一个input而已,如果渲染正常,应该在html代码中输出像这样的东西:

<input type=”text” id=”…” name=”…” />

接着我们先确保这个组件能在页面中正常渲染并显示,所以我们先注册一下这个组件,并看一下效果,后面再实现组件的Ajax功能.

步骤2.创建UIComponentTag – HtmlHelloTag.java

 


public   class  HtmlHelloTag  extends  UIComponentELTag{

    @Override
    
public  String getComponentType() {
        
return   " demo.component.HtmlHello " ;
    }

    @Override
    
public  String getRendererType() {
        
return   null ;
    }

}


这一步中我们只是创建了一个java类并扩展UIComponentELTag, 覆盖了getComponentType, 这个方法会告诉JSP使用哪一个主类来处理页面标签.类似于一个桥梁作用,后面会看到这是如何联系到我们的主类HtmlHello.java的.

getRendererType方法只返回null, 因为我们的组件主类HtmlHello会自行渲染.所以不需要其它渲染类.

好了,HtmlHelloTag.java就这样简单,我们暂时不需要其他属性(idrendered属性默认已经有了,我们只要在tld文件中登记一下就可以),接着我们来将这个HtmlHelloTag注册到tld文件中.


步骤3.创建TLD标签库描述符文件 – MyComponent.tld


<? xml version="1.0" encoding="UTF-8" ?>
< taglib  xsi:schemaLocation ="
http://java.sun.com/xml/ns/javaee 
http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
 
xmlns
="http://java.sun.com/xml/ns/javaee"  
xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"  
version
="2.1" >
    
< description > 在这里登记标签库的名称,版本,以及页面引用时指定的uri </ description >
    
< display-name > MyComponents </ display-name >
    
< short-name > mc </ short-name >
    
< tlib-version > 1.0 </ tlib-version >
    
< uri > http://mycomponents/demo </ uri >
    
    
< tag >
        
< name > hello </ name >
        
< tag-class >
            demo.component.HtmlHelloTag
        
</ tag-class >
        
< attribute >
            
< name > id </ name >
        
</ attribute >
        
< attribute >
            
< name > rendered </ name >
            
< deferred-value >
                
< type > java.lang.Boolean </ type >
            
</ deferred-value >
        
</ attribute >
    
</ tag >
</ taglib >

MyComponent.tld这个文件的名称并没有什么特殊的或需要约定的规则,把它直接放在WEB-INF文件夹下就可以了,JSF会自己去找到它.

你完全可以直接复制这个文件来进行修改,这里指定了组件库的名称,版本,引用时的uri,需要注意的是uri中指定的http://mycomponents/demo可以自己指定,但要与JSP页面引用时一致如:<%@taglib prefix="mc" uri="http://mycomponents/demo"%>

另外,你可以在<tag>中看到我们将HtmlHelloTag注册到了这个tld描述文件,<tag-class>中我们指定了标签处理类的完全限定类名,<name>中我们给这个标签指定了一个名称:hello, 后面我们可以这样使用这个标签组件:<mc:hello />,同时我们把idrendered属性登记了上去,这是两个基本属性,每个扩展自UIComponentELTag的类都会处理,所以这里登记一下就可以了。

处理完UIComponentTagtld文件之后,我们只要再一步将自己的Component主类注册到faces-config.xml文件中就可以了。

步骤4.将组件注册到faces-config.xml

< faces-config  version ="1.2"  
    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" >

    
< component >
        
< component-type > demo.component.HtmlHello </ component-type >
        
< component-class >
            demo.component.HtmlHello
        
</ component-class >
    
</ component >
</ faces-config >

faces-config.xml文件中,我们注册了前面创建的组件HtmlHello. <component-class>中指定了这个组件的主类的完全限定类名,<component-type>指定了这个组件的类型,实际上你可以使用其它自定的component-type,但是这个名称必须与HtmlHelloTag.java中的方法:getComponentType所返回的名称是一致的:

public String getComponentType() {

        return "demo.component.HtmlHello";

    }

tmlHelloTag.java就是这样联系到这个组件的主类的。

提示:你可以自己新创建一个faces-config.xml文件或使用JSF自己的faces-config.xml来注册你的新组件,如果另外创建一个faces-config.xml,那么你需要在web.xml中登记这个文件的路径。

步骤5.先测试一下这个组件

接着,我们先创建一个 jsp 页面 HelloDemo.jsp 来测试一下新创建的组件,


然后引入我们自定义的标签库,uri需要与我们在tld中定义的相同。

<%@taglib prefix="mc" uri="http://mycomponents/demo"%>


这时当我们打入“<m”的时候jsp已经有了新定义组件的一些提示,下面看一下组件是否可以正常显示,以下是HelloDemo.jsp的代码:


<% @page contentType = " text/html "  pageEncoding = " UTF-8 " %>
<% @taglib prefix = " f "  uri = " http://java.sun.com/jsf/core " %>
<% @taglib prefix = " h "  uri = " http://java.sun.com/jsf/html " %>
<% @taglib prefix = " mc "  uri = " http://mycomponents/demo " %>
<! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd"
>

< f:view >
< html >
    
< head >
        
< meta  http-equiv ="Content-Type"  content ="text/html; charset=UTF-8" >
        
< title > Demo </ title >
    
</ head >
    
< body >
        
< h2 > Hello Demo </ h2 >
        
        
<mc:hello />
        
        
<% @ include file = " ../back.jsp "   %>
    
</ body >
</ html >
</ f:view >


可以看到组件已经可以正常的显示了, 简单的显示了一个input,虽然确实非常简单,并且几乎没有一点作用。不过这基本上就是一个标准JSF组件的创建过程,知道了原理之后我们就可以扩展出更多更高级的功能了。如果你只需要一个标准组件,那么到这一步就可以了.

接下来我们将使用QFaces给组件增加Ajax的功能,提高用户体验。

步骤6Ajax扩展 创建javascript文件 HtmlHello.js

    先创建一个javascript文件:HtmlHello.js 为了方便起见,在这里将它创建在了component包中,与组件的主类等放在一起,这也有利于以后将组件打包成jar,方便部署.


接着开始编写这个js脚本,敲入如下的ajax请求代码,后面你会知道组件是如何触发这个脚本的.


function qfaces_demo_hello(clientId, componentClass) {
    var obj 
=  QFaces.getObj(clientId);  //  获取QFacesObject对象
    var hello  =  QFaces.getComponent(clientId);  //  获取组件
    obj.put( " componentClass " , componentClass);  //  这个参数是组件get请求必要的
    obj.put( " myname " , hello.value);  //  这个参数是我们自己要进行传递的参数
    var process  =  function () {  //  定义回调处理函数
        alert(obj.request.responseText);
    }
    obj.setProcess(process); 
//  设置回调处理函数
    obj.get() //  发送请求(get方式,必须传递参数componentClass)
}

一些解释:

QFaces是我自定义的一个javascript类,可以方便处理ajax请求,已经简化掉了很多几乎没有作用,或经常重复多余的代码.这个类是如何引入的,后面会在组件的渲染中介绍.(你可以直接解开QFacesjar文件,从中找到这个js进行一些修改或许对你有用)

clientId组件的客户端id, 查看html源码,可以看到jsf组件的客户端id都像这样 xxx:xxx:xxx

componentClass 组件的java类的完全限定类名.

后面在组件的渲染中,我们将传递这两个值给这个js函数.下面是QFacesQFacesObject类的解释:

1.       QFaces.getObj(clientId):可以获取一个处理这次请求的js对象QFacesObject,为了避免当页面同时存在多个hello组件时发生全局的XMLHttpRequest冲突,所以传递了组件唯一的clientId, 并且在整个请求过程中,你仍然可以通过clientId在其它方法中获得这个QFacesObject,它是全局的,里面包含了一些有用的东西,如XMLHttpRequest对象,下面是QFacesObject的一些有用的东西:

2.       put()方法:可以很方便的设置传递参数,经过改造看起来很像java Map类的put方法.

3.       setProcess(function):设置回调时的处理函数,在这里我们直接将Ajax带回来的数据alert出来.

4.       get() post()方法:这两个方法分别表示了get请求与post请求.但是有一些不同,使用get方法必需要传递参数”componentClass”即组件的完全限定类名.而post方法必需要传递”clientId”即组件的客户端id.

因为get方法中框架使用了反射机制处理请求,所以需要知道是哪一个组件类发起的请求,并调用相应的处理方法(ajaxInvokeOnGet),但是Post方法却是通过clientId来查找组件,并调用相应的处理方法(ajaxInvokeOnPost).

Post方法性能较差,因为他会传递整个组件树的状态信息,并进行恢复视图等处理.在我的多次测试中,这个阶段几乎至少要花掉约20毫秒的时间,如果页面视图足够复杂可能花费的时间更多,但是Get方法不需要这个阶段,它不需要跑任何生命周期,就好像你写servletFilter来处理这个请求一样.

但是在某些时候post方法非常有用,他可以访问到整个组件树中的所有组件.QFaces.jar包中的validator组件使用的就是这个方式,它需要访问目标组件的value,validator,convert等属性,

尽管post方式性能稍差,但是QFaces中还是帮你省下了JSF生命周期中的后面5个阶段.所以性能还是有所保障的.

5.       QFaces.getComponent(“id”) 获取页面组件,为什么不使用document.getElementById(“id”)? 有时候你可能会发现某些浏览器下无法正常通过id获取页面组件,所以定义了这个方法,更好的兼容多浏览器.

步骤7Ajax扩展 让组件UIComponent触发js

现在开始升级一下前面创建的组件主类HtmlHello.java,让它能触发js调用,并进行ajax请求.


public   class  HtmlHello  extends  UIComponentBase  implements  Ajax{

    @Override
    
public  String getFamily() {
        
return   null ;
    }

    
public   void  ajaxInvokeOnPost(Map < String, String >  params, FacesContext fc) {
        
throw   new  UnsupportedOperationException( " Not supported yet. " );
    }

    
public   void  ajaxInvokeOnGet(Map < String, String >  params, FacesContext fc) {
        
//  我们将实现这个方法
    }

    @Override
    
public   void  encodeBegin(FacesContext fc)  throws  IOException {
        QFaces.loadRequired(); 
// 装载必要的资源如QFaces.js
        QFaces.loadJavascript("demo/component/HtmlHello.js"this); // 装载自定义的js
        String componentClass = this.getClass().getName(); // 获取组件的完全限定类名
        String clientId = this.getClientId(fc); // 获得组件的客户端ID
        
        // 组织js函数用于组件的onblur - javascript:qfaces_demo_hello("…", "…");
        StringBuilder onblur = new StringBuilder("javascript:qfaces_demo_hello(");
        onblur.append(
"'").append(clientId).append("'");
        onblur.append(
",'").append(componentClass).append("'");
        onblur.append(
")"
);
        
        ResponseWriter rw 
=  fc.getResponseWriter();
        rw.startElement(
" input " this );
        rw.writeAttribute(
" id " , clientId,  null );
        rw.writeAttribute(
" name " , clientId,  null );
        rw.writeAttribute(
" type " " text " null );
        rw.writeAttribute(
"onblur", onblur, null );
        rw.endElement(
" input " );
    }

}

你可以看到升级的encodeBegin方法在渲染组件之前装载了QFaces必要的js资源及我们自定义的HtmlHello.js资源(注意资源路径是"/"而非"."符号), 并且给组件增加了一个onblur属性, 这个就是调用我们新定义的js函数的属性了:qfaces_demo_hello(clientId,componentClass)

你可能会担心多个组件同时在页面的时候会导致重复加载js资源的问题,不过这个问题QFaces已经作了处理.

现在先来测试一下组件是否可以正常的触发这个js函数吧,稍微修改一下:qfaces_demo_hello:


function  qfaces_demo_hello(clientId, componentClass) {
    alert(
" clientId= "   +  clientId  +   " \ncomponentClass= "   +  componentClass);
//     var obj = QFaces.getObj(clientId);
//
    var hello = QFaces.getComponent(clientId);
//
    obj.put("componentClass", componentClass);
//
    obj.put("myname", hello.value);
//
    var process = function () {
//
        alert(obj.request.responseText);
//
    }
//
    obj.setProcess(process);
//
    obj.get();
}


可以看到正常的触发了这个函数,显示了组件传递给jsclientIdcomponentClass

现在重新修改回正常的js请求,并进行下一步Ajax请求的最终应答处理:


function  qfaces_demo_hello(clientId, componentClass) {
    
var  obj  =  QFaces.getObj(clientId);
    
var  hello  =  QFaces.getComponent(clientId);
    obj.put(
" componentClass " , componentClass);
    obj.put(
" myname " , hello.value);
    
var  process  =   function  () {
        alert(obj.request.responseText);
    }
    obj.setProcess(process);
    obj.get();
}

步骤8Ajax扩展 让组件UIComponent响应Ajax请求

 

现在我们开始处理Ajax请求的响应,回到组件主类HtmlHello.java来实现最初的方法ajaxInvokeOnGet, 下面是响应的方法实现:

public void ajaxInvokeOnGet(Map<String, String> params, FacesContext fc) {

        String myname = params.get("myname");

        String message = "Hello, welcome to use QFaces! " + myname;

        QFaces.ResponseHTML(fc, message);

    }

你可以看到这个方法很简单,取回了我们通过js发送过来的参数myname的值,并组织新值message,然后使用QFacesResponseHTML方法直接响应这个字符串.当然你也可以从FacesContext中获得response对象进行自定义响应.现在看一下最终效果截图:


在输入了一些信息之后,焦点离开组件,弹出了我们最终想要的效果!这已经是一个完整的带有Ajax功能的组件了.但它的复用性并不好,因为我们硬编码了Ajax响应.接下来的"进一步升级"会让组件支持BackingBean方法绑定.使它可以进行重用.如果你有兴趣就继续往下看.

3. 进一步升级 - 创建一个可重用的Ajax组件

现在先简单回顾一下上面整个组件的制作过程,及处理流程:

制作过程

1.创建组件主类HtmlHello.java ->

2.创建标签属性处理类HtmlHelloTag.java ->

3.创建tld标签描述符定义标签库,并将HtmlHelloTag.java注册到其中 ->

4.创建faces-config.xml(可以直接使用jsf自带的),并将组件注册到其中. ->

5.测试组件可以正常渲染并运行 ->

6.(升级)创建js文件HtmlHello.js ->

7.(升级)让组件能装载js并触发jsajax请求 ->

8.(升级)让组件响应Ajax请求

处理流程

1.JSP页面发现组件标签<mc:hello /> ->

2.JSF根据tld中定义的TagHtmlHelloTag.java来设置相应标签属性的值 ->

3.HtmlHelloTag.java根据getComponentType的返回值确定组件的主处理类的类型 ->

4.HtmlHelloTag.java将相应的属性和值绑定等赋给组件主类 ->

5.组件主类HtmlHello.java开始渲染自己(1.加载QFaces.js, HtmlHello.js 2.渲染一个input) ->

6.页面逞现,input输入信息并离开焦点后触发js : qfaces_demo_hello进行Ajax请求 ->

7.QFaces根据请求的参数componentClass确定相应的处理类HtmlHello.java

8.QFaces调用HtmlHello.javaajaxInvokeOnGet进行Ajax的响应.

现在开始升级方法绑定,为了节省篇幅,后面的叙述及部骤可能不会太过详细,但代码仍是完整的.我们将使组件可以绑定一个这样的方法:

java.lang.String showMessage(java.lang.String)

这个方法将获取用户输入组件的值,同时用Ajax返回一些提示或验证信息,使用方法像这样

<mc:hello showMessage=”#{DemoBean.showMessage}” />

1.       升级MyComponent.tld


<? xml version="1.0" encoding="UTF-8" ?>
< taglib  xsi:schemaLocation ="
http://java.sun.com/xml/ns/javaee 
http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
 
xmlns
="http://java.sun.com/xml/ns/javaee"  
xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"  
version
="2.1" >
    
< description > 在这里登记标签库的名称,版本,以及页面引用时指定的uri </ description >
    
< display-name > MyComponents </ display-name >
    
< short-name > mc </ short-name >
    
< tlib-version > 1.0 </ tlib-version >
    
< uri > http://mycomponents/demo </ uri >
    
    
< tag >
        
< name > hello </ name >
        
< tag-class >
            demo.component.HtmlHelloTag
        
</ tag-class >
        
< attribute >
            
< name > id </ name >
        
</ attribute >
        
< attribute >
            
< name > rendered </ name >
            
< deferred-value >
                
< type > java.lang.Boolean </ type >
            
</ deferred-value >
        
</ attribute >
        
<attribute>
            
<name>showMessage</name>
            
<deferred-method>
                
<method-signature>
                    java.lang.String showMessage(java.lang.String)
                
</method-signature>
            
</deferred-method>
        
</attribute>

    
</ tag >
</ taglib >

现在我们在tld文件中注册了一个新的属性showMessage,他绑定了一个这样的方法:

java.lang.String showMessage(java.lang.String)

2.       升级组件主类HtmlHello.java的渲染


public   class  HtmlHello  extends  UIComponentBase  implements  Ajax{
    @Override
    
public  String getFamily() {
        
return   null ;
    }

    
public   void  ajaxInvokeOnPost(Map < String, String >  params, FacesContext fc) {
        
throw   new  UnsupportedOperationException( " Not supported yet. " );
    }

    
public   void  ajaxInvokeOnGet(Map < String, String >  params, FacesContext fc) {
        String myname 
=  params.get( " myname " );
        String message 
=   " Hello, welcome to use QFaces!  "   +  myname;
        QFaces.ResponseHTML(fc, message);
    }

    @Override
    
public   void  encodeBegin(FacesContext fc)  throws  IOException {
        QFaces.loadRequired();
        QFaces.loadJavascript(
" demo/component/HtmlHello.js " this );
        String componentClass 
=   this .getClass().getName();
        String clientId 
=   this .getClientId(fc); 
        //  取得方法绑定的表达式
        String messageExp  = (this.showMessage != null ? 
                    
this.showMessage.getExpressionString() : null
);
        
        
//  组织js函数用于组件的onblur:javascript:qfaces_demo_hello("", "", "");
        StringBuilder onblur  =   new  StringBuilder( " javascript:qfaces_demo_hello( " );
        onblur.append(
" ' " ).append(clientId).append( " ' " );
        onblur.append(
" ,' " ).append(componentClass).append( " ' " );
        onblur.append(
",'").append(messageExp).append("'" );  //  增加传递的参数
        onblur.append( " ) " );
        
        ResponseWriter rw 
=  fc.getResponseWriter();
        rw.startElement(
" input " this );
        rw.writeAttribute(
" id " , clientId,  null );
        rw.writeAttribute(
" name " , clientId,  null );
        rw.writeAttribute(
" type " " text " null );
        rw.writeAttribute(
" onblur " , onblur,  null );
        rw.endElement(
" input " );
    }
    
    
private MethodExpression showMessage;
    
public void setShowMessage(MethodExpression showMessage) {
        
this.showMessage =
 showMessage;
    }

}

3.       升级 HtmlHelloTag.java


public   class  HtmlHelloTag  extends  UIComponentELTag{

    @Override
    
public  String getComponentType() {
        
return   " demo.component.HtmlHello " ;
    }

    @Override
    
public  String getRendererType() {
        
return   null ;
    }

    @Override
    
protected void setProperties(UIComponent ui) {
        
super.setProperties(ui);
        
if (ui instanceof demo.component.HtmlHello) { // 设置组件的方法绑定
            ((HtmlHello) ui).setShowMessage(showMessage);
        }
    }


    @Override
    
public void release() {
        
super.release();
        
this.showMessage = null// 释放资源
    }
    
    private MethodExpression showMessage;

    
public void setShowMessage(MethodExpression showMessage) {
        
this.showMessage =
 showMessage;
    }

}

4.       升级 HtmlHello.js


function  qfaces_demo_hello(clientId, componentClass, messageExp) {
    
var  obj  =  QFaces.getObj(clientId);
    
var  hello  =  QFaces.getComponent(clientId);
    obj.put(
" componentClass " , componentClass);
    obj.put(
" myname " , hello.value);
    obj.put(
"messageExp" , messageExp);  //  传递方法绑定的表达式
     var  process  =   function  () {
        alert(obj.request.responseText);
    }
    obj.setProcess(process);
    obj.get();
}

5.       升级组件主类的响应处理

现在升级一下主类的ajaxInvokeOnGet使它能处理方法绑定.

public   void  ajaxInvokeOnGet(Map < String, String >  params, FacesContext fc) {
        String myname 
=  params.get( " myname " );
        String messageExp 
=  params.get( " messageExp " );  //  取回方法绑定的表达式
        MethodExpression me  =  QFaces.createMethodExpression(messageExp, 
                String.
class new  Class[]{String. class });  //  重建这个方法绑定
        String result  =  (String) me.invoke(fc.getELContext(),  new  Object[]{myname});  //  调用
        QFaces.ResponseHTML(fc, result);  //  输出响应
}

6.       新建BackingBean – DemoBean.java

现在新建一个backingBean – DemoBean.java 并增加一个方法进行测试

public   class  DemoBean {
    
public  String showMessage(String myname) {
        String message 
=   " 你好, 很高兴见到你!  "   +  myname;
        
return  message;
    }
}

7.       最终测试


<% @page contentType = " text/html "  pageEncoding = " UTF-8 " %>
<% @taglib prefix = " f "  uri = " http://java.sun.com/jsf/core " %>
<% @taglib prefix = " h "  uri = " http://java.sun.com/jsf/html " %>
<% @taglib prefix = " mc "  uri = " http://mycomponents/demo " %>
<! DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd"
>

< f:view >
< html >
    
< head >
        
< meta  http-equiv ="Content-Type"  content ="text/html; charset=UTF-8" >
        
< title > Demo </ title >
    
</ head >
    
< body >
        
< h2 > Hello Demo </ h2 >
        
        
< mc:hello  showMessage ="#{DemoBean.showMessage}"   />
        
        
<% @ include file = " ../back.jsp "   %>
    
</ body >
</ html >
</ f:view >

现在输入信息并onblur之后你可以看到更好的响应输出了,组件支持了方法绑定,重用程度变得更好!

好了就写到这里吧.更多的值绑定,状态保存,validator...等等.还是需要自己更深入的了解JSF,当能够自如的了解并制作组件这后,我相信你应该也会觉得它确实很好用的. 实际上这也并没有什么高深的知识,任何复杂的问题都是由日常生活中非常简单的道理构成的.只要知道了原理,再深入研究,一切都会变得很简单.这与其它行业不同,比如重工业,你知道了某些原理,没有一些资金支持,购买硬件设备供研究的话也是白搭,

但编程却不同,几乎只要一台电脑就什么都有可能,呵呵! 这也是编程诱人的地方.

这篇文章仅供学jsf组件制作的朋友参考,如果你已经是高手,或者你发现有什么不对的地方欢迎拍砖,批评指正,共同交流学习!QQ: 31703299

QFaces相关完整示例下载



- [email protected]
- http://www.huliqing.name

你可能感兴趣的:(一个带有Ajax功能的JSF组件的完整详细开发过程)