我们在开发当中经常发现,有一些页面的某些部分在很多页面相同的出现,或者几个控件一样的组合经常出现在不同页面。出现这样的问题,一般的做法是把这些控件都定义在view.xml和Jsp里来实现,或者封装ViewModel和Jsp组合实现,或者单独把这些控件放在一个Jsp里实现然后再引用这个jsp。这些做法都可以实现我们需要的功能,但一旦有改动,就必须大量去改每个ViewModel或者Jsp;或者导致开发难度增大。
就上面出现的问题,我们通过下面的一些封装来最好的实现这些功能:
在原有Control的输出中封装
我们想把几个控件绑定在一起用,我们可以在一个Control的输出Html中输出几个Controls的Html内容。
下面我们想在TextEditor后面增加一个清除按钮,清除按钮时用来清除TextEditor的内容。
- 新建一个TestTextEditorOutputter类来输出Html和js,该类继承于com.bstek.dorado.view.smartweb.v2.output.TextEditorOutputter:
代码 5.18:TestTextEditorOutputter.java
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>");
//}
}
}
因为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把控件做排版。 - 根据5.3.1后面Outputter输出的说明,我们还需要在home下新建outputters.xml:
代码 5.19: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>
这样我们就可以覆盖原来TextEditor的页面输出内容了。
通过上面两个步骤,我们就可以实现每个TextEditor后面都带一个清除Button,而且在页面定义标签的时候还是引用之前的<d:TextEditor>来做,不需要通过<d:TextEditor><d:Button>来实现。新建标签把Controls封装在一起输出
5.4.1的实现还可以通过新建一个标签来实现: - 新建一个TestTag类:
代码 5.20:TestTag.java
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.4.1差不多,只是TextEditor也需要跟Button一样处理,其中id需要标签在jsp定义(如需要创建TextEditor则需要dataset和field)。这里重点是怎样取到对应的ViewModel:viewModel = JspHelper.getViewModel(pageContext)。 - 在WEB-INF下新建tld文件或者在dorado.tld下增加对新标签的定义:
代码 5.21: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>
。。。
在这里对新增的标签作定义,其中id是必须要输的内容,dataset和field可输可不输。 - 在Jsp中引用新的标签:
代码 5.22:jsp
<d:TestTag id="textEditor"/>
通过上面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
更名