在NC二開中峻贮,經(jīng)常要在保證系統(tǒng)核心業(yè)務不變的情況下儿子,對系統(tǒng)的業(yè)務邏輯進行擴展腌紧,這些行為統(tǒng)稱為“后端擴展”贱枣。
對于單據(jù)而言监署,“業(yè)務規(guī)則擴展”和“業(yè)務事件擴展”是兩種最常見的擴展方式。這兩種方式并不沖突纽哥,可以同時使用钠乏,下面我們就來一步一步探索這兩種方式。
我們知道所有的單據(jù)都會走單據(jù)動作腳本N_XX
春塌,一般來說晓避,動作腳本會調(diào)用相應Service
的增刪改查方法,方法里會調(diào)用諸如InsertAction
之類的動作只壳。一些單據(jù)沒有自己的action
俏拱,會調(diào)用使用泛型編程的公共action
,我們就以其中一個為例來分析吼句,先看代碼:
public class InsertAction<T extends IBill> {
// ...
public T[] processAction(T[] billVOs) {
// 業(yè)務規(guī)則處理類
AroundProcesser<T> processor = new AroundProcesser<T>(this.point);
// 添加業(yè)務規(guī)則
addInnerRule(processor);
// 派發(fā)動作前業(yè)務事件
fireBeforeBusinessEvent(billVOs);
// 執(zhí)行動作前業(yè)務規(guī)則
billVOs = processor.before(billVOs);
// 由于支持FilterRule锅必,所以返回的billVOs可能是null
if (billVOs == null || billVOs.length == 0) {
return null;
}
// 新增保存
T[] resultVOs = this.insert(billVOs);
// 執(zhí)行動作后業(yè)務規(guī)則
resultVOs = processor.after(resultVOs);
return resultVOs;
}
/**
* 添加業(yè)務規(guī)則
*/
protected void addInnerRule(AroundProcesser<T> processor) {
for (IRule<T> rule : beforeRule) {
processor.addBeforeRule(rule);
}
for (IFilterRule<T> rule : beforeFilterRule) {
processor.addBeforeRule(rule);
}
for (IRule<T> rule : afterRule) {
processor.addAfterRule(rule);
}
for (IFilterRule<T> rule : afterFilterRule) {
processor.addAfterRule(rule);
}
}
/**
* 動作前業(yè)務事件
*/
protected void fireBeforeBusinessEvent(T[] billVOs) {
try {
EventDispatcherDelegate.fireEvent(IPMEventType.TYPE_INSERT_BEFORE, billVOs);
} catch (BusinessException e) {
ExceptionUtils.wrappException(e);
}
}
/**
* 動作后業(yè)務事件
*/
protected void fireAfterBusinessEvent(T[] billVOs) {
try {
EventDispatcherDelegate.fireEvent(IPMEventType.TYPE_INSERT_AFTER, billVOs);
} catch (BusinessException e) {
ExceptionUtils.wrappException(e);
}
}
// ...
}
其實說到底,所謂的“業(yè)務規(guī)則”和“業(yè)務事件”惕艳,不過是在代碼里預留位置執(zhí)行的一段邏輯搞隐。通過分析上面的代碼,我們可以發(fā)現(xiàn)他們是如何被觸發(fā)的:
- 業(yè)務規(guī)則
通過業(yè)務規(guī)則處理類例如AroundProcesser
執(zhí)行远搪,并且可以通過業(yè)務規(guī)則處理類的addBeforeRule()
和addAfterRule()
方法直接在代碼里添加前后規(guī)則劣纲。 - 業(yè)務事件
通過EventDispatcherDelegate
的fireEvent()
進行事件派發(fā)。
“后端擴展”要保證系統(tǒng)核心業(yè)務不變谁鳍,理論上來說在代碼里直接為AroundProcesser
等業(yè)務規(guī)則處理類的add
方法添加業(yè)務規(guī)則是不規(guī)范的癞季,因為他還是改動了源碼。但是在實際的二開中倘潜,如果能獲取源碼的話绷柒,改源碼是最方便快捷的方式,下面我們來說說標準的擴展方式:
- 業(yè)務規(guī)則
在數(shù)據(jù)表pub_pluginitem
里注冊涮因,下面的SQL語句中出現(xiàn)的字段是必須的废睦。
insert into pub_pluginitem (pk_pluginitem, vmodulename, vcomponentname, vextendpointname, veventtype, vextendtype, vruleclass) values ('主鍵', '模塊名', '組件名', '業(yè)務規(guī)則擴展點', '擴展事件類型(before、after)', '擴展類型(addAfter蕊退、addBefore郊楣、replace)', '擴展規(guī)則類'); - 業(yè)務事件
在NC的“業(yè)務插件注冊”模塊里注冊,事件源ID為單據(jù)對應元數(shù)據(jù)中的主表ID瓤荔,事件類型編碼需要與代碼中EventDispatcherDelegate.fireEvent()
的首個參數(shù)對應净蚤。
講了業(yè)務規(guī)則和業(yè)務事件的使用方式,最后來看他們自身的代碼實現(xiàn):
- 業(yè)務規(guī)則
實現(xiàn)IRule
输硝、ICompareRule
或者IFilterRule
接口今瀑。 - 業(yè)務事件
實現(xiàn)IBusinessListener
接口,與業(yè)務規(guī)則能直接獲取到VO
不同,業(yè)務事件能直接獲取到的是IBusinessEvent
類型的業(yè)務事件event
橘荠,通過event.getEventType()
可以獲取到事件類型編碼屿附。獲取編碼的意義在于,我們可以將一個業(yè)務事件配置到業(yè)務插件注冊里的不同事件類型下哥童,然后通過代碼判斷執(zhí)行不同的邏輯挺份。這樣可以讓不同事件類型共享同一段代碼,避免代碼冗余贮懈。
至于VO
如何獲取匀泊,最好是通過debug分析參數(shù)IBusinessEvent
的實例,因為可能獲取到不同的事件類型朵你,獲取VO
方式也不同各聘,一般來說event.getUserObject()
是第一步。