jxTMS架構

jxTMS架構

jxTMS架構

jxTMS自帶了一個web服務,10018端口用於提供動態web界面的操作,10119端口用於提供系統管理。

系統需要一個commonDB,用於用戶信息、組織信息、消息這三者以及其它必要數據的保存。所有部件通過rabbitMQ消息總線進行通信。

針對每個組織,jxTMS會創建一個ORG對象來提供app服務來監聽消息總線對其訪問,並代理該組織私有數據庫的管理,緩存組織內的各種數據以降低數據庫的訪問開銷。

由於採取了消息總線進行訪問,所以理論上,web服務、ORG的app服務、第三方微服務都是可以獨立的、多機負載均衡的,也沒有數量上的限制。只是目前所開放的jxTMS版本,採取瞭如下的限制:

  • web服務和ORG的app服務合併在一臺服務器上,第三方微服務目前只有前端

  • 每個jxTMS系統,目前有一個demo的app,額外預留了5個組織可供開發者使用,每個組織在創建時,jxTMS同時自動創建一個正式組織的app服務、一個Test組織的app服務,所以目前每臺服務器可使用的ORG共11個,可同時爲5個組織提供服務

commonDB

jxTMS設計思想就是平臺化,就是要支持用戶在多個企業之間協作、入職離職等。所以就必然需要一個公共的數據庫用來保存所有用戶的一致性信息並保留平臺的登錄信息。同時還需要保存所有組織的相關信息、個人的消息等等。

目前,jxTMS對這些信息只具備最基本的使用,尚不支持:

  • 用戶在各組織的經歷、工作評價等檔案信息

  • 個人消息是基於組織內各容器的,尚不支持個人之間的私信,同時考慮到目前也不太會有太多通過jxTMS進行消息交互的需求,所以消息功能目前暫不提供前端訪問接口

注1:所謂的容器是指部門、班級、大賽這樣有多個參與者的事物,其消息發送邏輯是發出一條消息,所有參與者在輪詢接收消息時會檢查該容器是否有新消息。參與者加入與退出該容器時,綁定或解綁這個消息查詢點。所有消息是統一增加消息號的,用戶各自記錄自己已經查看過的最老的消息號,然後以此消息號爲基礎,檢查自己當前綁定的所有容器的最新消息
注2:消息是全站的,即如果用戶同時加入了多個組織,這些組織所發送的消息他都可以查看的到而不需切換到這些組織才能查看

app

jxTMS爲每個組織創建一個ORG對象,該對象在加載時自動啓動一個app服務。其主要完成:

  • 監聽消息總線上發送給本ORG的消息

  • 處理用戶在本組織的登錄,爲其創建上下文,包括準備web訪問的關聯、用戶信息、ORG信息等

  • 接收web服務等前端發送過來的數據,將其關聯到相應的上下文中

  • 接收web服務等前端發送過來的用戶操作,覈驗用戶是否有執行該操作的權限

  • 爲其加載相應的功能模塊,並關聯上下文,然後調用該操作所對應的函數

  • 根據用戶請求,發送web界面描述,並根據用戶提交的參數,對該界面進行初始化,包括數據裝定、工具條準備、權限審查準備

  • 爲該函數準備數據庫連接,並將整個函數的數據庫操作打包爲數據庫事務,在函數執行完畢統一提交

  • 處理函數異常,將其保存到系統日誌併發送到web服務端通知用戶

  • 將事件處理函數的輸出轉換後發送到相應的web服務

注:上述所有處理,開發者不需關注與介入,jxTMS完全根據開發者的定義完成上述處理。如根據入口中定義的role以及人員所映射的role進行匹配來完成權限審查;根據web文件,將其轉換爲json發送到web服務;根據python代碼進行初始化等等

app的web數據訪問

jxTMS目前支持兩種前端的數據交互方式:

  • 異步模式:jxTMS設計用來實現web界面、後端業務處理的一人式開發,從而大幅度的降低開發成本。所以原生的web界面都是動態的,由後臺根據用戶請求發送json描述到前端,由前端動態生成各種web控件。用戶的輸入則是觸發相應的change事件,統一收集,以異步輪詢的方式發送到後臺並捎帶回後臺的輸出來更新各控件的顯示

  • 同步模式:由於動態web界面都是系統固化的控件,其風格等比較單一,而且大小、對齊等控制就難以精細化,所以難以做到美學上的優化,只能提供一個入門級的用戶界面,這對於部分對美學要求較高的項目,客戶難以接受。所以,jxTMS增加了支持靜態web界面的同步模式。即開發者需自行開發web界面及其交互管理與數據讀寫,而jxTMS只在進行頁面初始化時也之執行數據裝定功能

