从2006年至2011年底,泽元软件一直都在以JSP为主要的展示层技术,而在长期的使用过程中,我们发现了JSP的一些问题,主要有:

  1)JSP是一个开放的模型,既可以使用标签并自定义标签,也可以使用<%%>来直接嵌入JAVA代码,这就导致了我们的许多同事特别是为客户进行二次开发的人员,为了方便省事,在JSP页面尤其是项目专有的JSP页面中嵌入小段的JAVA代码,为后续升级带来许多麻烦。

  2)由于允许<%%>嵌入代码,JSP须将整个页面文件转换成对应的JAVA代码,再将JAVA代码编译成class文件,通过浏览器访问jsp页面时实际执行的是这个class文件。这就导致了第一次访问JSP页面或者JSP页面有修改时会比较慢,出现有明显的停顿现象。

3) 因为是开放的模型,所以JSP必须要做很多准备工作,以使嵌入其中的JAVA代码和标签能够正常运行,这就导致了运行性能不是很理想。

  4)不同的中间件在实现J2EE标准时会在一些细节方面存在差异,导致一些JSP页面在不同的中间件上有不同的表现。特别明显的是WebSphere的一些版本,在编译JSP页面时会将两个紧密相连的自定义标签中的第二个删除掉,必须在两个标签之间加空格才能够正常编译。

  2012年初我们升级了泽元通用框架到2.0版本,开始以插件机制为核心开发产品和客户系统,这时候发现JSP和插件机制出现很不协调的现象,主要有两个方面:

  1)插件机制要求插件可热部署、热启动和热卸载,这就要求插件中的class能够随着插件停止而移出内存,以免出现插件没有了但它的类还在使用的情况。但JSP编译后的类由中间件管理,这些JSP类以及它们引用到的class都没有办法移出内存,除非应用整体重启。

  2)插件机制要求各个插件中的页面文件、资源文件和class分别打成jar包,不再以单个文件的形式存放在应用目录下,这样做的目的是为了便于项目实施时覆盖产品中的文件,项目实施人员可以将要修改的资源文件和页面文件从jar包中解压出来放到应用根目录的对应路径下,然后再进行修改,这样在用户请求某个资源文件或者页面文件时框架会优先使用应用目录下的单个文件,如果没有找到再从jar包中读取。例如项目要求修改登陆界面,开发人员就可以从com.zving.platform.ui.jar中将login.zhtml解压出来,放到应用根目录下,然后修改login.zhtml,这时候用户再请求/login.zhtml,即会访问到修改后的login.zhtml,并且产品升级后修改的login.zhtml不会被覆盖。在JSP中要实现以上的机制会比较困难。

  于是我们决定寻找一种动态页面适用的模板机制来替换JSP,考察了Velocity和FreeMarker,发现都不太符合我们的使用习惯,对于前端人员来说还需要比较多的学习时间。考虑到我们的ZCMS产品中也有简单的用于静态化的模板机制,使用起来和JSP比较类似,但性能不能满足动态页面的需要。经反复思考决定改造ZCMS中的模板机制,提升成框架的一个组成部分,同时适用于动态页面和静态化shtml文件。最终经过一个月的开发和调试,实现了现在所使用的模板机制,在用作动态页面时后缀为zhtml。zhtml的模板机制有以下优点:

  1)和JSP使用起来完全一致,除了不能使用<%%>代码块和不能使用jsp前缀的内置标签除外;

  2)能使用EL表达式,但和中间件的EL没有关系,是从apache的EL表达式移植并改造过的;

  3)能在EL表达式中使用函数,内置了常用函数并可以自行扩展;

  4)内置了if/else之类的常用标签并可以自行扩展;

  5)在ZCMS的模板中可以调用ZHTML中的标签;

  6)在ZHTML中也可以调用ZCMS中的模板标签,前提是将这些标签用<z:site>包起来,以便为ZCMS标签指明上下文循环;

  7)性能比JSP快,根据页面的复杂度不同要快上5%-50%;

  8)编译时间非常短,是JSP的几十分之一;

  9)可以在JAVA代码中执行模板片段;

  10)在所有中间件上表现得一模一样。

  缺点当然也同时存在:

  1)不是标准;

  2)没有第三方标签库之类的支持;

  3)Tree、DataGird及DataList三个标签还没有完全协调,在这三个标签体内使用表达式输出的效果和其他标签不一致,这是因为这三个标签是要通过AJAX加载数据的,不能像其他标签一样直接执行EL表达式,而是将标签体作为模板,在数据都准备好了以后批量替换的。

  最后一个缺点将在后续版本修改,以使所有标签表现一致。