节点解析

request-map

你可以将其理解为controller的配置,如果你了解或使用过struts的配置或springmvc的annotation,就会发现这个定义跟它们是很相似的:

  1. <request-map uri="createCreditCardAndPostalAddress">
  2. <security https="true" auth="true"/>
  3. <event type="service" path="" invoke="createCreditCardAndAddress"/>
  4. <response name="success" type="request" value="finalizeOrder"/>
  5. <response name="error" type="view" value="billsetting"/>
  6. </request-map>

该元素定义了请求的映射关系。它使用名为uri的属性,表述该uri将要映射的请求。内部包含三个常用的子元素,分别是:security,event,response。

  • security:表示该uri应该对应的安全级别(是否应该是https的,是否要进行权限检查)
  • event:该请求触发的事件,这个后面在讲解handler的时候再谈
  • response:指定响应的配置

view-map

一个常见的view-map配置:
  1. <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的定义就很容易理
解了:
  1. <!-- event handlers -->
  2. <handler name="java" type="request" class="org.ofbiz.webapp.event.JavaEventHandler"/>
  3. <handler name="soap" type="request" class="org.ofbiz.webapp.event.SOAPEventHandler"/>
  4. <handler name="xmlrpc" type="request" class="org.ofbiz.webapp.event.XmlRpcEventHandler"/>
  5. <handler name="service" type="request" class="org.ofbiz.webapp.event.ServiceEventHandler"/>
  6. <handler name="service-multi" type="request" class="org.ofbiz.webapp.event.ServiceMultiEventHandler"/>
  7. <handler name="service-stream" type="request" class="org.ofbiz.webapp.event.ServiceStreamHandler"/>
  8. <handler name="simple" type="request" class="org.ofbiz.webapp.event.SimpleEventHandler"/>
  9. <handler name="groovy" type="request" class="org.ofbiz.webapp.event.GroovyEventHandler"/>
  10. <handler name="rome" type="request" class="org.ofbiz.webapp.event.RomeEventHandler"/>
  11. <handler name="script" type="request" class="org.ofbiz.webapp.event.ScriptEventHandler"/>
  12. <!-- view handlers -->
  13. <handler name="screen" type="view" class="org.ofbiz.widget.screen.MacroScreenViewHandler"/>
  14. <handler name="screenxml" type="view" class="org.ofbiz.widget.screen.MacroScreenViewHandler"/>
  15. <handler name="screentext" type="view" class="org.ofbiz.widget.screen.MacroScreenViewHandler"/>
  16. <handler name="screencsv" type="view" class="org.ofbiz.widget.screen.MacroScreenViewHandler"/>
  17. <handler name="screenfop" type="view" class="org.ofbiz.widget.screen.ScreenFopViewHandler"/>
  18. <handler name="jsp" type="view" class="org.ofbiz.webapp.view.JspViewHandler"/>
  19. <handler name="ftl" type="view" class="org.ofbiz.webapp.ftl.FreeMarkerViewHandler"/>
  20. <handler name="http" type="view" class="org.ofbiz.webapp.view.HttpViewHandler"/>
  21. <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收到一个请求为示例,展示其利用MVC模型处理请求的完整过程:

先我们假设OFBiz web
container收到请求:createCreditCardAndPostalAddress。然后OFBiz会根据每个app下面的
controller配置文件中request-map定义,查找并匹配uri为createCreditCardAndPostalAddress的映
射节点(就是上文中讲解request-map使用的节点)。
  1. <request-map uri="createCreditCardAndPostalAddress">

然后根据其子元素security的配置,对其进行安全检查:

  1. <security https="true" auth="true"/>

因为有event元素,那么此处会触发一个“事件”(注意,不一定会有event元素)。这里是通过ofbiz的ServiceEngine来调用一个service:

  1. <event type="service" path="" invoke="createCreditCardAndAddress"/>

调用完该service后,根据service执行的结果,匹配不同的响应视图:

  1. <response name="success" type="request" value="finalizeOrder"/>
  2. <response name="error" type="view" value="billsetting"/>

这里(也是通常情况下)有两种不同的响应配置:success,error。而且他们的响应方式不同,我们分开来看:


