Apache OFBiz源码解读之MVC模型
节点解析
request-map
你可以将其理解为controller的配置,如果你了解或使用过struts的配置或springmvc的annotation,就会发现这个定义跟它们是很相似的:
- <request-map uri="createCreditCardAndPostalAddress">
- <security https="true" auth="true"/>
- <event type="service" path="" invoke="createCreditCardAndAddress"/>
- <response name="success" type="request" value="finalizeOrder"/>
- <response name="error" type="view" value="billsetting"/>
- </request-map>
该元素定义了请求的映射关系。它使用名为uri的属性,表述该uri将要映射的请求。内部包含三个常用的子元素,分别是:security,event,response。
- security:表示该uri应该对应的安全级别(是否应该是https的,是否要进行权限检查)
- event:该请求触发的事件,这个后面在讲解handler的时候再谈
- response:指定响应的配置
view-map
- <view-map name="billsetting" type="screen" page="component://order/widget/ordermgr/OrderEntryOrderScreens.xml#BillSettings"/>
包含的属性:
- name:当前view-map的名称,通常被<request-map>子元素<response>的value属性引用
- type:其表示用什么技术展示视图,通常为screen,该值其实引用的是后面要讲解的handler
- page:指定真实用于前端展示的视图布局文件
handler
OFBiz中大致会划分两种类型的handler:event和screen。其实个人认为此处将handler理解为engine更为贴切一点,因为叫
handler很容易跟业务联系到一起,而如果称之为engine则可以完全跟业务隔离开来,它只是纯技术组件而已。看看handler的定义就很容易理
解了:
- <!-- event handlers -->
- <handler name="java" type="request" class="org.ofbiz.webapp.event.JavaEventHandler"/>
- <handler name="soap" type="request" class="org.ofbiz.webapp.event.SOAPEventHandler"/>
- <handler name="xmlrpc" type="request" class="org.ofbiz.webapp.event.XmlRpcEventHandler"/>
- <handler name="service" type="request" class="org.ofbiz.webapp.event.ServiceEventHandler"/>
- <handler name="service-multi" type="request" class="org.ofbiz.webapp.event.ServiceMultiEventHandler"/>
- <handler name="service-stream" type="request" class="org.ofbiz.webapp.event.ServiceStreamHandler"/>
- <handler name="simple" type="request" class="org.ofbiz.webapp.event.SimpleEventHandler"/>
- <handler name="groovy" type="request" class="org.ofbiz.webapp.event.GroovyEventHandler"/>
- <handler name="rome" type="request" class="org.ofbiz.webapp.event.RomeEventHandler"/>
- <handler name="script" type="request" class="org.ofbiz.webapp.event.ScriptEventHandler"/>
- <!-- view handlers -->
- <handler name="screen" type="view" class="org.ofbiz.widget.screen.MacroScreenViewHandler"/>
- <handler name="screenxml" type="view" class="org.ofbiz.widget.screen.MacroScreenViewHandler"/>
- <handler name="screentext" type="view" class="org.ofbiz.widget.screen.MacroScreenViewHandler"/>
- <handler name="screencsv" type="view" class="org.ofbiz.widget.screen.MacroScreenViewHandler"/>
- <handler name="screenfop" type="view" class="org.ofbiz.widget.screen.ScreenFopViewHandler"/>
- <handler name="jsp" type="view" class="org.ofbiz.webapp.view.JspViewHandler"/>
- <handler name="ftl" type="view" class="org.ofbiz.webapp.ftl.FreeMarkerViewHandler"/>
- <handler name="http" type="view" class="org.ofbiz.webapp.view.HttpViewHandler"/>
- <handler name="birt" type="view" class="org.ofbiz.birt.webapp.view.BirtViewHandler"/>
handler包含的属性:
- name:指定handler的名称,通常会被<request-map>子元素的event的type属性以及<view-map>的type属性所引用
- type:有两种取值:request和view。request应对的是<request-map>中的event的处理器;view对应的是<view-map>的处理器
- class:指定当前处理器实现类的完全限定名
mvc串接
先我们假设OFBiz web
container收到请求:createCreditCardAndPostalAddress。然后OFBiz会根据每个app下面的
controller配置文件中request-map定义,查找并匹配uri为createCreditCardAndPostalAddress的映
射节点(就是上文中讲解request-map使用的节点)。
- <request-map uri="createCreditCardAndPostalAddress">
然后根据其子元素security的配置,对其进行安全检查:
- <security https="true" auth="true"/>
因为有event元素,那么此处会触发一个“事件”(注意,不一定会有event元素)。这里是通过ofbiz的ServiceEngine来调用一个service:
- <event type="service" path="" invoke="createCreditCardAndAddress"/>
调用完该service后,根据service执行的结果,匹配不同的响应视图:
- <response name="success" type="request" value="finalizeOrder"/>
- <response name="error" type="view" value="billsetting"/>
这里(也是通常情况下)有两种不同的响应配置:success,error。而且他们的响应方式不同,我们分开来看:
如
果event触发调用createCreditCardAndAddress服务的返回结果为success,那么将触发一个请求(type为
request表示再次触发一个请求,但这个请求是服务端的请求,有点像servlet里的forward动作),uri为
finalizeOrder(它是另一个request-map的定义):
- <request-map uri="finalizeOrder">
其语义为:完成订单创建。
如
果event触发调用createCreditCardAndAddress服务的返回结果为error,那么它将会向浏览器展示一个视图(type为
view),而该视图的名称为:billsetting。那接下来ofbiz就去查找名为:billsetting的view-map,查找到如下的结
果:
- <view-map name="billsetting" type="screen" page="component://order/widget/ordermgr/OrderEntryOrderScreens.xml#BillSettings"/>
发
现它是一个widget配置(type为screen表示OFBiz中采用的一种xml的widget),而该配置的路径
为:component://order/widget/ordermgr/OrderEntryOrderScreens.xml文件中名称为
BillSettings的screen。然后就利用名为screen的handler,来解析该screen配置:
- <handler name="screen" type="view" class="org.ofbiz.widget.screen.MacroScreenViewHandler"/>
screen
上面提到ofbiz在渲染视图的时候,采用了一个元素名为screen的配置:
- <screen name="BillSettings">
- <section>
- <actions>
- <set field="stepTitleId" value="OrderOrderEntryPaymentSettings"/>
- <set field="stepLabelId" value="AccountingPayment"/>
- <script location="component://order/webapp/ordermgr/WEB-INF/actions/entry/BillSettings.groovy"/>
- </actions>
- <widgets>
- <decorator-screen name="CommonOrderCheckoutDecorator">
- <decorator-section name="body">
- <platform-specific>
- <html><html-template location="component://order/webapp/ordermgr/entry/billsettings.ftl"/></html>
- </platform-specific>
- </decorator-section>
- </decorator-screen>
- </widgets>
- </section>
- </screen>
这牵扯到OFBiz前端screen以及form的widget布局设计。
section
它是screen的子元素,一个screen可以包含n个section。而它可以又会由actions以及widgets元素组成。
action
在actions元素下,你可以定义若干个不同种类的action:
- label:将值绑定到label
- entity action:利用entity engine进行action操作
- set action:简单的赋值以及groovy表达式语法
- script action:调用一个groovy脚本
- service action:调用一个服务
widgets
这
里首先定义了一个名为:CommonOrderCheckoutDecorator的decorator-screen。所谓的decorator-
screen你可以将其理解为页面的模板或者占位。比如,就一个页面而言,部分内容与空间是固定的,主要变化的是某个特定的区域。此时布局一个新页面的时
候就没必要为其每个区域都重复编写html,对于公共区域直接引用已经定义好的模板即可。
比如此处的CommonOrderCheckoutDecorator装饰器screen,其定义中,它又引用了该app的一个main-decorator:
- <decorator-screen name="main-decorator" location="${parameters.mainDecoratorLocation}">
这
个是当前app最外层的装饰器模板。这样就形成了widget的两层嵌套关系:BillSettings引用了
CommonOrderCheckoutDecorator,而CommonOrderCheckoutDecorator又引用了main-
decorator,这种嵌套关系,也同时建立了页面显示的联系。
一个通常的应用,其mainDecoratorLoaction参数可以在其web.xml中的context-param配置中找到:
- <context-param>
- <param-name>mainDecoratorLocation</param-name>
- <param-value>component://order/widget/ordermgr/CommonScreens.xml</param-value>
- <description>The location of the main-decorator screen to use for this webapp; referred to as a context variable in screen def XML files.</description>
- </context-param>
回到正题,在BillSettings的第一个decorator-screen:CommonOrderCheckoutDecorator,还有一个decorator-section:body,它是对内容区域的模板占位。
widget
内部拥有一个platform-specific子元素,它可以看做是一种switch-case语句。OFBiz widget
工具集没用对render html
UI的方式进行限制。理论上,你可以采用任何技术来render浏览器能显示内容。在这里UI被render成HTML,而且还使用了html模板,该模
板的路径通过location属性指定。此处该模板使用的是freemarker(这也是OFBiz中用得最多的一种模板技术)。
数据绑定
就前端展现而言,除了需要有由html标签组成的模板,还需要绑定数据才能形成完整的页面。
OFBiz提供了两种绑定数据的方式:
- form-action:如果你使用form widget,绑定数据的最好方式是采用action子元素。这可以有效得帮助你增强该form的复用性。
- groovy script action:如果你使用的是freemarker模板,此时form便是由html原生标签表示,那么推荐的方式是采用groovy脚本来获取数据并绑定至模板来显示,本文所举的示例就是这种模式。
Apache OFBiz源码解读之MVC模型的更多相关文章
- Apache Beam WordCount编程实战及源码解读
概述:Apache Beam WordCount编程实战及源码解读,并通过intellij IDEA和terminal两种方式调试运行WordCount程序,Apache Beam对大数据的批处理和流 ...
- apache flink源码挖坑 (未完待续)
Apache Flink 源码解读(一) By yyz940922原创 项目模块 (除去.git, .github, .idea, docs等): flink-annotations: flink ...
- Bert系列(二)——源码解读之模型主体
本篇文章主要是解读模型主体代码modeling.py.在阅读这篇文章之前希望读者们对bert的相关理论有一定的了解,尤其是transformer的结构原理,网上的资料很多,本文内容对原理部分就不做过多 ...
- spring IOC DI AOP MVC 事务, mybatis 源码解读
demo https://gitee.com/easybao/aop.git spring DI运行时序 AbstractApplicationContext类的 refresh()方法 1: pre ...
- Spark Streaming源码解读之流数据不断接收和全生命周期彻底研究和思考
本节的主要内容: 一.数据接受架构和设计模式 二.接受数据的源码解读 Spark Streaming不断持续的接收数据,具有Receiver的Spark 应用程序的考虑. Receiver和Drive ...
- AFNetworking 3.0 源码解读(三)之 AFURLRequestSerialization
这篇就讲到了跟请求相关的类了 关于AFNetworking 3.0 源码解读 的文章篇幅都会很长,因为不仅仅要把代码进行详细的的解释,还会大概讲解和代码相关的知识点. 上半篇: URI编码的知识 关于 ...
- Apache Spark源码剖析
Apache Spark源码剖析(全面系统介绍Spark源码,提供分析源码的实用技巧和合理的阅读顺序,充分了解Spark的设计思想和运行机理) 许鹏 著 ISBN 978-7-121-25420- ...
- [Hadoop源码解读](六)MapReduce篇之MapTask类
MapTask类继承于Task类,它最主要的方法就是run(),用来执行这个Map任务. run()首先设置一个TaskReporter并启动,然后调用JobConf的getUseNewAPI()判断 ...
- 《Apache Spark源码剖析》
Spark Contributor,Databricks工程师连城,华为大数据平台开发部部长陈亮,网易杭州研究院副院长汪源,TalkingData首席数据科学家张夏天联袂力荐1.本书全面.系统地介绍了 ...
随机推荐
- 删除链表中等于给定值val的所有节点。
样例 给出链表 1->2->3->3->4->5->3, 和 val = 3, 你需要返回删除3之后的链表:1->2->4->5. /** * D ...
- ssh连接虚拟机失败解决办法
首先,你需要知道本机IP跟虚拟机IP,然后让两者互相ping一下,看能否ping通 让主机ping虚拟机 :ping (虚拟机ip) 出现如下: 表示主机可以ping通虚拟机 然后让虚拟机ping主机 ...
- git使用教程之git基础
1 获取Git仓库 在现有目录中初始化仓库 git init 克隆现有的仓库 git clone https://github.com/yangwang12345/node_test.git Git ...
- CSS与JS中的相对路径引用
javascript和css文件中采用相对路径,其基准路径是完全不同的. 1.javascript引用资源(比如图片)相对路径是以宿主路径(被引用的网页比如你在首页index.php引用了某js文件, ...
- 【前端】跨浏览器事件处理程序EventUtil.js个人注释及详解
<javascript高级程序设计>跨浏览器事件处理程序EventUtil.js个人注释 EventUtil.js // 跨浏览器事件处理程序封装 var EventUtil = { // ...
- vue 集成 axios 发送post请求 payload导致后台无法接收到数据问题
vue 集成axios之后,发送的post请求默认为payload 方式. 如果想改为正常的方式,需要增加headers头,并且将发送是数据json格式改为 querystring的方式. 安装依赖 ...
- Asp.Net MVC 中的 Cookie(译)
Asp.Net MVC 中的 Cookie(译) Cookie Cookie是请求服务器或访问Web页面时携带的一个小的文本信息. Cookie为Web应用程序中提供了一种存储特定用户信息的方法.Co ...
- 【Spring】Spring MVC高级技术
前言 前面学习了简单的Spring Web知识,接着学习更高阶的Web技术. 高级技术 Spring MVC配置的替换方案 自定义DispatcherServlet配置 在第五章我们曾编写过如下代码. ...
- 我从.net转到java的心得和体会
前言:由于有不少人咨询过我如果从.net转java,有什么技巧吗,我现在就分享我从.net转java的历程,这里不涉及两门语言的比较,记录的都是我个人的观点. 一:从.net转java的初衷 我是20 ...
- 系统学习DOM事件机制
本文将从以下几个方面介绍DOM事件: 基本概念:DOM事件的级别 DOM事件模型,事件流 描述DOM事件捕获的具体流程 Event对象的常见应用 自定义事件 DOM事件的级别 //DOM0 eleme ...