欢迎光临
我们一直在努力

Java Web Framework综述-JSP教程,Java技巧及代码

建站超值云服务器,限时71元/月

java web framework综述

0.简介

本文介绍java web framework的基本工作原理,和一些常用的开源web mvc framework(struts, web work, tapestry, echo, jsf, maverick, spring mvc, turbine, cocoon, barracuda)。

web开发的最重要的基本功是http;java web开发的最重要的基本功是servlet specification。http和servlet specification对于web server和web framework的开发实现来说,是至关重要的协议规范。

应用和剖析开源web framework,既有助于深入掌握http & servlet specification, 也有助于了解一些现代的b/s web框架设计思想,如mvc,事件处理机制,页面组件,ioc,aop等。在这个现代化的大潮中,即使servlet规范本身也不能免俗,不断引入filter、listener等现代框架设计模式。同是sun公司出品的jsf更是如此。

关于mvc模型、项目简介、配置文件、入门示例等基础知识,网上已经有大量的重复资料信息,本文不再赘述。

文中会提到一些相关的开源项目,和一些编程思想,如有需要,可以用相关的关键字在网上搜索,获取基本的背景知识。

本文力图言简意赅,突出重点。着重描述其他资料没有提到、或很少提到的较重要内容,如运行原理、主流用法,相关知识,关键特性等。

1. java web程序工作原理

tomcat的server.xml文件中定义了网络请求路径到主机本地文件路径的映射。比如,<context path="/yourapp" docbase="yourapp_dir/webapp"/>

我们来看一下,一个http request-response cycle的处理过程。

http request url一般分为三段:host, context, path。

如http://yourhost/yourapp/en/index.html这个url,分为host=yourhost, context=yourapp, path=en/index.html三段。其中,context部分由request.getcontext()获得,path部分由request.getservletpath()获得(返回结果是“/en/index.html”)。

yourhost主机上运行的tomcat web server接收到这个url,根据context定义,把yourapp这个网络路径映射为yourapp_dir/webapp,并在此目录下定位en/index.html这个文件,返回到客户端。

如果我们这个url更换为http://yourhost/yourapp/en/index.jsp,这个时候tomcat会试图把yourapp_dir/webapp/en/index.jsp文件编译成servlet,并调用运行这个servlet。

我们再把这个url更换为http://yourhost/yourapp/en/index.do。

注意,戏剧化的事情就发生在这个时候,servlet规范中最重要的类requestdispatcher登场了。requestdispatcher根据web-inf/web.xml配置文件的定义,调用对应的servlet来处理en/index.do这个路径。

假设web.xml里面有这样的定义。

<servlet>

<servlet-name>dispatchservlet</servlet-name>

<servlet-class>yourapp.dispatchservlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>dispatchservlet</servlet-name>

<url-pattern>*.do</url-pattern>

</servlet-mapping>

那么,requestdispatcher会调用yourapp.dispatchservlet类处理这个路径。

如果web.xml没有定义对应en/index.do这个路径的servlet,那么tomcat返回“您请求的资源不存在”。

requestdispatcher用于web server中,也可以用于应用程序中进行处理转向,资源定位。比如,我们在处理en/index.do的代码中调用,

request.getrequestdispatcher(“cn/index.jsp”).forward(request, response), 就可以转交另外的资源cn/index.jsp来处理。

几乎所有的web framework都需要定义自己的dispatch作用的servlet,并调用requestdispatcher进行转向处理。

阅读web framework源代码,有两条主要线索,(1)根据web.xml找到对应的servlet类;(2)搜索包含“requestdispatcher”词的代码文件。

我们看到,request, response 这两个参数,被requestdispatcher在各种servlet之间传来传去(jsp也是servlet)。所以,request的setattribute()和getattribute()方法是servlet之间传送数据的主要方式。

在mvc结构中,一般的处理流程如下:

处理http request的基本单位一般称为action,是一个比servlet轻量得多的接口定义,通常只有一两个方法,如execute(perform), validate等。

我们知道,url->servlet映射,定义在web.xml配置文件里,但mvc框架通常会有另外一个定义url-> action映射的配置文件。

入口dispatcher servlet根据url -> action的映射关系,把请求转发给action。

action获得输入参数,调用商业逻辑,并把结果数据和view标识给(model & view)返回给dispatcher servlet。