果event触发调用createCreditCardAndAddress服务的返回结果为success,那么将触发一个请求(type为
request表示再次触发一个请求,但这个请求是服务端的请求,有点像servlet里的forward动作),uri为
finalizeOrder(它是另一个request-map的定义):

  1. <request-map uri="finalizeOrder">

其语义为:完成订单创建。


果event触发调用createCreditCardAndAddress服务的返回结果为error,那么它将会向浏览器展示一个视图(type为
view),而该视图的名称为:billsetting。那接下来ofbiz就去查找名为:billsetting的view-map,查找到如下的结
果:

  1. <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配置:

  1. <handler name="screen" type="view" class="org.ofbiz.widget.screen.MacroScreenViewHandler"/>

screen

上面提到ofbiz在渲染视图的时候,采用了一个元素名为screen的配置:

  1. <screen name="BillSettings">
  2. <section>
  3. <actions>
  4. <set field="stepTitleId" value="OrderOrderEntryPaymentSettings"/>
  5. <set field="stepLabelId" value="AccountingPayment"/>
  6. <script location="component://order/webapp/ordermgr/WEB-INF/actions/entry/BillSettings.groovy"/>
  7. </actions>
  8. <widgets>
  9. <decorator-screen name="CommonOrderCheckoutDecorator">
  10. <decorator-section name="body">
  11. <platform-specific>
  12. <html><html-template location="component://order/webapp/ordermgr/entry/billsettings.ftl"/></html>
  13. </platform-specific>
  14. </decorator-section>
  15. </decorator-screen>
  16. </widgets>
  17. </section>
  18. </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

widgets是OFBiz布局的特点之一,它可以将一个完整的html页面拆分为一个个小块的widget,最终的页面是通过widget组合而成。


里首先定义了一个名为:CommonOrderCheckoutDecorator的decorator-screen。所谓的decorator-
screen你可以将其理解为页面的模板或者占位。比如,就一个页面而言,部分内容与空间是固定的,主要变化的是某个特定的区域。此时布局一个新页面的时
候就没必要为其每个区域都重复编写html,对于公共区域直接引用已经定义好的模板即可。

比如此处的CommonOrderCheckoutDecorator装饰器screen,其定义中,它又引用了该app的一个main-decorator:

  1. <decorator-screen name="main-decorator" location="${parameters.mainDecoratorLocation}">


个是当前app最外层的装饰器模板。这样就形成了widget的两层嵌套关系:BillSettings引用了
CommonOrderCheckoutDecorator,而CommonOrderCheckoutDecorator又引用了main-
decorator,这种嵌套关系,也同时建立了页面显示的联系。

一个通常的应用,其mainDecoratorLoaction参数可以在其web.xml中的context-param配置中找到:

  1. <context-param>
  2. <param-name>mainDecoratorLocation</param-name>
  3. <param-value>component://order/widget/ordermgr/CommonScreens.xml</param-value>
  4. <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>
  5. </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提供了两种绑定数据的方式:

    1. form-action:如果你使用form widget,绑定数据的最好方式是采用action子元素。这可以有效得帮助你增强该form的复用性。
    2. groovy script action:如果你使用的是freemarker模板,此时form便是由html原生标签表示,那么推荐的方式是采用groovy脚本来获取数据并绑定至模板来显示,本文所举的示例就是这种模式。

