打造一个自己的模板引擎(四)
接下来我们要写几个扩展标签,使其支持动态include.
在前面我们的编译器会支持静态include,静态包含是把要包含的文件在编译期就包含进来一起编译。
动态包含是在运行期调用模板引擎编译并执行一个模板,然后把结果包含进来。
如果纯粹是包含一个文件,那么从结果上看动态包含和静态包含没有任何区别,我们要支持的这个动态包含是类似于struts2中的<s:action>标签
不但能够动态的包含一个文件,而且能在包含之前执行某一个类的某一个方法,然后再调用模板引擎把模板进行渲染。
这样做的一个好处是主页面只是一个框架,不包含任何数据或者只包含很少的数据,然后页面的每一个部分通过调用不用的标签来完成渲染。
这样可以使页面上的逻辑尽可能的分离,比如某一块数据可能被很多页面引用,这样分离之后可以把每一块都做成一个组件,不同的页面进行不同的组合。
先来定义一下标签的结构:
<t:action className="test.mytest.HelloAction" method="execute" page="/template/hello.html">
<t:param name="var1" value="test1"/>
</t:action>
当这个标签执行的时候会先调用HelloAction, 然后再调用模板引擎渲染hello.html。数据通过pageContext进行传递。
我们需要定义两个标签,一个是ActionTag, 一个是ParameterTag, 先看代码:
public class ActionTag extends TagSupport implements com.skin.ayada.tagext.ParameterTag{ private String className; private String method; private String page; private Parameters parameters = new Parameters(); @Override public int doStartTag(){ super.doStartTag(); this.parameters.clear(); return TagSupport.EVAL_PAGE; } @Override public int doEndTag(){ Map<String, Object> context = null; if(this.className != null) { // 调用指定的类的某个方法, 这个方法返回渲染页面需要用到的数据 context = ActionDispatcher.dispatch(pageContext, this.parameters, this.className, this.method); } if(this.getPage() != null) { // 调用模板引擎进行渲染 // 此处不使用当前的pageContext, 模板引擎在渲染一个新的页面的时候会创建一个新的PageContext // 这样是为了做到数据隔离 TemplateManager.execute(this.getPage(), context, pageContext.getOut()); } return TagSupport.EVAL_PAGE; } @Override public void setParameter(String name, Object value){ parameters.setParameter(name, value); } // getter & setter ...}public class ParameterTag extends BodyTagSupport{ private String name; private String value; @Override public int doEndTag() { Tag parent = this.getParent(); if(parent instanceof com.skin.ayada.tagext.ParameterTag) { String value = this.getValue(); if(value == null) { BodyContent body = this.getBodyContent(); value = (body != null ? body.getString() : null); } com.skin.ayada.tagext.ParameterTag tag = (com.skin.ayada.tagext.ParameterTag)(parent); tag.setParameter(this.getName(), value); return TagSupport.EVAL_PAGE; } else { throw new RuntimeException("Illegal use of parameter-style tag without servlet as its direct parent"); } } // getter & setter ...}