Dorado 5 : 5.4.封装Controls (T32)

我们在开发当中经常发现,有一些页面的某些部分在很多页面相同的出现,或者几个控件一样的组合经常出现在不同页面。出现这样的问题,一般的做法是把这些控件都定义在view.xml和Jsp里来实现,或者封装ViewModel和Jsp组合实现,或者单独把这些控件放在一个Jsp里实现然后再引用这个jsp。这些做法都可以实现我们需要的功能,但一旦有改动,就必须大量去改每个ViewModel或者Jsp;或者导致开发难度增大。
就上面出现的问题,我们通过下面的一些封装来最好的实现这些功能:

在原有Control的输出中封装

我们想把几个控件绑定在一起用,我们可以在一个Control的输出Html中输出几个Controls的Html内容。
下面我们想在TextEditor后面增加一个清除按钮,清除按钮时用来清除TextEditor的内容。

  1. 新建一个TestTextEditorOutputter类来输出Html和js,该类继承于com.bstek.dorado.view.smartweb.v2.output.TextEditorOutputter:

    import java.io.Writer;

    import javax.servlet.ServletRequest;

    import com.bstek.dorado.view.EventHandler;
    import com.bstek.dorado.view.ViewModel;
    import com.bstek.dorado.view.control.Button;
    import com.bstek.dorado.view.control.Control;
    import com.bstek.dorado.view.control.TextEditor;
    import com.bstek.dorado.view.smartweb.OutputHelper;
    import com.bstek.dorado.view.smartweb.Outputter;
    import com.bstek.dorado.view.smartweb.v2.output.TextEditorOutputter;

    public class TestTextEditorOutputter extends TextEditorOutputter {

    public void doOutputStartSection(Writer writer, Object object, ServletRequest request)
    throws Exception
    {
    TextEditor textEditor = (TextEditor)object;
    // if("button".equals(textEditor.getTag())){
    writer.write("<table><tr><td>");
    // }
    super.doOutputStartSection(writer, object, request);
    }

    public void doOutputEndSection(Writer writer, Object object, ServletRequest request)
    throws Exception
    {
    super.doOutputEndSection(writer, object, request);

    TextEditor textEditor = (TextEditor)object;
    //if("button".equals(textEditor.getTag())){
    writer.write("</td><td>");
    ViewModel viewModel = textEditor.getViewModel();
    Control control = viewModel.getControl(textEditor.getId()+"_Button");
    Button button;
    if(control==null){
    button = (Button)viewModel.createControl("Button", textEditor.getId()+"_Button");
    button.setValue("清除");
    EventHandler event = new EventHandler("onClick");
    event.setScript(textEditor.getDataset()".setValue(\""+textEditor.getField()"\",\"\");");
    button.addEventHandler(event);
    }else{
    button = (Button)control;
    }
    Outputter outputter = OutputHelper.getOutputter(Button.class, viewModel.getClientType());
    outputter.outputStartSection(writer, button, request);
    outputter.outputEndSection(writer, button, request);
    writer.write("</td></tr><table>");
    //}

    }

    }

    代码 5.18:TestTextEditorOutputter.java
    因为TextEditorOutputter类中已经定义好了输出Html和js的内容,我们只需要super就可以把Html和js内容输出来。上面代码重要的部分是:ViewModel viewModel = textEditor.getViewModel();,先拿到对应的viewModel,先查找一下ViewModel定义了Button没有,如没有就增加多一个Button控件,并把Button的定义和操作默认化。后面通过Outputter outputter = OutputHelper.getOutputter(Button.class, viewModel.getClientType());和接下来的两句代码就可以把定义好的Button输出到页面了。因为所有的Js代码都是在页面最后把所有控件的js输出来的,所以我们在这里不需要调用输出js代码的方法。中间我们还通过writer把控件做排版。
  2. 根据5.3.1后面Outputter输出的说明,我们还需要在home下新建outputters.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <elements>
    <element clazz="com.bstek.dorado.view.control.TextEditor">
    <outputter type="smartweb2" clazz="TestTextEditorOutputter"/>
    </element>
    </elements>

    代码 5.19:outputters.xml
    这样我们就可以覆盖原来TextEditor的页面输出内容了。
    通过上面两个步骤,我们就可以实现每个TextEditor后面都带一个清除Button,而且在页面定义标签的时候还是引用之前的<d:TextEditor>来做,不需要通过<d:TextEditor><d:Button>来实现。

    新建标签把Controls封装在一起输出

    5.4.1的实现还可以通过新建一个标签来实现:
  3. 新建一个TestTag类:

    package com.dorado.tag;

    import java.io.IOException;
    import java.io.Writer;

    import javax.servlet.ServletRequest;
    import javax.servlet.jsp.JspException;
    import javax.servlet.jsp.tagext.TagSupport;

    import com.bstek.dorado.view.EventHandler;
    import com.bstek.dorado.view.JspHelper;
    import com.bstek.dorado.view.ViewModel;
    import com.bstek.dorado.view.control.Button;
    import com.bstek.dorado.view.control.Control;
    import com.bstek.dorado.view.control.TextEditor;
    import com.bstek.dorado.view.smartweb.OutputHelper;
    import com.bstek.dorado.view.smartweb.Outputter;

    public class TestTag extends TagSupport {

    private ViewModel viewModel;
    private Writer writer;
    private ServletRequest request;

    private String dataset;
    private String field;

    public TestTag() throws IOException
    {
    }

    public int doStartTag() throws JspException {
    try {
    viewModel = JspHelper.getViewModel(pageContext);
    writer = pageContext.getResponse().getWriter();
    request = pageContext.getRequest();
    writer.write("<table>");
    writer.write("<tr><td>");


    writer.write("<table>");
    writer.write("<tr><td>");
    Control control = viewModel.getControl(id);
    TextEditor textEditor;
    if(control==null){
    textEditor = (TextEditor)viewModel.createControl("TextEditor", id);
    textEditor.setDataset(dataset);
    textEditor.setField(field);
    }else{
    textEditor = (TextEditor)control;
    }
    Outputter outputter = OutputHelper.getOutputter(TextEditor.class,viewModel.getClientType());
    outputter.outputStartSection(writer, textEditor, request);
    outputter.outputEndSection(writer, textEditor, request);

    writer.write("</td><td>");

    control = viewModel.getControl(textEditor.getId()+"_Button");
    Button button;
    if(control==null){
    button = (Button)viewModel.createControl("Button", textEditor.getId()+"_Button");
    button.setValue("清除");
    EventHandler event = new EventHandler("onClick");
    event.setScript(textEditor.getDataset()".setValue(\""+textEditor.getField()"\",\"\");");
    button.addEventHandler(event);
    }else{
    button = (Button)control;
    }
    Outputter outputter2 = OutputHelper.getOutputter(Button.class,viewModel.getClientType());
    outputter2.outputStartSection(writer, button, request);
    outputter2.outputEndSection(writer, button, request);

    writer.write("</td></tr>");
    writer.write("</table>");
    } catch (IOException e) {
    e.printStackTrace();
    throw new JspException(e.getMessage());
    }catch (Exception e) {
    e.printStackTrace();
    throw new JspException(e.getMessage());
    }

    return 0;
    }

    public int doEndTag() throws JspException {
    try {
    writer.write("</td></tr>");
    writer.write("</table>");
    } catch (IOException e) {
    e.printStackTrace();
    throw new JspException(e.getMessage());
    } catch (Exception e) {
    e.printStackTrace();
    throw new JspException(e.getMessage());
    }
    return 6;
    }

    public String getDataset() {
    return this.dataset;
    }

    public void setDataset(String dataset) {
    this.dataset = dataset;
    }

    public String getField() {
    return this.field;
    }

    public void setField(String field) {
    this.field = field;
    }

    }

    代码 5.20:TestTag.java
    这里跟5.4.1差不多,只是TextEditor也需要跟Button一样处理,其中id需要标签在jsp定义(如需要创建TextEditor则需要dataset和field)。这里重点是怎样取到对应的ViewModel:viewModel = JspHelper.getViewModel(pageContext)。
  4. 在WEB-INF下新建tld文件或者在dorado.tld下增加对新标签的定义:

    。。。
    <tag>
    <name>TestTag</name>
    <tagclass>com.dorado.tag.TestTag</tagclass>
    <attribute>
    <name>id</name>
    <required>true</required>
    <rtexprvalue>true</rtexprvalue>
    </attribute>
    <attribute>
    <name>dataset</name>
    <required>false</required>
    <rtexprvalue>true</rtexprvalue>
    </attribute>
    <attribute>
    <name>fueld</name>
    <required>false</required>
    <rtexprvalue>true</rtexprvalue>
    </attribute>
    </tag>
    。。。

    代码 5.21:tld
    在这里对新增的标签作定义,其中id是必须要输的内容,dataset和field可输可不输。
  5. 在Jsp中引用新的标签:

    <d:TestTag id="textEditor"/>

    代码 5.22:jsp
    通过上面3个步骤就可以实现控件的封装。
    如果你不想新增标签和对标签的定义,可以参考一下5.3.3的做法,可以新建一个控件,再定义这个控件的输出(几个控件的输出内容放在新定义的控件输出方法中),这样的话就可以在Jsp中使用<d:Control>来输出内容。
    5.3和5.4中只是简单地说明一下原理和用法,根据它们的内容,你可以做到很多复杂的控件实现、控件封装和功能扩展,如果再结合本文档中的一些内容(比如ViewModel的事件使用,Dataset的事件使用等等),你会发现Dorado5能做到的功能超出你的想象和简单。







    (完)
    文档信息

    文档中文名称

    Dorado 5原理、特性与高级用法V1.0

     

     

     

    文档英文名称

     

     

     

     

    文档内容简介

    由《精通Dorado5》更名为《Dorado 5原理、特性与高级用法》

     

     

     

    日期

    作者

    版本

    变更说明

    2008年06月06日

    steven.zheng@bstek.com (mailto:steven.zheng@bstek.com?subject=《DORADO整合SynchroFlow开发指南》交流)

    V0.9

    创建

    2008年09月03日

    Steven

    V1.0

    出版

    2008年09月07日

    Steven

    V1.0

    更名