dispatcher servlet根据这个view 标识,定位相应的view template path,把处理转交给view(jsp +taglib, velocity, free marker, xsl等)。

view一般通过request.getattribute()获得结果数据,并显示到客户端。至于是谁把结果数据设置到request.attribute里面,有两种可能:action或dispatcher servlet。

2. struts

http://struts.apache.org/

struts是目前用户群最大、开发厂商支持最多的开源web framework。

struts劳苦功高,为普及mvc框架作出了不可磨灭的贡献。显赫的声望,趋于老化的厚重结构,令struts成为很多现代web framework参照、挑战的目标。

struts应用主要包括3件事情: 配置struts-config.xml文件,实现action类,实现view;还有一些高级扩展用法。下面分别讲述。

1. 配置struts-config.xml文件:

struts支持多级配置文件,具体用法和限制,详见struts文档。这里只讨论struts-config.xml主流配置的内容。:-)

(1) url path到action的映射。

如<action path="/logonsubmit" type="app.logonaction" … />

struts的入口servlet是actionservlet。

actionservlet需要此信息把url path调用对应的action类处理。

在struts运行期间,一个url path,只存在一个对应的struts action实例。所有的该url path的请求,都经过这同一个struts action实例处理。所以struts action必须线程安全。

想想看,其实这个要求并不过分,action只是一个处理程序,不应该保存跨http请求的状态数据,按理来说,也应该做成线程安全的。

(2) template name到view template path的映射。

<forward name="success" path="/pages/welcome.jsp"/>

action类返回一个template name,actionservlet根据这个template name获得对应的view template path,然后调用

request.getrequestdispatcher(“view template path”),把处理转向路径对应的servlet。在这个例子中,是转向/pages/welcome.jsp编译后的servlet。

我们来看一个一个velocity的例子。

<include name="success" path="/pages/welcome.vm"/>

web.xml的定义如下

<servlet>

<servlet-name>velocity</servlet-name>

<servlet-class>org.apache.velocity.tools.view.servlet.velocityviewservlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>velocity</servlet-name>

<url-pattern>*.vm</url-pattern>

</servlet-mapping>

这时,request.getrequestdispatcher(“/pages/welcome.vm”)会调用velocityviewservlet,由velocityviewservlet负责装并驱动运行/pages/welcome.vm这个模板文件。

这里面有一个问题,如果调用的是dispatchrequester.include()方法,那么如何才能把pages/welcome.vm传给velocityviewservlet呢?

如前所说,requestdispatcher传递的参数只有两个,request和response。那么只能通过request attribute。正是为了解决这个问题,servlet2.3规范之后,加入了javax.servlet.include.servlet_path这个属性。

参见velocityviewservlet的代码(velocity-tool开源项目)

// if we get here from requestdispatcher.include(), getservletpath()

// will return the original (wrong) uri requested. the following special

// attribute holds the correct path. see section 8.3 of the servlet

// 2.3 specification.

string path = (string)request.getattribute("javax.servlet.include.servlet_path");

从这里我们可以看出,为什么通晓servlet specification对于通晓web framework至关重要。

(3) form bean的定义

如<form-bean name="logonform" type="app.logonform"/>

struts form bean需要继承actionform类。

form bean类,主要有三个作用:

[1]根据bean的定义,利用reflection机制,自动把request参数转化为需要的数据类型,填入到bean的属性当中。actionform类名中虽然有form这个词,但不仅能够获取form提交后的http post参数,也可以获取url后缀的http get参数。

[2]输入验证。用户可以配置validation.xml,定义各属性的验证规则。

[3]当作view object来用。用户需要熟练掌握struts html taglib的用法,才能把form bean的属性正确显示出来。

(4)其他定义。详见struts文档。不再赘述。

2.实现action。

action类从form bean或直接从request中获得输入参数,调用商业逻辑,把结果数据(也许会包装成view object),用request.setattribute()放到request中,最后返回一个用forwardmapping类包装的template name。

3.实现view。

struts view的标准实现方法是jsp + struts taglib,其中最重要的就是struts html taglib。

html:form tag则是整个html tag的核心,其它的如html:input, html:select等tag,都包含在html:form tag里面。

html:form tag用来映射form bean(也可以通过适当定义,映射其他的bean,但使用上会有很多麻烦)。html:form tag包含的其他struts html tag用来映射form bean的属性。