Apache OFBiz源码解读之MVC模型的更多相关文章

  1. Apache Beam WordCount编程实战及源码解读

    概述:Apache Beam WordCount编程实战及源码解读,并通过intellij IDEA和terminal两种方式调试运行WordCount程序,Apache Beam对大数据的批处理和流 ...

  2. apache flink源码挖坑 (未完待续)

    Apache Flink 源码解读(一) ​ By yyz940922原创 项目模块 (除去.git, .github, .idea, docs等): flink-annotations: flink ...

  3. Bert系列(二)——源码解读之模型主体

    本篇文章主要是解读模型主体代码modeling.py.在阅读这篇文章之前希望读者们对bert的相关理论有一定的了解,尤其是transformer的结构原理,网上的资料很多,本文内容对原理部分就不做过多 ...

  4. spring IOC DI AOP MVC 事务, mybatis 源码解读

    demo https://gitee.com/easybao/aop.git spring DI运行时序 AbstractApplicationContext类的 refresh()方法 1: pre ...

  5. Spark Streaming源码解读之流数据不断接收和全生命周期彻底研究和思考

    本节的主要内容: 一.数据接受架构和设计模式 二.接受数据的源码解读 Spark Streaming不断持续的接收数据,具有Receiver的Spark 应用程序的考虑. Receiver和Drive ...

  6. AFNetworking 3.0 源码解读(三)之 AFURLRequestSerialization

    这篇就讲到了跟请求相关的类了 关于AFNetworking 3.0 源码解读 的文章篇幅都会很长,因为不仅仅要把代码进行详细的的解释,还会大概讲解和代码相关的知识点. 上半篇: URI编码的知识 关于 ...

  7. Apache Spark源码剖析

    Apache Spark源码剖析(全面系统介绍Spark源码,提供分析源码的实用技巧和合理的阅读顺序,充分了解Spark的设计思想和运行机理) 许鹏 著   ISBN 978-7-121-25420- ...

  8. [Hadoop源码解读](六)MapReduce篇之MapTask类

    MapTask类继承于Task类,它最主要的方法就是run(),用来执行这个Map任务. run()首先设置一个TaskReporter并启动,然后调用JobConf的getUseNewAPI()判断 ...

  9. 《Apache Spark源码剖析》

    Spark Contributor,Databricks工程师连城,华为大数据平台开发部部长陈亮,网易杭州研究院副院长汪源,TalkingData首席数据科学家张夏天联袂力荐1.本书全面.系统地介绍了 ...

随机推荐

  1. 删除链表中等于给定值val的所有节点。

    样例 给出链表 1->2->3->3->4->5->3, 和 val = 3, 你需要返回删除3之后的链表:1->2->4->5. /** * D ...

  2. ssh连接虚拟机失败解决办法

    首先,你需要知道本机IP跟虚拟机IP,然后让两者互相ping一下,看能否ping通 让主机ping虚拟机 :ping (虚拟机ip) 出现如下: 表示主机可以ping通虚拟机 然后让虚拟机ping主机 ...

  3. git使用教程之git基础

    1 获取Git仓库 在现有目录中初始化仓库 git init 克隆现有的仓库 git clone https://github.com/yangwang12345/node_test.git Git ...

  4. CSS与JS中的相对路径引用

    javascript和css文件中采用相对路径,其基准路径是完全不同的. 1.javascript引用资源(比如图片)相对路径是以宿主路径(被引用的网页比如你在首页index.php引用了某js文件, ...

  5. 【前端】跨浏览器事件处理程序EventUtil.js个人注释及详解

    <javascript高级程序设计>跨浏览器事件处理程序EventUtil.js个人注释 EventUtil.js // 跨浏览器事件处理程序封装 var EventUtil = { // ...

  6. vue 集成 axios 发送post请求 payload导致后台无法接收到数据问题

    vue 集成axios之后,发送的post请求默认为payload 方式. 如果想改为正常的方式,需要增加headers头,并且将发送是数据json格式改为 querystring的方式. 安装依赖 ...

  7. Asp.Net MVC 中的 Cookie(译)

    Asp.Net MVC 中的 Cookie(译) Cookie Cookie是请求服务器或访问Web页面时携带的一个小的文本信息. Cookie为Web应用程序中提供了一种存储特定用户信息的方法.Co ...

  8. 【Spring】Spring MVC高级技术

    前言 前面学习了简单的Spring Web知识,接着学习更高阶的Web技术. 高级技术 Spring MVC配置的替换方案 自定义DispatcherServlet配置 在第五章我们曾编写过如下代码. ...

  9. 我从.net转到java的心得和体会

    前言:由于有不少人咨询过我如果从.net转java,有什么技巧吗,我现在就分享我从.net转java的历程,这里不涉及两门语言的比较,记录的都是我个人的观点. 一:从.net转java的初衷 我是20 ...

  10. 系统学习DOM事件机制

    本文将从以下几个方面介绍DOM事件: 基本概念:DOM事件的级别 DOM事件模型,事件流 描述DOM事件捕获的具体流程 Event对象的常见应用 自定义事件 DOM事件的级别 //DOM0 eleme ...