Template和JSP技术
(从csdn的blog上同步过来)(本文发于java emag第一期)关于Template和JSP的起源还要追述到Web开发的远古年代,那个时候的人们用CGI来开发web应用,在一个CGI程序中写HTML标签。在这之...
(从csdn的blog上同步过来)
(本文发于java emag第一期)
关于 Template 和 JSP 的起源还要追述到 Web 开发的远古年代,那个时候的人们用 CGI 来开发 web 应用,在一个 CGI 程序中写 HTML 标签。
在这之后世界开始朝不同的方向发展: sun 公司提供了类似于 CGI 的 servlet 解决方案,但是无论是 CGI 还是 servlet 都面对同一个问题:在程序里写 html 标签,无论如何都不是一个明智的解决方案。于是 sun 公司 于1999年推出了JSP技术。 而在另一个世界里,以 PHP 和 ASP 为代表的 scriptlet 页面脚本技术开始广泛应用。
不过即便如此,问题并没有结束,新的问题出现了:业务和 HTML 标签的混合,这个问题不仅导致页面结构的混乱,同时也使代码本身难以维护。
于是来自起源于 70 年代后期的 MVC 模式被引入开发。 MVC 的三个角色: Model ——包含除 UI 的数据和行为的所有数据和行为。 View 是表示 UI 中模型的显示。任何信息的变化都由 MVC 中的第三个成员来处理——控制器。
在之后的应用中,出现了技术的第一次飞跃:前端的显示逻辑和后端的业务逻辑分离, COM 组件或 EJB 或 CORBA 用于处理业务逻辑, ASP 、 JSP 以及 PHP 被用于前端的显示。这个就是 Web 开发的 Model 1 阶段(页面控制器模式)。
不过这个开发模式有很多问题:
1. 页面中必须写入 Scriptlet 调用组件以获得所必需的数据。
2. 处理显示逻辑上 Scriptlet 代码和 HTML 代码混合交错。
3. 调试困难。 JSP 被编译成 servlet ,页面上的调试信息不足以定位错误。
这一切都是因为在 Model 1 中并没有分离视图和控制器。完全分离视图和控制器就成了必须。这就是 Model 2 。它把 Model 1 中未解决的问题——分离对组件(业务逻辑)的调用工作,把这部分工作移植到了控制器。现在似乎完美了,不过等等,原来的控制器从页面中分离后,页面所需的数据怎么获得,谁来处理页面显示逻辑?两个办法: 1. 继续利用 asp , php 或者 jsp 等机制,不过由于它们是运行在 web 环境下的,他们所要显示的数据(后端逻辑产生的结果)就需要通过控制器放入 request 流中; 2. 使用新手法——模板技术,使用独立的模板技术由于脱离的了 web 环境,会给开发测试带来相当的便利。至于页面所需数据传入一个 POJO 就行而不是 request 对象。
模板技术最先开始于 PHP 的世界,出现了 PHPLIB Template 和FastTemplate这两位英雄。不久模板技术就被引入到java web开发世界里。目前比较流行的模板技术有:XSTL,Velocity, JDynamiTe ,Tapestry等。另外因为JSP技术毕竟是目前标准,相当的系统还是利用JSP来完成页面显示逻辑部分,在Sun公司的JSTL外,各个第三方组织也纷纷推出了自己的Taglib,一个代表是struts tablib。<o:p></o:p>
<o:p> </o:p>
模板技术从本质上来讲,它是一个占位符动态替换技术。一个完整的模板技术需要四个元素: 0. 模板语言, 1. 包含模板语言的模板文件, 2. 拥有动态数据的数据对象, 3. 模板引擎。以下就具体讨论这四个元素。(在讨论过程中,我只列举了几个不同特点技术,其它技术或有雷同就不重复了)
模板语言包括:变量标识和表达式语句。根据表达式的控制力不同,可以分为强控制力模板语言和弱控制力模板语言。而根据模板语言与 HTML 的兼容性不同,又可以分为兼容性模板语言和非兼容性模板语言。
模板语言要处理三个要点:
1. 标量标记。把变量标识插入 html 的方法很多。其中一种是使用类似 html 的标签;另一种是使用特殊标识,如 Velocity 或者 JDynamiTe ;第三种是扩展 html 标签,如 tapestry 。采用何种方式有着很多考虑,一个比较常见的考虑是“所见即所得”的要求。
2. 条件控制。这是一个很棘手的问题。一个简单的例子是某物流陪送系统中,物品数低于一定值的要高亮显示。不过对于一个具体复杂显示逻辑的情况,条件控制似乎不可避免。当你把类似于 <IF condition=”$count < = 40”><then><span class=”highlight”>count </span></then></IF> 引入,就象我们当初在 ASP 和 PHP 中所做得一样,我们将不得不再一次面对 scriptlet 嵌入网页所遇到的问题。我相信你和我一样并不认为这是一个好得的编写方式。实际上并非所有的模板技术都使用条件控制,很多已有的应用如 PHP 上中的以及我曾见过一个基于 ASP.NET 的应用,当然还有 Java 的 JDynamiTe 。这样网页上没有任何逻辑,不过这样做的代价是把高亮显示的选择控制移交给编程代码。你必需做个选择。也许你也象我一样既不想在网页中使用条件控制,也不想在代码中写 html 标记,但是这个显示逻辑是无可逃避的(如果你不想被你的老板抄鱿鱼的话),一个可行的方法是用 CSS ,在编程代码中决定采用哪个 css 样式。特别是 CSS2 技术,其 selector 机制,可以根据 html 类型甚至是 element 的 attributes 来 apply 不同的样式。
3. 迭代(循环)。在网页上显示一个数据表单是一个很基本的要求,使用集合标签将不可避免,不过幸运的是,它通常很简单,而且够用。特别值得一提的是 PHP 的模板技术和 JDynamiTe 技术利用 html 的注释标签很简单的实现了它,又保持了“所见既所得”的特性。
下面是一些技术的比较:
Velocity |
变量定义:用 $ 标志 表达式语句:以 # 开始 强控制语言:变量赋值: #set $this = "Velocity" 外部引用: #include ( $1 ) 条件控制: #if …. #end 非兼容语言 |
JDynamiTe 变量定义:用 {} 包装 表达式语句:写在注释格式( <!-- à )中 弱控制语言 兼容语言 |
XSLT 变量定义: xml 标签 表达式: xsl 标签 强控制语言:外部引用: import , include 条件控制: if , choose…when…otherwise 非兼容语言 |
Tapestry 采用 component 的形式开发。 变量定义(组件定义):在 html 标签中加上 jwcid 表达式语句: ognl 规范 兼容语言 |
<o:p> </o:p>
模板文件指包含了模板语言的文本文件。
模板文件由于其模板语言的兼容性导致不同结果。与 HTML 兼容性的模板文件只是一个资源文件,其具有良好的复用性和维护性。例如 JDynamiTe 的模板文件不但可以在不同的项目中复用,甚至可以和 PHP 程序的模板文件互用。而如 velocity 的非兼容模板文件,由于其事实上是一个脚本程序,复用性和可维护性大大降低。
模板文件包含的是静态内容,那么其所需的动态数据就需要另外提供。根据提供数据方式的不同可以分为 3 种:
1. Map :利用 key/value 来定位。这个是最常见的技术。如 velocity 的 VelocityContext 就是包含了 map 对象。
Example.vm : Hello from $name in the $project project. <o:p> </o:p> Example.java : VelocityContext context = new VelocityContext(); context.put("name", "Velocity"); context.put("project", "<st1:city w:st="on"><st1:place w:st="on">Jakarta</st1:place></st1:city>"); |
<o:p> </o:p>
2. DOM :直接操作 DOM 数据对象,如 XSLT 利用 XPath 技术。
3. POJO :直接利用反射取得 DTO 对象,利用 JavaBean 机制取得数据。如 Tapestry 。
模板引擎的工作分为三步:
1. 取得模板文件并确认其中的模板语言符合规范。
比如 velocity ,确定 #if 有对应得 #end 等。 Xml + xslt 的模型中, xml 文件标签是否完整等。在完成这些工作后,模板引擎通常会把模板文件解析成一颗节点树(包含模板文件的静态内容节点和模板引擎所定义的特殊节点)。
2. 取得数据对象。
该数据对象一般通过程序传递引用实现。现有的大量框架在程序底层完成,处理方式也各自不同,有两种技术分别为推技术和拉技术。推技术: controller 调用 set 方法把动态数据注入,模板引擎通过 get 方法获得,典型代表: Struts ;拉技术:模板引擎根据配置信息,找到与 view 对应的 model ,调用 model 的 get 方法取得数据,典型代表: Tapestry 。
3. 合并模板文件(静态内容)和数据对象(动态内容),并生成最终页面。
合并的机制一般如下,模板引擎遍历这颗节点树的每一个节点,并 render 该节点,遇到静态内容节点按正常输入,遇到特殊节点就从数据对象中去得对应值,并执行其表达式语句(如果有的话)。
以下详细说明:
Velocity |
Template template = Velocity.getTemplate("test.wm"); Context context = new VelocityContext(); context.put("foo", "bar"); context.put("customer", new Customer()); template.merge(context, writer); 当调用 Velocity.getTemplate 方法时,将调用 ResourceManger 的对应方法。 ResourceManger 先查看该模板文件是否在 cache 中,如果没有就去获取,生成 resource 对象并调用 process() 方法,确定该模板是否有效,如果有效,则在内存中生成一个 Node 树。 当调用 template.merge() 时,遍历这颗 Node 树,并调用每个 Node 的 render 方法。对于模板中的变量和对象 Node ,还将调用 execute() 方法,从 context 中取得 value 。 注: ResourceManger 在 runtime\resource 包下, Node 在 runtime\parser\node 包下 |
Tapestry |
Tapestry 比较麻烦,先介绍一下 http 请求的处理过程。 当 httprequest 请求到达时。该请求被 ApplicationServlet 捕获,随后 ApplicationServlet 通过 getEngine 取到对应的 Engine ,通过该 engine 的 getService 拿到对应的 service ,调用其 service 方法执行 http 请求。 每个 service 通过 RequestCycle 对象的 getPage |
更多推荐
所有评论(0)