zoukankan      html  css  js  c++  java
  • Dorado重用最佳实践

     

    关键字: dorado 重用 jsp view.xml
       在实际开发中我们都会面临组件重用的问题, 面向对象的语言可以通过各种设计模式来实现重用.那么在dorado框架中如何进行重用呢? 对于dorado的重用问题,下面我们从三个方面来进行说明.
    1.通过使用jsp:include指令进行重用
    将要重用的内容写到一个jsp页面中, 然后通过jsp:include标记在需要使用的位置进行重用, 该jsp中可再引用d:view标签,比如定义一个jsp页面:
    Html代码 复制代码
    1. <%@ page contentType="text/html; charset=UTF-8"%>  
    2. <%@ taglib uri="http://www.bstek.com/dorado" prefix="d"%>  
    3. <d:View config="com.baiyao.workflow.component.ChargeType">  
    4.     <d:SubWindow id="winChargeType" title="选择类型" width="300" height="200"  
    5.         draggable="true" resizable="true" status="hidden"  
    6.         showMinimizeButton="false" showMaximizeButton="false"  
    7.         showCloseButton="true">  
    8.         <d:Layout type="border" width="100%" height="100%">  
    9.             <d:Pane position="center">  
    10.                 <d:DataTable id="tblType" />  
    11.             </d:Pane>  
    12.             <d:Pane position="bottom" align="center">  
    13.                 <d:Button id="btnOK" />  
    14.             </d:Pane>  
    15.         </d:Layout>  
    16.     </d:SubWindow>  
    17. </d:View>  


    然后在另外一个页面中进行引入:
    Html代码 复制代码
    1. <d:View config="com.baiyao.workflow.charge.ChargeInput">  
    2.     <d:AutoForm id="frmForm">  
    3.         <d:FormElementRenderer group="group1" element="render1">  
    4.             <d:Layout type="border">  
    5.                 <d:Pane position="center">  
    6.                     <d:DataTable id="tblFormItem" />  
    7.                 </d:Pane>  
    8.                 <d:Pane position="bottom" align="center">  
    9.                     <d:Button id="btnAdd" />&nbsp;&nbsp;   
    10.                     <d:Button id="btnDelete" />  
    11.                 </d:Pane>  
    12.             </d:Layout>  
    13.         </d:FormElementRenderer>  
    14.     </d:AutoForm>  
    15.     <jsp:include page="/workflow/component/win_charge_type.jsp" />  
    16. </d:View>  

    该重用方式比较原始, 主要是利用了jsp:include指令, 会编写jsp的人都会用, 相对来说还是非常简单的. 比较适合组件在页面中的布局中规中矩的情况, 比如实现某一类功能的组件都集中在页面中的某一区域.如果某一类功能的组件在页面中的分布跨度比较大的话, 则会因为没法封装在一个jsp中而无法实现重用.由于重用范围仅限于jsp页面中, 因此其维护性还是非常不错的.但是如果对单个简单组件专门写一个jsp从而在多个jsp页面重用显然有些得不偿失.而且如果对于page1页面中适用到了conrol1,conrol2,conrol3几个组件, 同样在page2页面中也有这3个组件, 大部分属性都差不多, 但是只有少数几个属性不同, 那么我们只能对jsp进行重用, 而jsp对应的view.xml文件则需要写两个. 因此重用性会大一定的折扣
    易用程度:★★★★★
    适用范围:★★★☆☆
    重用粒度:★★☆☆☆
    可维护性:★★★★★

    2.对view组件定义进行重用
    view重用分为两种, 一种是通过调用Server API来创建客户端所需要的组件, 另外一种就是将多个view.xml中定义的组件进行组合

    2.1.通过调用Server API来创建客户端所需要的组件
    通过调用Server API使用java代码在后台来来创建页面所需要的各种Control和Dataset, 而不是在view.xml文件中定义需要的control和dataset, 因为采用这种方式就可以通过利用java的OO特性(封装, 继承和多态), 比如一个保存按钮, 可能在一个涉及到编辑操作的页面中都会用到, 因此我们可以创建一个ViewModel基类,在基类的initControls()方法中通过new Button()的方式来创建该按钮, 然后指定按钮的属性, 有时间的还要加上事件的javascript脚本, 这样所有从该基类继承的ViewModel所对应的view所在的页面都可以适用该按钮了.
    Java代码 复制代码
    1. @Override  
    2. protected void initControls() throws Exception {   
    3.     Button btnSave = (Button) createControl("Button""btnSave");   
    4.     btnSave.setCommand("cmdSave");   
    5.     btnSave.setValue("保存");   
    6.     btnSave.setWidth("70");   
    7.   
    8.     UpdateCommand cmdSave= (UpdateCommand) createControl(   
    9.             "UpdateCommand""cmdSave");   
    10.     cmdSave.setMethod("save");   
    11.     DatasetInfo info = cmdSave.addDatasetInfo("dsEntity");   
    12.     info.setSubmitScope(DatasetInfo.ALL_CHANGE);   
    13.     return btnSave;   
    14. }  


    该重用方式实际上就是将在view.xml配置文件中定义的control或者dataset通过java代码来实现, 实际上是换了一种写法而已, 但是相对于配置文件中的定义来说, 不够直观, 而且要写更多java的代码, 如果该该组件比较复杂的话, 比如写有复杂的事件代码, 则需要去拼javascript字符串脚本, 这样维护性将非常差.但是这种方式的重用粒度非常细, 比如可以只对一个button中的某几个属性进行重用. 而且对于基类定义的组件可以根据需要进行重载, 这样灵活性将非常好.
    易用程度:★★★☆☆
    适用范围:★★☆☆☆
    重用粒度:★★★★★
    可维护性:★☆☆☆☆

    2.2.多个view.xml中定义的组件进行组合重用
    在前面介绍jsp重用方式的时候, 我们知道是将一个jsp页面分解成多个页面来进行重用, 而这里我们换一个角度: 将一个view.xml根据重用的需要分解成多个view.xml文件, 其实在jsp重用中, 也使用了多个view.xml文件(进行了view.xml的分解), 但是二者的合并时机是不同的, jsp重用是在jsp页面的时候做的view.xml合并, 而这里的合并是在ViewModel初始化中进行的.
    这里先来介绍一下JSP Dorado Taglib, ViewModel和view.xml之间的关系(仅限个人理解)
    在dorado的view tag中, 根据给定的view文件所在的位置, 创建ViewModel对象, 该对象中会包含一个ViewModelConfig, 它是对应的view.xml文件的一个解析, 接着进行ViewModel的初始化工作, 初始化就是实际创建组件的过程, 这里面有一些细节我们这里不做研究(比如对于不同的control, 创建的时机是不同的). 最后得到的是一个个组件的Java对象, 我们可以将其看成一个个javabean, jsp页面上的dorado taglib就会根据这些组件对象来生成html或者js脚本.
    三者之间的关系大致是这样, 接着我们开始探讨将多个view.xml合并的时机, 最开始我采用在生成ViewModel的时候将要组合的其他view.xml引入, 来生成最终我需要的ViewModelConfig对象(在原有基础上添加了其他view.xml中的组件), 后来这种做法失败了(这个过程太多复杂, 比如还涉及到缓存问题, 很容易出现在第一次展现没有问题, 但是在通过command发送ajax请求找不到对应的对象而出错), 于是我在ViewModel初始化(就是init方法)的时候将要组合的view.xml引入进去, 这时候成功了, 没有出现问题.可能dorado原来的设计没有考虑到合并多个view.xml的做法, 因此ViewModel在这一方面还是很封闭的, 很多相关的方法都是private的, 因此需要copy出来
    Java代码 复制代码
    1. public class BaseViewModel extends DefaultViewModel {   
    2.     protected static ControlFactory controlFactory;   
    3.     protected List<ViewModelConfig> compositedViewModelConfigs;   
    4.     protected List<String> compositedConfigNames;   
    5.     private int state;   
    6.   
    7.     @Override  
    8.     public void init(int state) throws Exception {   
    9.         List<String> result = new ArrayList<String>();   
    10.         addViewModelConfig(result);   
    11.   
    12.         // 因为在初始化其他viewModelConfig的时候需要使用到状态, 而此时还没有执行super的init方法,   
    13.         // 因此sate还是最初的STATE_VIEW状态   
    14.         setState(state);   
    15.   
    16.         initCompositedViewModelConfigs(state, result);   
    17.         super.init(state);   
    18.     }   
    19.   
    20.     protected void setState(int state) {   
    21.         this.state = state;   
    22.     }   
    23.   
    24.     public int getState() {   
    25.         return state;   
    26.     }   
    27.   
    28.     /**  
    29.      * 添加需要组合的view.xml文件路径  
    30.      *   
    31.      * @param result  
    32.      */  
    33.     protected void addViewModelConfig(List<String> result) {   
    34.         result.add(JbpmConstants.VIEW_TASK_INSTANCE);   
    35.     }   
    36.   
    37.     /**  
    38.      * 根据ViewModelConfig初始化创建组件  
    39.      *   
    40.      * @param state  
    41.      * @param configNames  
    42.      * @throws Exception  
    43.      */  
    44.     protected void initCompositedViewModelConfigs(int state,   
    45.             List<String> configNames) throws Exception {   
    46.         for (String configName : configNames) {   
    47.             ViewModelConfig config = getViewModelConfig(configName);   
    48.   
    49.             loadDatasetConfigs(config);   
    50.             loadControlConfigs(config);   
    51.             if (state == STATE_VIEW) {   
    52.                 loadEventConfig(DoradoContext.getContext(), config);   
    53.             }   
    54.         }   
    55.     }   
    56.   
    57.     /**  
    58.      * 根据view.xml文件名得到ViewModelConfig对象  
    59.      *   
    60.      * @param configName  
    61.      * @return  
    62.      * @throws Exception  
    63.      */  
    64.     protected ViewModelConfig getViewModelConfig(String configName)   
    65.             throws Exception {   
    66.         ViewModelConfig config = null;   
    67.         if (compositedViewModelConfigs == null) {   
    68.             compositedViewModelConfigs = new ArrayList<ViewModelConfig>();   
    69.             compositedConfigNames = new ArrayList<String>();   
    70.         }   
    71.         if (!compositedConfigNames.contains(configName)) {   
    72.             ViewModel viewModel = ViewModelManager.getViewModel(null,   
    73.                     configName, getNamespace(), "request");   
    74.             config = viewModel.getConfig();   
    75.             compositedViewModelConfigs.add(config);   
    76.             compositedConfigNames.add(configName);   
    77.         }   
    78.         return config;   
    79.     }   
    80.   
    81.     @SuppressWarnings("unchecked")   
    82.     protected static ControlFactory getControlFactory() {   
    83.         if (controlFactory == null)   
    84.             try {   
    85.                 String clazz = Setting.getString("view.controlFactory");   
    86.                 Class cl = Class.forName(clazz);   
    87.                 controlFactory = (ControlFactory) cl.newInstance();   
    88.             } catch (IllegalAccessException ex) {   
    89.                 Log.error(ex);   
    90.             } catch (InstantiationException ex) {   
    91.                 if (System.getProperty("java.version").compareTo("1.4") >= 0)   
    92.                     Log.error(ex.getCause());   
    93.                 else  
    94.                     Log.error(ex);   
    95.             } catch (ClassNotFoundException ex) {   
    96.                 Log.error(ex);   
    97.             }   
    98.         return controlFactory;   
    99.     }   
    100.   
    101.     @SuppressWarnings("unchecked")   
    102.     protected void loadDatasetConfigs(ViewModelConfig viewModelConfig)   
    103.             throws Exception {   
    104.         if (viewModelConfig == null)   
    105.             return;   
    106.         List keys = viewModelConfig.datasetNodes();   
    107.         int count = keys.size();   
    108.         for (int i = 0; i < count; i++) {   
    109.             String id = (String) keys.get(i);   
    110.             XmlNode node = viewModelConfig.getDatasetNode(id);   
    111.             if (state != 2 && state != 3)   
    112.                 createDataset(node);   
    113.         }   
    114.   
    115.     }   
    116.   
    117.     @SuppressWarnings("unchecked")   
    118.     protected void loadControlConfigs(ViewModelConfig config) throws Exception {   
    119.         if (config == null)   
    120.             return;   
    121.         List keys = config.controlNodes();   
    122.         int count = keys.size();   
    123.         for (int i = 0; i < count; i++) {   
    124.             String id = (String) keys.get(i);   
    125.             XmlNode node = config.getControlNode(id);   
    126.             String type = node.getAttribute("type");   
    127.             Class typeClass = getControlFactory().getControlType(type);   
    128.             if (typeClass != null) {   
    129.                 if ((com.bstek.dorado.view.control.Logical.class)   
    130.                         .isAssignableFrom(typeClass)) {   
    131.                     createControl(type, id);   
    132.                     continue;   
    133.                 }   
    134.                 if (state == STATE_VIEW   
    135.                         && !(com.bstek.dorado.view.control.Placeable.class)   
    136.                                 .isAssignableFrom(typeClass))   
    137.                     createControl(type, id);   
    138.             } else {   
    139.                 throw new IllegalArgumentException("Unknown control type '"  
    140.                         + type + "'!");   
    141.             }   
    142.         }   
    143.   
    144.     }   
    145.   
    146.     protected void loadEventConfig(DoradoContext context, ViewModelConfig config) {   
    147.         if (config == null)   
    148.             return;   
    149.         XmlNode eventNodes[] = null;   
    150.         XmlNode eventsNode = config.getRoot().getChild("Events");   
    151.         if (eventsNode != null)   
    152.             eventNodes = eventsNode.getChildren();   
    153.         if (eventNodes != null) {   
    154.             for (int i = 0; i < eventNodes.length; i++) {   
    155.                 XmlNode eventNode = eventNodes[i];   
    156.                 String script = XmlConfigUtils.getNodeContent(eventNode,   
    157.                         context);   
    158.                 EventHandler event = new EventHandler(eventNode   
    159.                         .getAttribute("name"), script);   
    160.                 addEventHandler(event);   
    161.             }   
    162.   
    163.         }   
    164.     }   
    165.   
    166.     public Control getControl(String id) throws Exception {   
    167.         ViewModelConfig config = getConfig();   
    168.         Control control = getControl(config, id, true);   
    169.         return control;   
    170.     }   
    171.   
    172.     /**  
    173.      * 在多个view.xml文件中遍历直到找出要对应的javabean模型数据来创建control  
    174.      *   
    175.      * @param config  
    176.      * @param id  
    177.      * @param loop  
    178.      *            是否循环查找, 如果是在compositeViewModelConfigs中查找的话应该避免循环查找, 否则会死循环  
    179.      * @return  
    180.      * @throws Exception  
    181.      */  
    182.     private Control getControl(ViewModelConfig config, String id, boolean loop)   
    183.             throws Exception {   
    184.         Control control = (Control) controls.get(id);   
    185.         if (control == null && config != null) {   
    186.             XmlNode node = config.getControlNode(id);   
    187.             if (node != null) {   
    188.                 String type = node.getAttribute("type");   
    189.                 control = createControl(type, id);   
    190.             } else if (loop) {   
    191.                 // 注意顺序, 添加组合的view.xml文件的原则是后添加的同id的control或dataset将覆盖前面的   
    192.                 for (int i = compositedViewModelConfigs.size() - 1; i >= 0; i--) {   
    193.                     compositedViewModelConfigs.get(i);   
    194.                     control = getControl(compositedViewModelConfigs.get(i), id,   
    195.                             false);   
    196.                     if (control != null) {   
    197.                         break;   
    198.                     }   
    199.                 }   
    200.             }   
    201.         }   
    202.         return control;   
    203.     }   
    204.   
    205.     public Control createControl(String type, String id) throws Exception {   
    206.         Control control = (Control) controls.get(id);   
    207.         if (control == null) {   
    208.             control = constructControl(type, id);   
    209.             ViewModelConfig config = getConfig();   
    210.             if (config != null) {   
    211.                 initControl(control, config, id);   
    212.             }   
    213.             controls.forceAdd(id, control);   
    214.             initControl(control);   
    215.         }   
    216.         return control;   
    217.     }   
    218.   
    219.     private void initControl(Control control, ViewModelConfig config, String id)   
    220.             throws Exception {   
    221.         XmlNode node = config.getControlNode(id);   
    222.         if (node == null) {   
    223.             for (int i = compositedViewModelConfigs.size() - 1; i >= 0; i--) {   
    224.                 config = compositedViewModelConfigs.get(i);   
    225.                 node = config.getControlNode(id);   
    226.                 if (node != null) {   
    227.                     break;   
    228.                 }   
    229.             }   
    230.         }   
    231.         control.init(DoradoContext.getContext(), node);   
    232.     }   
    233.   
    234.     protected ViewDataset createDataset(String type, String id, XmlNode node)   
    235.             throws Exception {   
    236.         ViewDataset dataset = constructDataset(type, id);   
    237.         DoradoContext context = DoradoContext.getContext();   
    238.         if (node != null) {   
    239.             dataset.init(context, node);   
    240.             if (state == STATE_REPORT)   
    241.                 dataset.setAutoLoadData(true);   
    242.         }   
    243.         datasets.forceAdd(id, dataset);   
    244.         initDataset(dataset);   
    245.         return dataset;   
    246.     }   
    247.   
    248.     public ViewDataset createDataset(XmlNode node) throws Exception {   
    249.         String type = node.getAttribute("type");   
    250.         String id = node.getAttribute("id");   
    251.         return createDataset(type, id, node);   
    252.     }   
    253.   
    254.     @Override  
    255.     public ViewDataset getDataset(String id) {   
    256.         // 在当前config中找, 如果找不到, 将在组合config中去找   
    257.         ViewDataset dataset = super.getDataset(id);   
    258.         if (dataset == null) {   
    259.             for (ViewModelConfig config : compositedViewModelConfigs) {   
    260.                 if (dataset == null && config != null) {   
    261.                     XmlNode node = config.getDatasetNode(id);   
    262.                     if (node != null)   
    263.                         try {   
    264.                             String type = node.getAttribute("type");   
    265.                             dataset = createDataset(type, id);   
    266.                             if (dataset != null)   
    267.                                 break;   
    268.                         } catch (Exception ex) {   
    269.                             Log.error(ex);   
    270.                         }   
    271.                 }   
    272.             }   
    273.         }   
    274.         return dataset;   
    275.     }   
    276.   
    277.     @Override  
    278.     public ViewDataset createDataset(String type, String id) throws Exception {   
    279.         XmlNode node = null;   
    280.         ViewModelConfig config = getConfig();   
    281.         if(config != null) {   
    282.             node = config.getDatasetNode(id);   
    283.             if (node == null) {   
    284.                 for (ViewModelConfig vmc : compositedViewModelConfigs) {   
    285.                     node = vmc.getDatasetNode(id);   
    286.                     if (node != null) {   
    287.                         break;   
    288.                     }   
    289.                 }   
    290.             }   
    291.         }   
    292.         return createDataset(type, id, node);   
    293.     }   
    294. }  

    该重用方式集成了jsp重用的优点, 又在一定程度上消除了它的缺点, 与jsp重用相比, 其优点在于, 它不会受到组件在页面中的位置布局的影响. 在重用粒度上能对单个的组件进行重用, 相比jsp重用要细, 但是比Server API的重用方式要粗一些. 因为只是配置文件上的重用, 因此主要是对配置文件的维护, 可维护性要比Server API方式要好, 该方式需要使用者对view.xml配置文件, jsp dorado taglib, ViewModel类三者之间的关系有非常好的认识.
    易用程度:★★☆☆☆
    适用范围:★★★★☆
    重用粒度:★★★★☆
    可维护性:★★★★★

    其他重用技巧
    如果view.xml文件都一样(说明界面一样), 只是ViewModel不同(说明后台业务逻辑不同)的情况下, 我们可以让其公用同一个view.xml, 只是在d:view的配置上加上clazz属性指定二者不同的ViewModel即可.比如这样的写法:
    Html代码 复制代码
    1. <d:View config="com.baiyao.workflow.settlement.SettlementInput"  
    2.     clazz="com.baiyao.workflow.settlement.ExpenseSettlementInputViewModel">  
    3.     <jsp:include page="/workflow/settlement/settlement_input.jsp" />  
    4. </d:View>  


    如何选择
    其实这几种重用方式互相之间并不矛盾, 可以在一个功能模块中根据需要结合起来适用.但是如果使用太多的重用方式, 会提高项目的复杂程度, 这样就会影响到可维护性, 因此重用也应该适可而止, 否则就是过犹不及.
  • 相关阅读:
    [导入]mootools框架【二】Core篇: 主要方法测试实例
    公司招聘中不能说的秘密 【转载】
    国外10个ASP.Net C#下的开源CMS
    [导入][Flash开发笔记] List控件删除指定label或data的项
    [导入]用C#截取指定长度的中英文混合字符串 改进版
    今天小侄子出生,想了一天的名字
    一个正则表达式的解释
    今日小收获
    昨天的事
    两点东西
  • 原文地址:https://www.cnblogs.com/linsond/p/1674409.html
Copyright © 2011-2022 走看看