我的U8二次开发经验分享
操作方法
- 01
目前U8产品越来越庞大,提供的应用与服务也越来越多样化。公司整体的发展战略要求U8要成为一个能支持规模化交付的产品。为了达到这样的目标,仅仅通过我们的水平产品是无法满足客户的行业化、个性化的要求的。所以二次开发就成为一个能满足可以要求的填充剂,填补水平产品与客户的需求中的差异的空隙。 二次开发是与一次开发是相对应的,所以凡是由U8产品开发部提供的U8产品、套件以外的都应属于二次开发的产品。从这个定义出发以下行为属于开发开发范畴。 分公司、大区的基于U8的开发行为。 第三方合作伙伴的基于U8的开发行为。 行业开发本部基于U8产品的开发行为。 目前我们的二次开发处于缺乏管理状态。由于U8软件缺乏足够的开发性,导致二次开发人员能利用的手段和方法非常有限。同时由于U8每年都需要年结,造成二次开发的数据需要手工结转。甚至有些是利用原代码进行的修改,这种方式会因为版本升级而造成功能实效。以下列出了主要的开发模式。 1.独立开发模式,独立于产品 模式描述: 在开发过程中基本不利用U8产品的构件(只利用登录构件),开发成果形成单独的可执行文件及动态库,模块不需要与U8门户程序集成,二次开发模块的权限设置、功能升级、部署均独立于产品。 优点: 对产品的影响小,产品可升级性强,不受产品功能制约。模块功能灵活度大,能够实现很复杂的功能。 缺点: 二次开发的模块产品风格与U8 产品风格差距较大,产品中一些很完善的功能(权限、打印、格式设置、输出等)不能被二次开发利用,打印、输出等基础功能需要重新开发,开发效率低。 注意问题: 如果使用了U8登录构件,在产品升级后,应测试登录构件是否向下兼容,如果不兼容要根据新版登录构件的使用文档对二次开发程序的登录部分作修改。 禁止行为: 为最大限度的保证产品的可升级性,禁止直接修改产品的系统数据表、视图、存储过程等数据库对象。 适用需求: 与产品关联度小,二次开发的功能与产品相对独立,属单独的功能需求,不影响产品的业务流程,但允许由产品中取数。例如:在U产品的基础上增加提成管理系统。 2.通过产品插件接口开发模式 模式描述: 此模式的开发是利用产品开放的插件接口对原产品模块做功能扩展。开发成果形成单独的动态链接库,模块功能不能单独使用,一般由产品模块通过插件接口依据插件注册信息自动调用。二次开发模块的权限设置、功能升级、部署均独立于产品。 优点: 利用插件方式开发,对产品影响小,产品可升级性强。插件机制可以规范二次开发模块的开发方式,插件产品重用性强,功能配置灵活。 缺点: 受产品插件接口开放程度的限制,目前只有库存模块提供了二次开发插件接口,其他模块还未提供,而库存模块也只提供了单据保存、审核、明细行双击等部分事件的插件接口,面对用户多种多样的二次开发需求,产品的插件接口开放程度还很不够。 注意问题: 插件开发应完全符合U8产品提供的插件二次开发规范,尽量采用与产品一致的开发语言(VB6.0)做插件,保证插件数据库操作与产品的数据库操作在同一事务中。 禁止行为: 适用需求:客户需求与产品模块结合紧密,需要基于某一产品模块做功能扩展,尽量采用插件方式。 3.利用产品提供的工具、服务的开发模式 模式描述:利用产品提供的二次开发工具、二次开发服务实现客户的个性化需求的开发模式。 优点:基本不用或只做少量的编码工作、开发效率高、与原产品风格一致、集成度高、易部署。 缺点:产品提供的开发工具能够解决的问题有限,特别是针对二次开发常涉及的供应链、财务等模块,目前只提供了自定义报表的二次开发工具。 注意问题: 禁止行为: 适用需求:能够利用产品提供的二次开发工具开发的需求尽量采用二次开发工具实现。例如:为客户定制开发的业务报表,一般的业务报表利用产品的自定义报表功能都可以实现。 4.申请产品源码做修改、替换原产品模块或新增模块节点的开发模式 模式描述:向集团申请源码直接修改产品功能模块的方式。 优点:基于原产品模块的代码进行二次开发可以实现很复杂的功能,开发灵活性、与产品集成度高。 缺点:如果需要以这种模式进行二次开发,必须首先向集团伙伴开发部申请开放部分源码,由伙伴开发部提供二次开发环境,分公司程序员不得将源码带回分公司。如果采用新增模块的方式,产品可以做补丁升级;如果采用替换原产品模块的方式导致产品不能进行升级,否则产品升级后会覆盖二次开发的模块,一定要升级需要二次开发人员对升级的安全性做测试,确认产品升级后不会影响二次开发模块的功能。 注意问题:应慎重选择此种开发模式,这种模式最大的问题就是严重影响产品的数据安全性、影响产品的正常升级。 禁止行为:没有二次开发程序员的指导,不能由用户自行进行产品补丁升级工作。 适用需求:适用于不能利用插件接口、外挂模块、二次开发工具的开发的需求,且此类需求的实现必须基于产品模块做修改。 5.行业插件的开发模式 模式描述:行业本部针对某个行业的行业特点对产品局部功能做行业化改造或开发新模块的开发模式,最终形成行业插件产品。 优点:开发规范遵循U8产品的开发规范,与产品开发过程一致。行业插件产品经过严格、专业的测试,保证开发质量。 缺点: 注意问题:行业插件产品要注明适用的产品版本,提供详尽的联机帮助、使用说明、升级方法。同时要考虑能够随产品的升级而升级。 禁止行为:禁止随意占用产品的模块编号做单据模板、报表模板的预置工作,行业本部增加模块前需向产品管理部申请全套模块代码及相关标识。 适用需求:行业插件产品的开发。 利用VB或其他开发工具开发独立的模块是目前一般的开发行为,这种开发方式对U8的依赖最低,藕合度小,受到的升级的影响也最小。在目前U8开发性比较低的情况下这是一种合理的选择。但是这种方式无法做到与系统的无缝结合。在UI的风格上也有可能造成较大的差异。开发分以下阶段进行。 需求调研阶段: 调研规范:二次开发调研不同于产品功能调研,客户提出的需求有可能代表一类行业的应用方式,但也有可能为该客户独有的需求。要求二次开发人员必须仔细分析客户提出需求的原因,首先确定是否可以通过软件以变通的方式实现用户的需求,确认没有其他解决方案后才可定义为二次开发需求。 需求规范:对于典型行业的二次开发的需求,且符合集团行业开发部做行业项目支持的条件,需要遵循行业开发部提供的二次开发需求模板编写二次开发需求文档。需求文档要严格按照模板内容逐项编写,特别要注意业务算法、数据精度、效率要求等设计相关的内容一定要作深入调研。对于分公司负责开发的项目,也可以参照行业开发部提供的二次开发需求模版进行需求编写,作为下一步设计、研发的指导性文档。 二次开发需求完成后,首先要经过用户确认,然后提交项目组召集相关需求、设计、研发人员进行需求评审,需求确认后即可进行设计、研发工作。 设计阶段: 设计原则: 1)需求设计一致性:二次开发模块设计必须满足软件需求说明书的所有要求,包括所有功能要求、性能要求和其它要求。软件需求说明的变化与软件设计说明书的变化必须保持一致。变化不能随意进行,应置于严格的配置管理之下,对于软件需求确认后的变更要严格控制,避免二次开发周期过长。 2)数据结构独立性:对于二次开发的模块禁止修改产品系统表数据结构及相关视图、存储过程、触发器等数据对象,最大限度的保证产品的可升级性。二次开发新建数据对象的命名规则应遵从二次开发数据对象命名规范。 3)数据一致性、合法性:设计过程中要考虑二次开发模块与相关产品模块数据的一致性。首先要保证产品的数据安全,尽量避免直接新增或修改系统数据表的记录。如果确实需要维护系统数据表的记录,尽量采用产品开放的业务组件操作数据库记录,保证数据的完整性、合法性。 4)产品化原则:对于有可能产品化或插件化的二次开发需求,在设计时要考虑二次开发模块的通用性、可推广性。二次开发模块要达到易安装、易使用、易维护的设计要求。尽量使用U8产品使用的构件,需要向集团申请模板编号、模块编号,避免和产品冲突。 编码阶段: 1)尽量采用与产品模块开发语言一致的开发语言。 2)首先VB语言编码规范遵循U8产品使用的VB编码规范,见附件。利于二次开发模块的产品化。其他开发语言编码规范也可参照VB的编码规范执行。 3)其次,作如下补充: 注释规范: 模块开头说明:增加“相关产品模块及本模块与产品模块的关系”、“作者单位”、“作者电子邮箱”、“适用产品版本” 4)配置管理工具可采用SourceSafe作配置管理。 自定义报表开发规范 1)开发模式: 采用产品提供的自定义报表工具开发报表。 优点:产品提供的自定义报表工具功能提供了友好的报表定义界面,能够满足用户提出的一般性报表的要求,适用范围广、不用编写代码,开发出的报表风格与产品一致,分发部署方便。 缺点:不能适应用户提出的复杂报表的二次开发需求,报表提供的功能有限。 2)部署方式:可采用“套件配置工具”由自定义报表的账套导出报表格式文件,利用该工具导入用户账套。 3)调试方法: 可利用自定义报表工具中的“生成SQL语句”生成SQL命令,然后利用“查看结果”测试由系统生成的SQL命令是否可以正常执行,执行后返回的数据是否为预期返回数据。如果生成的SQL命令为标准SQL命令,可以将命令串拷贝到MSSQL SERVER的查询分析其中进行调试。 4)不支持的功能及处理办法: a.自定义报表在调试交叉表的过程中不支持“查看结果”的功能,造成调试自定义报表困难。 b.在执行 “查看结果”时,如果SQL命令有错误,自定义报表均报“SQL语句定义错误,请查看别名定义是否有不合法的字符,条件是否输入关系操作符,关系定义是否正确,…”而不能反馈SQL命令错误的真实原因,造成调试不便。 当前的自定义报表功能开发较早,从产品的架构上看远远不能满足产品开发和二次开发的要求,特别是目前不支持存储过程,不支持用户自定义数据表的取数,不支持多层表头及不规则表头的报表的开发,不支持由筛选条件确定动态列的报表的处理。由U8平台设计部正在开发U8新一代报表引擎,提供了丰富的报表数据源定义及灵活的报表展现自定义功能,可以满足新时期产品报表开发及行业、伙伴二次开发的需要。 5)目前存在的BUG及问题: a.不支持报表数据源为存储过程; b.自定义的参照语句不支持U8参照窗体模式; c.不支持动态列及多表头(行或列为多表头); d.没有较细化的自定义报表功能的使用说明; e.报表定义出现错误,执行过程中不能提示发生错误的真正原因; f.报表没有数据不能预览 g.各列数据如果超过列宽,则不能自适应显示。 h.自定义报表引出数据(以excel格式为例),表头不能以在查询界面中的汉字显示,显示为定义时的名称。 COM+开发规范 Com+使用方式 在你的接口类(如BF,BFDISPATCH)上标记特性ServiceVisible。你可以使用ServiceVisible(ServiceTypes.SingleCall)或ServiceVisible(ServiceTypes.Singleton)来指定是SingleCall对象,还是Singleton对象。默认(ServiceVisible())是SingleCall。 如 [ServiceVisible(ServiceTypes.SingleCall)] public class BuesinessFacade{…} MethodTypes特性 MethodTypes特性可以指定在方法上,构造参数可以使用MethodTypesOption枚举 Sync :只生成同步方法(默认,或不写)。 Async:只生成异步方法,不包含同步方法。 Both:同时提供同步方法和异步方法。 OneWay:指定该方法为OneWay。 如 [MethodTypes(MethodTypesOption.Sync)] public DataSet GetData(string id){….} Context的使用 如果你的接口程序集是从UFSoft.U8.Framework.BizBase.dll中的BFBase和BOBase或IcontextContainer继承或实现,那么就可以利用Context来传递自定义对象或数据(必须是可序列化的)。 如,在客户端,对BF访问时,通过Add方法可以向Context传递额外的数据,该数据可以随着调用传递到服务端。 BFObject bf = new BFObject(); bf.context.Add(“key”,”value”); bf.DoSomrthing(); object value = bf.context[“key”] 在服务端的BF,你也可以取出并改变Context的值,然后让它原路返回到客户端。 this.context[“key”] = “new value”; 除此之外,SingleCall对象在服务端任何状态改变,客户端都无法直接得到。 不过,需要注意的是,当你从BFBase继承的时候,服务端无法向客户端传递数据,因为你的组件是COM+组件,具有JIT特性,状态无法取得,除非你禁用了JIT(非常不推崇)。如果不是COM+组件(从BOBase或实现IContextContainer),不会有此问题。客户端向服务端传递Context没有任何限制。 Com+生成方式 生成工具Generate.exe Usage:Generate source destination [-keyfile:] [-lib:] source:指定你的接口程序集位置 destination:指定你的生成目标路径,工具将在你指定的目录下建立ClientInterface和ServerInterface两个目录,用来存放文件,每个目录会生成两个文件,一个是接口,一个是代理. -keyfile:如果是强名称(COM+)文件,指定签名文件。 [-lib:]:指定你的接口程序集所依赖的文件的目录,用”;”来标记,如-lib:C;Winnt;C:winntsystem32 发布工具Publish.exe Usage Filepath|Directory [-si] [-ci] Filepath|Directory:可以指定一个文件,或则一个目录 [-si]:表明要发布SI [-ci]:表明要发布CI 可以把依赖文件放入Reference目录下 最后会在你指定的目录或文件所在的目录生成Portal.exe.config或web.config文件,如果原先已经存在,那么会在原来的基础上修改。 Com+组件规范 无状态性 开发的接口组件,最好不要具有公共属性,公共字段,不允许具有静态成员,静态方法。 可序列化 接口组件的接口类型必须可被序列化,及返回类型,参数类型必须是可被序列化的类型。特别注意的是,当你使用集合类型或DataSet的时候,你需要确保运行时,它里面所包含的类型必须能够被序列化。 out参数 不允许使用out参数,可以使用ref参数代替。 内部引用 接口组件的接口上所引用的类型,最好在其他的程序集中实现,最好不要在自己程序集中实现,因为如果是在自己内部实现,如果使用了自定义类型,那就不能写在你的接口程序集里,因为如果这样,就增加了CI对程序集自身的依赖性,这样CI被部署到客户端,程序集自身也要被部署到客户端了,但是CI和程序集同名,无法放在一起。但是生成工具也会尝试生成,不过将略去初始值(只具有默认值),移除内部逻辑代码(方法,属性中的逻辑)。如果在接口程序集中声明了一些类型,而在接口类中没有引用,那么生成工具将忽略(移除)这些类型。 类型忽略 接口组件的一些基类型将会被忽略,比如ServicedComponent,MarshalByRefObject等系统基类型,他们的属性,方法不会被生成。 OneWay方法 只能具有Void返回值,不能具有带ref参数的方法。 EAI应用开发规范: EAI工具目前不适用于大数据量的一次性导入,否则会导致导入时间过长甚至造成不能导入的问题,在数据量较大时最好拆分成多个小文件,再做导入。 目前EAI不支持对业务单据的删除、修改功能,要求第三方软件的业务单据导出数据后不能再在原系统中修改造成系统间业务数据不一致。 在从第三方软件导出业务单据前,要保证业务单据上涉及的基础档案在U8系统内已存在,否则应连带先将关联基础档案导出,向U8系统导入相关基础档案后,再导业务单据,保证业务数据的完整性。 年结与建帐 因U产品采用年度帐的形式,每年需要生成一个新帐套,年末需要利用年结工具进行年度结转的工作。对于标准产品年结工作可以利用年结工具完成,但产品未提供二次开发年结接口,二次开发的模块的年结必须单独进行。 二次开发年结常见的问题: 1)二次开发过程中新增的数据表、视图、存储过程等数据对象不能自动结转至新的年度帐套。 2)二次开发模块的年末数据不能自动结转到新年度帐套的期初。 3)目前没有二次开发模块与产品模块年结的强制顺序关系,造成结转数据不正确。 4)因二次开发过程中不规范的修改产品系统表的行为,导致帐套不能正常升级。 问题解决方案: 1)禁止直接修改产品系统表表结构。二次开发模块需单独建立数据表,数据表名参照二次开发规范(代码规范部分)。 2)在必须要增删产品系统表记录时,要严格遵守业务数据逻辑关系、数据表外键关系。 3)对于新增数据对象的年结问题,可采用先升级帐套模板库,在模板库中建好二次开发模块所需的数据对象,然后再进行年结。 4)对于新增数据表内数据的结转,必须由二次开发人员提供二次开发模块的年结工具或结转方法说明文档。 对于二次开发模块的结转顺序问题,可通过二次开发模块的年结工具编写代码判断前置模块结转标识,来决定是否可以结转。 建账过程描述 1.在UFSystem中的UA_Account中增加一条纪录,记录帐套信息 2.在UFSystemz中的UA_Period增加纪录,对应着当前年度帐的会计期间 3.恢复UFModel.bak到年度数据库UFData_帐套号_年度,在Ufsystem中的UA_account中填写对应的路径信息 4.打开年度库 在Accinformation表中作如下修改 1.cSysID=’AA’ and cName=’iSystemID’cValue=Ua_account中的cSysId 2. cSysID=’AA’ and cName=’ iSystemYearcValue=工业/商业 3. cSysID=’AA’ and cName=’ cSysVerNocValue=’SQL’ 4. cSysID=’AA’ and cName=’ bGoodClasscValue=是否存货分类 5. cSysID=’AA’ and cName=’ bCustClasscValue=是否客户分类 6. cSysID=’AA’ and cName=’ bProvClasscValue=是否供应商分类 7. cSysID=’AA’ and cName=’ bFrgnCurrencyAcccValue=是否使用外币 8. cSysID=’AA’ and cName=’ bGroupVercValue=是否集团版 存货、供应商、客户无分类时,建立分类档案的无分类初始记录 修改外币设置表Foreigncurrency 如果是集团帐套,改变年度帐的编码设置,并修改了单据头的自定义项目 如果是医药流通企业类型,修改自定义项 行业性质为医院时,从UFSub模板中复制模板数据在 aa_picture表中插入Logo信息 5.用户权限表中,加账套主管(该年度的)权限记录 6.按行业性质预置科目 7.调用调用编码方案控件 (U8GradeDef.IGradeDef) 8.调用数据精度控件 (数据精度.UFDataPre) 9.调用系统启用控件 (U8PSysStart.IsysStart) 10. 同步accinformation表和gradedef表中的编码规则 目前年结调用的DLL 子模块调用的DLL CRMUFCRMJZ.clsCRMJZ 网上报销 NEEndYear.EndYear 生产订单U8MDBSrv.clsDBTransfer 设备管理 UFEQEndY.EndYear 销售管理UFGXLJZ.clsJZSN 预算管理 U8BGJZ.clsBGJZ 合同管理 UFCMJZ.CCMJZ 资金管理 UFFmEndY.EndYear 应收/应付 UFARJZ.ClsJZ 结算中心 UsFDYear.clsUFFD 固定资产 UFFA_DLL.clsUFFA 人力资源UFHRJZ.clsHRJZ") 成本管理UfcaEndy.endyear 合并报表HBBB_DataTrans.Trans 总帐/集团财务UFGLJZ.clsGLJZZzPub.clsPub 项目管理UFPMJZ.clsPMJZZzPub.clsPub 网上银行USNBJZ.clsJieZhuan 报账中心UFWHJZ.clsWHJZ 外挂程序命名规范 U8中使用的产品有自己的规范,产品以大写的英文字母表示如AR应收系统,该产品下的子产品用产品的字母开头后面接字母或数字AR101设置,AR10101初始设置,在门户的中的显示为树的形式,其中AR为AR101的父节点,AR101为的父节点。其他新产品的起名,或二次开发的产品的起名必须遵循上面的规则,并不能和已有的产品名称相重,下面是在U中以使用的产品名称及相应的对应的关键字。 基于以上的列表先定义以下二次开发规范 二次开发项目的一级产品名开头必须是EF,然后是项目名,如EFNF表示是二次开发南孚项目。此长度不能超过6位。 二级产品如果是在U8的一级产品下,且必须加入EF。如MO(生产订单)下的产品名称可以是MOEFNF01。表明是生产订单下增加了南符项目的子节点EFNF01。 二级产品如果是在二次开发项目的一级产品下,则只需要遵循通用的命名规范就可以。 三级产品同二级产品要求。 .Net程序命名空间规范 U8 的命名空间规范应遵守.Net Framework规范的,在分段部分不完全一样,U8的规范分为至少4段,即 UFSoft.U8.AppSvr.UI. 1.分别为公司名段: UFSoft 2.总产品名段:U8 3.小产品名段,服务框架:指定产品模块名称和服务的框架,如AppSvr--应用服务器,Workflow工作流服务器,Sale销售管理, Stock库存, Framework等含义比较清晰的词或词组,不要用很难理解的太简单或太冗长的词或词组 4.界面层次名段:UI—User Interface,UIP—User Interface Processes,CI—Client Side Interface,SI—Server Side Interface,BF—Business Façade,BO—Business Object, DAO—Data Access Object, DO—Data Object 5.对后续的段不做要求 数据库规范 二次开发命名规范 凡是二次开发项目的数据库对象名前面必须增加项目简拼。以下例子以南孚电池为例 字段类型 对于数量、单价、金额字段应为decimal数据类型,如现存量表中的各累计字段、单据表中需回写累计值的字段、二次数据表中的累计字段等。 对于各种单据表,为解决加锁问题可考虑加时间戳字段(timestamp, not null) 建议不要使用float类型,否则可能会出现数据精度问题。 如果是字符则必须是NVarchar或NChar类型,不要使用varchar和Char类型。 建议减少使用NChar类型 如果是主键则建议使用GUID类型,默认值是Newid()。 性能规范 1. 在设计数据库中要考虑索引的建设问题。因为索引的建设和业务逻辑及性能及并发操作都有关系,因此在数据库设计中需要说明为什么建索引。哪种业务逻辑中需要建设索引。对每个字段只能建设一个索引,不得建设两个索引。在没有理由的情况下,不能随便建设索引。建设索引要具体情况具体分析,这方面要逐步加强对数据库基本理论中B+树及其上的并发操作的理解。但也有些一般性建议(这里需要说明的是:这不是规定): 1.1)在数据量很大且涉及到 where 语句的情况下可以考虑对where语句所对应的字段建设索引(如 where col = ‘hello’ 中的 col 字段),但是,col 字段的已经有的取值应该很广泛。 1.2) 在涉及到 range 查询(如:WHERE sales_quantity BETWEEN 500 and 1000 1.2))的时候应该考虑建设蔟集索引。 1.3)在涉及到内联接的时候应考虑对两个联接字段建立索引;在涉及到左联接的 时候应考虑对右面的字段建立索引;在涉及到右联接的时候应考虑对左边的字段建立索引。 1.4)在建立复合索引的情况下,如对(a, b)建立索引,可以应用对 a 字段的查 询,如 where a = ‘hello’;当然也可以应用对 (a, b) 字段的查询,如 where a = ‘hello’ and b = ‘how’;但是一般不适合对 b 字段的查询,如 where b = ‘hello’。 2. SQL Server 中若在一个表中有主键,则对于这个主键自动建立簇集索引。在数据库设计中若只涉及到用主键进行单一行的检索,应该考虑对此主键不用蔟集索引。而将簇集索引用在别的字段上。 3. 对于程序中涉及到多个表的联接的运算,应该对效率问题进行评估。在需要的情况下,应该考虑建设冗余表。特别是联接运算很频繁的情况下。在只涉及到内联接的情况下,为了效率问题要首先考虑建设索引视图。 4. 在设计过程中,若出现需要根据一个表中的数据进行计算。而在实际应用中要频繁查询或调用此计算出来结果的情况下,要考虑建立索引视图。 5. 数据库设计应尽可能满足第三范式。 6. 在对操作系统和数据库配置进行修改时,请说明原因。一般情况下不建议对操作系统和数据库配置进行修改。 7. 在设计数据库时,应考虑这种设计所面临的业务操作对并发的影响。在设计阶段避免死锁问题。每个数据库设计人员应该弄清楚什么是死锁,不清楚的请参阅任何数据库基本理论书籍或询问数据库组。 8. 应考虑对频繁使用的中间结果建立冗余表进行存储。 9.每个数据库设计人员应参加数据库组组织的培训。 10.为了提高效率,需要其它组为本组建设冗余表,建设冗余字段,增加字段,建立触发器的,请尽可能在数据库设计初期发现。并在数据库设计中说明。由数据库组和总体技术部协调处理。要其它组为本组建立冗余表,且工作量较大的情况下,将由数据库组组织会议协商解决,并计算增加的工作量。