NC业务插件模型源码分析
1. Summary
为了增加NC程序事件响应的可扩展性,在Java事件响应的前后添加一些必要的操作。
2. NC事件监听器数据库设计
表中字段的含义如下表:
pub_eventlistener
pk_eventlistener | 主键 | 1001ZF1000000000099E |
name | 名称 | 同步经销商云平台商家 |
implcalssname | 实现类的全限定名,需实现IBusinessListener接口 | OrgInsertAfterListener |
pk_eventtype | 外键,连接pub_eventtype表 | 1018Z01000000000LLB9 |
owner | 外键,连接dap_dapsystem | EC99 |
pub_eventtype
pk_eventtype | 主键 | 1018Z01000000000LLB9 |
eventtypename | 事件类型名称 | 新增后 |
sourceid | 元数据ID | 945f38b6-48ec-43e6-bb09-77ec89a3728f |
owner | ? | 1010 |
dap_dapsystem
moduleid | 主键,与pub_eventlistener表的owner关联 | EC99 |
devmodule | 模块名称 | eschain |
3 基本代码分析
3.1 代码配置组合
为了说明业务插件代码的运行原理,我们以品牌(bd_branddoc)插入后业务插件为例进行说明。VC6.0中大部分单据界面都需要一个Spring.xml 文件来配置界面,对界面进行布局。这个xml文件必须放在client文件夹下,路径和注册功能节点是注册的“BeanConfigPath”参数一致。
在uiuapbd_brand.jar文件中找到对应的spring配置文件:branddoc_globe.xml,主要配置如下:
<beans> <!-- 界面布局总装########################################################### --> <bean id="container" class="nc.ui.uif2.TangramContainer" init-method="initUI"> <property name="tangramLayoutRoot"> <bean class="nc.ui.uif2.tangramlayout.node.CNode"> <property name="component" ref="brandlist"></property> </bean> </property> <property name="editActions"> <list> <ref bean="saveAction" /> ...... </list> </property> <property name="model" ref="batchBillTableModel"></property> </bean> <bean id="saveAction" class="nc.ui.uif2.actions.batch.BatchSaveAction"> <property name="model" ref="batchBillTableModel" /> <property name="editor" ref="brandlist" /> <property name="validationService" ref="validatorServicer"></property> </bean> <!-- 批量操作应用模型 --> <bean id="batchBillTableModel" class="nc.ui.uif2.model.BatchBillTableModel"> <property name="service" ref="batchModelService"></property> <property name="businessObjectAdapterFactory" ref="objectadapterfactory"></property> <property name="context" ref="context"></property> </bean> <!-- 应用服务类,负责进行模型操作的处理 --> <bean id="batchModelService" class="nc.ui.bd.material.branddoc.model.BrandDocModelServicer" /> ...... </beans>
3.2 代码调用过程
当点击保存按钮时,会调用nc.ui.uif2.actions.batch.BatchSaveAction类(父类为:javax.swing.Action)的doAction方法。基本的类调用关系如下图:
nc.ui.uif2.actions.batch.BatchSaveAction#doAction()
↓
nc.ui.uif2.model.BatchBillTableModel#save()
↓
nc.ui.bd.material.branddoc.model.BrandDocModelServicer#batchSave
↓
nc.impl.bd.material.branddoc.BrandDocManagerImpl#batchSaveBrandDoc
↓
nc.impl.bd.material.branddoc.BrandDocManagerImpl(父类:nc.bs.bd.baseservice.md.BatchBaseService)#batchSave
↓
insertVO
↓
fireBeforeInsertEvent
fireAfterInsertEvent
↓
nc.bs.businessevent.bd.BDCommonEventUtil#dispatchInsertBeforeEvent
nc.bs.businessevent.bd.BDCommonEventUtil#dispatchInsertAfterEvent
↓
nc.bs.businessevent.EventDispatcher#fireEvent() // 静态方法
3.4 EventDispatcher事件派发过程
业务插件的事件派发过程主要有nc.bs.businessevent.EventDispatcher类的静态方法fireEvent完成,核心代码如下:
public static void fireEvent(IBusinessEvent event) throws BusinessException { writeDebugLog(event); // 从数据库中获取event listener 数据映射关系 Map<String, UnionVO> classNameMap = getListenersInfo(event.getSourceID(), event.getEventType()); if (classNameMap == null || classNameMap.isEmpty()) return; String className = null, devModuleCode = null; try { String currgroup_localtype = getCurrGroupLocalType(); String currgroup_industrytype = getCurrGroupIndustryType(); for (Iterator<String> iter = classNameMap.keySet().iterator(); iter .hasNext();) { // 获取event listener 的实现类名称 className = iter.next(); UnionVO unionvo = classNameMap.get(className); devModuleCode = unionvo.getDevmodulecode(); String classInfoMsg = "Plugin class [" + className + "] modulecode [" + devModuleCode + "] "; /* * 执行优先级为1/2/3/4的插件并集: * 行业为水平+本地化为国际化 * 行业为水平+ 本地化(如果本地化能匹配) * 匹配行业(如果行业能匹配)+ 本地化为国际化 * 匹配行业(如果行业匹配) + 本地化(如果本地化能匹配) * * 插件中,行业为空或者为默认值综合控股集团按水平算,本地化为空或为中国按国际化算 */ String localtype = StringUtil.isEmpty(unionvo.getLocaltype()) ? "" : unionvo.getLocaltype(); String industrytype = StringUtil.isEmpty(unionvo.getIndustrytype()) ? "" : unionvo.getIndustrytype(); int level = LocalAndIndustryLevelQueryUtil.getLevelByLocalAndIndustry( localtype, industrytype, currgroup_localtype, currgroup_industrytype); if (level == 1 || level == 2 || level == 3 || level == 4) { Logger.debug(classInfoMsg + " begin."); Long start = System.currentTimeMillis(); // 利用反射获取IBusinessListener实例 IBusinessListener instance = getInstanceByClassName(className, devModuleCode); // 执行Event listener 的doAction方法 instance.doAction(event); Logger.debug(classInfoMsg + " end successfully.cost time : " + (System.currentTimeMillis() - start)); } } } catch (BusinessException e) { Logger.error(getErrorMsg(event, className), e); throw e; } catch (RuntimeException e) { Logger.error(getErrorMsg(event, className), e); throw e; } }
fireEvent方法的主要任务是说先从表:pub_eventlistener,pub_eventtype与dap_dapsystem获取相应的数据并保存到Map中
nc.bs.businessevent.EventDispatcher#getListenersInfo() // 返回值:Map<String, UnionVO>
↓
getEventType_ClassNameMap() // 返回值为: Map<String, Map<String, UnionVO>>
↓
getAllListenersMap()
↓
getAllListenersByOrder()
↓
nc.impl.businessevent.EventListenerQryServiceImpl#getAllListeners()
//getAllListeners的代码实现如下:
public UnionVO[] getAllListeners() throws BusinessException { String sql = "select T1.sourceid as sourceid,T1.eventtypecode as eventtype," + "T0.implclassname as implclassname,T0.operindex as operindex," + "M.devmodule as devmodulecode," + "T0.localtype as localtype,T0.industrytype as industrytype " + "from pub_eventlistener T0 " + "left outer join pub_eventtype T1 on T0.pk_eventtype =T1.pk_eventtype " + "left join dap_dapsystem M on M.moduleid=T0.owner "+ "where T0.enabled = 'Y' or T0.enabled = 'y'"; List<UnionVO> vos = (List<UnionVO>) getBaseDAO().executeQuery(sql, new BeanListProcessor(UnionVO.class)); return vos.toArray(new UnionVO[0]); }
getEventType_ClassNameMap返回Map>的映射关系,他们的含义如下:
Key | SourceId+'@'+eventtytpe | 3ee53558-6398-4096-a91f-c7aa00e93701@新增后 |
Value | implclassname与UnionVo的映射 |
其中SourceId的获取是在nc.impl.bd.material.branddoc.BrandDocManagerImpl实例创建时指定的:
public BrandDocManagerImpl() { super(IBDMetaDataIDConst.BRANDDOC); }
nc.itf.bd.pub.IBDMetaDataIDConst中包含了所有模块对应的SourceId常量值。
以上。
相关推荐
在Eclipse中使用这样的插件,开发者可以获得针对NC的特殊功能,如NC特定的模板、API文档集成、代码分析工具等。 4. **代码辅助和自动完成**:NC_eclipse开发插件可能提供NC相关的代码补全功能,帮助开发者快速输入...
3. **NC二次开发**:二次开发通常是指在已有软件基础上进行的定制化开发,以满足特定用户或业务的需求。对于NC系统而言,二次开发可能涉及界面修改、功能增强、数据接口对接等方面。 4. **插件集成**:将NC的...
- **模型编辑器**:NC56插件可能包含了专门的模型编辑器,允许用户以图形化方式创建和编辑元模型。 - **语法支持**:它可能提供了特定的语法高亮和代码完成,以提高编写元模型时的效率。 - **代码生成**:根据元...
NC、NCC业务插件注册资料 NC、NCC业务插件注册资料是指在软件开发中使用的插件注册机制,它允许开发者创建自己的业务插件并将其注册到系统中,以便在业务流程中使用。下面是该资料的详细知识点: 插件注册 插件...
NC使用eclipse开发插件
本篇将围绕标题“matlab_netcdf_5_0_matlabnetcdf_matlab的读取nc格式的插件_matlabNC_源码”和描述中的知识点进行详细解释。 标题中的“matlab_netcdf_5_0”指的是该插件针对MATLAB的NetCDF接口的版本5.0,它可能...
"hrwa"可能是指人力资源工作分析模块,用于职位描述、工作职责分析以及能力模型构建。 NC63作为版本号,可能表示这是该人力资源系统的第六十三个迭代或更新版本,通常意味着在前一版本基础上修复了已知问题,增加了...
适用于NC65开发和NCC后端开发, 插件的使用教程: http://note.youdao.com/noteshare?id=6e1591b9b4d5bf4f842cff071607bc5d&sub=62E4EF1925254C099584D056FD174993
在NC后台任务插件开发中,`nc.bs.pub...通过这些接口和类的设计,NC后台任务插件可以灵活地处理各种业务场景,根据上下文信息执行相应的任务,并返回处理结果。开发者可以根据需求创建自己的插件,以扩展NC系统的功能。
5. **源码分析**:通过阅读nc-Source中的文件,我们可以学习到如何在Delphi环境下实现P2P即时通讯系统。这可能包括: - 数据结构设计:如消息结构、用户信息存储、会话管理等。 - 网络编程:TCP/IP套接字编程,...
通过以上知识点,我们可以看出,【进出口管理NC57插件】是针对企业全球化贸易需求设计的一款强大工具,它通过自动化和优化关键业务流程,降低了企业的运营成本,提高了业务处理效率,对于用友NC57系统的用户来说,...
"NC57财务源码"是一个专为财务领域设计的软件系统,其核心目标是提供高效、准确的财务管理解决方案。这个源码集包含了多个关键模块,如“UAP”(通用应用平台)、“GL”(总账)、“CMP”(成本管理)、“IC”(存货...
学习【NC63供应链源码】,不仅可以深入了解供应链管理的业务流程,还能提升在软件开发中应用数据结构、算法和数据分析的能力。这个压缩包提供了实际操作的实例,对于想要从事供应链信息化或者系统集成开发的工程师来...
总的来说,"用友NCC NC bip二开idea开发插件"是专为提升用友系统开发效率而生的利器,结合IntelliJ IDEA的强大功能,让开发者能更加专注于业务逻辑的实现,从而推动项目的快速进展。对于从事用友系统二次开发的...
总之,“NC57 webservice 开发插件”是针对用友NC57平台的一款强大工具,它极大地提升了开发webservice的效率和便利性,使得开发人员能够更加专注于业务逻辑,而不是繁琐的配置和代码编写工作。通过Eclipse的集成,...
标题中的“excle打开nc文件插件”指的是在Microsoft Excel中处理NetCDF(Network Common Data Form)文件的扩展工具。NetCDF是一种开放源代码的数据格式,广泛用于气象、海洋学、气候模型等领域,存储多维科学数据。...
NC63人力资源源码,包含hrbm、hrcm、hrcp、hrdm、hrhi、hrjf
NC-ERP二次开发 MDE插件,放在plugins下
NC65审批流与业务流是企业中非常关键的流程管理工具,它们通常用于规范和自动化企业的业务处理过程。本文将详细介绍在配置NC65审批流和业务流时需要了解的关键知识点,包括接口配置、字段映射、Java源代码生成、元...