注1:兩種模式的切換,通過送入staticWeb=true的參數實現,默認即動態
注2:同步模式還用於自動化測試
注3:tms目錄下的webRoot是動態web界面的根目錄,staticWeb是靜態web的根目錄,但考慮到目前精力需主要集中於接受開發者提交的bug修復和文檔編寫,所以暫不開放靜態web界面的訪問接口

在異步模式下,setOutput會將輸出放入到上下文中的數據cache中。瀏覽器會定時調用pollData函數提交當前界面中各輸入控件的change,同時將後臺cache中的數據捎帶回前端並更新各控件的顯示。

pollData函數的調用:

  • 用戶每次操作前【點擊各種按鈕、工具條、快捷入口、菜單等】會觸發一次

  • 用戶操作完,pollData函數按每隔一秒的頻率進行調度,每執行5次,調度間隔加倍,直到調度間隔超過一分鐘,即長時間無操作後是每64秒調度一次

注1:原生採用異步模式的原因乃在於,有些操作,如統計、分析、智能計算等非常耗時,那麼同步模式下爲了避免用戶失去耐心就需要分成多個接口,將其中的部分操作以異步的方式後臺執行,而javascript本身又是不支持異步編程的,這就會導致編程模型的複雜化。違背了簡化編程、降低編程門檻的初衷。而這種情況下,異步模式就非常簡單了,耗時操作執行前,對某個web控件輸出【執行中,請耐心等待】,執行完畢輸出【執行完畢】,然後將執行結果輸出即可。用戶是否想執行其它操作完全不需考慮
注2:此外,如果有後臺通知、告警等等,如果是同步模式,就需要開發者額外考慮整個界面中相應操作的管理,然後啓動定時器來輪詢。而異步模式則還是完全不需要開發者考慮,有了相關的消息等,後臺代碼直接輸出就可以了,前端最遲一分鐘後就會自動顯示出來

功能點capability

capability是jxTMS最核心的概念之一,所以的業務代碼都必須繼承自capability或其子類。jxTMS的用戶代碼組織是以組織爲最大容器的,然後分爲不同的空間,空間中又分爲不同的模塊,每個模塊包括5種用戶自定義的文件【不需要則可忽略】:

  • web:文本文件。用來逐個定義動態web界面中的控件

  • data:文本文件。用來定義數據庫中的數據表。jxTMS內置了部分通用數據表,併爲訪問這些數據表提供了預定義的接口,用戶可以直接使用。但由於這些表是通用的,所以其字段也自然無法反映業務,這樣其他人員閱讀源碼就有一定的困難。所以jxTMS開放了ORM定義,使得開發者可以直接用文本文件來定義數據表,這樣就更容易反映業務,其他人員的閱讀也自然更容易,但這就需要開發者自行編寫相關的數據訪問接口。所以開發者需要自己權衡這兩者的利弊

  • sql:文本文件。用來定義如何從數據庫中查詢業務所需要的數據。即便是jxTMS內置的數據表,根據業務需要也是必須由開發者在必要時定義專用的數據查詢語句的,jxTMS將這種sql語句稱之數據源。jxTMS提供了一種類似sql語句的語法讓開發者可以簡單的編寫數據查詢語句,然後在調用時直接引用就可以了

  • op.py:python代碼文件。用來定義用戶的操作入口。jxTMS動態界面中共有四種操作入口:菜單項、快捷欄項、界面中的按鈕【即button】、界面中的工具條【即a】。這四種控件,點擊後即會發送給後臺一個操作指令,這個操作指令即被稱爲一個入口。如果該入口未被顯示定義,則jxTMS會拒絕執行。該入口定義中最重要的就是role,其指定了可執行該入口的角色,如果當前用戶未映射該角色,則jxTMS會報告無權執行該操作

