StrutsCX是一个Struts框架的插件,属于源代码开放的产品,植根于纯XML和XSLT技术,支持多种语言。有了StrutsCX,我们可以方便地用标准的XML和XSL技术生成HTML、XML、PDF等多种输出格式,而Struts则是执行这类XSLT转换的理想的支持技术。 StrutsCX允许我们以不同的语言和编码方式保存、输出内容,用StrutsCX可以方便地处理中文、英文、德文、法文、西班牙文以及朝鲜文、阿拉伯文、俄文等各种语言文字。
一、简单回顾Struts
Struts鼓励按照Model 2方式构建应用的体系。Model 2是MVC基本设计模式的一种变体。MVC设计模式的优点是,它使得Model、View和Controller各个部分之间相对独立。Struts在一个中心位置装配ActionServlet、ActionMapping和各种Action类,处理所有传入的HttpServletRequest。ActionServlet把各个传入的HttpServletRequest分发给Action类,而ActionMapping对象可通过Struts-config.xml配置文件控制,它告诉ActionServlet如何分发请求。
图一:Struts各个部分之间的通信过程
图一阐述了Controller的功能:在客户端、View和Model之间起协调、仲裁的作用。只有Controller才会与Model和View联系,在这中间它就象是一个交换机,而Model和View之间不会直接通信,这样,Model、View和Controller就被分隔开来。这是成功运用Struts的关键所在。
说明一下:所有Controller的逻辑应当放入Action类,与应用的其他层的通信可以在这里进行。虽然我们可以把业务逻辑也放入Controller,但一般而言最好不要这么做。应当改用Model部分的组件,因为这些组件才是真正处理数据的地方。把数据保存到数据库也应当是Model的功能之一。
当Controller处理好一个HttpServletRequest,它把请求转发给View。View的唯一任务是表现数据,在Struts中,View一般使用JSP技术。
在Struts中,Controller和View之间的所有通信都通过HttpServletRequest、HttpSession和ServletContext间接完成,对于这些操作来说,首选的技术莫过于Servlet,Struts直接把HttpServletRequest传递给Servlet——或者是JSP,不过Servlet容器会自动把JSP转换成Servlet。
二、Struts和JSP的局限
作为一个开放的框架,Struts允许使用JSP之外的技术构造View。在考虑改进Struts应用中的View技术时,人们首先想到的往往是用其他Servlet技术替代JSP,例如用XSLT或在Servlet管理之下的XSLT。
图二描述了在Struts框架中应用JSP的情况。View由JSP定制标记库和JSP页面共同构造,其中ActionForm类是一种类似JavaBean的ValueObject对象,带有set和get方法,用来保存客户的状态。按照Struts的MVC概念,ActionForm位于View和Controller之间的中间地带。Struts提供了一组完备的专用标记,用来从JSP访问ActionForm里面的数据。
图二:Struts应用体系
JSP有力地推动了Java在Web开发中的应用。在JSP标记库技术的帮助下,JSP为Web和J2EE应用中的表现层开发提供了丰富和强大的工具。但是,JSP也存在一些局限:
·程序员可以把应用逻辑放入JSP。但是,按照MVC的设计思想,JSP的唯一用途是显示出数据,否则,程序结构很容易变得复杂和难于管理。
·JSP对XML的支持不佳。JSP不能保证输出的XML内容100%“格式良好”(Well-Formed)。在这个无数支持XML的Internet访问设备不断涌现的时代,缺乏对XML的支持无疑不是小问题。
·开发过程中每一次修改JSP都会导致Servlet容器重新把JSP转换成Servlet。对于有些Servlet引擎,开发过程中由此引起的延迟带来很多麻烦。
三、XSLT的优势
作为一种W3C的正式标准,XSLT提供了一种把XML数据转换成纯文本、PDF、HTML/XHTML、WML、VoiceXML等任意XML格式的灵活、强大的工具。XSLT处理器,例如Xalan和Saxon,通过XSL样式执行转换,XSL样式本身实际上也是一种XML文档(参见图三)。
XSL样式定义了转换XML数据的规则,XSLT处理器按照这些规则实施转换。在XSL样式中,我们可以利用XPath表达式以一种紧凑而高效的形式选取XML文档的一部分进行处理。
图三:XSLT转换原理
XSLT/XPath的基本理念是分离XML数据内容和它的表现形式,以便把同一份数据方便地以不同的形式(或格式)输出,满足各种不同显示设备的需要。也就是说,在不改动输入的XML文档的条件下,对于每一种不同的输出格式,只需定义相应的XSL样式。对于Struts应用来说,这意味着:
·在单一XML文档中存储(描述)所有的数据。
·在XSL样式的帮助下,把该XML文档转换成任意数据格式。
当然,XML文档可以在内存中生成,不一定要有保存在磁盘上的文件。例如,以Java对象的形式创建XML文档,然后直接用XSLT处理器加以处理,从而极大地提高处理速度。
四、StrutsCX:加上了XSLT的Struts
StrutsCX把Struts和XSLT的优势结合到了一起,它用XSLT来替换生成View的JSP,但原封不动地保留Struts的Controller和Model部分。
图四比较了Struts和StrutsCX的差异。在View中,StrutsCX传递的目标不再是JSP,而是一个Servlet,由Servlet组织、构造XML文档,并利用XSL样式转换XML文档。如果有ActionForm Bean,Action对象把它复制到HttpServletRequest,然后也被加入到XML输出文档。类似于Struts,StrutsCX动作的功能也是协调Web应用或J2EE应用的表现层和其他各个层,例如业务层等。
图四:StrutsCX应用体系
StrutsCX与Struts的不同表现在下面几个方面:
·在View中,StrutsCX使用的是XSLT而不是JSP。
·应用的国际化不再通过Java资源捆绑技术实现,而是通过纯XML技术实现。
·StrutsCX不需要为了输出错误信息而使用任何标记库,它使用XML和XSLT/XPath之类的W3C标准技术。
尽管StrutsCX和Struts有着许多不同,我们还是可以结合运用StrutsCX和现有的Struts应用。实际上,StrutsCX只不过是放弃了某些标准的Struts技术,代之以XML、XSLT和XPath。
五、StrutsCXServlet转换原理
在StrutsCX中,XSLT转换由StrutsCXServlet和它的几个辅助类完成,包括StrutsCXDocumentBuilder和StrutsCXTransformer。StrutsCXServlet通过如下方式控制转换工作:
·在StrutsCXDocumentBuilder的帮助下,构造一个XML文档。
·把该文档传递给StrutsCXTransformer,执行转换。
StrutsCXDocumentBuilder通过HttpServletRequest、HttpSession和ServletContext获得创建XML输出文档所需要的信息,所有这些工作通过一个唯一的公用方法createDocument完成。Struts的Action在HttpServletRequest、HttpSession或ServletContext中检查所需信息,具体依赖于哪儿才是保存这些信息的最佳位置。StrutsCXDocumentBuilder创建的XML输出文档包含如下信息:
·整合层(Integration Tier)的数据:可能包括数据库数据、来自EJB的数据、或直接来自其他XML文件的数据。
·一个(可选的)ActionForm Bean,其中保存了客户端的状态信息。
·一个(可选的)ActionErrors对象,包含Struts的错误信息。
·StrutsCX的资源属性,在StrutsCX下它用来替代Java资源捆绑信息。
·HttpServletRequest的数据。
·HttpSession的数据。
六、构造XML输出文档
在StrutsCX中,数据集的值可以作为XML对象或JavaBean提供给StrutsCXServlet,如果选择后者,则需要把一个或多个JavaBean加入到一个ArrayList对象,然后经由HttpServletRequest把它传递给StrutsCXDocumentBuilder。trutsCXDocumentBuilder利用它的辅助类StrutsCXBeanToElement自动从JavaBean的数据创建XML元素,再把XML元素加入到XML输出文档。
StrutsCXBeanToElement类大致以Model 2X为原型。Model 2X是一个类似于StrutsCX的项目,由Julien Mercay和Gilbert Bouzeid开发,它利用Java Reflection API和Java BeanInfo接口分析JavaBean,从JavaBean的set和get方法生成相应的XML元素。
StrutsCX资源属性也是XML文件,相当于Struts的应用属性文件。如果要让应用支持多种语言,则每一种语言都要有对应的StrutsCX资源属性文件,StrutsCX资源属性文件应当包含应用所需的所有国际化的文本字符串。与ActionForm和ActionErrors不同,StrutsCX资源属性文件不应该通过HttpServletRequest传递给StrutsCXServlet,而是应当在Servlet容器启动时调用一次ServletContext,即在第一次调用某个Action类之后立即进行,从而确保获得更好的性能。
实际的XSL转换过程由StrutsCXTransformer类完成。StrutsCXTransformer类利用JAXP封装了整个转换过程。JAXP是一个用来解析XML的Java API——一个很酷的API,它抽象了底层用到的XSLT处理器。当然,要顺利执行转换,我们必须提供一个适当的XSL样式,同样也由Action类选择并加入到HttpServletRequest。只有当XSL样式在最后一次读取之后又被更改,StrutsCXTransformer才会重新读取并解析XSL样式。StrutsCXTransformer要用到一个辅助类StrutsCXURIResolver,StrutsCXURIResolver的作用是自动把相对URI转换成绝对URI。
StrutsCXTransformer还提供了几种很实用的小工具。例如,如果要把XML输出文档直接传递给HttpServletResponse,只要把“debugxml=true”这个参数加入到HttpServletRequest就可以了,在开发XSL样式时,这一功能带来很多方便,我们可以用IE或Netscape/Mozilla直接看到结果。
又如,如果要减轻Web服务器的负担,在客户端执行XSLT转换,我们可以为HttpServletRequest设置另一个参数:xsl_clientside=true。StrutsCXDocumentBuilder把一个处理指令加入到XML输出文档,并指明XSL样式文件的位置。该文档被直接发送到客户端浏览器,不需要执行服务器端的转换。
如前所述,StrutsCX放弃了Java资源绑定技术,改用StrutsCX资源属性(StrutsCX-Resource-Properties)——这是一些用来国际化Web应用的文本字符串的简单XML文件。类似于Struts,StrutsCX能够在运行时通过检查java.lang.Local对象选择出适当的文件。改用StrutsCX资源属性的好处很多:
·和使用Java资源绑定技术相比,StrutsCX资源属性允许通过DTD或XML模式来验证属性文件的一致性。
·在XML中,内容总是能够方便地以分层的形式组织,例如:
<variables lang="de">
<strings>
...
<day>Tag</day>
...
</strings>
...
</variables>
在XSL样式中,我们可以方便地用W3C标准XSLT/XPath表达式(而不是JSP标记)访问上例定义的值:
<xsl:value-of select="//variables/strings/day"/>
XML用UTF-8作为标准编码方式,支持对所有语言字符的访问。StrutsCX资源属性文件充分利用了这一优势。
·StrutsCX资源属性文件可以放在CLASSPATH之外。就象对于其他不想被用户直接通过HTTP访问的文件,StrutsCX资源属性文件最好放入/WEB-INF文件夹下面的某个目录。
·可以利用流行的XML编辑器方便地编辑各种语言的XML文件。与此相对,对于Java资源绑定文件来说,类似的支持工具很缺乏。
·在StrutsCX中,所有的配置文件都是XML格式的,不象在Struts那样既有Java属性文件也有XML属性文件。注意,StrutsCX资源属性应当在某个Action类第一次被调用时以org.jdom.Document对象的形式读入到ServletContext。StrutsCX从一个专用的配置文件strutscx-config.xml获知到哪里去寻找StrutsCX资源属性文件,因此在web.xml中,用来读取资源绑定信息的初始化参数将被丢弃。
七、结束语
综上所述,在Struts中使用XSLT有很多优势:
·整个Web应用避免了使用JSP和标记库。由于可以省略大量的声明,web.xml变得更加小巧灵活。
·使用XSLT和XPath之类的标准技术。
·不能再把业务逻辑放入到XSL样式。XSLT技术的目标之一就是分离数据、应用逻辑、表现逻辑。
·利用XSLT可以方便地获得各种输出格式:纯文本、HTML和其他各种XML格式。不再象JSP那样以HTML为中心。
·XSLT保证输出的内容是100%“格式良好”的XML。
因此,试试StrutsCX是一件很值得做的事情。你可以从http://sourceforge.net/projects/strutscx下载StrutsCX。下载包中包含了一个完整的应用实例。
本文译自:http://www.devx.com/Java/Article/11381
原文题目:《GenerateWeb Output in Multiple Formats and Languages with StrutsCX》。