`
webee
  • 浏览: 9222 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
最近访客 更多访客>>
社区版块
存档分类
最新评论

将ExtJs包装成JSF组件的设计思路及过程-Fence

阅读更多

在阅读本文之前,你必须熟悉这两个流行的web开发框架-Extjs和JSF。熟悉他们基本的开发技术及基本原理。本文将简要介绍包装的过程及思想,以及Fence包装时的实例。

一、阅读本文你所需要了解的知识
    1、ExtJS组件的概念、书写方式、与服务端交互方式、组件组合方式等;
    2、JSF1.2+的技术原理、生命周期过程、组件概念及渲染器的概念;
    3、熟悉Http,ajax的基本知识,基本概念及使用方法;
    4、你所使用的JDK必须在1.5+,并熟悉其一些新特性,如泛型、元数据、注释等;

    在以上技术的基础上,我们开始吧!

二、将Ext组件转化成JSF的组件java类
    Ext是一套完整的API,组件全面丰富,如果你要一个一个改成JSF组件的话,估计你会累的半死,再加上ExtApi的不断更新,你的组件类将无法保证 与Ext一致。所以必须要有工具自动生成JSF组件类。这里生成的方式可以就多样了,比喻使用dom4j解析Api文档等多中方式,本人是就地取材,使用 Ext的Xtemplate的功能生成的,呵呵,此处不赘述了。

    所有的JSF自定义组件都是继承自UIComponentBase,由于我们都是输出组件,所以直接继承UIOutPut组件,以Menu的Textitem为例,生成完整的代码如下:

从代码中我们可以看出,我在生成组件的时候,放弃了Ext api中的方法和事件,只包含了config,并且生成的时候完全遵循Ext的继承逻辑结构,这样组件的属性在JSF类中将与Ext完全一致。

package ext.menu;

import javax.el.ValueExpression;
import javax.faces.context.FacesContext;

import ext.annotation.InstanceOf;
import ext.annotation.ParseConfigMode;
import ext.annotation.PersistenceMode;
import ext.annotation.ReferenceMode;
import ext.annotation.XType;

/**
 *Note:This java code is auto generated by abner,do not edit it. Adds a static
 * text string to a menu, usually used as either a heading or group separator.
 */
@XType("menutextitem") //ext bug
@InstanceOf("Ext.menu.TextItem")
@ParseConfigMode(name = "items", pmode = PersistenceMode.ParentProperty, rmode = ReferenceMode.Config)
public class TextItem extends BaseItem{
    public static final String COMPONENT_TYPE = "Ext.menu.TextItem";
    public static final String COMPONENT_FAMILY = "Ext.menu.TextItem";

    /**
     *


     * Create a new {@link TextItem} instance with default property values.
     *

     */
    public TextItem() {
        super();
        setRendererType(COMPONENT_FAMILY);
    }

    public String getFamily() {
        return (COMPONENT_FAMILY);
    }

    private Boolean hideOnClick;

    /**
     * True to hide the containing menu after this itemis clicked (defaults to
     * false)
     */
    public Boolean getHideOnClick() {
        if (null != this.hideOnClick) {
            return this.hideOnClick;
        }
        ValueExpression _ve = getValueExpression("hideOnClick");
        if (_ve != null) {
            return (Boolean) _ve.getValue(getFacesContext().getELContext());
        } else {
            return null;
        }
    }

    /**
     *


     * Set the value of the hideOnClick property.
     *

     */
    public void setHideOnClick(Boolean hideOnClick) {
        this.hideOnClick = hideOnClick;
        this.handleConfig("hideOnClick", hideOnClick);
    }

    private String itemCls;

    /**
     * The default CSS class to use for text items(defaults to "x-menu-text")
     */
    public String getItemCls() {
        if (null != this.itemCls) {
            return this.itemCls;
        }
        ValueExpression _ve = getValueExpression("itemCls");
        if (_ve != null) {
            return (String) _ve.getValue(getFacesContext().getELContext());
        } else {
            return null;
        }
    }

    /**
     *


     * Set the value of the itemCls property.
     *

     */
    public void setItemCls(String itemCls) {
        this.itemCls = itemCls;
        this.handleConfig("itemCls", itemCls);
    }

    private String text;

    /**
     * The text to display for this item (defaults to'')
     */
    public String getText() {
        if (null != this.text) {
            return this.text;
        }
        ValueExpression _ve = getValueExpression("text");
        if (_ve != null) {
            return (String) _ve.getValue(getFacesContext().getELContext());
        } else {
            return null;
        }
    }

    /**
     *


     * Set the value of the text property.
     *

     */
    public void setText(String text) {
        this.text = text;
        this.handleConfig("text", text);
    }
   
   

    private Object[] _values;

    public Object saveState(FacesContext _context) {
        if (_values == null) {
            _values = new Object[4];
        }
        _values[0] = super.saveState(_context);
        _values[1] = hideOnClick;
        _values[2] = itemCls;
        _values[3] = text;

        return _values;
    }

    public void restoreState(FacesContext _context, Object _state) {
        _values = (Object[]) _state;
        super.restoreState(_context, _values[0]);
        this.hideOnClick = (Boolean) _values[1];
        this.handleConfig("hideOnClick", this.hideOnClick);
        this.itemCls = (String) _values[2];
        this.handleConfig("itemCls", this.itemCls);
        this.text = (String) _values[3];
        this.handleConfig("text", this.text);

    }
}
 

三、渲染组件
    从上面的代码中有个关键的地方在于类的注释,如下:

@XType("menutextitem") //ext bug
@InstanceOf("Ext.menu.TextItem")
@ParseConfigMode(name = "items", pmode = PersistenceMode.ParentProperty, rmode =     ReferenceMode.Config)
 

    通过JSF配置组件的renderer之后,在渲染器中就可以找到此组件的元数据,一看即明白:InstanceOf代表组件渲染时候的实例类,如此组件 渲染后就是 var j_id = new Ext.menu.TextItem({....});当然所有的属性就会变成ext的config。在这个过程中将会有一些复杂的处理,比喻 config类型。生成后模式,这个就主要靠ParseConfigMode来控制了。当然无法一一将其细节写出来,到时候发布源码了大家自然可以看到。

四、处理特殊重要的组件
   在Ext中主要的容器是panel及其子类,数据输出主要靠Form中的field和store,所以对这些组件当然有各自的渲染器。例如Field的渲 染,要保证field在JSF中生效,则必须实现ValueHolder接口、要保证按钮与JSF整合,则必须要实现ActionSource2接口 (1.2)等,如果你熟悉JSF组件的开发,此处就不再赘述,我们主要的是渲染Ext组件。

五、Ajax的处理
    在Ext中formpanel及store主要是靠ajax来与服务端交互数据,所以支持ajax当然是最重要的。本然在渲染处理ajax时,完全遵循 Ext的api,在渲染过程中给按钮动态添加事件即可,在事件中带上参数,如Ext_ajax表示这个请求是ajax请求,则在后台即通过不同的方式处 理,此处就是用到JSF的生命周期了,在ViewHanler及ViewRoot中(都支持装饰模式)分别都拦截Ajax请求,这样你就是随意输出想输出 的数据结构,本人多数采用Xml格式输出数据,当然有些要与Ext一致,如Store有时是直接输出的数据Json格式。如果按钮渲染的重要代码:

 

 .......................................................................代码片段
           if (this.isTypeOf(commandBtn, "submit")) {
                Boolean stSubmit = form.getStandardSubmit();
                if (stSubmit != null && stSubmit.booleanValue()) {
                    String hiddenId = form.getClientId(context)    + ExtFormPanelRenderer.EVENT_SUFFIX;
                    String funBody = hiddenId + ".setValue(src.getId());";
                    sb.append(funBody);

                    hiddenId = form.getClientId(context) + ExtFormPanelRenderer.VIEWSTATE_SUFFIX;
                    funBody = hiddenId + ".setValue(Fence.getViewState());";
                    sb.append(funBody);
                }
                sb.append(form.getVar());
                sb.append(".getForm().submit(");
                if (stSubmit == null || !stSubmit.booleanValue()) {
                    sb.append(encodeFormCommandOptions(context, form,
                            commandBtn, "submit"));
                }
                sb.append(");");
            } else if (this.isTypeOf(commandBtn, "load")) {
                sb.append(form.getVar());
                sb.append(".getForm().load(");
                sb.append(encodeFormCommandOptions(context, form, commandBtn,"load"));
                sb.append(");");
            } else if (this.isTypeOf(commandBtn, "reset")) {
                sb.append(form.getVar());
                sb.append(".getForm().reset();");
            }
............................
.................
if (action != null) {
            if (action.getFailure() == null)
                action.setFailure(JSUtils.ActionFailureCallBack);

            if (action.getSuccess() == null)
                action.setSuccess(JSUtils.ActionSuccessCallBack);

            if (action.getUrl() == null)
                action.setUrl(Ext.PREFIX_RAW_VALUE + ScriptManager.AJAX_PATH);

            if (action.getWaitMsg() == null)
                action.setWaitMsg("Loading...");

            params.putAll(ExtBasicRenderer.getParamList(action));
        } else {
            action = new Submit();
            action.setFailure(JSUtils.ActionFailureCallBack);
            action.setSuccess(JSUtils.ActionSuccessCallBack);
            action.setUrl(Ext.PREFIX_RAW_VALUE + ScriptManager.AJAX_PATH);
            action.setWaitMsg("Loading...");
        }
...................................................
 

 

 六、如何显示界面
    按照传统的Ext写页面的方式,每个页面包含一个或者多个JS,然后在Js文件中写Ext脚本。而包装成JSF组件之后,这部分工作已经交由JSF框架来 处理了,将所有渲染的组件生成的JS通过一个对象存储,在页面渲染时,作为一个JS资源嵌套在页面中,这样请求的资源输出页面生成的脚本文件即可。

	<script type="text/javascript" src="/extjs/faces/abner.fence.script.js?st=1261213194245"><!--{12612165030800}-->script>
     在生成的页面有这么一句,此处及包含整个页面生成的所有脚本,而脚本是通过一个Servlet输出的。到此从页面书写
一个JSF组件标签到最终生成页面的过程及完成!

 包装的效果可以查看本版块帖子:http://www.iteye.com/topic/548626

 博客地址:http://www.5base.net/10/section.aspx/7

分享到:
评论
10 楼 atian25 2010-04-15  
对比几次版本的更新就知道了,每次更新都是完善了xxx的doc.
而且通过源码可以知道里面很多属性是doc里面不会体现出来的. (别说private)
用多了自然会知道.

另外,jsf我没怎么用过,按你的说法,js是直接输出的,那事件方面的你如何处理呢?
9 楼 czpae86 2010-04-14  
atian25 写道
extjs doc中有很多缺漏和错误的地方,如何保证解析的准确度?

例如?
8 楼 atian25 2010-04-12  
extjs doc中有很多缺漏和错误的地方,如何保证解析的准确度?
7 楼 webee 2010-03-17  
<div class="quote_title">littlealan 写道</div>
<div class="quote_div">
<p>還望可以說明清楚一點 <img src="/images/smiles/icon_wink.gif" alt=""></p>
<p> </p>
<p>首先是否用 extJS 那些 API doc 的 html files 作為 input file?</p>
<p>然後如何用 extJS 的 Xtemplate 去生成 java component code? Xtemplate 不是用來定義 html templates 的嗎? 可以用他來定義 java code template?</p>
<p> </p>
<p>還有我見有些 annotation, e.g. <span><span class="keyword" style="font-weight: bold; color: #7f0055;">import</span><span style="color: black;"> ext.annotation.XType, 不在 extJS source package 裡的, 是自定的 annotation?</span></span></p>
<p> </p>
<p>希望可以放些 pseudo code/sample code 參考一下</p>
<p> </p>
<p>我本身公司的系統是用 JSF 1.2 + facelets + richfaces, 現在想再用到一些 UI component 而再整合 extJS 上去, 現在正是尋找不同的整合 JSF/facelets 的方法.</p>
<p> </p>
</div>
<p> </p>
<p>这些annotation是自定义的。主要是在渲染阶段用来注释组件用的。JSF和facelets本身不需要整合,本来就是一个整体来着!在2.0中已经不存在facelets了,已经包含在jsf-api中了!我有个项目Fence现在基于2.0正在开发中,带有测试版本后将会开源!</p>
6 楼 littlealan 2010-03-17  
<p>還望可以說明清楚一點 <img src="/images/smiles/icon_wink.gif" alt=""></p>
<p> </p>
<p>首先是否用 extJS 那些 API doc 的 html files 作為 input file?</p>
<p>然後如何用 extJS 的 Xtemplate 去生成 java component code? Xtemplate 不是用來定義 html templates 的嗎? 可以用他來定義 java code template?</p>
<p> </p>
<p>還有我見有些 annotation, e.g. <span style=""><span class="keyword" style="color: #7f0055; font-weight: bold;">import</span><span style="color: black;"> ext.annotation.XType, 不在 extJS source package 裡的, 是自定的 annotation?</span></span></p>
<p> </p>
<p>希望可以放些 pseudo code/sample code 參考一下</p>
<p> </p>
<p>我本身公司的系統是用 JSF 1.2 + facelets + richfaces, 現在想再用到一些 UI component 而再整合 extJS 上去, 現在正是尋找不同的整合 JSF/facelets 的方法.</p>
<p> </p>
5 楼 webee 2010-03-16  
<div class="quote_title">littlealan 写道</div>
<div class="quote_div">
<div class="quote_title">引用</div>
<div class="quote_div">本人是就地取材,使用 Ext的Xtemplate的功能生成的,呵呵,此处不赘述了</div>
<p> </p>
<p>可否解釋一下怎樣用 Ext.Xtemplate 去生成 UIComponent 的代碼? 能夠自動生成就不用逐個 tag 去維護了</p>
</div>
<p>有很多方式的!可以用客户端javascript 去解释!可以用dom xml去做!</p>
4 楼 littlealan 2010-03-14  
<div class="quote_title">引用</div>
<div class="quote_div">本人是就地取材,使用 Ext的Xtemplate的功能生成的,呵呵,此处不赘述了</div>
<p> </p>
<p>可否解釋一下怎樣用 Ext.Xtemplate 去生成 UIComponent 的代碼? 能夠自動生成就不用逐個 tag 去維護了</p>
3 楼 dieslrae 2009-12-21  
对JSF不是很了解,观望中
2 楼 webee 2009-12-19  
<div class="quote_title">引用</div>
<div class="quote_div">封装成标签的话,会不会影响效率,必竟在服务端做了处理。 </div>
<p>为什么会在这方面担心效率问题,我们所使用的所有框架都是在java中扩展写出来的,页面点个动作,也不知道要执行几百、几千、几万行代码,可我们还是要使用这些框架,说明什么?效率不是由于多几行代码导致的,效率往往是大数据量操作、数据库连接/操作、递归的业务运算所导致,而我们在外围做些包装和装饰,也不过区区多几十、几百行代码而已。呵呵!</p>
1 楼 beck5859509 2009-12-19  
封装成标签的话,会不会影响效率,必竟在服务端做了处理。

相关推荐

    Ext组件转化成JSF

    【Ext组件转化成JSF】是指将基于ExtJS的组件转换为JavaServer Faces (JSF)框架中的组件,以便在JSF应用中使用。ExtJS是一个强大的JavaScript库,提供了丰富的用户界面组件,而JSF是一种Java Web应用程序开发框架,...

    ExtJS开发插件及Ext包

    - 在开发ExtJS应用时,遵循最佳实践至关重要,例如使用SASS预处理器进行样式管理,使用CMD进行模块化构建,以及遵循组件设计原则,使代码可复用且易于维护。 - 保持代码结构清晰,合理组织目录结构,以及使用命名...

    extjs时间日期选择组件

    在EXTJS这个强大的JavaScript框架中,时间日期选择组件是一个至关重要的元素,它为用户提供了方便的方式来选择和输入日期和时间。这些组件使得Web应用程序能够更好地处理时间相关的数据输入,提高用户体验,同时也...

    EXTJS高级程序设计源代码6-4

    EXTJS高级程序设计源代码6-4 EXTJS高级程序设计源代码6-4

    EXTJS高级程序设计源代码6-3

    EXTJS高级程序设计源代码6-3 EXTJS高级程序设计源代码6-3

    ExtJS 组件扩展

    本文将重点探讨ExtJS中组件扩展的两种主要层次及其实践要点。 #### 二、常见错误及原因分析 在使用ExtJS进行组件扩展时,开发人员常常会遇到一些典型的问题: 1. **没有封装**:这通常是由于开发者对ExtJS机制...

    ExtJS日期多选组件源码

    通过研究和理解"ExtJS日期多选组件源码",开发者可以深入学习ExtJS组件设计、事件处理、数据绑定等核心概念,并能进一步定制适合自己项目需求的日期选择组件。这样的组件对于提高开发效率和用户体验具有积极的意义。

    extjs 3.1 组件 使用

    在本篇文章中,我们将深入探讨如何在实际项目中使用ExtJS 3.1的组件。 首先,`css`目录包含了ExtJS 3.1的样式文件。这些CSS文件用于定义组件的外观和布局,包括颜色、字体、边距、边框等。在使用过程中,我们需要...

    Extjs3.0 常用组件介绍及怎么安装开发利器Spket

    **ExtJS 3.0 常用组件介绍** ExtJS 是一款强大的JavaScript库,用于构建富客户端Web应用。在3.0版本中,它提供了一系列丰富的组件,这些组件可以帮助开发者构建功能丰富的用户界面。以下是一些ExtJS 3.0中的常用...

    Extjs树分页组件扩展

    "Extjs树分页组件扩展"就是为了解决这一问题而设计的,它通过扩展TreeLoader和PagingToolbar,实现了在树形组件中进行分页加载的效果。 **TreeLoader的扩展** TreeLoader是ExtJS中负责异步加载树节点的类。在原生...

    EXTJS高级程序设计源代码6-2

    EXTJS高级程序设计源代码6-2 EXTJS高级程序设计源代码6-2

    EXTJS 上传组件及示例

    本篇文章将详细解析EXTJS中的上传组件及其示例,帮助开发者更好地理解和使用这一功能。 EXTJS 的上传组件通常通过`Ext.form.field.File`(也称为FileField或UploadField)实现。这个组件提供了一个表单字段,用户...

    Extjs自定义组件-下拉树

    本文将围绕“Extjs自定义组件—下拉树”这一主题,详细阐述其实现原理、使用方法以及核心代码分析。 #### 一、理解下拉树组件 下拉树组件结合了下拉框(ComboBox)与树形结构(Tree),旨在提供一种直观、高效的...

    ExtJS 界面设计器

    10. **文档和支持**:ExtJS社区提供了详尽的文档和论坛支持,遇到问题时可以查阅官方文档或向社区求助,以解决在使用设计器过程中遇到的任何问题。 总的来说,ExtJS界面设计器是ExtJS开发者的强大辅助工具,它通过...

    extjs入门之组件学习

    extjs入门学习,各个组件的使用,包括Observable、Observable、BoxComponent、Container、Panel、Viewport及Window...

    Extjs图片展示组件实例

    漂亮的Extjs图片展示组件实例,类似于幻灯片,可直接拿去用,非常不错的哦

    ExtJS-3.4.0系列目录

    **ExtJS-3.4.0系列目录** 在ExtJS框架中,3.4.0版本提供了丰富的组件和功能,适合构建复杂的Web应用程序。以下是对标题和描述中提及的几个关键知识点的详细解释: 1. **Ext JS 下载及配置** 在开始使用Ext JS前,...

Global site tag (gtag.js) - Google Analytics