struts bean taglib的用法比较臃肿,一般情况下可以用jstl代替。当然,如果需要用到bean:message tag实现国际化,那又另当别论。

struts tile taglib用于页面布局。开源portal项目liferay使用了struts tile taglib做为布局控制。

4.高级扩展用法

用户可以重载struts的一些控制类,引入自己的一些定制类。详见struts文档。

本文不是struts专题,只讲述最重要的主流用法,其它边边角角的,不再赘述。

3. webwork

http://www.opensymphony.com/webwork/

webwork由于灵活的可插拔特性,受到很多资深程序员的欢迎。似乎很有可能大肆流行起来。

webwork项目建立在xwork项目上。入口servlet是webwork项目中定义的servletdispatcher,而action在xwork项目中定义。

xwork action接口的execute()方法没有参数,不像struts action那样接受request, response参数,所以xwork action能够脱离web环境被直接调用,便于单元测试。

这里引入了一个问题。没有了request参数,那么xwork action如何获得request parameters作为输入数据?又通过什么桥梁(struts用request.setattribute)把结果数据传送到view层?

在web work中,只能通过action本身的getter, setter属性来传送输入参数和输出结果。

比如,我们有这样一个实现了xwork action接口的类,

youraction implements action{

int productid = null;

string productname = null;

public void setproductid(int productid){this.productid = productid;}

public string getproductname(){return productname;}

public string execute(){

productname = findnamebyid(productid);

return “success”;

}

}

这个类里面的productid将接受request输入参数,productname是输出到页面显示的结果。

比如,这样的请求,http://yourhost/yourapp/myaction.action?productid=1

web work会把1填到youraction的productid里面,然后执行execute()方法,jsp里的语句<ww:property value=“productname”>会把youraction的productname显示在页面上。

如果一个web framework采用了这种屏蔽action的request, response参数的设计方式,一般也同时会采用这种action和输入输出数据结合成一体的解决方式。类似的情形也存在于tapestry和maverick中,后面会讲到。

当webwork servletdispatcher接收到http request的时候,首先把所有相关的信息(包括request, response, session, servlet config, servelt context, 所有request参数)等存放到acationcontext中,然后根据interceptor配置信息,生成一个youraction的动态代理类对象。实际上运行的正是这个代理对象,如同servlet filter的工作机制一般,所有注入的interceptor方法会先于actio方法运行。

我们来看一下action和interceptor的地位:action没有参数,无法获得actioncontext;而interceptor接受的actioninvoication参数拥有包括actioncontext在内的所有重要信息。

这种权力分配的不平等,注定了action的作用非常有限,只限于调用商业逻辑,然后返回一个成功与否标志。所有与外部web世界打交道、协调内部工作流程的重担,都责无旁贷地落在interceptor的肩上。

我们可以设想一个极端的例子。我们声明一批不做任何事情的空action,我们只是需要它们的空壳类名;我们制作一批对应的interceptor,所有的转发控制、商业逻辑都在interceptor上实现,然后把interceptor都注入到对应的空action。这在理论上是完全可行的。

在web海洋的包围中,action可少,interceptor不可少。action是一个孤岛,如果没有外来盟友interceptor的协助,只能在自己的小范围内独立作战(比如unit test),而对整体大局的作战目标无法产生影响。

下面我们来看一下action是如何在interceptor的全程监管下工作的。

在webwork中,我们需要如下配置xwork.xml。

<xwork>

<!– include webwork defaults (from webwork-2.1 jar). –>

<include file="webwork-default.xml" />

<!– configuration for the default package. –>

<package name="default" extends="webwork-default">

<!– default interceptor stack. –>

<default-interceptor-ref name=" defaultstack" />

<!– action: youraction. –>

<action name="youraction" class="yourapp.youraction">

<result name="success" type="dispatcher">

youraction.jsp

</result>

</action>

</package>

</xwork>

webwork-default.xml里面的相关定义如下:

<interceptors>

<interceptor name="validation" class="com.opensymphony.xwork.validator.validationinterceptor"/>

<interceptor name="static-params" class="com.opensymphony.xwork.interceptor.

staticparametersinterceptor"/>

<interceptor name="params" class="com.opensymphony.xwork.interceptor.parametersinterceptor

"/>

<interceptor name="conversionerror" class="com.opensymphony.webwork.interceptor.

webworkconversionerrorinterceptor"/>