注:如果是動態web界面,未映射相應的role則不會顯示相應的入口控件

  • capa.py:python代碼文件。用來定義業務處理代碼的capability。用戶定義的入口,有兩種類型,一種是打開一個頁面進行顯示的,對於這種入口,capability將其映射爲和頁面同名的prepareDisp事件,開發者要在自定義的capa中綁定這個同名的prepareDisp事件進行數據裝定;一種是用戶在該頁面中的點擊操作,對於這種入口,capability將其映射爲和操作同名的cmd事件,開發者要在自定義的capa中綁定這個同名的cmd事件來執行用戶期望的操作

capability在發射這兩種事件到執行開發者自定義的python代碼時,會爲其準備好上下文並打開一個本ORG私有數據庫的連接並準備好數據庫事務,這些代碼如果執行出現異常,capability也會收集異常,然後將其記入系統日誌併發給用戶一個彈窗消息通知其出現了問題,好讓其聯絡現場維護人員進行處理。

注1:capability如何編寫,請閱讀服務器tms目錄下codeDefine目錄中各模塊中的capa.py源文件中的註釋【先讀manager、msg下的源文件,最後讀demo下的源文件】
注2:codeDefine目錄下msg、manager這樣的兩級子目錄是系統通用模塊,即每個ORG都有的公共模塊;而demo這樣的三級子目錄,是ORG自定義的模塊,以組織全名【創建該組織時所給出的組織全名,最好是工商註冊名,以避免重名】爲目錄名,其下一層子目錄即空間名,再下一層即模塊名

需要注意的是,capability的資源名,如web控件、sql數據源都是以空間名爲前綴的,即在同一個空間中,這兩樣資源不得同名;而操作入口的命名格式形如:空間名.模塊名.disp或cmd.操作名。所有的權限檢查、模塊加載、工具條鏈接等都是以這種形式的全名爲準的。

只要知道了各資源或入口的全名,在模塊導入後,即可在ORG範圍內通過該全名加以引用,系統會自動加載相應的資源或capa來提供開發者所需的服務,當然,前提是開發者爲其指定了相應的角色併爲用戶映射了該角色。

capability還集成了其它一些常用功能:如簡易流程、業務規則、統計等。請閱讀源碼和後繼的專項說明。

affairMgr類

affairMgr類繼承自capability,主要用於提供對事的管理。其提供了:

  • 流程管理,功能完備而強大的流程定義與驅動

  • 簡單流程管理,流程管理對大多數業務來說都比較複雜,所以affairMgr類特意提供了一個簡化的流程管理能力,以更快更簡便的開發各種簡單的小流程

注:由於目前精力不夠,而流程又比較複雜,所以目前暫不開放流程功能,請開發者先集中嘗試簡易流程的使用

  • 現場保存,流程操作需要保存前一個業務點用戶填寫的流程數據以及審批動作、處理情況等,如果這些信息全部由開發者自行保管則較爲繁瑣而且是完全重複性的,所以affairMgr類提供了一個對這些信息的現場保存與自動復現功能

  • 快照,由於流程可能被打回重做,則相關的業務數據就存在多次修改的情況,爲了追溯流程的執行情況,affairMgr類提供了快照功能,即每次現場保存的信息發生變化時即加以保存,同時affairMgr類還提供了流程流轉的日誌記錄、數據變動記錄等功能。以在審計或事後追責時可用於明確責任、固定證據

  • 合規性檢查,業務管理需要對業務操作是否合規進行檢查。這種檢查包括兩個層面:一是用戶輸入的數據是否符合要求,這被放入了web端進行檢查,以降低系統開銷並提高用戶感知到的反應速度;二是業務邏輯的合規性審查,比如,銷售給出的折扣太深,超出了其權限,則自動將訂單審批流程流轉到更高層級的領導處進行審批,並將超權限部分標紅以做提醒。爲實現這一功能,jxTMS提供了業務規則編寫與應用能力。業務規則當然也可以直接編碼來實現,但絕大多數的用戶都對代碼看起來頭痛,而文本樣式的如果…則…,其就能接受,也就是開發者和用戶有了一個討論業務邏輯或規則的橋樑

  • 自動計算,提供類似excel的行累加、折扣計算等功能,爲了提供效率,此部分也是推到了web端執行【所以嚴格來說,自動計算和數據項檢查都屬於jxTMS固有能力而不是affairMgr類提供的】

  • 列表查詢頁面的標準化操作,針對大量的列表查詢類頁面,提供了基於分頁控件的工作邏輯。原則上,用戶只要用文本定義了該頁面的表格,並定義了查詢該表格的數據源【sql文件中定義】,如果有條件查詢則再編寫條件查詢的代碼,則該查詢頁面即可自動工作。這種自動化表格輸出的工作邏輯即是由affairMgr提供的

