Openbravo3.0 体系结构
? ?在Openbravo 3.0中,我們由一個(gè)傳統(tǒng)的servlet結(jié)構(gòu)轉(zhuǎn)換到了一個(gè)全新的富因特網(wǎng)應(yīng)用程序結(jié)構(gòu)(Rich Internet Application (RIA))。在這種富客戶端結(jié)構(gòu)中,請(qǐng)求頁面與請(qǐng)求數(shù)據(jù)是分開的。第一次點(diǎn)擊的時(shí)候,請(qǐng)求到了頁面,如果不關(guān)閉這個(gè)頁面的話,這個(gè)頁面一直可以重用,只需要繼續(xù)請(qǐng)求你需要的數(shù)據(jù)填充到頁面即可。與js框架jquery,ext,還有flex雷同,只是openbravo里面用的是另外一種技術(shù)叫做smartclient。
?
? ? ? ? ?一. 體系構(gòu)架圖
?
? ? ? ? ?1. JSON模塊
? ? ? ? ?用于客戶端與服務(wù)器端數(shù)據(jù)交換,是一種約定的數(shù)據(jù)交換的格式。
?
? ? ? ? ?2. Weld模塊
? ? ? ? ?該模塊提供獨(dú)立的注入與組件的的管理。
?
? ? ? ? ?3. kernel模塊
? ? ? ? ?該模塊專注于一些基礎(chǔ)任務(wù),比如:請(qǐng)求的處理,事件的處理,壓縮信息,緩存。
?
? ? ? ? ?4. datasource模塊
? ? ? ? ?該模塊使用json模塊提供的數(shù)據(jù),將這些數(shù)據(jù)整理成客戶想要的結(jié)果。
?
? ? ? ? ?5. smartclient模塊
? ? ? ? ?提供smartclient用戶客戶端庫類
?
? ? ? ? ?6. application模塊
? ? ? ? ?該模塊管理導(dǎo)航欄,表格,單據(jù)等客戶端組件的生成以及服務(wù)器端代碼
?
?
?
? ? ? ? ?二. 操作界面主要概念: 控件和控件提供者
?
? ? ? ? ?openbravo3.0前臺(tái)界面是由各種控件組成的,控件可以是一個(gè)多選框,一個(gè)文本框,或者僅僅是一個(gè)布局或者一個(gè)表格。
? ? ? ? ?控件是在模塊里面實(shí)現(xiàn)的。在模塊中,控件是由控件提供者管理的,它負(fù)責(zé)創(chuàng)建控件,并且將控件提供給Openbravo kernel模塊。控件提供者也負(fù)責(zé)一些靜態(tài)內(nèi)容的注冊(cè),下面會(huì)提到。
?
? ? ? ? ? 控件可以通過一個(gè)URL獲取,比如下面一個(gè)URL可以獲取銷售發(fā)票窗口的javascript腳本:
http://localhost:8080/openbravo/org.openbravo.client.kernel/OBUIAPP_MainLayout/View?viewId=_167
?
? ? ? ? ?OBUIAPP_MainLayout?標(biāo)志請(qǐng)求的是客戶端模塊,模塊中的控件提供者知道怎么通過剩下的那段URL:View?viewId=_167來創(chuàng)建控件,也就是請(qǐng)求的javascript。下面這個(gè)圖演示了這個(gè)流程:
?
?
? ? ? ? 整個(gè)請(qǐng)求流程有如下步驟:
?
? ? ? ? 1. 一個(gè)控件請(qǐng)求(包含控件類型和ID)到達(dá)客戶端Kernel模塊
?
? ? ? ? 2. 基于控件類型,kernel模塊找到負(fù)責(zé)處理這類請(qǐng)求的模塊(后面稱之為A模塊),將這個(gè)請(qǐng)求轉(zhuǎn)發(fā)過去。于是A模塊根據(jù)控件ID來創(chuàng)建模塊。
?
? ? ? ? 3. A模塊從數(shù)據(jù)庫表,或者其他資源讀取到控件的定義,然后實(shí)例化這個(gè)控件。
?
? ? ? ? 4. 這個(gè)控件會(huì)創(chuàng)建返回客戶端的形式,如果是一個(gè)模板控件,這個(gè)控件會(huì)調(diào)用一個(gè)模板程序來創(chuàng)建一個(gè)模板。
?
? ? ? ? 5. 返回的“視圖”是由模板創(chuàng)建的或者由java后臺(tái)代碼生成的一段字符串。
?
? ? ? ? 6. 返回的視圖被客戶端kernel模塊接收,kernel模塊會(huì)檢查結(jié)果的語法和壓縮要返回的結(jié)果。
?
? ? ? ? 7. 將壓縮的結(jié)果返回給請(qǐng)求者。
?
?
? ? ? ? 三. Weld模塊介紹
?
? ? ? ? Weld 是一個(gè)實(shí)現(xiàn)了JSR-299標(biāo)準(zhǔn)的框架,JSR-299定義了java上下文依賴注入的標(biāo)準(zhǔn)。Openbravo使用weld框架來實(shí)現(xiàn)獨(dú)立注入,控件管理以及業(yè)務(wù)事件管理。首先,定義控件和控件的生命周期。然后,將定義的控件注入其他控件當(dāng)做。需要注意的是,如果要使用weld獨(dú)立注入功能,我們不可以通過原始的構(gòu)造器來創(chuàng)建對(duì)象。
?
? ? ? ? ?1. 生命周期定義
? ? ? ? ? 控件的生命周期可以有三種類型:ApplicationScope,SessionScope,RequestScope。生命周期是通過聲明的形式表達(dá)的。比如:
?
?
@SessionScoped public class MenuManager implements Serializable { .... } ??
? ? ? ? ? 2. 注入
? ? ? ? ? 定義好的控件可以被自動(dòng)注入到其他的控件里面,通過使用注入聲明。比如:
?
?
@Inject private MenuManager menuManager; ??
? ? ? ? ? 3. Weld實(shí)例化對(duì)象
? ? ? ? ? weld框架在新建對(duì)象的時(shí)候通常要注入一些控件,也就意味著不能通過new 這樣的方式創(chuàng)建對(duì)象。其實(shí),通常我們不需要直接通過new的方式創(chuàng)建對(duì)象,對(duì)象一般都是通過注入的方式來傳遞的。不過如果你的對(duì)象不能夠注入的方式傳遞,Openbravo提供了一個(gè)工具方法來幫助你:
? ? ? ? ? ?org.openbravo.base.weld.WeldUtils.getInstanceFromStaticBeanManager(Class<T> type);
? ? ? ? ? ?會(huì)返回一個(gè)實(shí)例化的對(duì)象。
?
? ? ? ? ? 4. 分析路徑
? ? ? ? ? ?Weld 根據(jù)路徑來找到哪些控件有聲明為注入方式(路徑被定義在META-INF/beans.xml),為了避免搜索所有的class文件,beans.xml文件定義了哪些路徑不進(jìn)行搜索。
?
?
? ? ? ? ? ?四. Etags,Caching(緩存)和Compressing(壓縮)
?
? ? ? ? ? ?為了提高用戶的訪問速度和體驗(yàn),我們需要在瀏覽器端和服務(wù)端提供緩存機(jī)制。
? ? ? ? ? ?Openbravo實(shí)現(xiàn)了幾種不同類型的緩存在不同的應(yīng)用層次,它利用了模塊管理的優(yōu)點(diǎn),一個(gè)模塊是否在開發(fā)狀態(tài),緩存機(jī)制是不同的。如果一個(gè)模塊在開發(fā)狀態(tài),會(huì)阻止使用緩存,因?yàn)槲覀儾幌胍彺嬗绊懥宋覀兊臏y(cè)試結(jié)果。但是,如果不是處于開發(fā)狀態(tài),就會(huì)最大化使用緩存機(jī)制。
?
? ? ? ? ? ? 1. 靜態(tài)JS文件緩存與更新
? ? ? ? ? ? ?一個(gè)靜態(tài)的JS文件包含了控件使用的一個(gè)文本庫或者一個(gè)標(biāo)準(zhǔn)的控件。通常瀏覽器會(huì)緩存這個(gè)JS文件,不過與這個(gè)JS文件相關(guān)的模塊更新時(shí),這個(gè)靜態(tài)的JS文件也會(huì)更新。過程如下:
? ? ? ? ? ? JS靜態(tài)文件是由模塊提供的,模塊通過它的控件提供者(ComponentProvider)發(fā)布它的靜態(tài)資源,ComponentProvider通過GetGlobalResources方法獲得資源,Openbravo將所有相關(guān)聯(lián)的靜態(tài)資源整合到一個(gè)大的JS文件當(dāng)中,整合的順序與根據(jù)模塊間的關(guān)系有關(guān). 這個(gè)JS文件的名稱是一串字符串,比如:088afd247a8fe06c91a654891a1358a2.js?名稱與內(nèi)容相關(guān)。如果內(nèi)容發(fā)生改變,名稱也會(huì)變,這樣瀏覽器也就會(huì)重新加載。這個(gè)靜態(tài)的JS文件生成在web/js/gen下面。(如果模塊屬于開發(fā)狀態(tài),JS文件將不會(huì)被壓縮)
?
? ? ? ? ? ? ?2. 控件的緩存與更新
? ? ? ? ? ? ?控件是動(dòng)態(tài)的,包含運(yùn)行時(shí)從數(shù)據(jù)庫讀取的數(shù)據(jù)。所以控件是在用戶請(qǐng)求的時(shí)候生成的,緩存在服務(wù)器端。服務(wù)器端可以驗(yàn)證一個(gè)控件是否已經(jīng)改變,從最后一次請(qǐng)求開始。在客戶端,是不可以進(jìn)行驗(yàn)證的。
? ? ? ? ? ? ?為了驗(yàn)證服務(wù)器端緩存的控件是否與客戶端的緩存的一致,我們使用了一個(gè)概念Etag,Etag類似于一個(gè)hashcode。用于驗(yàn)證,服務(wù)端緩存的控件的內(nèi)容是否改變,自從瀏覽器最后一次請(qǐng)求之后。
? ? ? ? ? ? ?Etag生成方式:
? ? ? ? ? ? ?a. 模塊不屬于開發(fā)狀態(tài),Etag=用戶名稱+模塊版本
? ? ? ? ? ? ?b. 模塊屬于開發(fā)狀態(tài),Etag=用戶名稱+當(dāng)前時(shí)間(精確到毫秒)
?
? ? ? ? ? ? ?3. 壓縮與語法檢查
? ? ? ? ? ? ?模塊輸出的內(nèi)容在發(fā)給客戶端前,可以進(jìn)行語法檢查和壓縮。壓縮用的是jsmin, 語法檢查用的是JSLint和JSLint4Java. 如果模塊屬于開發(fā)狀態(tài),會(huì)進(jìn)行語法檢查但是不會(huì)壓縮。但是,如果模塊不屬于開發(fā)狀態(tài),只進(jìn)行壓縮,不進(jìn)行語法檢查。
?
?
? ? ? ? ? ? ?五. 模塊的代碼構(gòu)架
?
? ? ? ? ? ? ? 一個(gè)模塊在openbravo里面的代碼結(jié)構(gòu)是固定的,參考如下圖:
? ? ? ? ??
? ? ? ? 1. java代碼放在src目錄下面
? ? ? ? 2. 靜態(tài)的JS文件放在:web/[modulepackage]/js
? ? ? ? 3. 樣式文件(css, images, js)所在目錄:web/org.openbravo.userinterface.smartclient/3.00/[modulepackage]? ? ? ? ? ? ?
?
? ? ? ? ?六. 控件提供者
?
? ? ? ? ? 每一個(gè)module都會(huì)實(shí)現(xiàn)一個(gè)控件提供者,一個(gè)控件提供者(componet provider)完成如下二個(gè)任務(wù):
? ? ? ? ? 1. 用戶的請(qǐng)求從kernel模塊發(fā)過來后,它負(fù)責(zé)創(chuàng)建用戶請(qǐng)求的控件(componet)
? ? ? ? ? 2. 它負(fù)責(zé)將module中的注冊(cè)靜態(tài)的資源到openbravo kernel。
?
? ? ? ? ? 控件提供者(componet provider)是一個(gè)weld控件,一個(gè)控件提供者類必須有2個(gè)聲明:
? ? ? ? ? 1. @ApplicationScoped標(biāo)志, 標(biāo)明這個(gè)類是一個(gè)單例。
? ? ? ? ? 2. @ComponetProvider.Qualifier 為這個(gè)類注冊(cè)一個(gè)唯一的標(biāo)識(shí)
? ? ? ? ? 比如:
?
@ApplicationScoped @ComponentProvider.Qualifier(ExampleComponentProvider.EXAMPLE_VIEW_COMPONENT_TYPE) public class ExampleComponentProvider extends BaseComponentProvider {public static final String EXAMPLE_VIEW_COMPONENT_TYPE = "OBEXAPP_ExampleViewType";? ? ? ? ?PS:控件提供者類必須跟它的module處于同一個(gè)包下面。
?
? ? ? ? 控件提供者還有另外一個(gè)事情,實(shí)例化一個(gè)控件。
? ? ? ? 比如:
?
public Component getComponent(String componentId, Map<String, Object> parameters) {if (componentId.equals(ExampleViewComponent.EXAMPLE_VIEW_COMPONENT_ID)) {final ExampleViewComponent component = new ExampleViewComponent();component.setId(ExampleViewComponent.EXAMPLE_VIEW_COMPONENT_ID);component.setParameters(parameters);return component;}throw new IllegalArgumentException("Component id " + componentId + " not supported."); }? ? ? ? ?PS:這個(gè)方法是在你有動(dòng)態(tài)內(nèi)容的時(shí)候才有用處,如果你的module只有靜態(tài)的JS/CSS,這個(gè)方法可以為空,或者直接拋異常。
?
? ? ? ? ?控件可以很簡(jiǎn)單,如果它集成系統(tǒng)的BaseComponet類,只需要實(shí)現(xiàn)generate方法即可。
?
? ? ? ? ?控件提供者最后一個(gè)事情是,注冊(cè)靜態(tài)資源(CSS,JS).這些靜態(tài)資源會(huì)被Openbravo kernel 關(guān)聯(lián)壓縮。比如:
?
public List<ComponentResource> getGlobalComponentResources() {final List<ComponentResource> globalResources = new ArrayList<ComponentResource>();globalResources.add(createStaticResource("web/org.openbravo.client.application.examples/js/example-view-component.js", true));globalResources.add(createDynamicResource("org.openbravo.client.kernel/"+ ExampleViewComponent.EXAMPLE_VIEW_COMPONENT_ID + "/"+ ExampleViewComponent.EXAMPLE_VIEW_COMPONENT_ID));globalResources.add(createStyleSheetResource("web/org.openbravo.userinterface.smartclient/openbravo/skins/"+ KernelConstants.SKIN_VERSION_PARAMETER+ "/org.openbravo.client.application.examples/my-styles.css", false));return globalResources; } ??
? ? ? ?七. 服務(wù)端處理客戶端請(qǐng)求集散中心
?
? ? ? ?openbravo提供一種方便客戶端發(fā)送給服務(wù)端請(qǐng)求的機(jī)制,叫做ActionHandler(請(qǐng)求控制中心)。
?
? ? ? ?服務(wù)器端代碼示例:
?
?
package org.openbravo.client.application.examples;....public class MyActionHandler extends BaseActionHandler {/*** Needs to be implemented by a subclass.* * @param parameters* the parameters obtained from the request. Note that the request object and the session* object are also present in this map, resp. as the constants* {@link KernelConstants#HTTP_REQUEST} and {@link KernelConstants#HTTP_SESSION}.* @param content* the request content (if any)* @return the return should be a JSONObject, this is passed back to the caller on the client.*/protected JSONObject execute(Map<String, Object> parameters, String content) {try {// create the resultJSONObject json = new JSONObject();json.put("result", "success");// and return itreturn json;} catch (Exception e) {throw new OBException(e);}} } ?? ? ? ?客戶端代碼示例:
?
// define the callback function which shows the result to the user var callback = function(rpcResponse, data, rpcRequest) {isc.say('The result is : ' + data.result); };// and call the server OB.RemoteCallManager.call('org.openbravo.client.application.examples.MyActionHandler', {}, {}, callback); ??
? ? ? ?八. ?應(yīng)用初始化
?
? ? ? ? 當(dāng)我們的一個(gè)應(yīng)用啟動(dòng)的時(shí)候,我們通常要初始化一些事情。比如注冊(cè)SQL當(dāng)我們使用hibernate的HQL的時(shí)候。Openbravo提供一種機(jī)制來實(shí)現(xiàn)這種初始化工作。需要做到兩點(diǎn):
? ? ? ? 1. 創(chuàng)建一個(gè)實(shí)現(xiàn)了org.openbravo.client.kernel.ApplicationInitializer接口的類?
? ? ? ? 2. 聲明這個(gè)接口為@ApplicationScoped
? ? ? ? 比如:
?
@ApplicationScoped public class KernelApplicationInitializer implements ApplicationInitializer {public void initialize() {OBDal.getInstance().registerSQLFunction("ad_column_identifier_std",new StandardSQLFunction("ad_column_identifier_std", StandardBasicTypes.STRING));} }? ? ? ? Weld框架將會(huì)自動(dòng)找到這些初始化類,當(dāng)初始化數(shù)據(jù)庫訪問層的時(shí)候。
?
?
?
?
?
?
?
總結(jié)
以上是生活随笔為你收集整理的Openbravo3.0 体系结构的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: IT牛人进阶的必经之路
 - 下一篇: 最新oss对象储存防红直连 防红代码h