ofbiz全面解读.docx
《ofbiz全面解读.docx》由会员分享,可在线阅读,更多相关《ofbiz全面解读.docx(160页珍藏版)》请在冰点文库上搜索。
ofbiz全面解读
技术文档
第一部分、ofbiz表现
一、理解MVC模式
当涉及大量商业逻辑项目的时候,我们需要考虑什么?
如何分离用户界面和后台操作?
如何避免将商业逻辑混淆于一般的流程控制中?
作为企业信息系统,就需要考虑很多类似的问题。
源源不断的客户新需求,要进行功能修改和扩充,但是因为程序的高耦合,改动将变得非常困难,导致项目成本何风险增加。
而且,往往维护人员与开发人员不是同一个人,即使有详尽的文档,也很难理清程序里纵横交错的联系。
所以贯彻Model-View-Controller(MVC)模式的设计,在设计阶段首先杜绝此类问题,是一个非常好的方法。
1、MVC理论描述
所谓MVC模式,指的是一种划分系统功能的方法,它将一个系统划分为三个部分:
●模型(Model):
封装的是数据源和所有基于对这些数据的操作。
在一个组件中,Model往往表示组件的状态和操作状态的方法。
●视图(View):
封装的是对数据源Model的一种显示。
一个模型可以由多个视图,而一个视图理论上也可以同不同的模型关联起来。
●控制器(Control):
封装的是外界作用于模型的操作。
通常,这些操作会转发到模型上,并调用模型中相应的一个或者多个方法。
一般Controller在Model和View之间起到了沟通的作用,处理用户在View上的输入,并转发给Model。
这样Model和View两者之间可以做到松散耦合,甚至可以彼此不知道对方,而由Controller连接起这两个部分。
模型,即相关的数据,它是对象的内在属性;视图是模型的外在表现形式,一个模型可以对应一个或者多个视图,视图还具有与外界交互的功能;控制器是模型与视图的联系纽带,控制器提取通过视图传输进来的外部信息转化成相应事件,然后由对应的控制器对模型进行更新;相应的,模型的更新与修改将通过控制器通知视图,保持视图与模型的一致性。
下图(图1.1)描述了这三者之间的关系:
2、系统设计
系统属于浏览器/服务器模型(Browser/Server)。
一般的,客户通过浏览器发送HTTP请求给服务器端Web服务器,Web服务器接收该请求并且进行相应处理,然后将处理后的结果返回到客户的浏览器中。
在客户端,浏览器中呈现的正是该系统的视图部分。
视图的作用就是提供给客户一个可视化的界面,并且允许客户输入一些数据来与服务器端程序交互。
对客户来说,他只能看到视图,而模型和控制器对他则是透明的。
在这里Web服务器仅仅起到提供HTTP服务的作用。
Web服务器将客户提交的HTTP请求交给后方的Jsp、Servlet引擎,并且进一步交给其中的控制器来处理。
控制器按照从xml配置文件中提取的请求映射表将该请求映射到相应的处理器(Handler);处理器对模型进行更新、修改等操作,处理完后返回结果给控制器;控制器根据结果通知视图做相应变化,并且选择相应视图返回给客户。
下图(图1。
2)说明了这一协作过程。
3、OFBiz中MVC模式体现
OFBIZ的Web应用框架严格遵循MVC模式。
OFBizMVC中Model有它的封装业务逻辑的事件和服务承担.Control有controller承担,View有传统的jsp,和FreeMarker,JPublish,Beanshell承担。
这里我主要说明Control(Model,View将在相应技术的模块阐述).在OFBiz框架中,Controller是一组管理web表示层对象,其目的是将业务逻辑和表示层完全地分离开来。
1)过滤器(ContextSecurityFilter)
ServletAPI2.3中最重大的改变是增加了filters,filters能够传递request或者修改response。
Filters并不是servlets;它们不能产生response。
你可以把过滤器看作是还没有到达servlet的request的预处理器,或从servlet发出的response的后处理器。
一句话,filter代表了原先的"servletchaining"概念,且比"servletchaining"更成熟。
filter能够:
在servlet被调用之前截取servlet
在servlet被调用之前查看request
提供一个自定义的封装原有request的request对象,修改request头和request内容
提供一个自定义的封装原有response的response对象,修改response头和response内
ContextSecurityFilter(CSF)在/WEB-INF/web.xml定义,用来限制访问web应用程序的文件.具体参看下面的例子.
filter配置如下:
ContextSecurityFilter
ContextSecurityFilter
org.ofbiz.content.webapp.control.ContextSecurityFilter
allowedPaths
/control:
/index.html:
/index.jsp:
/default.html:
/default.jsp:
/images
errorCode
403
ContextSecurityFilter
/*
2)ControlServlet控制程序流程
ControlServlet是所有请求过程的核心.当收到一个请求时,servlet首先设置系统环境信息,初始化request,session,实体代表(采用了"业务代表"的设计模式,我们将在关于实体引擎文章中介绍),ServiceDispatcher,andSecurityHandler存放在ServletContext.随后controlserver将request交给了RequestHandler处理.RequestHandler处理完成后,返回给controlservlet,整个请求过程就结束了。
3)Handler对请求的处理过程
RequestHandler利用RequestManager帮助类收集在定义在/WEB-INF/controller.xml中的请求映射(mapping).映射建立了URI和VIEW的对应关系。
URI又和Event紧密相连,Events用来处理可以直接通过实体引擎,或者调用服务的方式处理业务逻辑。
当RequestHandler收到一个请求后,首先察看请求映射(mapping),如果没有发现对应的当前请求定义或者请求映射,返回错误。
如果察看成功,调用SecurityHandler检查当前的请求是否需要验证和使用这个请求的用户身份验证。
如果当前的用户没有验证,RequestHandler直接将请求转向到登录页面。
成功验证之后,RequestHandler寻找当前请求的事件Event。
并将请求转交给EventHandler.当事件处理完成之后,又将reuqest移交给ViewHandler.如果view类型是url,直接重定向到url,否则根据不同的view类型。
调用不同的viewhandler处理(如:
JPublishViewHandler,RegionViewHandler,FreeMarkerViewHandler)。
请求映射定义实例:
Verifyauserisloggedin.
invoke="checkLogin"/>
如上所示,事件返回"success"调用view:
main。
如果这里的type="request",返回成功以后,自动调用另外的请求。
这就是所谓的"请求嵌套"。
二、JPublish合成表示层
1、经典的合成器--JPublish
JPublish是一个功能强大的web发布系统.它的目的也是最大的特点是将web开发人员的角色严格并清晰的区分开来。
JPublish支持多种模版引擎,包括ApacheVelocity,FreeMarker和WebMacro. JPublish也支持各种脚本语言,如:
Python,BeanShell,andJavaScript。
JPublish是绝对是一个经典的"合成器",平滑的扩展性让人赞叹。
JPublish定义了多种角色用户:
◆应用程序设计师(Applicationdesigner)--主要是通过模板来为一个网站和这个网站的不同部分进行统一的设计,构架。
◆内容策划(contentproducer)--负责处理内容库(contentrepository)中的文档或其他信息。
内容策划在板面设计中通常使用一套有限的设计元素(比如粗体或斜体)。
◆特定业务领域的程序员(Domain-specificprogrammer)--负责build特定领域的Java代码,这可能是JavaBeans,或者与Web应用程序相关的普通Java类。
◆集成程序员(Integrationprogrammer)--负责新建一个将特定代码和Website连接起来的逻辑,该逻辑体现为JPublish的用于scripts自动化任务的actionsystem。
有了这种用户角色的清晰分离,实际上做到了内容,程序逻辑,和表示逻辑的分离。
大多数开发者往往会将所有的任务放在一起,而没有将它们更好地组织起来。
笔者之前所在的项目组也遇到了此类的问题:
项目开始时,似乎已经做了很好的设计。
然后将功能化成很多块,每个人负责一块。
但是到了项目后期发现,需求无奈变更,代码变得很糟糕。
程序员往往为了解决一个问题,乱塞代码。
导致原有的设计变形。
结果项目难以维护,不停地refactor。
导致这样的后果是因为在开发阶段没有将开发人员的职能清晰的分离开来。
调试程序时,总是将表示逻辑和程序逻辑,整合过程一同考虑。
这样代码的质量必然下降。
导致最后为解决问题牺牲了代码的质量。
而使用这种基于角色的工具会使你不得不将这些任务分开并重新合成,我相信这一点一定会使你的程序变得更好更高效。
"Noweveryonecandotheirspecifictaskandputitalltogether。
"
2、template+script
我们知道JPublish将template,script合成在一起。
OFBiz选择了FreeMarker和Beanshell. view的表示逻辑写在FreeMarker,程序逻辑写在BeanShell中,中间还有一个pagedef文件,将ftl和bsh结合起来。
这里还有一个好处要提一下,就是通过pagedef配置一个ftl对应多个bsh,那么就可以做到bsh文件封装的程序逻辑的重用,换一句话说就是一个bsh文件可以在多个地方使用。
所以完成一个jpublish类型的view实现,至少需要编写三个文件. ftl文件,pagedef,bsh,在不同的目录切换,某种意义上增加了工作量。
3、JPublish和MVC
JPublish遵循MVC吗?
回答是否定的.
笔者曾在网上看到“JPublish提供了MVC架构”,其实这是错误的。
从MVC模式的构成来,JPublish完全不是。
JPublish没有control, pagedef只是将template和srcipt合成起来。
每次在templatewebpage被执行之前首先执行对应的script.不存在控制流程的功能。
在OFBiz中,JPublish担任着view的
三、区块(Region)指南
1、简介
区块工具(或叫框架)是一个复合视图模式(在EnterpriseArchitecturePatterns描述的各种视图)的实现,同时也是基于DavidGeary著作的AdvancedJavaServerPages的一种实现。
在www.ofbiz.org的Docs&Books页面可以得到有关这本书更多的信息。
区块由许多命名节(准备插入到一个模板)组成的一个区域。
区块和节在每个webapp的WEB-INF/regions.xml文件里进行配置。
通过使用一个类型为region的视图,区块能与基于web应用的OFBizControlServlet协同工作。
在JSP文件中,可以对区块进行声明,并且通过使用regions.tld文件里的标记把区块包含进来。
这些标记也可以用在区块模板中,用来在模板的指定位置包含命名节。
2、定义区块
1)一个基本的区块定义
首先让我们看一下在WEB-INF/regions.xml文件中的一个实际区块的定义:
ApplicationPage--thisisadefaultandismeanttooverridden-->
--thisisadefaultandismeanttooverridden-->
define标记用来声明一个命名区块。
区块名在id属性指定。
这是使用JSP模板的基本区块。
你也可以定义一个从其他区块继承来的区块,并可以从下一节开始使用。
在模板属性中指定模板全路径,并且是相对webapp的根路径的一个webapp资源,就象一个webapp里的JSP或Servlet一样。
模板文件可以插入的内容是常规文本,或其他文本,这些文本被插入在不同的地方。
在一个区块中内容就是作为一个节而被插入。
在区块模板中,节由名称进行标识,并且在配置一个区块时,通过put标记对准备插入到每个节的内容进行定义。
put标记的section属性保存节名称。
content属性的值用来确定准备插入到节中的内容。
内容还可以嵌入到put标记的body里,类似于上面示例的标题节。
这里指的是直接内容。
缺省地,content属性值是用来定位当前webapp的某个资源的。
节类型在type属性中设定,并且缺省类型是default。
这些类型将在下面讨论。
注意:
如果一个节被包含到一个模板中,却没有在区块定义中为它指定内容,那么当模板被使用时不会插入任何东西。
2)一个继承的区块
下面是一个通过继承其他区块来定义区块的例子。
LoginPage
这个定义没有使用定义标记中的模板属性,而是使用区块属性和指定被继承区块来代替。
使用的模板与父区块模板相同,并且继承节的put标记中所有设定。
子区块的put标记设定将覆盖父区块的设定。
在这种情况,login区块从MAIN_REGION继承而来。
MAIN_REGION区块采用这种格式命名表示不直接使用,而是用来被login继承。
我们发现采用这样的约定很有用。
Login区块与MAIN_REGION布局相同,而"content"节内容将被覆盖,因此,可以在主内容区域(maincontentarea)使用login.jsp页面。
为了给页面指定一个自定义标题,title也要被覆盖。
3)在一个区块内的区块
下面的示例是一个主区块(mainregion)某节的内容,为了编写这种新风格的页面,通过继承主区块定义了一个区块。
下面还包括一个区块示例,它从新风格的页面继承而来,并且覆盖了主内容区域和title节内容。
这个示例能反映真实世界的状况。
---->
---->
ShowCart
4)不同类型的节
只有几种类型的节总是可用。
除了这些类型外,你还可以使用controller.xml文件里定义的任何类型的ControlServletView。
在示例中包括有http、velocity等。
总是可用类型是:
default、region、resource、direct。
direct是最简单的类型。
put标记的content属性值采用这种类型,或直接把put标记之body中的字符串插入到模板中。
使用region类型可以使得内容能既可以是区块,也可以是作为节内容包含到别的区块中的区块。
resource类型用来指定当前webapp相关资源(一个JSP、Servlet或其他webapp资源)的content属性值。
default类型是唯一不具direct意义的类型。
当类型设定为default(或者没有指定类型)时,将在区块名列表中查找content属性值,如果找到就把该区块作为节的内容。
如果content属性值不是一个区块名,那么content属性值就被假定是一个资源,并且区块框架会在当前webapp中查找该命名资源。
3、创建区块模板
1)简介
创建一个区块模板最简单的方式是:
创建一个使用区块标记库的JSP(在区块中使用节)。
JSPs模板能象任何其他JSP一样使用,但是最好保持他们的简单,而把更复杂内容放到webapp资源(webapp资源当作节内容包含)里。
正象一个边注,"stack"区块保存在一个request属性里,理论上,通过它可以创建一个servlet来作模板,或者为velocity开发一个工具,或者把其他模板机制作为区块模板。
2)标签
使用区块的第一步是,象下面的JSP一样用标记声明准备使用区块标记库:
<%@tagliburi='regions'prefix='region'%>
"regions"uri是来自web.xml文件的一个声明(采用标准方式声明)。
象下面一样,你可以指定在哪里插入每节内容,或在哪里使用region:
render标记:
rendersection='header'/>
在区块标记库中还有其他一些标记,能用来定义区块(象regions.xml文件里XML元素一样),并且可以指定到区块的每节内容
四、JSP标签库指南
1、简介
OFBiz的JSP标记库由一组自定义标记组成,利用这些标记可以很容易地使用OFBiz核心框架的其他构件。
然而有一些基本的条件性、循环控制、i18n和其他通用标记也能在更通用的标记库如Jakarta中找到。
我们也包含这些标记主要是为了使用方便,并且在缺省情况下OFBiz的这些标记对用户更友好。
下面是OFBiz的标记表和一些基本参考信息。
在文档的其他内容将详细解释每个标记。
标记名
Body内容
标记类
TEI类
url
JSP
UrlTag
contenturl
JSP
ContentUrlTag
if
JSP
IfTag
unless
JSP
UnlessTag
iterator
JSP
IteratorTag
IteratorTEI
iteratorNext
JSP
IterateNextTag
IterateNextTEI
iteratorHasNext
JSP
IteratorHasNextT