一个带有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.
classnew 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相关完整示例下载



- huliqing@huliqing.name
- http://www.huliqing.name

posted on 2008-11-30 23:41 huliqing 阅读(4318) 评论(4)  编辑  收藏 所属分类: JSF

评论

# re: 一个带有Ajax功能的JSF组件的完整详细开发过程 2008-12-03 09:15 taijh

谢谢分享  回复  更多评论   

# re: 一个带有Ajax功能的JSF组件的完整详细开发过程[未登录] 2009-04-29 19:26 IceRao

感谢。不错的文章。  回复  更多评论   

# re: 一个带有Ajax功能的JSF组件的完整详细开发过程 2009-04-29 22:56 huliqing

@IceRao
谢谢关注:)
QFaces在1.4版之后,取消了对jsp的支持,现在必须使用facelets,因为facelets与JSF才是绝配,所以该组件的制作在1.4后的版本是不能运行的。但是在facelets下的制作过程与这个是基本上一样的,并且更简单。
为什么会取消对jsp的支持,主要是考虑到精力有限,并且在双支持的情况下往往顾此失彼,所以希望集中精力做好facelets,并且一般使用JSF的,都强烈建议配合facelets视图技术。
  回复  更多评论   

# sss 2014-07-09 11:38 sssssss

sssssssssssssssssssssss  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航:
 

导航

统计

公告

文章原创,欢迎转载
——转载请注明出处及原文链接

随笔分类(60)

随笔档案(33)

最新评论

评论排行榜