python中繼承affairMgr類的示例源碼

 一般來說,開發者需要編寫的python代碼都是繼承自affairMgr類,然後簡單修改並增加業務處理代碼即完成了python的代碼編寫工作。其代碼結構爲:

#導包,原則上直接將demo中這一部分直接copy過來即可,一般有30個左右
from data import ...

#自定義的名爲testDemo的capa
class testDemo(affairMgr):
	#系統在用戶請求執行某操作時發現需要加載testDemo,則將調用本函數生成一個新的capa對象來提供服務
    def New(self, con):
	return testDemo(con)

	#本capa所屬的空間名
    def module(self):
	return 'test'

	#模塊名
    def name(self):
	return 'demo'

	#本capa操作的數據對象的類型【或者是jxTMS內置的或者是開發者在data文件中定義的數據表名】,主要是用於查詢時自動將查詢出來的數據轉換爲相應的對象
    def joType(self):
	return 'demo'

	#在列表本capa所操作的數據對象時,自動生成的【查看】入口所對應的disp入口的界面名稱
    def viewWebInterface(self):
	return 'viewDemo'

	#如果希望自動生成流水號,則該流水號的模板格式。此處爲:Demo-000001、Demo-000002等等
    def SerialNumberModel(self):
	return 'Demo-{SNT6}'

	#定義一個cmd入口,用戶點擊某按鈕以請求訪問test.deom.cmd.testOp1入口,將調用本函數提供服務
	#db:數據庫接口
	#ctx:上下文
    @myModule.event('testDemo','cmd', 'testOp1')
    def testOp1(self,db,ctx):
    	#相應的業務處理代碼

	#列表時,從數據查詢出來的數據如何顯示到前端【因爲有數據格式以及改名的可能】
	#如數據庫爲了節省空間,將狀態用1/2/3等等進行保存,但要顯示給人看,就得轉換成:未開始/進行中/已結束
	#又如,開發者爲了減少代碼編寫,不定義專用的數據表,而是直接採用了jxTMS內嵌的數據表,但這些表的
	#屬性名是通用的,如Number,無法反應業務情境,所以就需要在這裏改爲【庫存數量】這樣的名字
    def dispAffairInfo(self,db,ctx,json, jo):
	json.set("demoID", jo.ID)
	json.set("demoName", jo.Name)
	json.set("demoState", tools.transState(jo.State))
	json.set("storeNumber", jo.Number)
	#其它顯示

	#用戶請求test.deom.disp.viewSubject時,執行本函數對界面進行初始化以及數據裝定
    @myModule.event('testDemo','prepareDisp', 'viewSubject')
    def prepare_viewSubject(self,db,ctx, page):
	#相應的頁面初始化以及數據裝定
	
	#列表查詢時設置動態查詢變量值
    def setSearchConditionVarValue(self, db, ctx):
	if self.dataSource == 'test.sqlListDemo':
	    self.infoSearch.setVar('demoID',self.getInput('demoID'))

	#列表查詢時根據用戶輸入增加查詢條件,一般用於用戶按條件搜索
	#
	#setSearchCondition是動態的給列表查詢增加一個篩選條件,如根據用戶輸入的銷售名查詢其名下的銷售訂單
	#根據用戶輸入的時間段,查詢那個時間段內的銷售訂單
	#
	#setSearchConditionVarValue則是根據上下文的不同,對一個已經確定的查詢條件設置當前的取值,如所有的銷售都有
	#【我的訂單】這一個查詢入口,但是在真正執行時就要根據查詢者的不同來設置不同的用戶ID進行查詢的
	#
    def setSearchCondition(self, db, ctx):
	if self.dataSource == 'test.sqlListDemo':
		#添加查詢條件
	    
# 一定要有,否則無法順利註冊
# 由於testDemo是一個類,所以在此生成一個testDemo對象,以將testDemo這個capa註冊到系統中
sp=testDemo(biz)

目前,jxTMS已經打包爲雲服務器鏡像,開發者開箱即用:
jxTMS-騰訊雲市場​

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章