<interceptor-stack name="defaultstack">

<interceptor-ref name="static-params"/>

<interceptor-ref name="params"/>

<interceptor-ref name="conversionerror"/>

</interceptor-stack>

</interceptors>

从上述的配置信息中可以看出,youraction执行execute()方法的前后,会被

defaultstack所定义的三个intercepter截获。这些interceptor的任务之一就是把输入参数设置到action的对应属性当中。

如果我们需要加入对youraction的属性的验证功能,只要把上述定义中的validation interceptor加入到defaultstack中就可以了。当然,实际工作还没有这么简单,一般来说,还要为每个进行属性验证的action的都配置一份validation.xml。

xwork interceptor能够在package和action级别上,进行截获处理。

servlet filter能够在url patten级别上,进行截获处理。虽然实际上,servlet filter截获的是servlet,但某些情况下,可以达到和截获一批action的同样效果。

比如,在web work中,我们可以为所有admin package的action,加入一个interceptor,当检查到当前session的用户没有admin权限时,统一返回一个警告页面:您没有足够的权限执行这个操作。

我们看到也可以为所有url pattern为“admin/*.action”的url定义一个servlet filter,当检查到当前session的用户没有admin权限时,统一返回一个警告页面:您没有足够的权限执行这个操作。

webwork的interceptor配置是相当灵活的,相当于对action实现了aop。interceptor相当于aspect,基类aroundinterceptor的before(), after()方法相当于advice。

另外,xwork也提供了从xml配置文件装配component的机制,相当于实现了对于component的ioc。

提到aop和ioc,顺便多讲两句。spring aop能够截获所有interface,不限于某个特定接口;spring框架支持所有类型的ioc,不限于某种特定类型。

要知道,aop, ioc可是现在最时髦的东西,一定不要错过啊。:d

相关概念导读(如果需要,请用如下关键字搜索网络):

aop — aspect oriented programming — 面向方面编程。

ioc – inversion of control –控制反转

dynamic proxy — 动态代理,jdk1.4引入的特性。还可以进一步参考cglib, asm等开源项目。

webwork直接支持所有主流view — xsl,velocity, freemarker,jsp。webwork还提供了自己的taglib。“直接支持”的意思是说,不用像struts那样,使用velocity的时候,还需要引入辅助桥梁velocity-tool。

webwork中用到一种功能和xpath类似的对象寻径语言ongl,是一个开源项目。ongl同样用在下面要介绍的tapestry项目中。

opensymphony下还有一个sitemesh项目,通过servlet filter机制控制布局。可以和webwork组合使用。

4. tapestry

http://jakarta.apache.org/tapestry/

tapestry近来突然火了起来,令我感到吃惊。也许是jsf带来的page component风潮令人们开始关注和追逐tapestry。

tapestry的重要思想之一就是page component。

前面讲到,xwork能够自动把request参数映射到action的属性当中。tapestry走得更远,甚至能够根据request参数,映射到action(tapestry里面称为page)的方法,并把request参数映射为page方法需要的参数,进行正确的调用。就这样,tapestry不仅把输入输出数据,而且把事件方法也绑定到了page上面。

在tapestry框架中,action的概念已经非常模糊,而换成了page的概念。而tapestry page是拥有属性和事件的页面组件,其中的事件处理部相当于action的职责,而属性部分起着model的作用。

除了使用page和其它的tapestry页面组件,用户也可以自定义页面组件。

这种页面组件/属性事件的编程模型,受到一些程序员的欢迎。当然,这种编程模型并不是没有代价的,每个tapestry模板文件都需要一个对应的.page文件。这些.page文件定义了页面组件的属性、事件、validator等信息。

我们来看一下b/s结构中,组件的属性、事件和http request绑定的基本原理。一个能够发出请求的页面组件(比如link和button),在输出自己的html的时候,需要输出一些特殊的信息来标志本组件的属性/事件,这样下次http request来的时候,会把这些信息带回来,以便web framework加以辨认识别,发给正确的page component处理。

这些特殊信息通常包含在url参数或hidden input里面,必要的时候,还需要生成一些java script。tapestry,echo,jsf都是这种原理。

tapestry的例子如下:

<a href="#" jwcid="@directlink" parameters="ognl:currentitem.itemid" listener="ognl:listeners.showitem">

jsf用taglib实现页面组件,也提供了类似的commandlink和commandbutton tag。其中对应tapestry listener的tag属性是action。后面会讲解。

tapestry的模板标签是html标签的扩展,具有良好的“所见即所得”特性,能够直接在浏览器中正确显示,这也是tapestry的一个亮点。

5. echo

http://sourceforge.net/projects/echo

echo提供了一套类似swing的页面组件,直接生成html。

从程序员的角度看来,用echo编写web程序,和用swing编写applet一样,属于纯面向组件事件编程,编程模型也以event/listener结构为主体。

echo没有dispatcher servlet,也没有定义url->action映射的配置文件。

echo的action就是实现了actionlistener接口(参数为actionevent)的servlet(继承echoserver类)。

所以,echo直接由web server根据web.xml配置的url -> servlet的映射,进行转发控制。

echo也没有明显的view层,echo在页面组件方面走得更远,所有的html和javascript都由框架生成。你不必(也没有办法)写html,只需要(也只能)在java代码中按照类似swing编程方式,生成或操作用户界面。用户也可以定制自己的echo组件。

echo的ui component的实现,采用了两个重要的模式。一个是peer(component -> componentpeer)模式,一个是ui component -> renderer模式。

虽然echo的api更类似于swing,但实现上却采用更接近于awt的peer模式。每个component类(代表抽象的组件,比如button),都有一个对应的componentpeer类(代表实际的组件,比如windows桌面的button,linux桌面的button,html button等)。

先别急,这个事情还没有完。虽然componentpeer落实到了具体的界面控件,但是它还是舍不得显示自己,进一步把显示工作交给一个renderer来执行。

比如,在echo里面,button类对应一个buttonui(继承了componentpeer)类,而这个buttonui类会把最终显示交给buttonrender来处理。

据说多了这么一步,能够让显示控制更加灵活丰富。比如,同一个renderer可以处理不同的ui component,同一个ui component也可以交给不同的renderer处理。

jsf的页面组件也采用了ui component -> renderer模式,后面会讲到。

6. jsf

http://java.sun.com/j2ee/javaserverfaces/index.jsp

http://wwws.sun.com/software/communitysource/jsf/download.html download source

jsf的中心思想也是页面组件/属性事件。一般来说,jsf的页面组件是一个三件套{ ui component, tag, renderer}。

ui component有可能对应model,event,listener。tag包含componenttype和renderertype两个属性,用来选择对应的的ui component和renderer。

jsf的应用核心无疑是jsf taglib。jsf taglib包含了对应所有重要html元素的tag,而且input tag可以直接包含validator tag或者validator属性,来定义验证手段。

我们通过jsf携带的cardemo例子,来看jsf的处理流程。

(1) cardetail.jsp有如下内容:

<h:commandbutton action="#{carstore.buycurrentcar}" value="#{bundle.buy}" />

可以看到,这个button的submit action和carstore.buycurrentcar方法绑定在一起。我们在tapestry里面曾经看到过类似的情景。

(2) carstore在faces-config.cml中定义:

<managed-bean>

<managed-bean-name> carstore </managed-bean-name>

<managed-bean-class> carstore.carstore </managed-bean-class>

<managed-bean-scope> session </managed-bean-scope>

</managed-bean>

(3) carstore.carstore类中的buycurrentcar方法如下:

public string buycurrentcar() {

getcurrentmodel().getcurrentprice();

return "confirmchoices";

}

(4) confirmchoices转向在faces-config.cml中定义:

<navigation-rule>

<from-view-id>/cardetail.jsp</from-view-id>

<navigation-case>

<description>

any action that returns "confirmchoices" on cardetail.jsp should

cause navigation to confirmchoices.jsp

</description>

<from-outcome>confirmchoices</from-outcome>

<to-view-id>/confirmchoices.jsp</to-view-id>

</navigation-case>

</navigation-rule>

(5)于是转到页面confirmchoices.jsp。

除了interceptor之外,jsf几乎包含了现代web framework应该具备的所有特性:页面组件,属性事件,ioc (managedbean),component -> renderer,类似于swing component的model-event-listener。

也许设计者认为,众多庞杂的模式能够保证jsf成为一个成功的框架。portal开源项目exo就是建立在jsf框架上。

可以看出这样一个趋势,现代web framework认为b/s结构的无状态特性和html界面是对编程来说是需要极力掩盖的一个缺陷,所以尽量模拟c/s结构的组件和事件机制,以吸引更多的程序员。

7. maverick

http://mav.sourceforge.net/

maverick是一个轻量而完备的mvc model 2框架。maverick的action不叫action,直截了当的称作controller。

controller只接受一个controllercontext参数。request,response, servlet config, servelt context等输入信息都包装在controllercontext里面,而且model也通过controllercontext的model属性返回。整个编程结构清晰而明快,令人赞赏。

但这个世界上难有十全十美的事情,由于controllercontext只有一个model属性可以传递数据,程序员必须把所有需要的数据都打包在一个对象里面设置到model属性里。这种麻烦自然而然会导致这样的可能用法,直接把controller本身设置为model,这又回到了controller(action)和model一体的老路。

前面讲到,webwork也把所有的输入信息都包装在actioncontext里面,但action并没有权力获取。而在maverick中,controller对于controllercontext拥有全权的控制,两者地位不可同日而语。当然,由于参数controllercontext包含request,reponse之类信息,这也意味着,maverick controller不能像webwork action那样脱离web环境独立运行。

当然,这也并不意味着任何结构性缺陷。程序的结构由你自己控制,你完全可以把需要unit test的那部分从web环境脱离开来,放到business层。

如同webwork,maverick直接支持所有的主流view。maverick的配置文件采struts, cocoon两家之长,url -> action -> view映射的主体结构类似于struts,而view定义部分对transform的支持则类似于cocoon。如:

<command name="friends">

<controller class="org.infohazard.friendbook.ctl.friends"/>

<view name="success" path="friends.jsp">

<transform path="triminside.jsp"/>

</view>

</command>

8. spring mvc

http://www.springframework.com/

spring mvc是我见过的结构最清晰的mvc model 2实现。

action不叫action,准确地称做controller;controller接收request, response参数,干脆利落地返回modelandview(其中的model不是object类型,而是map类型)。

其它的web framework中, action返回值一般都只是一个view name;model则需要通过其它的途径(如request.attribute,context参数,或action本身的属性数据)传递上去。

spring以一招ioc名满天下,其aop也方兴未艾。“spring出品,必属精品”的观念已经深入人心。我这里多说也无益,强烈建议读者去阅读spring doc & sample & code本身。

9. turbine

http://jakarta.apache.org/turbine/

turbine是一个提供了完善权限控制的坚实框架(fulcrum子项目是其基石)。turbine的个人用户不多,但不少公司用户选择turbine作为框架,开发一些严肃的应用(我并没有说,用其它框架开发的应用就不严肃^_^)。portal开源项目jetspeed建立在turbine上。

turbine用rundata来传递输入输出数据。如同maverick的controllercontext,rundata是整个turbine框架的数据交换中心。除了request, response等基本信息,rundata直接包括了user/acl等权限控制相关的属性和方法,另外还包括action name和target template name等定位属性。

module是turbine里面除了rundata之外的又一个核心类,是turbine框架的基本构件,action是module,screen也是module。turbine提供了loginuser和logoutuser两个action作为整个系统的出入口。而其余流量的权限控制则由类似于servlet filter机制的pipeline控制。

turbine pipeline的编程模型和servlet filter一模一样:turbine pipeline的valve就相当于servlet filter,而valvecontext则相当于filter chain。还有更相近的例子,tomcat源代码里面也有valve和valuecontext两个类,不仅编程模型一样,而且名字也一样。

权限控制贯穿于turbine框架的始终。要用好turbine,首先要通晓子项目fulcrum 的security部分的权限实现模型。

fulcrum security的权限实体包括四个– user, group, role, permission。

实体之间包含{role,permission}和{ group, user, role}两组关系。

{role,permission}是多对多的关系,一个role可以具有各种permission;{ group, user, role}之间是多对多的关系,一个group可包含多个user,并可以给user分配不同的role。

权限模型的实现同样采用peer模式,entity -> entitypeer, entity -> managerpeer。

entity和entitymanger代表抽象的模型概念,而entitypeer和managerpeer代表具体的实现。

用户可以根据模型,提供不同的实现,比如,用内存结构中实现,用数据表结构实现,与windows nt权限验证机制结合,与osworkflow的权限控制模型结合,等等。其中,用数据表结构实现,又可以选择用torque实现,或者用hibernate实现。(torque是turbine的o/r mapping子项目)

例如,falcrum.property配置文件包含如下security相关选项:

# ——————————————————————-

# s e c u r i t y s e r v i c e

# ——————————————————————-

services.securityservice.user.class=org.apache.fulcrum.security.impl.db.entity.turbineuser

services.securityservice.user.manager=org.apache.fulcrum.security.impl.db.dbusermanager

services.securityservice.secure.passwords.algorithm=sha

# ——————————————————————-

# d a t a b a s e s e r v i c e

# ——————————————————————-

services.databaseservice.database.newapp.driver=org.gjt.mm.mysql.driver

services.databaseservice.database.newapp.url=jdbc:mysql://127.0.0.1/newapp

services.databaseservice.database.newapp.username=turbine

services.databaseservice.database.newapp.password=turbine

这说明,权限控制实现由数据库提供,需要根据权限模型创建如下数据表:

turbine_user,turbine_role,turbine_group,

turbine_permission,turbine_role_permission,

turbine_user_group_role。

10. cocoon

http://cocoon.apache.org

cocoon项目是一个叫好不叫做的框架。采用xml + xslt pipeline机制,java程序只需要输出xml数据,cocoon框架调用xsl文件把xml数据转换成html、wml等文件。

cocoon强大灵活的xsl pipeline配置功能,xslt的内容/显示分离的承诺,一直吸引了不少程序员fans。怎奈天不从人愿,由于复杂度、速度瓶颈、xsl学习难度等问题的限制,cocoon一直主要限于网站发布出版领域,向cms和portal方向不断发展。另外,cocoon开发了xsp脚本和cocoon form技术。

cocoon的sitemap.xmap配置文件比较复杂,与其它的web framework差别很大。

主体pipelines配置部分采用pattern match的方式,很像xsl语法,也可以类比于web.xml里面servlet mapping的定义。比如,一个典型的url->action的映射定义看起来是这个样子:

<map:pipelines>

<map:pipeline>

<map:match pattern="*-dept.html">

<map:act set="process">

<map:parameter name="descriptor"

value="context://docs/department-form.xml"/>

<map:parameter name="form-descriptor"

value="context://docs/department-form.xml"/>

<map:generate type="serverpages" src="docs/confirm-dept.xsp"/>

<map:transform src="stylesheets/apache.xsl"/>

<map:serialize/>

</map:act>

<map:generate type="serverpages" src="docs/{1}-dept.xsp"/>

<map:transform src="stylesheets/apache.xsl"/>

<map:serialize/>

</map:match>

</map:pipeline>

</map:pipelines>

11. barracuda

http://barracudamvc.org/barracuda/index.html

barracuda是一个html dom component + event/listener结构的框架。

根据模板文件或配置文件生成静态java类,并在代码中使用这些生成类,是barracuda的一大特色。

barracuda需要用xmlc项目把所有的html或wml模板文件,静态编译成dom结构的java类,作为页面组件。xmlc会根据html元素的id定义,生成相应dom结点的简便操作方法。

barracuda的事件类也需要用barracuda event builder工具把event.xml编译成java类,引入到工程中。barracuda直接用java类的继承关系映射事件之间的父子层次关系。比如,childevent是parentevent的子类。

barracuda的事件分为两类:request events(control events)和response events(view events)。

barracuda事件处理过程很像windows系统消息队列的处理机制。

(1) barracuda根据http request生成request event,放入到事件队列中。

(2) eventdispatcher检查事件队列是否为空,如果为空,结束。如果非空,按照先进先出的方式,从事件队列中取出一个事件,根据这个事件的类型,选择并调用最合适的eventlistener,参数event context包含事件队列。

“根据事件类型,选择最合适的eventlistener对象”的过程是这样的:比如,

eventdispatcher从时间队列里取出来一个事件,类型是childevent;barracuda首先寻找注册了监听childevent的eventlistener,如果找不到,再上溯到childevent的父类parentevent,看哪些eventlistener对parentevent感兴趣。

详细过程参见barracuda的defaulteventdispatcher类。

(3) eventlistener根据event context包含的request信息,调用商业逻辑,获得结果数据,然后根据不同情况,把新的事件加入到event context的事件队列中。

(4) 控制交还给eventdispatcher,回到第(2)步。

the end.

enjoy.

赞(0)
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » Java Web Framework综述-JSP教程,Java技巧及代码
分享到: 更多 (0)