NC开发笔记——二开知识点

时间:2022-02-09 10:31:51

用友集团ERP客户化开发系列丛书

NC客户化开发进阶

培训教程

V2.0版

本教程是用友软件股份有限公司内部培训资料,只限于用友公司内部开发应用,任何人未经过事先书面许可不得扩大本教程的使用范围。同样,未经过用友公司书面许可,任何人不得以任何形式对本手册进行增删、改编、节选、翻译、翻印或仿制,违者必究!

?本手册的著作权属于用友软件股份有限公司

版权所有?翻制必究

2009年1月第一次印刷

在*印制

用友软件股份有限公司

目录

第一篇 入门篇 ................................................................................................................................. 5

1. 建立NC环境 ........................................................................................................................... 5

内容概述 ................................................................................................................................... 5

详细介绍 ................................................................................................................................... 6

1.1.1. 建立数据库 ....................................................................................................... 6

1.1.2. 安装NC ............................................................................................................ 7

1.1.3. 配置启动NC .................................................................................................... 9

1.1.4. Eclipse中建立NC开发环境 ......................................................................... 13

1.1.5. 产品参数,档案初始化 ................................................................................. 19

1.1.6. 权限管理 ......................................................................................................... 22

1.1.7. 产品主要目录结构介绍 ................................................................................. 24

2. NC基础技术 .......................................................................................................................... 25

内容概述 ................................................................................................................................. 25

详细介绍 ................................................................................................................................. 25

2.1.1. NC UAP 总体介绍 ........................................................................................ 25

2.1.2. NC开发中的一些基本概念 .......................................................................... 30

2.1.3. NC的开发模型 .............................................................................................. 32

2.1.4. 开发远程接口 ................................................................................................. 34

? 定义接口 ......................................................................................................... 34

? 实现该接口 ..................................................................................................... 34

? 部署组件 ......................................................................................................... 34

? 客户端调用 ..................................................................................................... 35

? 事务型组件发布 ............................................................................................. 36

? 客户端代码 ..................................................................................................... 38

3. 数据建模 ................................................................................................................................. 40

内容概述 ................................................................................................................................. 40

详细介绍 ................................................................................................................................. 40

3.1.1. PowerDesigner建模 ....................................................................................... 40

3.1.2. 生成NC数据字典 ......................................................................................... 48

第二篇 中级篇 ............................................................................................................................... 49

4. 单据开发 ................................................................................................................................. 50

内容概述 ................................................................................................................................. 50

详细介绍 ................................................................................................................................. 50

4.1.1. 进入Workshop ............................................................................................... 50

4.1.2. 表单开发流程导航工具 ................................................................................. 52

4.1.3. UI工厂............................................................................................................ 65

5. NC数据库持久化技术 .......................................................................................................... 68

内容概述 ................................................................................................................................. 68

详细介绍 ................................................................................................................................. 69

5.1.1. 核心类介绍: ................................................................................................. 69

5.1.2. 通过JDBC FrameWork访问数据库 ............................................................. 70

5.1.3. 通过BaseDao进行对象的持久化................................................................. 73

1

用友软件股份有限公司

5.1.4. 结果集控制 ..................................................................................................... 74

6. 单据开发其他相关技术 ......................................................................................................... 75

内容概述 ................................................................................................................................. 75

详细介绍 ................................................................................................................................. 75

6.1.1. 参照开发 ......................................................................................................... 75

6.1.1.1. 参照的类结构图 ..................................................................................... 75

6.1.1.2. 自定义参照开发规范 ............................................................................. 76

6.1.1.3. UIRefPane 和refModle设置 ................................................................ 78

6.1.2. 单据号 ............................................................................................................. 79

6.1.2.1. 单据号规则 ............................................................................................. 79

6.1.2.2. 接口方法 ................................................................................................. 81

6.1.3. 公式 ................................................................................................................. 83

6.1.4. 锁 ..................................................................................................................... 88

6.1.5. 日志 ................................................................................................................. 90

6.1.6. 异常 ................................................................................................................. 91

7. 报表开发 ................................................................................................................................. 93

内容概述 ................................................................................................................................. 93

详细介绍 ................................................................................................................................. 93

7.1.1. 入门 ................................................................................. 错误!未定义书签。

7.1.2. 查询模型 ......................................................................... 错误!未定义书签。

7.1.3. 格式设计 ......................................................................... 错误!未定义书签。

7.1.4. 发布报表 ......................................................................... 错误!未定义书签。

第三篇 高级篇 ............................................................................................................................... 93

8. 预警平台 ................................................................................................................................. 93

内容概述 ................................................................................................................................. 93

详细介绍 ................................................................................................................................. 94

8.1.1. 预警类型注册 ................................................................................................. 94

8.1.2. 预警条目注册 ................................................................................................. 96

9. 交换平台 ............................................................................................................................... 101

内容概述 ............................................................................................................................... 101 详细介绍 ............................................................................................................................... 101

9.1.1. 交换平台使用 ............................................................................................... 101

9.1.2. 交换平台插件开发 ....................................................................................... 107

10. 流程平台 ....................................................................................................................... 109

内容概述 ............................................................................................................................... 109 详细介绍 ............................................................................................................................... 109

10.1.1. 流程平台介绍 ............................................................................................... 109 10.1.2. 业务流程 ....................................................................................................... 111

业务类型 ............................................................................................................... 112

流程配置 ............................................................................................................... 113

单据权限配置 ....................................................................................................... 114

单据来源配置 ....................................................................................................... 115

动作约束配置 ....................................................................................................... 116

动作事件控制配置 ............................................................................................... 117

2

用友软件股份有限公司

动作驱动配置 ....................................................................................................... 117

单据VO交换 ....................................................................................................... 118

下面是一个最小化的推式流程过程 ................................................................... 120

拉式单据(单据的上下游参照) ....................................................................... 121

10.1.3. 审批流 ........................................................................................................... 122

审批流定义 ........................................................................................................... 122

审批流编程 ........................................................................................................... 127

10.1.4. 消息中心 ....................................................................................................... 135

11. 会计平台 ....................................................................................................................... 139

内容概述 ............................................................................................................................... 139 详细介绍 ............................................................................................................................... 139

11.1.1. 会计平台注册 ............................................................................................... 140 11.1.2. 代码调用 ....................................................................................................... 146

12. 单点登陆 ....................................................................................................................... 147

内容概述 ............................................................................................................................... 147 详细介绍 ............................................................................................................................... 148

12.1.1. 单点登陆 ....................................................................................................... 148 12.1.2. 打开代办事项 ............................................................................................... 151

13. NC开发webservice-Axis ............................................................................................ 152

内容概述 ............................................................................................................................... 152 详细介绍 ............................................................................................................................... 152

13.1.1. 发布webservice ............................................................................................ 152 13.1.2. 客户端代码调用 ........................................................................................... 156 第四篇 附录 ................................................................................................................................. 157

14. XML和EXCEL ........................................................................................................... 157

内容概述 ............................................................................................................................... 157 详细介绍 ............................................................................................................................... 157

14.1. 利用XmlUtils读取XML ............................................................................ 157 14.2. Excel文件读写 ............................................................................................. 163

15. 多语言 ........................................................................................................................... 164

内容概述 ............................................................................................................................... 164 详细介绍 ............................................................................................................................... 164

15.1.1. 生成资源文件 ............................................................................................... 165 15.1.2. 代码调用 ....................................................................................................... 165

16. 补丁与安装盘 ............................................................................................................... 166

内容概述 ............................................................................................................................... 166 详细介绍 ............................................................................................................................... 166

16.1. 安装盘结构 ................................................................................................... 166 16.2. 产品结构 ....................................................................................................... 167 16.3. 模块结构 ....................................................................................................... 167 16.4. 制作补丁 ....................................................................................................... 170

17. 设计开发规范 ............................................................................................................... 173

内容概述 ............................................................................................................................... 173 详细介绍 ............................................................................................................................... 173

3

用友软件股份有限公司

17.1. SQL规范 ...................................................................................................... 173 17.2. java开发规范 ............................................................................................... 176

18. 开发常见问题与技巧 ................................................................................................... 189

内容概述 ............................................................................................................................... 189 详细介绍 ............................................................................................................................... 189

18.1. 环境变量类 nc.ui.pub.ClientEnvironment................................................... 189 18.2. 发送待办消息 ............................................................................................... 191 18.3. 模板中下拉框的值 ....................................................................................... 192

4

用友软件股份有限公司

第一篇 入门篇

欢迎您成为用友NC开发队伍中的一员!如果您从未接触过NC的开发,本篇将从NC产品使用开始,序渐进的带您步入精彩的NC产品世界.本学时教程是在完成NC产品使用入门阅读的最佳起点。在开始学习之前,您需要掌握以下基本技能:

? Eclipse使用

? JAVA和JE22基础知识

本学时教程中将会讲述以下内容:

NC产品入门,本章旨在为那些对NC尚不了解的新进人员就NC的大体形态做个简单的讲解,以便对NC产品有个简单的认识,并学习到与NC产品二次开发有关的产品操作技术入门知识。

开发环境的安装和搭建,本章是为第一次使用NC的人员做准备,达到迅速的安装和搭建NC环境。

NC技术框架简介,本章您将会学习NC技术框架理论概念,通过学习范例代码掌握VO\BO\远程接口的概念。

NC5.X的数据建模,使用PowerDesigner进行数据库建模。

1. 建立NC环境

内容概述

第一次在NC环境中做开发,需要首先建立一个数据库环境,这个数据库环境中指定了NC所要使用的表空间,并预先建立了NC的系统表、视图、索引等,并预置了大量的初始化数据。然后,在Eclipse中建立一个开发项目,引用UAP的jar包即可。经过这两步,就完成了NC开发环境的建立。

NC环境安装完成后还需要对系统进行初始化,包括参数,组织结构,权限,基本档案的建立,这样一个系统才算真正可以使用。

5

用友软件股份有限公司

详细介绍

1.1.1. 建立数据库

在数据库服务器(Oracle,MS SQLServer,DB2)中新建一个空数据库,并执行数据库脚本建立NC需要的表空间,不同的数据库使用的脚本不一样(正式安装盘下有安装说明),以MS SQLServer为例:假设新建的数据库叫ncdemo,MS SQLServe的数据文件存放在D:\Microsoft SQL Server\data 下,那么数据库脚本为

6

用友软件股份有限公司

安装NC

该步骤的目的是建立NC测试服务器,并利用它建表,并初始化数据表。 运行UAP V5安装盘 下的ncsetup.bat文件,会进入下面的安装向导:

1) 选择NC服务器端环境根目录:

2) 选择要安装的UAP产品模块:

3) 开始NC环境的安装

7 1.1.2.

用友软件股份有限公司

4) 选择第三方中间件,如果没有则默认使用NC自带中间件。

执行完此向导后,可以在你指定的NC_HOME目录中创建NC服务器端环境,如下图:

8

用友软件股份有限公司

1.1.3. 配置启动NC

1)在NC_HOME\BIN 目录下运行ncSysConfig.bat,首先需要建立数据源。

2)部署代码,NC5.X需要通过部署生成Ejb代码,否则程序无法使用。所以在添加数据源后必须部署产品,选择需要部署的模块,点击部署按钮。

9

用友软件股份有限公司

3)修改服务器端口,可以在server页签修改web服务器的端口

4) 下面启动NC自带的中间件,方法是在上面的NC_HOME目录中双击startup.bat,中间件即可启动,启动界面如下:

10

用友软件股份有限公司

5) 利用InternetExplore作为客户端登陆,在地址栏输入即可看到下面的界面:输入用户名root,密码为空,登陆到系统管理帐套中

6)帐套管理里面新建帐套,用户。

前面建立了NC要使用的数据库,并为数据库设置了表空间信息,但这还不够,还必须为其安装NC的系统数据表和初始化数据。方法是点击上面 帐套管理 页面的“升级帐套”按钮,开始进行数据表的建立和初始化,如下图:

11

用友软件股份有限公司

然后开始初始化:

12

用友软件股份有限公司

至此,NC数据环境已准备好。注销后再登陆到”学习帐套”,即进入了真正的NC系统,如下所示:

1.1.4. Eclipse中建立NC开发环境

在上一个步骤中,演示了怎么搭建NC的数据环境和测试环境,但作为开发人员,日常的工作都是在Eclipse开发环境中进行。在Eclipse中建立开发环境分下面几个步骤:

1.在Eclipse插件中加入NC开发所需的MDE插件(nc.uap.mde.editor_1.0.1.jar和

13

用友软件股份有限公司

nc.uap.mde_1.0.2.jar),这些插件可以在 相关工具\Eclipse_NC插件 中找到,拷贝到eclipse安装路径下的plugins目录下即可。

2.取得NC_HOME,NC_HOME包含了开发环境所需的所有jar包, NC_HONE就是安装完NC产品的主目录。通过Preferences中MDE Development 中设置NC Home。 还可以设置数据源,模块选择。

3.打开Eclipse,点击菜单“新建/项目”,弹出下面的对话框:

14

用友软件股份有限公司

选择MDE Development下的Moudle Project即可。

4.点击下一步,开始创建Moudle Project,在下面的对话框中填入信息:

5.点击完成后,会创建项目,形成下图所示的目录结构:

15

用友软件股份有限公司

6.至此,开发环境已建立完毕。在开发环境中调试程序,一般需要首先启动NC中间件,然后启动UAP客户端调试器。下面我们在eclipse调试器中建立这两个程序:

建立中间件调试启动点,方法是在调试点管理界面左边列表的Module Application下新建一个调试点,MDE插件会为它设置默认参数,我们只需改变一下调试点名称,如下所示:

16

用友软件股份有限公司

program arguments设置如下:

${FIELD_NC_HOME}/ierp/bin/prop.xml -Dnc.server.location=${FIELD_NC_HOME} -DEJBConfigDir=${FIELD_NC_HOME}/ejbXMLs

-DExtServiceConfigDir=${FIELD_NC_HOME}/ejbXMLs

VM arguments设置如下:

-Dnc.server.location=${FIELD_NC_HOME}

-DEJBConfigDir=${FIELD_NC_HOME}/ejbXMLs

-DExtServiceConfigDir=${FIELD_NC_HOME}/ejbXMLs

Working directory

选择Other 内容为 ${FIELD_NC_HOME}

启动中间件快捷方式是在工程点击右键,在run as出点击NC Milldeware就可以。

建立UAP客户端调试器启动点,该调试器的入口类是nc.starter.test.Jstarter,因此可以新建一个 Java Application类型的调试点,输入入口类,如下所示:

在设立这两个调试点之后,要注意两个问题:一是你的项目所使用的JRE的安全

17

用友软件股份有限公司

策略必须是:

这可以通过修改 {$JRE根目录}/jre/lib下的java.policy文件来实现,否则在启动中间件时会出现java.security.AccessControlException;二是要成功运行UAP客户端调试器(JStarter),必须将jre/lib下的plugin.jar,Tools.jar也加入到项目默认的JRE的classpath中,如下所示:

此时即可先启动中间件,再启动客户端调试环境。客户端调试环境启动图如下:

18

用友软件股份有限公司

上面显示连接的是本机中间件,如果在远程有中间件,填入其IP和端口,也可用

于调试开发环境中的客户端代码。点击“Start”按钮后即可进入NC登陆界面,如

下所示:

至此,NC的环境完全建立起来。

1.1.5. 产品参数,档案初始化

利用NC-UAP进行开发的时候并不是做一个单据,报表就可以运行的,NC作为一个ERP软件,需要对系统进行一些初始化才可以正常运行,主要是对组织机构,人员,权限,会计期间,参数,档案的初始化。(本节只对这些设置进行简单描述,详细介绍可参考相应产品手册,比如基本档案,权限手册)

? 参数

在 NC 管理软件中,参数设置平台管理系统所有的参数,并对参数按实际需要进行逐级分配,实现既能统一控制,又能满足单位灵活运用。参数包括公共参数和业务参数,以集团进入还是以公司进入看到的参数设置界面内容是不同的。主菜单中双击【客户化】-【参数设置】:

19

用友软件股份有限公司

必须设置的参数是集团本位币。

? 币种

对于全集团用到的币种在本功能中进行设置。总公司或上级单位确定集团公司或所属下级单 位使用的全部币种,包括本位币。币种设置完成后,集团公司所有内部单位还需在各自单位 账中录入相应的主辅币信息及汇率信息,待这些信息录入完毕后,方能在日常业务使用的这 些币种。在主菜单中双击【客户化】-【基础数据】-【币种】,系统将弹出界面。属于集团档案

20

用友软件股份有限公司

? 会计期间方案和会计期间

会计期间方案用来定义账套拥有的会计期间数目,然后为每个期间方案定义一套会计期间。 在主菜单中双击击【客户化】-【基础设置】-【会计期间方案】

会计期间节点用来定义账套的会计月度和会计季度。启用多账簿的情况下会计期间按照会计 期间方案分别进行设置。

在主菜单中双击击【客户化】-【基础设置】-【会计期间】,

? 公司目录

公司目录用于定义集团公司所有公司的基本信息、联系信息,包括公司编号、名称、联系方 式等相关信息,并确定分子公司之间的关系。以公司身份登陆后,只能查询。

在主菜单中双击【客户化】-【基础数据】-【公司目录】

? 建公司帐

新建公司账是为已经存在公司目录中的公司建账、增补系统模块,以便初始化业务数据及业 务参数,已建账的公司才能处理有关业务。新建公司账还可为已建账公司增补功能节点。 在主菜单中双击【客户化】-【建公司账】-【新建公司账】

21

用友软件股份有限公司

? 基本档案

在基本档案节点为集团和公司建立基本信息,以便于业务系统使用,包括部门、人员、库存、自定义项、组织机构、财务信息、业务信息、制造信息等等。除少数几个档案只能在集团增加外,其他档案受集团参数设置节点的【客户化】中的【基本档案】参数决定,为“是”公司和集团均可增加档案内容,为“否”则公司不能增加。

常见的档案添加比如:部门档案在公司增加,人员类别在集团,人员档案在公司。具体档案初始化参考基本档案产品手册,不一一介绍。

1.1.6. 权限管理

NCV5.0权限管理与之前版本最大的区别在于在权限管理中引入了“角色”概念。先规划好各种角色并分配权限,再将用户与角色关联起来,将角色作为桥梁把“用户”和“权限”连接起来。换句话说就是:通过规划好各种角色先将用户分类,再为各类用户分配权限。

资源权限控制界面用来为当前登录公司以及当前登录公司的下属公司启用按钮权限控制和数据权限控制。

NC系统中的权限由三个部分构成,分别为功能权限、数据权限和按钮权限。功能权限是指节点的查看和打开的权限;数据权限是指档案的参照权限,而按钮权限是只指各个界面上按钮的查看和使用权限。如果不启用权限控制,则不需要分配权限,系统默认角色具有所

22

用友软件股份有限公司

有权限;启用权限控制后,可以为具体的角色分配具体的权限。NCV5.0系统默认启用了功能权限控制,且该设置不可修改;数据权限和按钮权限的权限控制默认为不启用状态,但可在本界面对设置进行修改。

在用户管理界面可以为当前登录公司以及当前登录公司的下级公司增加用户,还可以为在这些公司创建的用户委派角色。用户必须被委托角色才有相应权限

角色管理的界面如图所示。角色管理节点用来为当前登录公司以及当前登录公司的下属公司创建角色,将创建的角色分配给下属公司以及为角色关联用户。

23

用友软件股份有限公司

权限分配的界面如图所示。权限分配节点用来为当前登录公司和当前登录公司下属公司的角色分配功能权限、按钮权限以及档案的数据权限。

经过以上操作可以为公司建立角色,用户,并赋予相应权限。深入的权限管理参考权限管理产品手册。

1.1.7. 产品主要目录结构介绍

ierp/bin: 与整个产品相关的配置文件都存放在该目录,如日志配置文件logger-confing.properties

modules: NC产品模块存放的目录,下面的所有模块在系统启动时得到加载

modules/<模块名>: 某个模块的目录,模块名必须是小写的英文字母,在能表达意义的

24

用友软件股份有限公司

基础上尽量的短

modules/<模块名>/META-INF/module.xml: 必须存在,配置模块的一些通用属性,如名称,描述,classloader等,注意名称必须与模块名称同名

modules/ <模块名>/lib: 模块公开的API类,如接口,接口相关的VO等,放JAR包 modules/ <模块名>/classes:模块公开的API类,如接口,接口相关的VO等,放带目录的.class文件等,用于补丁

modules/ <模块名>/META-INF/lib: 模块私有的代码,如DMO, 业务实现等,放JAR包 modules/ <模块名>/META-INF/classes:模块私有的代码,放带目录的.class文件等,用于补丁

modules/<模块名>/extension/lib,classes: 用于二次扩展的公开的API

modules/<模块名>/extension/META-INF/lib,classes:用于二次扩展的私有的API

modules/<模块名>/client/lib,classes: 用于从目标上来说不属于公共的API,但是客户端用到的代码

webapps/nc_web:NC产品的web应用

hotwebs: 下面放其他的web应用,如hrss, lfw等

resource: 存放与整个产品相关的资源,如产品的多与资源

lib, classes, external/lib, classes: 由平台维护和提供的类库,不允许第三方调整

2. NC基础技术

内容概述

本章将介绍UAP-NC平台的技术结构,开发模型,并通过一个例子亲身感受远程接口开发。

详细介绍

2.1.1. NC UAP 总体介绍

UAP-NC作为基于多组织架构的企业应用运行平台、基于模式化的开发平台、开放的系

25

用友软件股份有限公司

统集成平台及统一的系统管理平台,是建立在Java语言所提供的强大功能的基础上开发的。Java是一种简单的、面向对象的、分布式的、结构中立的、安全的、可移植的、性能优异的、多线程的、动态的开发语言,适合构建基于网络计算的企业应用。由于Java的平台无关性,使得UAP-NC可以运行在不同硬件平台、不同操作系统平台上。基于UAP-NC所开发的应用软件采用Browser/Server(浏览器/服务器)的方式来运行。B/S的运行方式最大限度地方便了用户部署和维护大型软件系统,保证了瘦客户机运行,从而大大降低了用户目标系统的总体拥有成本(TCO)。

UAP-NC体系框架图

系统框架层主要指基础软件,如操作系统、数据库及J2EE应用服务器。UAP-NC支持多种操作系统(Solaris、AIX、Linux、Windows等),可运行于符合J2EE规范的多种应用服务器(IBM WebSphere、BEA WebLogic、UFIDA Application Server等),支持多种数据库DBMS(DB2、Oracle、SQL Server、OSCAR等)。UAP-NC还提供Portal服务器进行内容集成以使用户对企业资源有一个统一的访问点。

技术框架层是在系统框架层(操作系统、数据库及应用服务器)和应用系统之间建立的一层技术封装层和系统资源监控和管理层。技术框架层屏蔽不同具体技术实现的细节,减少

26

用友软件股份有限公司

直接使用系统资源带来的复杂性、异构性、不安全性及不稳定性;技术框架层监控和管理系统资源,保证系统资源的可用性及其合理使用;技术框架层提供最佳编程模式,加快在不同技术平台上开发和部署应用的速度,保证应用的健壮性。技术框架层所屏蔽技术实现细节包括界面风格、远程接入、EJB实现/访问、多数据库适配、事务处理、并发处理、缓存处理、安全管理等等。

? 企业服务架构(Enterprise Service Architecture,ESA)

企业服务架构是一个服务集成总线,支持异构环境的服务、消息及基于事件的交互。通过ESA,可以使用与实现无关的接口来定义服务,可发现和调用所需的服务,可解决服务之间的相互依赖。

? 连接框架(Connect Framework)

连接框架连接客户端与服务器,使不同客户端(浏览器小应用程序、Java应用程

序、浏览器JSP)可通过不同访问协议(HTTP/HTTPS,RMI)使用服务器提供的服务。 ? 同步(Synchronization)

同步服务实现客户端与服务器代码和数据的同步,及集群环境下服务器之间的资源

同步。

? SQL翻译器(SQL Translator)

SQL翻译器将SQL翻译成适合目标数据库的SQL语句,以适配不同数据库厂商提供

的产品;优化SQL,充分发挥不同数据库的最大性能。

? 元数据管理(Metadata Management)

元数据是描述系统数据(包括界面定义、规则定义、流程定义等)的数据。通过元

数据管理,对系统数据统一进行维护以支持用户自定义,如改变字段的可编辑属性、字段的取值范围等。

? 工作流引擎(Workflow)

? 工作流引擎根据工作过程的描述,通过执行一系列已定义的工作项,完成此工作过程。UAP-NC的工作流引擎支持多种工作流模式,如分支、合并、并行、选择、循环、回退等;支持工作项的抢占与会签;支持可配置的动作执行脚本,等等。

? 规则引擎(Rule Engine)

? 规则引擎用来定义和执行各种规则,包括界面规则、关联关系、计算规则、条件跳转规则等。使用规则可以让应用更加富有柔性。规则需要通用的行业化语言精确表达且浅显易懂。规则引擎需要满足一定的计算速度,支持规则的批量处理及理解外部数据。

27

用友软件股份有限公司

? 持久化框架(Persistence Framework)

封装不同持久化技术(如JDBC、普通文件、XML、Excel)。持久化框架可解决对象与关系之间的“阻抗失配”问题。

? 基础算法(Basic Algorithms)

提供统一的基本算法,如排序,XML文档操作,方便开发与编程,统一代码规范。 ? 登录和安全(Login/CA Security)

统一管理系统登录时的身份认证。支持多种身份认证策略,如静态密码认证、基于USB Key的CA身份认证等。支持对业务敏感数据使用证书进行签名和验证以防止数据篡改和提供抗抵赖性。

? 调度引擎(Scheduler)

? 调度引擎对服务和线程进行统一管理,以屏蔽不同应用服务器的异构性。调度引擎调度各种服务、常驻系统服务、客户端的请求服务、以及一些服务的组合。

? 异常(Exception)

统一解释与封装异常消息,如不同厂商的数据库异常的不一致。

? 缓存(Cache)

提供在服务器端与客户端的临时内存中进行缓存的机制,包括对象的创建、共享访问、假脱机(Spooling)、失效等,加快对用户操作的响应。

? 日志(Log)

日志机制提供对系统运行时的监控及支持对系统异常的追踪与定位。日志机制可控制日志输出的格式、日志信息的级别、日志信息输出的目的地(文件、控制台、SocketServer等)。通过配置文件进行灵活的设置,用户可以细致地控制日志的生成过程,而不需修改程序代码。

应用框架层是基于企业建模理论的、以业务导向和驱动的、可快速构建应用软件的软件平台。应用框架层的出现是一种技术创新,它使软件平台多了一个具有革命性意义的战略层次,为降低大型复杂软件系统的实现难度提供了新的途径。将应用软件的业务逻辑和开发技术相对分开,使得应用软件的开发者可以仅关注应用的业务逻辑,而不必关注其繁琐的技术实现。这使管理层与业务人员参与应用软件的开发成为可能。UAP-NC应用框架层基于业务和管理层面,以业务建模(组织、流程、功能、资源、信息)为基本手段,从而构造、开发和维护业务应用系统。使用UAP-NC提供的应用框架层,可大大缩短研发周期,提高研发效率,加快应用开发的速度;减少企业信息系统开发的风险;降低开发成本;实现最终用户的

28

用友软件股份有限公司

个性化的需求;支持用户在发展过程中各种各样的需求变化;提供应用的高价值。

? 国际化(I18N)

实现界面的多语化及数据和展示的本地化。界面的多语化是指根据用户登录时指定的语种显示相应的语言界面。企业用户可以修改相应的语言信息及显示的图片。数据和展示的本地化指日期、时间、数字、货币、汇率等可根据企业用户本地的习惯进行展示。 ? 消息管理(Message Management)

消息管理集中显示通过ESA所传送的消息,如应用系统所产生的预警消息,通知消息,业务流程相关的消息,及企业公告和用户对发消息等。

? 移动管理(Mobile Management)

支持通过移动设备进行消息的交互及操纵业务数据等。对无线设备的广泛支持,UAP-NC带来的是企业管理的无处不在和服务的无限拓展,同时也为企业决策人员提供了高端、迅捷的管理机制。

? 组织管理(Organization Management)

提供从不同维度管理企业,如公司、部门、主体账簿等。

? 数据传输(Data Transfer)

数据传输负责传输以规则定义的数据集以支持数据层的应用集成。

? 数据交换(Data Exchange)

与第三方系统进行数据交换,提供灵活的数据映射及数据绑定,支持根据业务规则的转换,同时结合工作流平台整合业务流程。

? 动态会计平台(Financial Account Platform)

通过定义会计科目类别和凭证模板,使用凭证生成器,根据业务数据生成实时凭证。在保持业务数据与财务数据相对独立的基础上保证数据的一致性和及时性。 ? 预警平台(PreAlert)

? 在预警平台上可定义多种方式的预警条件以进行形式多样的预警,如时间条件、库存大小、生日等。预警还可配置在用户登录时触发。预警消息可以用HTML网页的形式发布,可以通过邮件发布,还可使用短消息发送。

? 业务流程和审批流程的编排(Business Process and Approval Flow

Orchestration)

用来定义业务流程和审批流中数据的流向,数据间的关系及以人员的关系。

? 访问控制(Access Control)

29

用友软件股份有限公司

使用基于用户角色和对象权限的权限分配方式。每一角色都包含公有权限和属于某一具体公司的私有权限。角色还提供信任功能。

? 应用模式(Application Patterns)

UAP-NC根据经验积累与用户实施,总结出一套与应用界面相关的模式(表单、报表和打印),更好地提供满足用户需求的界面展现,更快地满足用户个性化的需求。

UAP 部署图

2.1.2. NC开发中的一些基本概念

单据:比如报销时的报销单,一般由表头和表体组成(有些时候还含有表尾)。表头中包含了单据的主信息,比如日期、部门、预算项目;表体包含了单据的明细信息,比如具体的事项和金额;

单据类型:一个业务系统为了使结构更清晰,通常也是分层的。比如,供应链系统包含了采购、库存等子系统,每个子系统都具有一个系统类型,而每个子系统都会具有很多张单据,为了区分这些单据,为每张单据命名一个单据类型,作为唯一标识;

30

用友软件股份有限公司

模板:单据开发涉及到三大模板(单据模板、查询模板、打印模板)。单据模板定义了单据的显示外观和基本框架,查询模板定义了单据的查询对话框,打印模板定义了单据信息打印到打印机的样式和格式;

VO是ValueObject的简写,在NC中是一个抽象类,它实现了Cloneable和Serializable接口。是NC业务数据的载体在系统各层之间传递业务数据。

CircularlyAccessibleValueObject是ValueObject的子类,提供了对自身的属性进行存取操作的方法。

SuperVO是CircularlyAccessibleValueObject的子类,是NC系统中最常使用的VO类型,它与一张数据库表对应,可以方便的利用NC的JDBCFramework进行持久化操作。

以上是对一个数据对象的抽象,在NC产品中,绝大部分功能是通过单据的形式提供的,而NC的单据大部分是一对多的关系,我们称之为一个主表记录对应多个子表记录。

AggregatedValueObject就是用于存储一对多关系的主子表数据。对于一主多子的情况,实现IExAggVO接口。

聚合VO:单据一般由表头和表体构成,因此单据的数据表通常设计成主表和子表。聚合VO是对单据数据的抽象,它用于装载主表VO和一组子表VO.;

UI工厂:虽然能通过三大模板定义出单据的显示,但每张单据都有一些公共的或特殊的行为。UI工厂是一种单据开发框架,它将常用单据抽象成了很多类型,因此,UI工厂相当于是单据开发的代码模板,预置了单据的各种公共行为,比如增、删、改、查,并且可以连接到NC流程平台,支持审批、单据驱动等应用。

远程接口:V5远程组件开发都是基于接口(替代原先的BO访问),访问也都是基于接口。

参照:是一种辅助的数据输入方式,通常弹出界面的形式提供可以参考的数据,比如在录入省份信息时,提供一个全国省份列表以供选择。单据开发中,有很多输入字段存在类似的需求。NC系统中预置了很多种常见参照(基本覆盖了所有的基本档案,比如人员参照,存货参照),如果要自定义一种参照,则需要简单的开发工作。

ToftPanel:提供对NC产品功能节点开发的支持,统一功能节点的注册类型(ToftPanel)。提供了节点开发过程中按钮的注册机制以及按钮与界面的互动机制(通过ToftPanel的onButtonClick(bo)方法进行事件响应)。节点打开时,真正运行的是FramePanel实例,它提供了ButtonBar进行按钮展示,TitlePanel进行节点标题的显示,同时将用户开发的ToftPanel子类放置到中心位置进行展现。下图是ToftPanel区域介绍:

31

用友软件股份有限公司

2.1.3. NC的开发模型

系统前端为客户端UI代码,UI端代码继承ToftPanel,UI代码通过调用远程组件与服务器端进行交互,中间传递的数据模型为VO,远程组件调用底层的业务实现代码,完成整个交互逻辑。通过JDBCFramework,系统提供了一套良好的数据持续机制,解决数据库交互的复杂问题。

下图是NCV5的代码结构图

32

用友软件股份有限公司

NC5后将代码分区域存放:

? Public目录存放 接口和公共代码(比如VO和公共算法)

? Private目录存放 实现和其它实现细节

? Client目录存放 客户端代码

? gen 目录存放 工具生成的ejb代码

? META-INF目录存放模块配置文件目录,包括module.xml文件和xxx.module

接口配置文件。

针对上面的开发模式,我们规范一下代码的包结构:

33

用友软件股份有限公司

? nc.itf.<模块>: 表示该模块定义的接口

? nc.impl.<模块>:表示该模块定义的接口实现

? nc.vo<模块>: 表示VO的实现

? nc.bs.<模块>: 普通的后台应用

? nc.ui.<模块>.*: 客户端代码

2.1.4. 开发远程接口

V5.0版本的远程组件开发是基于接口,因此远程组件的开发按照下面两个步骤开发: 定义远程接口,注意这里的远程接口不用实现java.rmi.Remote接口,普通接口就可以了 对该接口进行实现

把该组件部署为远程组件

下面以HelloWord为例子:

? 定义接口

? 实现该接口

?

部署组件

编辑或新建该产品模块下的模块部署描述文件(META-INF下的.module文件),加入一个公共组件:

34

用友软件股份有限公司

远程组件只要指出他的remote属性为true即可。

? 客户端调用

接下来客户端就可以通过下面的方式进行远程访问了:

系统输出:

你的一个实现可以同时实现多个接口,并且可以在部署的时候选择性的公布出你需要远程分布的接口,例如你的一个实现类,实现了多个接口IService1, IService2, IService3,你可以选择只远程公布接口IService2, IService3,部署信息如下:

35

用友软件股份有限公司

注意我们使用了supportAlias属性,指出我们可以通过两个接口中的任何接口进行远程组件的查找。supportAlias为true只有在公共组件中才起作用。

? 事务型组件发布

定义远程接口,就是普通接口,分有事务和无事务,区别在于部署文件时 放在private下而不是public下,部署成private的接口需要生成ejb代码,否则无法调用,部署成public的代码不需要生成ejb代码。一般来说,增删改操作发布成private接口,查询发布成public接口。下面是两种接口的发布事例:

配置文件规范:

36

用友软件股份有限公司

对于事务型的组件 (是指该组件的方法调用中事务处理会自动参与 )可通过后缀名来判断事务类型:

方法名后缀RequiresNew: 新事物

方法名后缀Mandatory: 必须在一个已有的事务环境中运行改方法

方法名后缀Supports: 只是支持事务,不建议使用

方法名后缀NotSupported:不支持事务,不建议使用

方法名后缀Never:不能有事务,否则出错

37

用友软件股份有限公司

没有方法名后缀: 如果有事务,就在该事务环境下工作,否则新启事务,这是大部分事务型组件的情况

事务型组件一般都是针对数据库等事务性资源进行操作,如果没有对事务性资源进行操作,请不要把组件定义为事务性组件。

对于发布成private的组件,需要点击xxx.module部署文件,在代理组件生成页签,选择需要发布的接口,输入ejb名字,点击生成就可将代码生成到gen目录下。只有这样,才可以调用private的接口。安装nc产品后通过sysconfig部署代码操作也是这个过程。

? 客户端代码

客户端调试代码可以通过junit和注册Toftpanel来实现。

通过junit运行调试接口比较方便,不需要进行客户端登陆。新做一个类继承AbstractTestCase,实现一个以test开头的方法,在方法里面写调用远程组件的方法。然后以JUnit来运行。

Toftpanel方式是写一个ToftPanel的子类,将此类注册成nc节点,然后通过eclipse启动jstarter来进入nc,点击相应节点执行相应方法。通过扩展ToftPanel,实现getTitle()方法,在postInit()方法中初始化界面,调用

38

用友软件股份有限公司

setButtons(ButtonObject[])方法设置菜单,实现onButtonClicked(ButtonObject)方法响应菜单事件。

39

用友软件股份有限公司

3. 数据建模

内容概述

通过PowerDesigner进行数据库模型,建表,建数据字典,生成VO。为以后的单据,报表开发提供数据模型。

详细介绍

3.1.1. PowerDesigner建模

安装数据库设计工具:Sybase PowerDesigner Version 9.5.0.648(以下简称PD) 为了给数据表自动生成时间戳(ts)、删除标志(dr)字段,需给PD打上插件补丁(将三个补丁文件db2cs7.xdb,oracl8i2.xdb,sqlserv7.xdb全部拷贝到PD的安装目录的 Resource Files\DBMS 下即可)。如果没有补丁,在建表的脚本处需要手工增加下面两个字段。Ts字段是时间戳,供系统判断修改时使用,dr字段是删除标记,NC系统单据表删除时并不是物理删除,而是更新dr字段为1。

ts char(19) null default convert(char(19),getdate(),20), dr smallint null default 0,

PD是一种高端的数据建模工具,使用它可以很方便的建立数据库、导出SQL脚本,其物理模型文件的后缀名为pdm,所以,NC辅助开发工具多处依赖PD来完成数据库相关操作。

? 数据模型

我们的员工信息管理系统包括员工的基本信息,员工的类别信息,员工工资,为了增强系统的可扩展性,从员工基本信息中独立出员工的家庭住址信息,街道信息。下图显示了实体间的关系。

40

用友软件股份有限公司

? 生成pdm步骤

第一步、打开PD文件夹中的可执行文件pdshell9.exe,启动PD,会出现如下界面,选择新建一个物理模型。

第二步、我们以MS SQL Server数据库为例,选择数据库为Miscrosft SQL Server 7.x,注意,由于补丁文件只针对SQL Server 7.x版本,所以,无论我们用SQL Server 7.x还是2000或以上版本,此处的DBMS都要选择SQL. Server.7.x。

41

用友软件股份有限公司

第三步、确定后左侧面板中会出现一个节点,双击弹出如下对话框,设置此模型的name,code等

第四步、在新建节点上点击右键选择 New->Table

42

用友软件股份有限公司

第五步、在General选项卡中,设置表名,表的中文描述

第六步、在Columns选项卡中定义列,列的中文描述。注意此处列的数据类型,一般地,

43

用友软件股份有限公司

主键前缀为pk_,数据类型为char(20),boolean类型的列前缀为b,数据类型为char(1),日期类型前缀为d,数据类型为char(10),等等,更多数据库表字段命名规范参照附录开发规范文档。

第七步、保存到指定目录,便得到pdm文件

? 生成SQL脚本步骤

第一步、选择菜单项 Database -> Generate Database ?

44

用友软件股份有限公司

第二步、在弹出界面中,设置生成脚

45

用友软件股份有限公司

第三步、对Keys & Indexs 选项卡做如下设置,注意,取消除主键外的所有选项,因为此时我们没有这些选项信息

46

用友软件股份有限公司

第四步、取消 Database 选项卡中的所有选项

47

用友软件股份有限公司

第五步、按下确定按钮后,便生成了SQL脚本

将生成的Sql脚本在数据库中执行,建表完成。

3.1.2. 生成NC数据字典

数据字典是NC二次开发工具中探测数据库表结构的数据基础,而不是采用每次需要数据都连接数据库的方式。数据字典由上一步骤生成的pdm文件生成,NC二次开发工具提供了相应的生成工具。在节点客户化-二次开发工具-系统管理工具-数据字典

48

用友软件股份有限公司

选择菜单项 工具 -> 导入数据字典

选择pdm文件,按照向导就可以将表结构导成数据字典。

第二篇 中级篇

经过入门篇的学习,你已经初步了解了NC的环境,使用和技术规范。但是离真正的业务开发还差很远,通过本篇的学习,你将真正进入NC的业务开发,了解NC单据的开发,

49

用友软件股份有限公司

数据库操作,报表等技术,通过本章的学习,你将可以具备实用的需求业务开发能力。

4. 单据开发

内容概述

NC中最重要的概念就是单据,几乎大部分业务数据录入都是通过单据完成,所以单据开发是NC中最重要的技术。单据开发中重要的技术是单据模板和UI工厂。我们开发可以通过集成开发工具向导完成初步开发,经过集成开发工具设计的单据,已经可以完成日常的操作,比如增删改,审核等工作,如果有需要,可以把集成开发工具生成的代码导出到eclipse,然后继续修改,完成复杂业务逻辑功能。

UAP发展到现在,已经提供了不少二次开发工具和其他辅助性开发工具,更重要的是,也同时积累下来了一些标准的开发流程。作为NC内部和外部的开发者,通常的疑惑是如何使用这些工具,以及标准开发流程到底是什么(比如在表单开发中,何时该导入数据字典,何时配置单据模板)。NC集成开发工具(UAP Developer Workshop)的目标就是:集成UAP现有的所有二次开发工具,对其进行一定的组织;集成内置标准开发流程的(具有增值性)开发工具,比如表单开发工具、报表开发工具,以插件的形式组装起来。

详细介绍

4.1.1. 进入Workshop

登陆到NC后,点击功能节点 客户化/二次开发工具/UAP集成开发工具,可打开下面的页面:

50

用友软件股份有限公司

点击最左边的图标即可进入UAP集成开发工具中,主界面为:

Workshop一共分为6个区域:

菜单区:显示所有操作菜单;

1) Toolbar区:与菜单相互为补充,提供快捷操作方式;

51

用友软件股份有限公司

2) 导航区:内置三种导航视图,每个导航视图都针对一种开发人员要操作的对象,比如在

功能节点导航中,开发人员的操作对象是NC功能节点,在流程导航中,开发人员的操作对象是NC单据类型,在工具导航中,开发人员的操作对象是UAP对外提供的二次开发工具;

编辑区:它是开发人员做各项配置的区域,比如进行表单开发、单据交换配置等,分为多个可切换页签;

3) 视图区:提供一些用于展示信息的面板,比如功能节点的属性信息,表单信息的透视图

等;

状态区:显示当前操作状态。

Workshop对原来客户化/二次开发工具下的节点进行了组织,将其放入工具导航中。如下图:

4.1.2. 表单开发流程导航工具

Workshop目前提供的包含标准开发流程的增值性工具是表单开发工具,它能通过一个开发向导,辅助开发人员配置一张表单的所有信息,最后生成UI工厂代码。下面演示在开发环境中从头至尾制作一张基本档案:

针对新的二次开发项目,需要在Workshop中新建一个项目,点击菜单项 新建/项目,打开

52

用友软件股份有限公司

下面的对话框:

在上面填入项目信息,根节点编码是项目的根功能节点编号,项目编码对应NC的系统类型编码,项目名称对应NC的系统类型名称,如下所示:

点击确定后在左侧的功能节点导航中即可看到新增加的DEMO节点(注意事项:客开的根节点必须以H开头比如H1,否则会有产品授权问题导致无法打开节点),选择它后点击菜单中的 新建/功能,弹出下面的对话框:

53

用友软件股份有限公司

在上面的对话框中填入功能节点编码,功能节点名称和入口类名,然后在左侧的功能类型列表中选择基本档案(如果单据需要相关流程操作,就需要选择有单据类型的,可以新建一个单据类型),最后选定这张表单的界面类型(卡片界面一般作为录入使用,列表界面作为浏览查询使用,一般选择管理界面),如下所示:

点击确定后此新增节点即可在功能节点导航树中显示,如下所示:

54

用友软件股份有限公司

双击此节点,即在编辑区打开一个表单开发向导,如下所示:

在第一步中,只显示一些单据基本信息,点击下一步,设置单据数据信息,如下:

55

用友软件股份有限公司

在此界面中,点击增加按钮选择表单的主表和子表(也可以只选择单表,对于单表头,单表体的特殊操作可参考下一节UI工厂中介绍),在下方的调整单据值对象信息中会默认为其加上要生成的值对象类的包名和类名。

下一步,设置单据模板信息:

在编辑区选择某个属性控件后可以在右下方的属性编辑区进行属性编辑。可以设置其可见性、是否必输项、参照信息等属性。

56

用友软件股份有限公司

单据模板相应区域,项目上点击右键可以新加项目,项目排序

在高级页签可以设置数据类型,编辑,显示公式。

数据类型选择参照时,可以通过下拉框选择系统内置的参照。

57

用友软件股份有限公司

对于自定义项档案可以选择数据类型是自定义项档案,参照类型输入:{档案名称} 对于自己写的自定义参照,数据类型选择参照,参照类型输入:<参照模型类名(含包名)>

对于一些字段我们可能需要显示公式,编辑公式。显示公式界面加载时会执行,编辑公式在编辑框发生改变时会被执行,表头的公式默认是不被自动执行的,需要在界面初始化时执行如下代码:

getBillCardPanel().setAutoExecHeadEditFormula(true)

getBillCardPanel().execHeadEditFormulas()等对应方法。

下图是公式编辑框,,系统预制很多公式,可以根据需要选择,每个公式界面都会有注释。 ,

58

用友软件股份有限公司

一般使用公式的地方包括计算字段,主键显示名称,控制字段。

这里需要讲下主键显示名称,因为使用NC中单据字段都是保存相应档案的主键,但界面需要显示相应编码或者名称,在录入时可以通过参照,但显示的时候就会出现只显示主键,所以需要通过公式进行转换。对于表头的参照字段,设置显示公式就可以,公式使用getColValue来进行主键和编码,名称的转换(getColValue实际是通过key来查询字段的公式)。对于表体,一般是新增一个表体项目显示名称,高级属性那里设置参照,关键字属性填写实际保存的单据字段,而保存主键的单据字段则进行隐藏,并设置显示公式使得对应新增的项目可以显示编码或者名称。

设置完成后,点击下一步,会提示保存单据模板,填入相关信息即可,如下所示:

59

用友软件股份有限公司

通过右上角通过单据模板生成查询模板,打印模板,报表模板(查询模板需要进行模板权限分配,在集成开发工具的工具导航页签-)模版管理工具-〉模版分配)。 进行单据按钮设置,进入下面的界面:

点击增加按钮,弹出下面的对话框:

60

用友软件股份有限公司

表单开发工具预置了常用的系统按钮,比如新增、查询等,可以直接利用系统按钮参照选取,如下:

确定后这些按钮即可自动添加到表单编辑区左侧和右侧的树中,如下所示:

61

用友软件股份有限公司

左侧的树用于设置按钮属性,右侧的树用于控制按钮的界面显示顺序。

对于有单据类型的单据,需要编译按钮动作脚本,否则单据的按钮无法运行, 需要编译的按钮包括增加,保存,提交,作废,审核,反审核六个,

鼠标点到按钮上,点击右键,选择动作设置,弹出下面对话框,点击确定后进行脚本编译,生成相应动作脚本。(动作脚本存放在nchome\modules\产品目录\META-INF\var\source下,可将代码导入eclipse进行跟踪调试,一般后动作处理后的逻辑也可写入相应脚本)

62

用友软件股份有限公司

下一步,进行单据校验规则设置,如下所示:

上面的表格用于设置编辑或新增单据时,表体内容是否为空。下面的表格用于设置编辑或新增单据时,表体数据的唯一性校验信息。

至此,整个单据配置完毕,点击完成会询问是否将代码自动部署到中间件上,因为目前是在开发环境,所以选择“取消”即可:

63

用友软件股份有限公司

下面,可将刚才开发的单据代码导出。点击菜单项 表单/导出单据源代码,会弹出下面的对话框:

在本地工作区中填入二次开发项目的源代码路径,然后选择确定,代码会生成到这个目录中。

在Eclipse中刷新编译一下,然后点击菜单项的 表单\预览单据,即可打开新开发的基本档案。

64

用友软件股份有限公司

对于部署到服务器,重启中间件后进入集团即可测试相应节点。

4.1.3. UI工厂

UI工厂是一套基于NC-UAP的UI开发框架。它的产生是通过对大量的 业务节点的总结,把常见的UI进行分类,分别抽取其中公有的代码,形成不 同的UI基类。UI工厂综合运用了单据模板,查询模板,打印模板,实现对这 些基本构件的运用的最优化。

UI工厂结构图:

UI工厂最基础类说明:

65

用友软件股份有限公司

单据模型介绍:

66

用友软件股份有限公司

界面加载:

BillCardPanelWrapper 和BillListPanelWrapper

处理卡片式和列表式的单据模板的加载及设置工作。另外这两个Wrapper提供了一些单据模板自身不够完善的功能,比如按行执行公式等等。上述的两个Wrapper是UI工厂的两个重要的基本工具类,但是其也可以被独立于UI工厂使用。只需提供合适的Controller,Wrapper就能完成单据模板的加载和设置。

通过调用getBillCardPanel 可以得到单据模板类的实例,这个Panel可以被放到其他任何Panel或者Dialog中。

事件处理:

67

用友软件股份有限公司

MyEventHandler 中

public void onButton(ButtonObject bo)

private void onBoCommand(IButtonCommand command, ButtonObject bo)

ClientUI中

afterEdit 当单据模板的表头或者表体的某个项目被编辑后会触发该方法。

bodyRowChange当选中卡片模板的表体,列表模板的表头或表体的不同的行时会 触发该方法。BillManageUI中在该方法中实现列表界面的表头选

中一行数据后,显示其子表数据。

beforEdit 当单据模板的表头或者表体的某个项目被编辑前会触发该方法。

集成开发环境生成的UI端的框架类:

5. NC数据库持久化技术

内容概述

在NC中很多时候需要我们直接操作数据库,对数据库德访问NC提供了框架类。 JDBC FrameWork为NC访问数据库提供统一的数据操作访问,简化数据访问操作。 BaseDao是在JDBC FrameWork之上提供数据持久化的工具类。

下图是NC 数据库访问的层次图:

68

用友软件股份有限公司

详细介绍

5.1.1. 核心类介绍:

PersistenceManager

管理连接会话的生命周期,并提供了对单表VO操作的常用实现可以传递构造参数选择不同的数据源

JdbcSession

对JDBC的API封装和简化

SQLParameter

封装执行SQL的参数

ResultSetProcessor

结果集处理回调接口,封装结果集处理

DbException

封装不同数据库的异常,和统一处理不同数据库的Error Code BaseDAO / IUAPQueryBS / IVOPersistence

管理连接会话的生命周期,提供了对单表VO操作的常用实现

69

用友软件股份有限公司

5.1.2. 通过JDBC FrameWork访问数据库

通过代码和注释来看如何通过JdbcSession访问数据库 PersistenceManager sessionManager=null;

try {

sessionManager =PersistenceManager. getInstance ();//构造参数可指定数据源 JdbcSession session = sessionManager. getJdbcSession ();//开始jdbc会话

String sql = "update bd_invmandoc set pk_invmandoc ='0001AA10000000000DDD' where pk_invmandoc=?”;

SQLParameter parameter = new SQLParameter(); 构造参数对象

parameter.addParam("0001AA10000000000DDD");添加参数,JdbcSession会将参数对象中的每个对象放入到预处理对象的相应位置

session.executeUpdate(sql,parameter);

} catch (DbException e) {

//根据数据库的不同统一异常处理

if(e.isBadSQLGrammar())//如果是语法错误

//to do 相关处理

if(e.isDataIntegrityViolation())//如果是数据一致性错误

//to do 相关处理

}

}

finally {

if(sessionManager!=null)

sessionManager. release ();//需要关闭会话

}

下面是几种参数语法介绍:

1.无参查询

String sql = "select * from bd_deptdoc"; //构造查询语句

List list = (List) session.executeQuery(sql, new ArrayListProcessor());

70

用友软件股份有限公司

2.有参查询

String sql = "select * from bd_deptdoc where dept_code=?";

SQLParameter param = new SQLParameter(); //构造参数对象

param.addParam(“aaa”); //添加参数

List list=(List) session.executeQuery(sql, param, new ArrayListProcessor());

3.有参更新

String sql = "update bd_deptdoc set dept_code =?aaa? where dept_code=?”;

SQLParameter param = new SQLParameter(); //构造参数对象param.addParam(“bbb”); //添加参数

session.executeUpdate(sql, param);

5.无参批量更新

String sql = "update bd_deptdoc set dept_code =?aaa? where dept_code=?bbb?";

session.addBatch(sql); //添加需要执行的同构SQL

int rows = session.executeBatch(); //执

6.特殊参数

1. Null参数 param.addNullParam(java.sql.Types.INTEGER);

2. Blob参数 param.addBlobParam (new Object());

3. Clob参数 param.addClobParam (new String());

结果集合的处理:

对查询结果集合的处理,主要由ResultProcessor类来实现,这是一个接口 ResultProcessor包含有一个简单的方法,不同的ResultProcessor实现返回不同的结果对象。系统提供了一系列常用的默认实现。

71

用友软件股份有限公司

ArrayProcessor 数组处理器,返回一个对象数组,结果集中只有一行数据,其中结果集中每一列对应数组的一个元素。

ArrayListProcessor 数组集合处理器,返回一个ArrayList集合,集合中的每一个元素是一个数组,每个数组对应结果集中的一行数据,其中结果集中每一列对应数组的一个元素。 MapProcessor HashMap处理器,返回一个HashMap, 结果集中只有一行数据,其中结果集合中每一列的列名和列值对应HashMap的一个关键字和相应的值。

MapListProcessor HashMap集合处理器,返回一个ArrayList集合,集合中的每一个元素是一个HashMap,每个HashMap对应结果集中的一行数据, 其中结果集合中每一列的列名和列值对应HashMap的一个关键字和相应的值。

BeanProcessor 值对象处理器,返回一个JavaBean,结果集中只有一行数据,该处理器能自动把结果集中的值按列的名称映射到javaBean中,如结果集中有名称为”name”的字段,那么只要该java对象中有getName()方法就能把结果集合中”name”对应的值映射到对象中。 BeanListProcessor值对象集合处理器,返回一个ArrayList集合,集合中的每一个元素是一个javaBean,每个javaBean对应结果集合中一行数据,其中每个JavaBean中的数据映射关系和BeanProcess同理。

还有ColumnProcessor ,BeanMappingListProcessor ,BeanMappingProcessor几个类 BeanListProcessor作为结果集的例子:

ArrayList list=(ArrayList) session.executeQuery(sql, param, new BeanListProcessor(TrainReqmatbillVO.class)); // TrainReqmatbillVO是一个普通vo类

72

用友软件股份有限公司

int listcount = list.size();

TrainReqmatbillVO[] vos = new TrainReqmatbillVO[listcount];

for (int i = 0; i < vos.length; i++) {

}

vos[i] = (TrainReqmatbillVO)list.get(i);

5.1.3. 通过BaseDao进行对象的持久化

通过持久层框架可以很方便的实现把内存中的对象持久化到数据库、把数据库中的关系数据加载到内存中。作为入门的一个例子,我们使用一个简单的Java Bean Person类(注意需要进行持久化的VO类必须符合Java Bean规范)

1.前台数据访问:

使用IVOPersistence服务组件,进行增删改操作;

使用IUAPQueryBS服务组件,进行查询操作。

IUAPQueryBS iUAPQueryBS = (IUAPQueryBS)NCLocator.getInstance().lookup(IUAPQueryBS.class.getName()); iUAPQueryBS. executeQuery()

2.后台数据访问 :

使用BaseDAO工具类

3.对象读取

BaseDAO dao=new BaseDAO();//构造参数可以指定数据源

PersonVOMeta meta=new PersonVOMeta();

dao.retrieveByClause(Person.class,meta,"id=5");

4.对象写入

BaseDAO dao=new BaseDAO();

Person person=new Person();

person.setName(“tom”);

73

用友软件股份有限公司

person.setAge(“20”);

PersonVOMeta meta=new PersonVOMeta();

dao.insertObject(person,meta);//默认会为Person对象生成主键

类说明

Person是普通值对象, PersonVOMeta映射元数据类 实现IMappingMeta 接口,用于影射值对象和数据库关系,SupperVO不需要实现影射类

5.1.4. 结果集控制

在NC持久层中为了防止执行大查询后返回结果集合过多导致系统内存溢出系统默认设置了最大返回结果集行数是10万行,如果如要返回更多行数或者不限制返回行数,需要做如下设置:

在SuperDMO中设置返回行数

SuperDMO superDmo=new SuperDMO();

superDmo. setMaxRows(行数);

如果rows= -1表示不限制返回行数

在BaseDAO中设置返回行数

BaseDAO baseDao=new BaseDAO();

BaseDAO. setMaxRows(行数);

如果rows= -1表示不限制返回行数

在ResultsetProcessor中设置返回行数

BaseProcessor processor=new ArrayListProcessor();

Processor. setMaxRows(行数);

在结果集中设置返回行数

CrossDBResultset resultset=( CrossDBResultset)rs;

Resultset.setMaxRows(行数);

74

用友软件股份有限公司

6. 单据开发其他相关技术

内容概述

在NC中进行单据开发时,除了单据模板等技术,还有很多使用的技术,比如单据号,参照开发,公式,日志等,这些技术是单据开发中必备的技术。

详细介绍

6.1.1. 参照开发

6.1.1.1. 参照的类结构图

UIRefPane是NC参照的界面模型,refmodel是参照的数据模型

NC系统中存在大量的基本档案,与之对应,每种基本档案都配置了相应的参照。 下面初始化一个系统默认参照的方法:

UIRefPane是一个控件

UIRefPane ref = new UIRefPane();

Ref.setRefNodeName(nc.vo.bd.ref.RefNodeNameConst.DEPTDOC);//部门档案

这样就定义好了一个部门档案参照。

系统提供的RefNodeName请参见nc.vo.bd.ref.RefNodeNameConst

75

用友软件股份有限公司

6.1.1.2. 自定义参照开发规范

参照分为表型、树型、树表型参照三种。继承了UIDialog并实现了IRefUINew接口。 程序员可自定义参照界面,最好也继承UIDialog,须实现IrefUINew接口。

对应与3种类型的参照,Model也有3个抽象类:

表型: AbstrarctRefModel

树型 AbstractRefTreeModel

树表型 AbstractRefGridTreeModel

要自定义不同类型参照Model ,请继承相关的抽象类。

下面以CashflowrefModel来学习自定义参照的开发: /**

* 此处插入类型描述。

* 创建日期:(2004-3-3 13:42:55)

* @author:

*/

public class CashflowrefModel extends nc.ui.bd.ref.AbstractRefModel {

/**

* CashflowrefModel 构造子注解。

*/

public CashflowrefModel() {

}

/**

* 显示字段列表

* 创建日期:(01-4-4 0:57:23)

* @return java.lang.String

*/

public java.lang.String[] getFieldCode() {

} return new String[]{"cfitemcode","cfitemname"}; super();

76

用友软件股份有限公司

/**

* 显示字段中文名

* 创建日期:(01-4-4 0:57:23)

* @return java.lang.String

*/

public java.lang.String[] getFieldName() {

return new String[]{nc.ui.ml.NCLangRes.getInstance().getStrByID("10081812","UC000-0003279")/*@res "编码"*/,nc.ui.ml.NCLangRes.getInstance().getStrByID("10081812","UC000-0001155")/*@res "名称"*/}; }

/**

* 主键字段名

* @return java.lang.String

*/

public String getPkFieldCode() {

}

/**

* 参照标题

* 创建日期:(01-4-4 0:57:23)

* @return java.lang.String

*/

public String getRefTitle() {

return nc.ui.ml.NCLangRes.getInstance().getStrByID("10081812","UC000-0002922")/*@res "现return "pk_cashflow"; public String[] getHiddenFieldCode() { } return new String[]{"pk_cashflow"}; 金流量项目"*/;

}

77

用友软件股份有限公司

/**

* 参照数据库表或者视图名

* 创建日期:(01-4-4 0:57:23)

* @return java.lang.String

*/

public String getTableName() {

}

} return "bd_cashflow";

实现自定义参照后,在代码中就可以如下调用:

UIRefPane ref = new UIRefPane();

Ref.setRefUI(自定义界面,一般不需定义用系统默认的);

Ref.setRefModel(自定义参照模型,比如CashflowrefModel)

6.1.1.3. UIRefPane 和refModle设置

1. UIRefPane中的设置:

setToolTipText(String);//设置参照控件的toolTip

setMaxLength(int);//设置输入字符的最大长度,默认20;

setEditable(boolean);//设置参照是否可编辑

setEnabled(boolean);//设置参照是否可以使用

setDelStr(String);//设置参照输入框不能输入的字符串。

setColor(Color);//设置参照输入框的背景色。

setCacheEnabled(boolean);// 是否使用缓存

setMultiSelectedEnabled(boolean);//是否允许多选择

setAutoCheck(boolean);//是否自动解析输入的参照数据

setButtonFireEvent(boolean);//按钮选择数据后是否触发ValueChanged事件 setNotLeafSelectedEnabled(Boolean);//非末级节点是否可选择(对树参照有效) setIsCustomDefined(boolean);//是否为用户自定义参照模型

setIncludeSubShow(boolean);//树型参照是否包含下级复选框是否显示

78

用友软件股份有限公司

setMultiCorpRef(boolean);//树表参照是否显示公司选项(在参照中动态切换公司)

setTreeGridNodeMultiSelected(boolean);//树表参照是否允许选择不同树节点下的数据。

2. refModle中的设置

setUseDataPower(boolean) ;//设置参数是否自动关联基本档案数据权限

setSealedDataShow(boolean);//设置封存数据是否显示

setRefQueryDlgClaseName(String);//设置参照查询类名称(参照的查询功能)

setLocQueryEnable(boolean);//树表参照,在启用查询功能后,是否启用定位查询功能 setDynamicColClassName(String);//是否为动态列参照。

setFormulas(String[][] formulas);//设置公,用于参照内容转换;

setDispConvertor(java.util.Hashtable newDispConvertor);//用于参照内容转换的影射表 setMatchField(String);//设置参照setpk时匹配的字段

getRefVO_mlang();//为多语言添加此方法, 请覆盖此方法返回要翻译字段数组。详见DefaultRefModel_multiLang

addWherePart(String);参照在运行中动态添加过滤条件,每次在原始的WherePart上添加

6.1.2. 单据号

在基于UAP-NC的企业管理系统内,根据企业的特点和行业规范,存在着大量的业务单据和基础档案数据,如何标识这些数据?如何自动给每个新的业务单据分配一个唯一的单据号?并且保证单据号规则可以进行配置,可灵活嵌入业务对象、日期、时间及流水编号,还要求单据号可以保持连续,能自动在断号时进行补号,不重号,能处理集群及并发环境下的单据号申请,这些就是单据号管理模块需要解决的问题。

对于使用集成开发工具开发的单据,只需要设置单据号规则单据编辑时就可以取得相应单据号。

6.1.2.1. 单据号规则

单据号编码规则初始是系统预制的,程序员发版前要提供pub_billcode_rule表的初始化脚本。集团可以修改单据号编码规则,而公司只能浏览各单据类型的编码规则。

79

用友软件股份有限公司

1. 单据类型:以树型结构列示出系统内的单据类型。

2. 编码范围:用来控制该单据号是集团统一编码或各公司自成体系或按照对象统一编码。

3. 编码参数控制:如果设置唯一性检查,则申请的单据号不会和自定义单据号重复,唯一性检查范围和编码范围一致;如果单据号保留占用,则删除的单据号不会再利用;如果设置了自动补号,则回退的单据号会被申请得到。

4. 单据类型简称:可以定义单据类型简称作为单据号编码的一部分。这是可选项。

5. 对象:最多可以选择两个对象作为单据号编码的一部分,如部门、仓库、存货分类、人员等。这两个对象也是可选,如果选择了对象,则此对象标识将出现在申请的单据号编码钟,具体的对象标识定义参见下一节。

另外,对于不同的单据类型,其可以选择的对象可能不同,这部分数据是系统预制的。

6. 顺序号:单据编码中,用来表示单据的顺序号的一串数字,包括年月日及流水号。

1) 年:用2位字符来表示。

2) 月:用2位字符来表示。如果选了月,也必须选年。

3) 日:用2位字符来表示。如果选了日,也必须选月。

4) 流水号:流水号的位数可在2位到10位间进行设置,范围从0..1到9..9,例如:如果定义4位,则流水号范围为0001到9999。

5) 流水号归0标志:归0表示流水号到一定时候会再从0开始编号;通过归

80

用友软件股份有限公司

0标志可以控制流水号是否归0或归0方式。

按“日”归0表示流水号按日编码,每天的流水号都从0重新开始;

按“月”归0表示流水号按月编码,每月的流水号都从0重新开始;

按“年”归0表示流水号按年编码,每年的流水号都从0重新开始;

不归0表示流水号一直编号下去,不会归0。

6) 流水号的长度一定要结合编码规则及具体单据的业务量来设置。如果是按年流水的话,流水号位数可以长些;如果是按日流水的话,则流水号可少些。

7. 指定流水号:对于单据号编码范围是集团或公司,如果不希望单据号按照当前的流水号继续编号,则可以对此单据号编码规则重新指定流水号基准号。

8. 生成单据号时检查唯一性,如果选择,那么生成单据号时检查生成的单据号是否与用户自定义号重复,而不检查生成的单据号与以前生成的单据号是否重复,所以建议产品组开发人员在保存单据时自行检查新生成的单据号与现有单据是否重复。唯一性检查范围和编码范围一致。

9. 删除单据号时保留占用:该参数如果勾择,对于自动编号的单据,删除单据号时不会将删除的单据号回退到退号表,再增加新单据时,不会自动补前面的缺号,会自动生成一个新的单据号,但此时如果手工输入删除的单据号,仍可以保存。如果设置了自动补号,则回退的单据号会被申请得到。

10. 自动进行退号补号,如果选择,则生成单据号时会首先到回退表里去取,反之,则会直接生成新的单据号。需要注意的是,自定义号不会回退到退号表,如果发现自定义号被回退到退号表,则说明没用使用单据号申请API去申请自定义号,也就是说自定义号也需要调用API去申请一下,以便单据号模块统一管理。

6.1.2.2. 接口方法

对于非独立事务的业务,原有独立事务回退号方法被删除,不再需要调用,现在只需要关心两个方法:

(1) 独立事务申请单据号,批量:BillcodeGenerater. getBatchBillCodes();非批量:BillcodeGenerater. getBillCode()

(2) 删除单据时非独立事务回退单据号:IBillcodeRuleService.returnBillCodeOnDelete

81

用友软件股份有限公司

对于独立事务的业务,基本用法同上,但是需要额外调用另外3个方法:

(1) 申请单据号区域 IBillcodeRuleService.requireNewRegion(String regionid),用于开始独立事务之前

(2) 释放单据号区域 IBillcodeRuleService.releaseRegion(String regionid),当业务正常结束时,调用此方法释放区域

(3) 停用单据号区域 IBillcodeRuleService.stopRegion(String regionid),当业务非正常结束时,调用此方法固化此区域

注意:(2)(3)方法是互斥的,不能同时被调用,写程序时请注意。

推荐写法:

try

{

//申请特定内存区域

SFAppServiceUtil.getBillcodeRuleService().requireNewRegion(regionid);

//做独立事务业务操作

//释放申请的内存区域

SFAppServiceUtil.getBillcodeRuleService().releaseRegion(regionid);

}

catch (Exception e)

{

//停止申请的内存区域

}

82 SFAppServiceUtil.getBillcodeRuleService().stopRegion(regionid); //异常处理代码

用友软件股份有限公司

6.1.3. 公式

1. 支持一般的算术运算+,-,*,/,?,%

例如: sin(1.35)*a/b + cos(3.4)/c

其中a,b,c均为变量

2. 支持对数值型计算结果小数位的控制

3. 支持逻辑运算符&&(兼容老版&),||(兼容老版|),!

例如: iif((a&b)||(c&&d),"right","wrong")

其中a,b,c,d均为变量

4. 支持比较运算符>,>=,<,<=,==,!=等,支持null值的处理。

例如: iif((a>b && a != null)||(c<=d),"right","wrong")

其中a,b,c,d均为变量

5. 支持自定义变量,变量可按Object和String两种方式传入

例如: col1->var1+var2

其中var1,var2均为自定义变量,可以为String型,也可以为任意类型

6. 公式除了支持String,Number型数据运算,还支持自定义类型

例如: combine(vo1,vo2)

其中vo1,vo2可为自定义的数据类型,具体用法参考后面的说明

7. 支持操作符(+,-,*,/,>,>=,<,<=,==)重载(通过实现相应的接口)

例如: iif((car1>car2)||(factory1<=factory2),"right","wrong")

其中car1,car2,factory1,factory2的运算符通过实现相应的接口进行重载。 8. 可以在数值型一维数组之间进行加减乘除运算(数组长度必须相等),即支持列操作.

例如var1 = [1,2,3,4]; var2 = [2,3,4,5]; 可对var1,var2进行各种运算。 9. 系统函数支持,NC常用函数支持

例如:

sin,cos,ceil,floor,toChinese,getChineseCurrency(),iif()

等等,详细支持的函数请参见附录。

10. 支持外接用户函数.(可以是一个java的方法)

例如:公式combine("nihao","hao")中,combine是一个自定义函数,可以指定绑定到一个JAVA类的具体方法,可参考后面的例子。

83

用友软件股份有限公司

11. 支持自定义函数.具体应用可参考后面的详细说明(第1.8节)

有时候公式解析器内部的函数并不能完全满足用户的要求,此时用户可添加自定义函数。

例如:hello("say something",person),hello为一个自定义函数,

动态注册到公式解析器中。

12. 支持客户端公式和服务端公式.

以满足前台及后台调用,主要体现在数据库查询的方式上有一定的差别。

13. 支持多行公式批量运算,且保持变量的传递性.

例如:

a->col1+col2;

b->a+col1*col3;

c->a+b;

14. 支持一个线程内多个公式执行器实例交替运行的情况,但不支持多个线程内同一公式执行器实例交替运行。所以如果程序中起多线程的话,建议每个线程单独创建自己的公式解析器示例。

例如下面的代码是可行的:

FormulaParseFather f= new FormulaParse();

f.setExpress(formula);

f.setNullAsZero(true);

FormulaParseFather f1=

new FormulaParse(); f1.setNullAsZero(false);

f.setDataSArray(map);

String[] res = f.getValueS();

? 创建公式执行器

如果在客户端使用公式解析:

FormulaParseFather f = new nc.ui.pub.formulaparse.FormulaParse();

如果在服务端使用公式解析:

FormulaParseFather f = new nc.bs.pub.formulaparse.FormulaParse();

如果不知道当前的代码会在哪一端运行,可以用下面的方法进行判断:

84

用友软件股份有限公司

if (RuntimeEnv.getInstance().isRunningInServer()) {

parse = new nc.bs.pub.formulaparse.FormulaParse();

} else {

}

? 设置公式执行器环境

(自定义变量及自定义函数可参考后续章节描述)

这里可以给公式执行器添加自定义变量,例如:

UFDouble var1 = new UFDouble(5.368);

f.addVariable(var1);

或者添加自定义函数,例如:类YourFunction是一个定义的函数类(关于如何自定义函数,请参考自定义函数一节),在公式中函数取名为"yourfun",则可以这样添加你的自定义函数: f.addFunction("yourfun",new YourFunction);

? 设置公式的值

设置公式执行器环境非必须步骤。

对于单行公式:

String fomula = "sin(30)*2-56/78";

f.setExpress(fomula);

对于多行公式:

String[] formulas = new String[]

{

"viewmny1->viewnum*viewprice-rate*0.23 ",

"viewmny2-> viewnum*viewprice-rate*0.24"

};

f.setExpressArray(formulas);

? 对公式进行语法检查

在设置完公式之后,直接调用执行器的check()方法便可以进行公式检查:

bool isok = f.check();

如果返回结果为false,那么说明公式存在语法错误,调用getError()可以获得具体的错

85 parse = new nc.ui.pub.formulaparse.FormulaParse();

用友软件股份有限公司

误信息:

String errmsg = f.getErrorMsg();

下面是一段具体应用的代码:

FormulaParseFather f= new nc.ui.pub.formulaparse.FormulaParse();

String formula = "a->getChineseCurrency(cchmny,34)";

boolean isok= f.check(); if(!isok)

{

System.out.println(f.getError());

return;

}

另外,如果还没有设置公式,仅仅是想校验公式的正确性,则可以直接通过

checkExpress(String formula)

或者:

checkExpressArray(formulas)

来检查公式,例如:

bool isok = f. checkExpress (formulas); //单行公式

bool isok = f. checkExpressArray(formulas); //多行公式

注意:如果是多行公式,那么只要有一个公式写法是错误的,那么检查结果就会是false。 ? 提取公式变量

在单据模板和打印模板的应用中,公式中的变量并不是已知的,需要从公式中分析得到,取得公式中的变量之后,再把相应的值赋给变量。新版公式解析器

中提取公式中变量的接口和老版是一致的:

VarryVO[] varrys = f.getVarryArray();

下面是单据模板里取公式变量的典型代码:

//设置表达式

formulas = filterUsedFormulas(bfc, formulas);

if (formulas == null)

return null;

f.setExpressArray(formulas);

//获得变量名

86

用友软件股份有限公司

final VarryVO[] varrys = f.getVarryArray(); ? 给公式变量赋值

下面是一段给公式变量赋值的代码:

//下列代码假设varrys不会为null

VarryVO[] varrys = f.getVarryArray();

for (int i = 0; i < varrys.length; i++)

{

String[] varries = varrys[i].getVarry();

//提取公式变量非必须步骤

if(varries != null)

{

for (int j = 0; j < varries.length; j++)

{

//从外部环境取得变量的值

Object varryValue = getVarryValue(varries[j]); //传递给公式

f.addVariable(varries[i],varryValue);

}

}

}

? 取得公式的值

根据公式具体的应用场景,取值有多种形式,如下所示: 单行公式返回单个值:

Object res = f.getValueAsObject();

单行公式返回一列值:

Object[] res =f.getValueO();

多行公式返回多列值:

Object[][] res = f.getValueOArray();

单行公式返回单个字符串

String res = f.getValue();

87

用友软件股份有限公司

单行公式返回一列字符串:

String[] res =f.getValueS();

多行公式返回多列字符串

String[][]res = f.getValueOArray();

6.1.4. 锁

锁的意义在于防止对同一单据进行并发操作,NC的锁是在中间件进行加锁。

锁的主要API为PKLock,提供了两种机制,一种锁为普通锁,程序员加锁后必须释放,一般流程如下:

普通锁在一个事务型组件方法中调用,如

我们会发现执行过程如下

88

用友软件股份有限公司

这样进行并发操作时,(针对一张)有一个动作先解锁,但是没有提交事务,

另一个动作加锁成功,由于第一个事务没有提交,ts检查也能通过。这样会造

成两个都会成功

该问题整体解决方案:

把业务锁放在事务之外,可行原因主要有业务锁不是基于数据库和业务锁是基于Select的处理,无需事务。

做法如下: 在IOC容器中创建public服务IplatFormEntry.它作为平台的直接入口,主要实现业务锁的处理。它的实现代码

如果调用流程平台的PfUtilClient.processAction()等方法的类,平台进行默认实现,对于产品组自己的防止并发问题,需要参考以上方案进行实现。

1. 为了实现业务的并发量,对于业务代码中小锁建议实现方案如下:

Lock

Try{lock.lock}

Finally{

释放锁}

还有一种锁为动态锁,用户加锁后,远程调用结束,系统自动释放锁:

89

用友软件股份有限公司

6.1.5. 日志

NC5的日志输出可以分级别分模块,日志文件存放在nchome \ nclogs下,可以通过sysconfig来设置日志的现实级别,存放路径等熟悉,或者直接修改 nchome\ ierp\bin\logger-config.properties。

日志输出使用两个类:Logger 后台输出 ,Debug 前台输出。

1. 日志API的选择

日志API的选择决定程序对日志的要求:

? 在所有业务组的代码中严禁出现System.out.println()代码,除中间件组代码外

? 如果日志输出不要求在运行时刻发生变化,用Log,它具有更高的效率,中间件组的纯技术代码使用,其它开发不需使用

? 如果日志输出需要输出到某个发起调用的模块,而不是代码本身所属模块,使用Logger动态日志。如供应链模块的BService调用财务模块的BService,发起端为供应链模块,我们希望在供应链模块能个够跟踪到信息的时候,财务模块的BService采用Logger作为日志API,如果发起方是它自己模块,则输出在自己的模块内,如果未配置模块,则日志在匿名模块内

? 基础算法的程序(供给所有模块使用),统一采用Logger作为API

? 后台业务程序和前后台公共程序、全部业务程序采用Logger。

90

用友软件股份有限公司

? 平台类级程序需要进行采用Logger.init/reset设置,放在各自设置的模块中如:(plateform,pa等)

平台级日志的使用遵循有init就必须reset的原则。

2. 日志级别的选择

目前规定日志只有四种日志级别DEBUG、INFO、 WARN、 ERROR,顺序为DEBUG<INFO、 <WARN<ERROR,如果日志级别调的较高,低级别的日志就不能输出如,设置位WARN,那么DEBUG与INFO的信息就不能输出。

对四个级别的信息输出:

? DEBUG: 输出普通的调试信息,主要用于开发环境的信息输出

? INFO: 输出提示性的信息,如程序运行所花费的时间等

? WARN: 输出警告性的信息,如系统设置了一个需要打开的文件,但是系统在打开他的时候有问题,而用了一个缺省的文件,为此系统还是能够正常运行,但却不符合某些期望,采用警告

? ERROR: 错误信息输出,表示系统出了错误,影响了系统的功能,如系统抛出了一个NullPointException,系统不能正常运行。系统运行时默认输出级别为ERROR

6.1.6. 异常

1. 规则

业务异常必须继承BusinessException或BusinessRuntimeException;

2. 前台代码格式

必须按照下面内容书写:

try {

//业务处理调用服务接口

} catch (BusinessException e){

Debug.error(e.getMessage(),e);

MessageDialog.showErrorDlg(this,null,e.getMessage());

} catch (BusinessRuntimeException e){

Debug.error(e.getMessage(),e);

MessageDialog.showErrorDlg(this,null,e.getMessage());

} catch (Exception e) {

91

用友软件股份有限公司

Debug.error(e.getMessage(),e);

MessageDialog.showUnknownErrorDlg(this,e);

}

3. Impl类

1) 业务代码中的业务异常无需捕获,其他异常需要捕获后转换成自己的XX BusinessException或XX RuntimeBusinessException;

2) 由业务逻辑引发的异常必须为XX BusinessException或XX RuntimeBusinessException;

3) 代码格式:要求在方法上只能抛BusinessException

public String queryTemplateId(TemplateParaVO tptParaVo) throws BusinessException{

}

4. DAO类

1) 不需处理的业务异常

try {

//数据库处理

} catch (DbException e){

Logger.error(e.getMessage(),e);

throw new XXBusinesseRuntimeException(e. Message());

2) 需要处理的业务异常

try {

//数据库处理

} catch (DbException e){

Logger.error(e.getMessage(),e);

throw new XXBusinessException(业务提示信息);

92 //业务代码中 } }

用友软件股份有限公司

7. 报表开发

内容概述

查询引擎(Query Engine,简称QE)的功能定位是,一个面向高级实施人员和专业开发人员的查询建模产品,可以全面支持复杂查询的设计和个性化的报表展现。

详细介绍

第三篇 高级篇

通过前面的学习,你已经可以开发基本的NC单据,报表了。本篇将继续介绍NC的高级开发技术,包括预警平台,流程平台,交换平台等技术,通过这些技术,你将全面了解NC,可以完成99%的业务需求。

8. 预警平台

内容概述

现代企业要在激烈的市场竞争中生存并发展,就需要对自身的优势与缺陷都有一个清楚的了解,所谓知己知彼,企业要想在市场竞争中立于不败之地,就必须及时地发现自己的优势与缺陷,发挥自身的优势,弥补存在的缺陷,为企业的发展与壮大扫除障碍。

如何及时地发现自身的优势与缺陷,向来是企业界和理论界倾力研究的重点问题之一。于是NC的预警平台应求而生。NC预警平台分成两种类型的预警。一为定时预警。即用户可以指定何时或者以何周期去执行某项任务,并依照设置的阈值决定是否产生预警提示,致使企业及时合理做出正确的决策。二为即时预警。顾名思义即时是立即发生,NC中主要支持用户登录和打开节点两种,所作事情与定时预警一样。

93

用友软件股份有限公司

详细介绍

NC预警服务的整体示意图如图

由上图可知,预警平台主要由预警类型、预警条目以及预警消息三个组成部分。于是想要使用预警平台的预警功能,需要做两步工作:1.预警类型注册;2.预警条目注册。预警消息是在条目配置的时候配置的。

注意:从V502开始,预警平台功能并入任务中心。 预警平台服务示意图

8.1.1. 预警类型注册

预警类型就是一种预警的一个插件类型。它目的是对某个业务或操作的抽象,其可以定义一系列阈值。(这里也只是定义,真正的值还是由条目来设置的)。定义一个预警类型需要提供:名称、所属系统、业务插件、描述、阈值名称、编辑类型、参照名称(如果编辑类型为参照)

94

用友软件股份有限公司

项目说明:

? 名称:输入预警类型的名称。必填项。

? 所属模块:是区分各产品组模块的标识,即通常说的模块名。这值对应的是中间

件/modules目录下的子目录。按规定模块名都是小写的。必填项。

? 业务插件:输入业务插件的类名,此项不能为空。此类中需实现预警平台接口。

且可以放在业务模块中任何地方(即不限制Public/Client/Private).该类遵循开发规范见插件开发指南。必填项。

? 描述:指对预警类型的文字描述。

? 阈值名称:也就是条件的名称。阈值含义:对阈值名称的说明。

? 编辑类型:此处定义输入阈值的样式,系统提供五个选择:字符型、逻辑型、整

型、Double型和参照基础档案类型。如果将某个阈值的编辑类型定义为逻辑型,那么在进行预警条目设置时,此阈值的值以下拉框的形式出现,有是和否两个选择;如果选择编辑类型为基础档案,还要在后面的参照名称栏中选择参照哪个基础档案,这样当用户输入该阈值时会弹出相应的基础档案参照。

? 参照名称:如果编辑类型选择为参照基础档案,那么参数名称变为可选项,提供

选择的项有人员档案、部门档案、客户档案等等。

95

用友软件股份有限公司

8.1.2. 预警条目注册

预警类型和预警条目其实就是抽象和具体的关系。预警条目具体定义了的某个预警类型的预警执行任务。

预警条目是具体的预警任务,是预警平台调度执行的单位。一个预警类型可以根据不同的业务情况定义多个预警条目。

定义预警条目要完成三个步骤:定义常规属性、预警条件、预警方式。

常规属性主要定义了预警名称、预警状态、预警语言。

定义条目的预警条件首先选择预警类型,并为该预警类型中设置的阈值变量的值, 预警方式包括产生方式和发送方式。产生方式控制预警的发生时间,有即时和定时两种。发送方式是定义预警以何种方式发送给用户 。

1) 常规属性页签

图3-2条目常规属性页签

? 预警名称:即该条目的名称,一个显示的标记。同公司同类型不允许条目名相同。 ? 预警消息文件名:即消息生成时的HTML的文件名标记。(该HTML文件完整的

名称是由它和生成时时间组成)。

? 预警状态:激活态表示该条目是有效的,反之休眠则表示此时该条目是无效的。

默认为激活态。

? 预警消息:这个消息只有当消息接收配置为邮件时候才显示的邮件内容。

96

用友软件股份有限公司

? 预警提示语言:这里指定是当消息生成时候,调用插件的某些显示(如HTML文件

的标题)时,它的多语语种的选择。亦可参见多语支持

2) 预警条件页签

图3-3条目-预警条件页签

项目说明:

? 类型:即第二章所述的预警类型注册的预警类型。其以下拉框的形式显示,此处

对预警类型的选择将决定此预警条目将调用的业务插件。

? “条件”列表:在此处编辑预警条目的阈值。这里的阈值是从类型定义中带过来

的,这里要做的只是设置操作符合阈值设置。

? 帐簿:只是对于模块为财务和总帐的预警类型才必须设置值。其参照为主体账簿参

照。注其预警类型也是必须实现业务插件接口3。

3) 预警方式页签

97

用友软件股份有限公司

图3-4:预警方式页签

? :果选择的为即时产生,则系统会根据此处定义的触发方式来触发业务操作,并依据条件满足与否,来产生预警提示信息。如果选择定时产生,则预警平台会在设定的时间配置到来时进行业务检查,进行预警检查,并产生预警信息。两者产生的预警消息的如何接收都由消息接收者配置面板的来配置。关于定时配置稍候叙述。

? 触发方式: 只有当产生方式为即时的时候,此组才能编辑和有效。

? 系统登录:勾选并单击“系统登录”按钮,弹出系统登录用户选择界面。(如

图3-5)左侧为对本公司及其下级公司(通过界面的参照来切换)拥有登录权限

的角色和用户。右侧为已经选择的用户。这些用户在登录NC时,如果系统

有定义了该用户登录条目,并满足产生消息的条件,这时候会在消息中心的预警消息栏自动给登录用户发送一条消息,用户可以点击此来查看详细信息。但不会主动弹出IE。这点也是V5和以前的版本的不同之处。详细可见新特性。

? 触发点提示:勾选后单击“触发点提示”按钮,弹出“触发点选择”界面(如

图3-6),左侧为系统功能结点树,右侧为将触发预警的功能结点。当用户进

入该公司打开已经定义有条目功能结点时,如果有符合条件的预警消息产生,则会弹出IE窗口来显示预警信息的详细内容。注意:集团的是不能定义功能节点触发的。

? 按钮:只适用于HR。即在业务单据的某个按钮点击时触发。

98

用友软件股份有限公司 ? 消息接收者配置:配置消息的接收者。即当预警条目触发时,除了适当的时候弹

出IE之外的给用户的提示的配置。

?

? 定时配置:当产生方式选择的是定时:

(1) 此时的触发方式将不能编辑。

(2) 此时的消息接收者配置与即时意义是一样的。

(3) 此时的消息查询方式意义相同,但是不能编辑,只为自动调用。

(4) 定时配置界面(如图

3-8)

如图3-8定时配置

? 发生频率:包含天、周,月等三个时间量纲。当为周或月时候,还能够选折

对应的哪天,以及关于量纲的间隔。

? 一天内:因为不管频率制定的如何,具体到还是某一天中。这里就是具体设

置某一天内的时间关系。

? 有效期:这是优先级最高的设置,即频率和一天内的设置都必须要在此有效

期内。

系统会在设定的时间点进行业务检查,触发并合适地产生预警信息。

定义预警类型时必须提供做业务检查的业务插件,由开发人员编写。该业务插件必须实现预警业务插件接口。预警服务运行时,根据定义的预警条目执行业务插件的适当业务,

99

用友软件股份有限公司

并将产生的预警信息写入预警文件,进行企业业务预警。

? 预警平台业务插件接口

nc.bs.pub.pa.IBusinessPlugin最普通最原始的接口。定义接口如下:

100

用友软件股份有限公司

其接口中其它在此未列出的接口,在v5.0种都没有用, 现在只是为了产品的向下兼容性而而保留,开发人员之需要返回null即可。

关于key值的说明:Key其实就阈值的描述,但并不是5.0中对应的数据库表结构,由于也是为了向下兼容,而进行了转换,但对二次开发任意是透明的。

9. 交换平台

内容概述

外部数据交换平台主要用于外部系统和NC系统进行集成。利用外部数据交换平台,可以将外系统的基本档案和业务数据发送到NC系统中,并进行相关的业务操作,如审批、弃审,也可以通过发送XML格式的查询条件导出NC系统的数据(需业务插件支持),导出的数据可以附着在回执文件中,也可以直接向外部系统回发HTTP请求。

详细介绍

9.1.1. 交换平台使用

101

用友软件股份有限公司

图 1.1.1 外部交换平台总体结构图

? 外系统数据导入的一般步骤

外系统根据单据类型将相同单据类型的数据组织在一个XML文件中,然后将其发送到NC系统的某个账套下的某个公司或集团中(对于有账簿信息的单据而言,比如会计科目或者凭证,则是某个公司的某个账簿之下)。一般来说,如果需要发送某种单据类型的数据至NC系统中,需要如下几步:

一、注册外部系统。如果不存在可用的外系统的话,请在“外部系统信息注册”界面中注册一个外部系统。

102

用友软件股份有限公司

二、准备外系统数据。这份数据可能是外系统直接输出的,也可能是二次开发人员通过写程序从第三方系统数据库中抓出来的,或者由Excel格式或其他格式文件转换过来的。数据文件一般以XML文件为载体,数据格式可通过交换规则定义节点来查看,也可导出成XML格文件。

下面是一个XML数据文件的例子:

103

用友软件股份有限公司

三、配置辅助信息(可选)。如果要导入的单据数据需要辅助信息配置,在“辅助信息配置”界面根据外部系统、单据类型、接收公司及主体帐簿(如果带的话)为此次文件发送配置辅助信息。

四、设置基础数据对照(可选)。如果要导入的单据数据需要作基础数据对照(对于需要参照基本档案的字段,如果其值不能按名称或者编码自动翻译过来的话,在导入过程中系统会自动提示必须为该值做基础数据对照),在“基础数据对照”界面根据需要参照的外部系统、需要参照的基本档案、公司(取当前登陆公司)及主体帐簿(如果带的话)为需要对照的值做基础数据对照。

104

用友软件股份有限公司

五、配置Servlet的URL地址。将要发送至的帐套编码作为account属性值写入要发送到的Servlet的URL中(或者写入XML文件的头中),将接收公司和主体帐簿(如果带的话)的代码拼成接收方(接收公司编码@接收主体账簿编码)作为receiver属性写入要发送到的Servlet的URL中(或者XML文件的头中)。

六、利用客户端发送数据。

可以通过手动加载界面来进行加载:

以Java代码为例,介绍外系统作为客户端如何向NC系统发送数据:

105

用友软件股份有限公司

// 获取Servlet连接并设置请求的方法

String url = “http://10.7.3.225:8080/service/XChangeServlet”;

URL realURL = new URL(url);

HttpURLConnection connection = (HttpURLConnection)realURL.openConnection();

connection.setDoOutput(true);

connection.setRequestProperty(“Contect-type”, “text/xml”);

connection.setRequestMethod(“Post”);

// 将Document对象写入连接的输出流中

File file = new File(“C:/samples/psndoc.xml”);

InputStream input = new FileInputStream(file);

Document doc =XMLUtil.getDocumentBuilder().parse(input);

Writer writer = new OutputStreamWriter(connection.getOutputStream(), “UTF-8”);

XMLUtil.printDOMTree(writer, doc, 1); // 按照XML文件格式输出

// 从连接的输入流中取得回执信息

InputStream inputStream = connection.getInputStream();

Document resDoc = XMLUtil.getDocumentBuilder().parse(inputStream); // 解析为Doc对象 // 对回执结果的后续处理 …

[说明] 关于XML操作可以用XMLUtil类,关于发送的API,可以直接用PostFile类 还可以通过交换平台的后台任务来进行发送。

? 外部交换平台服务端的目录结构:

从上图可以看出,外部交换平台配置文件目录pfxx与webapps一样同在安装盘根路径下,其中:

pfxxtemp目录,存贮外部交换平台接受到的原始数据文件、转换翻译完毕的标准XML文件、传送失败的文件。

xmleditor 目录,存放校验文件管理的样式文件,可不用考虑。

exportbills 目录,存放外部交换平台发送给外系统的数据文件。

billdefine目录,存放所有需要交换的档案和单据的交换规则文件。

auxiregister目录,每个模块在这个目录下注册一个文件,文件的内容是模块所涉及单据的辅助信息格式。详细情况参考4.3节辅助信息项设置。

businessprocessor目录,每个模块在这个目录下注册一个文件,文件的内容是模块所涉及单据在外部交换平台的注册信息,如单据类型、业务插件类名称、业务操作、单据导入范围、单据加锁级别等。详细内容参考4.1节注册单据相关信息。

billconfiginfo目录,每个模块在这个目录下注册一个文件,文件的内容是模块所涉及单据的基本信息,如表和VO对象名。详细内容参考4.1节注册单据相关信息。

sendurl.xml 文件,定义了NC系统通过HTTP回发数据给外系统时的各种参数,如发送

106

用友软件股份有限公司

地址、业务操作、发送方、接受方、单据类型等等。

globalset.xml 用于存放外部交换平台的全局参数,如默认帐套、单篇最大传输上限等。

9.1.2. 交换平台插件开发

1. 以公司(或者集团)身份登陆NC系统。

2. 选择客户化>二次开发工具>UAP集成开发工具。

3. 在UAP集成开发工具界面,点击UAP表单集成开发中心。

4. 在UAP集成开发工具DeveloperWorkshop界面

5. 在菜单栏,选择外部交换平台>插件开发。

6. 在单据插件信息注册界面,在模块名输入框中输入uapbd。

7. 在单据标识输入框中输入defdoc,在单据描述输入框中输入自定义档案,在业务操作下拉框中选择add,在导入范围下拉框中选择集团公司,在单据加锁级别下拉框中选择单据类型+公司(账簿)+流水号,在插件类名称输入框中输入nc.bs.bd.pfxx.plugin.defdoc.DefdocPlugin。在选择VO类型单选按钮组中选择单表体,在子表名参照输入框中参照bd_defdoc,在子表VO名输入框中输入nc.vo.bd.def.DefdocVO。

8. 点击下一步。

3.2 单据转换规则定义

9.在校验文件生成规则界面上,选择重新生成校验文件多选框。

107

用友软件股份有限公司

10.点击下一步。

11.在校验&对照文件维护界面上,对自动生成的单据转换规则进行定义,主要工作:首先剔出每个记录中不需要的字段,然后修改每个字段的“最大长度”、“允许为空”、“需要参照的NC基础档案”三个属性值。不需要字段主要有记录本身的主键字段(如表头记录billhead的pk_defdoc、primaryKey等),对字段属性的修改需要参照该单据的单据模版(如表头记录billhead的字段pk_corp参照公司目录)。

表头记录billhead的pk_defdoclist字段节点,它需要参照bd_defdoclist表,但该表没有开放的参照,故写导入公式完成这个功能,导入公式如下:pk_defdoclist->getColValue(bd_defdoclist,pk_defdoclist,doclistname,pk_defdoclist);

右击左树pk_corp节点,在弹出的菜单中,选择需要与接收方一致,在右表修改需要与接收方一致的值为是。

12.点击下一步,保存单据转换规则(校验文件)。

13.点击下一步,跳过样本数据预览界面。

14.点击下一步,跳过辅助信息规则配置界面。

3.3 插件代码编写和部署

15.在插件代码维护界面上,选择代码导出路径,不必选择包含导出代码多选按钮。

16.点击生成按钮,开始编辑插件类DefdocPlugin的代码。

17.在方法processBill(Object, UfinterfaceVO, XsysregisterVO)中,编写如下代码: DefdocVO defdocvo = (DefdocVO)vo;

Idefdoc imp=(IDefdoc)NCLocator.getInstance().lookup(IDefdoc.class.

getName());

defdocvo.setDocsystype(new Integer(1));

defdocvo.setStatus(DefdocVO.NEW);

imp.saveVOs(defdocvo.getPk_defdoclist(),new DefdocVO[] {defdocvo});

return null;

18.点击编译按钮,将.java文件编译成.class文件。

19.点击下一步。

20.点击下一步,跳过交换平台测试界面。

21.点击完成,跳过导出和插件相关的配置文件界面,退出集成开发向导。

108

用友软件股份有限公司

10. 流程平台

内容概述

NC流程平台是对企业的流程进行建模的平台。其工作流模型由四部分组成,分别是过程模型、组织模型、功能模型以及信息模型(工作流相关数据)。过程模型用来定义工作流的过程逻辑,包括组成工作流的所有活动以及活动之间的依赖关系。组织模型用来定义企业人员的组织结构,包括几种不同形式的组织元素以及每种组织元素内部的递阶层次关系。功能模型说明企业中需要完成的工作或者任务是什么,或者说功能模型说明了企业的目标是通过哪些具体的功能活动来实现的。它确定了企业业务功能的逻辑结构和相互关系。信息模型说明了企业处理的业务对象中所包含的信息以及业务对象间的关系。

过程模型采取基于活动网络图的过程模型,与其他的过程模型(如事件驱动过程链EPC、Petri网、语义-行为模型等)比较,活动网络图具有直观自然、可读性好的特性。

详细介绍

10.1.1. 流程平台介绍

109

用友软件股份有限公司

NC流程平台包括业务流程和审批流程两个部分。

图 业务流程框架

整个业务流程框架的核心是工作流引擎。它负责解释执行由业务流设计器和审批流设计器设计的流程定义。流程定义可以引用NC系统建立的功能模型、组织模型以及各种元数据。NC用户可从工作列表中查看到工作流引擎分配给他的工作项。通过单据动作(比如提交、审批、弃审、驳回等)来处理工作项,从而驱动流程流转。工作流引擎在流转过程中还可以调用各种自动应用,包括电子邮件、脚本以及Web服务等。业务流程框架还提供了管理监控工具对运行中的流程实例进行状态查询和管理。对于流转过程中涉及到的数据交换,工作流引擎将调用交换引擎根据规则进行数据映射。

? 单据元模型

业务单据是描述企业业务信息的载体,是对业务数据的抽象。通过业务单据,可以清楚地反映企业的业务发生情况。企业中如请购单、采购订单、报销单、付款单等均为业务单据。 在NC系统中,一张业务单据的实现包括许多内容,比如单据类型、单据VO、单据UI、单据动作等。我们把这些用于描述某单据的信息统称为单据元模型。其组成如图所示。

110

用友软件股份有限公司

? 单据类型

单据是对业务数据的抽象,单据类型是对单据的分类。

? 单据动作及脚本

是对单据业务处理行为的抽象,具有可定制的动作脚本。用于驱动流程的流转。可对应 于单据UI上的某个菜单。

? 单据函数

是对服务于单据的业务功能的抽取。可用于动作脚本和条件判定。

? 单据UI

单据的界面展现模型,包括四大模板以及UI工厂等。

? 单据项目

是对单据业务数据的描述。一般与单据的VO模型对应。

? 单据VO对照

描述了流程平台所需的信息(比如制单人、审批人、单据ID等)在单据VO模型上的对应关系。

10.1.2. 业务流程

NC业务流平台进行了简化,其设计思想是基于以下认识:业务流程是由单据组成的,而单据是由动作驱动的,动作又是由组件组成的;单据、动作以及组件可以由业务系统开发实现。NC业务流提供一种平台机制,在此可以根据用户的实际业务重新组织这些单据、动作及组件,包括每种单据的来源单据是什么、又驱动生成哪些单据、完成什么动作、动作生

111

用友软件股份有限公司

效的约束条件以及动作生效后将配置哪些组件等,以此更好满足企业个性化的需求。

图 1普通采购流程

业务类型

对业务流程的分类。各个公司可定义自己的业务流程,5.0支持集团业务类型,即在集团定义业务类型,然后各个子公司使用。比如集中采购流程:请购单->采购订单->到货单->入库单->采购发票->应付单。由功能点[客户化]-[流程配置]-[业务类型管理]维护,如图15所示。

112

用友软件股份有限公司

图 2业务类型管理

流程配置

一个业务流程由相互关联的多个单据组成,通过定义单据间来源与动作驱动关系来定义业务流程。

113

用友软件股份有限公司

图 3流程配置

项目说明:

? 单据代码:该字段为参照选择,参照内容为NC安装过的功能模块的所有单据类型。每

个业务类型每张单据只能选择一次。

? 单据名称:显示选择的单据代码的名称,不能编辑,选择单据代码后自动带入

? 参照单据:勾选此项,表示该单据的业务数据可以参照其他单据(来源单据)的数据生

成(将进行单据VO交换)。勾选此项,在流程配置中才可配置该单据的来源单据,否则不可配置。

? 自制单据:勾选此项,表示该单据的业务数据可以手工输入。

? 权限控制:设置每个单据有权限的参与者。在单据UI界面,业务类型下拉菜单中,只

有有权限的用户才可看到该业务类型(参见第三章5.3.1节)。同时还控制了下游消息的接收者范围。

? 下游消息:上游单据审批通过后,会给下游单据的参与者发送拉式消息。上游单据的推

式动作执行完后会驱动下游单据的动作,并给下游单据的参与者发送推式消息。

流程配置由5个向导工具组成,分别阐述如下:

单据权限配置

5.0新增的配置,配置业务流程中每个单据有权限的参与者。用于业务类型的权限控制,以

114

用友软件股份有限公司

及下游消息的接收者范围。

图 4单据权限配置

单据来源配置

是对当前单据类型的数据来源单据进行定义的界面。被定义为当前单据来源单据的业务单据,可以在业务流程中为当前单据提供业务数据(使用单据VO交换),以保持业务数据的一致性。

115

用友软件股份有限公司

图 5单据来源配置

动作约束配置

配置业务单据的单据动作(可能为单据界面上的某些功能按钮)在发生前需要进行的条件检查。若发生的业务满足定义的条件,则该单据动作将被执行,否则不允许执行。流程配置通过本步骤,即可实现对当前业务环节的事前控制。

图 6动作约束配置

116

用友软件股份有限公司

动作事件控制配置

为业务流程配置个性化动作脚本。在这里,用户可以针对不同业务类型对公共的单据动作执行脚本(参见第三章第3节)进行定制。使单据动作按照自己定义的规则来执行,以此来完善企业的业务流程,并对当前业务环节实现事中控制。

图 7动作脚本定制

动作驱动配置

配置单据之间的动作驱动关系。左树列示了当前单据在单据动作管理中被定义为“进行驱动配置”的单据动作。

117

用友软件股份有限公司

图 8动作驱动配置

项目说明:

? 目的单据:在当前单据动作完成时,将要进行动作处理的单据。

? 操作员相关:选择与操作员或角色有关,则该动作仅在所选择的操作员或角色执行时,

才会驱动目的单据的动作。

? 动作:参照选择,选择目的单据被驱动的动作,该类动作在单据动作管理中被定义为“推

式动作”(参见1.2节)。

单据VO交换

单据类型之间存在相互转换的需求,平台提供了定义单据VO模型间的相互转换规则的机制。单据之间的上下游关系保存在表pub_billtobillrefer中,转换规则作为class文件保存,比如“nc.ui.pf.changedir. CHG21TO30”、“nc.bs.pf.changedir.CHG21TO30”等。单据VO交换可发生在前后或后台,并在交换后可进行特殊的业务处理。

数据交换修改保存会重新编译,分别产生前台(UI)和后台(BS)的数据交换类,类文件命名规则:CHG+上游单据编码+TO+下游单据编码,前台数据交换类用于拉式流程,后台数据交换类用于推式流程。

118

用友软件股份有限公司

图 9 单据交换信息

项目说明:

? 被参照单据类型:来源单据类型。

? 用于显示来源单据的UI类(拉式单据需要):参照来源单据时,使用的来源单据显示

UI。默认为“nc.ui.pub.pf.BillSourceDLG”。

? 用于查询来源单据的模板ID或UI类:查询来源单据需要使用的查询模板ID或UI。格

式有“<nc.ui.po.pub.PoToPiQueDLG>”、“SO30TO31000000000000”和NULL(默认查询模板)。

? 用于查询来源单据的节点标识:被参照的来源单据的Nodekey,用于选择查询模板。

单据间的交换规则支持简单属性和公式定义,以及额外的交换后业务处理。

119

用友软件股份有限公司

图 10单据交换规则

下面是一个最小化的推式流程过程

业务流程驱动生成单据分为推式流程和拉式流程,推式是上游单据制单后可直接生成下游的单据,不需要打开下游单据进行制单操作。拉式则是下游单据制单时通过参照上游单据来生成下游单据的数据。

为了使用方便,下面给出一个最小化的推式流程的步骤。

1【客户化】->【二次开发工具】->【单据管理】->【单据动作管理】

源单据按钮修改动作控制,目的单据增加PUSHSAVE

2【客户化】->【二次开发工具】->【单据管理】->【单据动作执行脚本】PUSHSAVE代码同WRITE

3【客户化】->【二次开发工具】->【流程配置】->【数据交换管理】注意单据类型,状态等字段

4【客户化】->【流程配置】->【流程配置】->【业务类型】->【增加】公司登陆,通用业务类型增加来源目的单据,进行配置

5【客户化】->【流程配置】->【流程配置】->【业务类型】->【单据】->【流程配置】目的单据设置来源

6【客户化】->【流程配置】->【流程配置】->【业务类型】->【单据】->【流程配置】来源

120

用友软件股份有限公司

单据设置 消息驱动设置

拉式单据(单据的上下游参照)

除了推式单据,我们还经常会用到拉式单据,就是通过参照上游单据来制单。

拉式单据需要在集成开发工具生成按钮的时候增加按钮“业务类型”,这样在我们配置好 来源单据后(具体配置参考上面章节),业务类型按钮下就会有下拉菜单,下面显示可选择的业务类型。在制单菜单下,如果相应业务类型下配置了相应上游单据来源,则在新增按钮下,会有自制单据和上游单据,通过点击不同的上游单据会弹出不同的查询对话框(单据VO交换中的用于显示来源单据的UI类,用于查询来源单据的模板ID或UI类都是为拉式单据做准备)。

图 增加菜单下可选择材料需求单来进行参照

121

用友软件股份有限公司

图 参照上游单据

可能需要编写的几个类

? 查询的DMO类(需要自己写的后台查询类,如果是UI工厂生成的单据,又

使用了默认查询模版则可以不需要)

? 参照查询类(如果参照的单据没有默认查询模版,可以自己写,如果是

UI工

厂生成的单据,都可根据单据模版生成查询模版,故一般也不需要)

10.1.3. 审批流

审批流定义

审批流平台为单据的审批处理提供平台支持。基于任务驱动的执行引擎使得流程流转与用户交互分离开来,具有更强的健壮性。支持分支/汇总(Split/ Join)、优先级(Priority)、

122

用友软件股份有限公司

子流程(Subflow)、可指派、抢占/会签、消息配置、代理人、弃审等流程特性。

NC5.0的审批流定义模型遵循WfMC的XPDL1.0过程定义规范,具有严格的语义和丰富的描述能力。

图 审批流定义-浏览

审批流定义按照单据类型(+业务类型)进行了分类。用户可以基于单据类型定义审批流,也可以基于单据类型+业务类型(如果配置了业务流程)来定义审批流。一个单据类型(+业务类型)下可以定义多个审批流,这里可以把单据类型(+业务类型)理解为过程包的概念。

123

用友软件股份有限公司

图 审批流定义-设计

设计审批流可通过拖放将工具控件和角色用户放置流程设计面板上,从参与者页签可将用户或者角色拖置面板,第一个被放到面板上的用户和角色被称为制单人,每一个单据类型下可建立多个审批流,但这些审批流的制单人不能相同。其他被拖放的用户或者角色是审核人,审核人数量不限。通过审批流的工具箱可把流程控件放到面板,每个审批流都要有一个开始和结束控件,控件和控件之间(包含用户和角色)需要用转移来连接。

每个转移和用户都可通过属性编辑器来修改其属性,比如转移一般可设计其表达式,一般双击转移就可以进行表达式设计。表达式为真时怎转移成功,否则转移不成功。

对用户和角色一般设置属性分支条件,抢占模式等属性。

经过以上设计,一个审批流就可完成。

通过集成开发工具生成的一个业务单据(有单据类型)此时就可以进行审批流程,不需要写任何代码。

? 流程模型:

过程(Process)

由许多被执行的活动和一系列决定活动执行次序的转移构成。

活动(Activity)

审批流程中的一个个步骤统称为活动(或任务),包括制单活动、审批活动、虚活动、子流程。第一个拖放到审批流设计器中的参与者所属的活动为制单活动。虚活动主要用于对分支/汇总进行建模。子流程可实施流程重用。

124

用友软件股份有限公司

参与者(Participant)

活动的一个属性,即活动的执行者,是对系统中组织模型的引用。目前支持『操作员』、『角色』和『动态组织』三种类型的参与者(HR岗位就是一种动态组织实现,具体扩展机制可参考附录)。第一个拖放到审批流设计器中的组织元素为制单活动的参与者。在设计器中,活动和参与者由同一个图元来展现。

转移(Transition)

活动间的流转,是两个活动间的有向连接。每个转移都具有转移条件(Condition),只有满足条件的转移才可流转。转移条件表达式除了审批结果表达式、单据函数表达式,5.0新增加了单据项目表达式。每个转移还具有优先级(Priority),优先级高的转移分支将被优先选择。

分支/汇总(Split/Join)

活动具有前驱条件(Join)和后继条件(Split)两个属性,可通过Split/Join-AND/XOR属性组合为过程的选择、并行结构进行建模。加上顺序和循环,这四个基本结构就可描述大多数过程结构。同时,工作流引擎还支持两种反向流转模式:驳回和弃审(参见3.4节)。 抢占和会签

审批活动的一个属性。会签:只有审批活动的参与者中所有用户完成审批后,该审批活动才能结束。抢占:只要审批活动的参与者中任何一人完成审批后,该审批活动即结束。 可指派

审批活动的一个属性。如果审批活动定义了可指派属性,则该审批活动的实际执行者需要从其参与者中手工选择。指派的分支优先被选择。

流程限定

审批活动的一个属性。用于设定前后两个活动的参与者之间的关系。支持“同公司”和“同部门”两种类型。只可为参与者为『角色』和『动态组织』的审批活动设置流程限定属性。

代理人(Agent)

审批活动的一个属性。制单活动不可设置代理人;只可为参与者为『操作员』类型的审批活动设置多级代理人;代理人只可为『操作员』。

消息配置(Message Config)

审批活动的一个属性。可为每个审批活动配置额外的消息通知机制。即在满足触发条件时,以消息、短信、邮件方式通知相关人员。

可以为每个审批活动配置额外的消息发送机制。对于制单活动,发送条件必须为“无条件”。对于审批活动,发送条件可为“无条件”、“审核通过”和“审核不通过”三种(注:

125

用友软件股份有限公司

对于审批活动,“无条件”即该审批活动完成之后就发送)。

在消息内容中我们可以使用宏表达式来获取一些业务相关数据。目前可从系统获取的宏对象变量仅有:

operater==当前登录操作员PK

vo==当前操作的单据VO

vos==当前操作的单据VO数组

paravo==当前单据的审批流参数VO

? 流程结果与单据状态

对于审批流程来说,流程实例正常结束后,必然会有一个审批结果。而单据的审批状态与流程结果密切相关。

工作项的审批结果

即登录到NC系统的操作员对流程平台分配给他的工作项的审批处理意见。包括“批准”、“不批准”、“驳回到制单人”三种。

活动的审批结果

对于角色/岗位类的参与者执行的审批活动,如果是会签属性,则只有所有会签操作员都审批通过,该活动结果才为审批通过,任何一个会签人审批不通过,该活动结果就为审批不通过;如果是抢占属性,则活动结果为抢占人的审批结果。

流程的审批结果

恒等于最后一个活动(即流转到结束节点的活动)的审批结果。恒等于最后一个审批人的审批结果。

一旦单据送审到审批流中,单据便处于某个审批状态。在审批流内部,单据的内部审批状态有5种:

表 1单据审批状态

业务单据根据自己的业务需求也可定义自己的单据业务状态,但不可与上述5种状态相

126

用友软件股份有限公司

冲突。比如UI模式化开发包中就定义了更多的单据状态。

表 2单据业务状态

*态

即单据尚在编写中(已保存或尚未保存)并未提交到审批流的状态。

提交态

通过执行单据动作SAVE或EDIT,将单据送审后的状态。提交态是审批流内部的一个状态,它的回写并不通过审批流检查类进行。只能由业务组通过SAVE动作脚本自己对单据状态进行设置。所以有的业务组的单据并没有提交态的概念。

审批进行中

流程实例正处于运行中的状态。

审批完成

如果流程实例正常运行完成,该单据的审批过程即完成。审批流程结束后具有最终审批结果:通过或不通过,这也是单据的最终审批结果。

流程编程

? 相关平台类介绍

127

用友软件股份有限公司

? 动作处理时序图:

128

用友软件股份有限公司

业务

? UI端调用-PfUtilClient

1. 单据动作处理("APPROVE")

Object nc.ui.pub.pf.PfUtilClient.processActionFlow(Container parent,

String actionName,

String billType,

String currentDate,

AggregatedValueObject vo,

Object userObj,

String strBeforeUIClass

) throws Exception

功能:

129

用友软件股份有限公司

1. 判断是否进行动作前提示

2. 动作执行前的事前处理

3. 如果单据动作以"APPROVE"开头,检查该单据是否处于审批流中并打开审批对话

4. 后台执行动作处理- PfUtilBO.processAction(…)

5. 如果动作执行的返回值为IProcActionRetObject,则进行事后前台处理

6. 如果上述过程发生异常,且异常为IPfRetException,则判断异常是否需要进行

业务处理后继续执行事后处理

7. 判断返回对象是否为PfUtilActionVO,然后前台显示

? BS端调用

后台类PfUtilBO动作处理其实委托给了5.0新增的业务组件IPFBusiAction。开发人员既可以直接调用PfUtilBO,也可查询到IPFBusiAction组件后调用。

1. 单据动作处理

Object nc.bs.pub.pf.PfUtilBO.processAction(

String actionName,

String billType,

String currentDate,

PfUtilWorkFlowVO workFlow,

AggregatedValueObject vo,

Object userObj

) throws RemoteException

功能:

1. 数据加锁和一致性检查

2. 动作执行前的工作流处理(弃审或删除)

130

用友软件股份有限公司

3. 进行动作约束检查

4. 执行动作脚本,并返回值

5. 如果返回值为IWorkFlowRet,则直接返回

6. 判断动作是否为最后一个动作,执行动作驱动

7. 如果动作编码以“SAVE”或“EDIT”结尾,则尝试启动审批流

参数说明:

? 审批状态回写与查询

状态回写

分为两种,一种是对单据聚合VO的回写;一种是对单据数据库表的回写,是在审批流检查类中完成。参见4.6.1节。

状态查询

后台API:

int nc.bs.pub.pf.PfUtilBO.queryWorkFlowStatus(

String busiType, //业务类型PK

String billType, //单据类型PK

String billId) //单据Id

返回值:

常量 对应的内部状态

IPfRetCheckInfo.COMMIT IWorkFlowStatus.NOT_STARTED_IN_WORKFLOW

IWorkFlowStatus.WORKFLOW_ON_PROCESS IPfRetCheckInfo.GOINGON

IWorkFlowStatus.NOT_APPROVED_IN_WORKFLOW IPfRetCheckInfo.NOPASS

IWorkFlowStatus.WORKFLOW_FINISHED IPfRetCheckInfo.PASSING

IPfRetBackCheckInfo.NOSTATE IWorkFlowStatus.BILLTYPE_NO_WORKFLOW

131

用友软件股份有限公司

IWorkFlowStatus.BILL_NOT_IN_WORKFLOW

IWorkFlowStatus.ABNORMAL_WORKFLOW_STATUS

? 送审

送审也称为提交,就是单据产生后进入到流程平台并启动审批流的步骤,通过调用单据动作处理来完成。审批流的触发支持两种单据动作,分别为“SAVE”和“EDIT”,即动作编码以两者结尾即可。送审后,流程平台会根据单据类型和制单人ID查找符合条件的流程定义并实例化然后启动它。如果找不到流程定义,则不启动审批流。

送审分为两种情形,一种是前台送审,即业务UI新增单据后保存并提交;另一种是后台送审,即某张单据在后台推式生成另一张单据时。

前台送审调用示例: Object retObj = nc.ui.pub.pf.PfUtilClient.processAction(parentUI, “SAVE”, “D1”, “2005-05-30 12:23:44”, billVo, userObj, null, null )

如果单据数据billVo中没有保存制单人的信息,则可通过动作编码来传递。但要求原动作编码不能长于20个字符。 Object retObj = nc.ui.pub.pf.PfUtilClient.processAction(parentUI, “SAVE”+billMakerUserId, “D1”, “2005-05-30 12:23:44”, billVo, userObj, null, null )

后台送审调用示例: Object retObj = new PfUtilBO().processAction( “SAVE”, “D1”, “2005-05-30 12:23:44”, null, billVo, userObj )

前台送审与后台送审的区别在于,前台送审会先向服务器获取流程定义中第一个审批人的可指派信息,以便于与客户端交互。而后台送审则默认为不可指派。

对于单张单据的送审,也可以按照批量的方式来处理(这种应用在NC财务和供应链产品中比较常见),这时VO数组中传递的就是一张单据。

送审的动作脚本没有特殊的要求,可以在脚本中进行单据VO的保存,也可以对单据VO进行更新。但如果单据UI的开发使用了UI工厂,为了维护单据数据的一致性,可在脚本中调用如下方法来保存单据并更新聚合VO。

132

用友软件股份有限公司

retObj=runClass("nc.bs.trade.business.HYPubBO", "commitBill",

"nc.vo.pub.AggregatedValueObject:01",vo,m_keyHas,m_methodReturnHas); 或者

SuperVO headVO = (SuperVO) billVo.getParentVO(); //主表必须为SuperVO SuperDMO dmo = new SuperDMO();

//从数据库获取到更新了ts的VO

billVo.setParentVO(dmo.queryByPrimaryKey(headVO.getClass(),

headVO.getPrimaryKey())); ? 审批

审批是登录到NC的操作员完成流程平台分配给他的工作项的过程,它是驱动流程流转 的关键应用。每个工作项的审批有“通过”、“不通过”和“驳回到制单人”三种结果。关于工作项的审批结果与流程审批结果的异同,参见第二章3.3节。

根据单据是否启动了审批流,审批分为:

有流程实例:单据送审后,根据制单人查询到流程定义,并启动了流程实例。如果对一个尚未提交的单据进行审批,会提示“单据尚未提交,无法审批。”的错误。

无流程实例:单据送审后,根据制单人查询不到流程定义,即没有启动流程实例。不管其是否提交,都不会启动审批流,任何人都可直接审批通过。这种审批由于没有流程实例和工作项,并不属于真正意义上的流程审批,更多的是进行业务处理。

根据业务需求,审批还分为两种情形,一种是前台审批,即业务UI查询到单据后进行审批或者通过待办事务来审批;另一种是后台审批,会将单据直接审批通过。后台审批只适用于无流程实例的情形,对于启动了流程实例的单据,不可进行后台审批。

前台审批调用示例:

Object retObj = nc.ui.pub.pf.PfUtilClient.processActionFlow(parentUI, “APPROVE”, “D1”, “2005-05-30 12:23:44”, billVo, userObj, null)

如果单据数据billVo中没有保存当前审批人的信息,则可通过动作编码来传递。

Object retObj = nc.ui.pub.pf.PfUtilClient.processActionFlow(parentUI, “APPROVE”+checkUserId, “D1”, “2005-05-30 12:23:44”, billVo, userObj, null,)

后台审批调用示例:

Object retObj = new PfUtilBO().processAction( 后台审批由于没有客户端的交互,会直接将该单据审批通过。但如果该单据启动了审批流程,“APPROVE”, “D1”, “2005-05-30 12:23:44”, null, billVo, userObj )

133

用友软件股份有限公司

实际上导致流程并没有结束,所以后台审批只用于那种“直批(即不启动流程实例)”的情

对于单张单据的审批,也可以按照批量的方式来处理(这种应用在NC财务和供应链产品中比较常见),这时VO数组中传递的就是一张单据。

? 弃审

弃审是审批流支持的两种流程反向流转模式之一,是指当前审批人审批(通过或不通过)完成之后,在下一个审批人尚未审批之前,可以主动弃审,让自己重新审批。当前操作员只有拥有该单据的弃审权限才可进行弃审,这由审批流平台控制。

NC5.0支持两种弃审模式:逐级弃审和一弃到底。这是通过单据聚合VO是否实现接口

nc.vo.pub.pf.IPfBackCheck2来控制。业务单据开发完毕,实际上也确定了该单据类型的弃审模式。只有审批流程结束后,才可一弃到底,即不允许审批进行中的一弃到底。 弃审也支持前台弃审和后台弃审。

前台弃审调用示例: Object retObj = nc.ui.pub.pf.PfUtilClient.processActionFlow(parentUI, “UNAPPROVE”, “D1”, “2005-05-30 12:23:44”, billVo, userObj, null)

或者 Object retObj = nc.ui.pub.pf.PfUtilClient.processAction(parentUI, “UNAPPROVE”, “D1”, “2005-05-30 12:23:44”, billVo, userObj, null)

如果单据数据billVo中没有保存当前弃审人的信息,则可通过动作编码来传递。

Object retObj = nc.ui.pub.pf.PfUtilClient.processActionFlow(parentUI, “UNAPPROVE”+unCheckUserId, “D1”, “2005-05-30 12:23:44”, billVo, userObj, null,)

后台弃审调用示例:

Object retObj = new PfUtilBO().processAction(parentUI, “UNAPPROVE”, “D1”, “2005-05-30 12:23:44”, null, billVo, userObj )

对于单张单据的弃审,也可以按照批量的方式来处理(这种应用在NC财务和供应链产品中比较常见),这时VO数组中传递的就是一张单据。

在弃审脚本中可对单据VO进行更新操作,也可在流程从完成态回到运行态时进行业务

处理。两种弃审模式的动作脚本具有不同的要求。

单张单据逐级弃审动作脚本示例:

134

用友软件股份有限公司

boolean isFinishToGoing = procUnApproveFlow(paravo);

//###返回值:true-审批流程由完成态返回到运行态;false-其他情况

if (isFinishToGoing) {

doBusi(getVo()); //业务处理

}

单张单据一弃到底动作脚本示例:

procUnApproveFlow(paravo); //只是回写单据状态为*态

//审批流程肯定是由完成态返回到运行态,因为不允许审批进行中的”一弃到底”

doBusi(getVo()); //业务处理

如果单据UI的开发使用了UI工厂,为了维护单据数据的一致性,需要在脚本中调用如下方法来更新聚合VO。

SuperVO headVO = (SuperVO) billVo.getParentVO(); //主表必须为SuperVO SuperDMO dmo = new SuperDMO();

//从数据库获取到更新了ts的VO

billVo.setParentVO(dmo.queryByPrimaryKey(headVO.getClass(),

headVO.getPrimaryKey()));

10.1.4. 消息中心

消息中心是用户与流程平台、预警平台进行交互的主界面,也是用户开展工作的基础。V5消息中心的需求来源于易用性小组以及NC产品自身的发展。

? 展现

整个消息中心分为上中下三栏,每栏都可最大化。分别是[公告栏]、[待办事务栏]、[预警消息栏]。

135

用友软件股份有限公司

图 11消息中心

所有栏目均使用表格UITable展现。除了UITable内置的定位功能和双击表头排序功能,还提供表格样式设置功能。包括:

1. 设置列宽度、列顺序;

2. 设置显示隐藏列;

3. 设置表格行列分割线的隐藏;

4. 设置表头的隐藏;

5. 设置三栏的区域分配比例。

136

用友软件股份有限公司

图 12设置表格样式

图 13设置消息刷新间隔和栏目大小分配比例

消息中心的三个栏目还提供类似查询模板的查询过滤功能(过滤器,或叫筛选器)。比如:

1. 按照优先级过滤;

2. 按照消息状态过滤;

3. 按照主题模糊匹配;

4. 按照发送人过滤;

5. 按照发送日期或处理日期过滤。

137

用友软件股份有限公司

注意:这里的过滤属于前台过滤功能,即只对当前客户端中已有的消息过滤。

图 14消息筛选过滤界面

这些表格样式和过滤器保存在每个客户端的用户缓存中,以维持多次登录的一致性。 ? 消息类型

1. 公告消息——可由任何人看到的消息,分为集团所有用户可见和公司所有用户可见两

种。显示在[公告栏]。

2. P2P对发消息——某人向另外一人直接发送的消息。显示在[公告栏]。

3. 审批流工作项——审批流平台产生的需要业务处理的工作项。同时包括审批通过、不通

过、驳回后给制单人发送的消息。显示在[待办事务栏]。

4. 业务流工作项——业务流平台产生的需要业务处理的推拉式消息。显示在[待办事务

栏]。

5. 通知消息——不需要业务处理的普通消息。审批流消息配置产生的消息以及业务代码产

生的一些消息。显示在[待办事务栏]。

6. 预警消息——预警平台产生的预警消息。显示在[预警消息栏]。

138

用友软件股份有限公司

11. 会计平台

内容概述

解决多个业务系统生成财务凭证的问题,会计平台一次开发完成,可以接入新的业务系统。 业务系统只需要注册部分信息和写少量的代码即可完成凭证的生成。

可以更改的系统定义信息保证业务生成凭证的灵活性

保证财务系统和业务系统的独立性

财务人员可以不需要关心业务系统的数据

业务人员不需要了解财务知识

业务系统的代码和财务系统的代码完全隔离

业务系统和财务系统的独立运行

详细介绍

财务会计平台可以帮助程序员将自己设计的业务单据的业务数据传向会计平台,并通过会计平台生成实时凭证或会计凭证。

财务会计平台的主要功能是根据事先定义好会计描述,对各系统的原始单据与业务处理自动生成实时凭证,并按照用户的设置将实时凭证生成会计凭证。主要由以下三部分构成:会计描述、实时凭证生成会计凭证、外部系统生成会计凭证的维护。内部关系见下图:财务会计平台业务单据

业务处理会计凭证会计描述实时凭证

139

用友软件股份有限公司

在这个业务关系图中,业务单据部分将由程序员定义,具体包括业务单据VO定义、单据项目注册、影响因素注册等。通过业务单据中项目的注册,这些业务单据项目将能够为会计平台所使用。会计描述将由实施人员进行定义,具体包括科目分类定义、凭证模板定义、入账规则定义等。

11.1.1. 会计平台注册

系统类型注册: 功能节点:客户化-》二次开发工具-》会计平台-》系统类型注册

140

用友软件股份有限公司

主要功能:定义系统类型,系统类型编码不能重复,生成凭证时候需要传送,

选上是否发送会计平台

单据类型注册:

功能节点:客户化-》二次开发工具-》单据管理-》单据类型定义

主要功能:选上是否发送会计平台 (是否显示根节点和单据大类注意,可能会影响凭证模板的单据显示

)

单据VO定义:

141

用友软件股份有限公司

功能节点:客户化-》二次开发工具-》单据管理-》单据VO定义

主要功能:定义系统模块的单据类型所对应的VO类。

定义的VO主子类需要继承nc.vo.pub.ValueObject

注意问题:集成开发生成单据不需要vo定义

系统影响因素定义:

功能节点:客户化-》二次开发工具-》会计平台-》影响因素定义

所谓影响因素是指对单据生成实时凭证时的入账科目、会计主体、账簿产生影响的特殊信息。影响因素定义与单据影响因素表共同完成了影响因素的定义,影响因素定义只是定义了某个系统包含哪些影响因素,而单据影响因素表建立了某个系统下的单据与影响因素的关联 会计平台在根据凭证模板生成会计凭证时,会查找对选取入账科目起作用的影响因素,影响因素的值不同,生成会计凭证的入账科目也会不同。在启用多账簿的情况下,会计平台会根据入账规则中影响因素的设置,生成对应主体账簿的会计凭证。

142

用友软件股份有限公司

单据影响因素定义:

功能节点:客户化-》二次开发工具-》单据管理-》影响因素定义

主要功能:定义每一个单据类型在取得影响因素值的时候对应的VO类的属性名称 注意问题:影响因素来源于系统影响因素定义的数据

属性名称来源于单据项目管理定义的数据

使用入账规则定义对照表和入账科目对照表,必须定义单据影响因素

增加一个新的影响因素必须增加相应的单据影响因素,否则对照表无法生效。

143

用友软件股份有限公司

入账规则定义:

(客户化-》会计平台-》财务会计平台 -》入账规则定义)

会计平台根据入账规则中定义的影响因素,将业务系统的单据向不同的主体账簿中生成会计凭证。入账规则定义功能在未启用多账簿的情况下是不可用的。

入账规则分为会计主体规则设置和账簿规则设置,会计主体规则决定生成的会计凭证入哪个主体,账簿规则决定生成的会计凭证入哪个账簿。

入账规则的影响因素和对照表的设置及匹配方式与科目分类的影响因素和对照表基本一致。 默认入账主体,默认入账账簿必须选择。

科目分类定义:(客户化-》会计平台-》财务会计平台 -》科目分类定义)

入账科目分类分为三个重要的操作,科目分类定义为业务系统生成会计凭证乃至的入账科目进行科目分类的定义,影响因素选择定义生成会计凭证时选取最终入账科目所需的影响因素,对照表定义影响因素内容与最终入账科目之间的影响关系。

业务单据在生成会计凭证时,财务会计平台系统会查找科目分类的影响因素,并根据影响因素的内容,查找该影响因素内容所对应的入账科目,最后确定凭证分录所使用的会计科目。

144

用友软件股份有限公司

凭证模板定义:(客户化-》会计平台-》财务会计平台 -》科目分类定义)

凭证模板是对应到单据或者业务处理过程的会计描述,是单据及业务处理生成凭证的依据。凭证模板定义就是要设置各原始单据及业务处理的凭证模板,即通过指定单据项与凭证字段之间的对应关系完成凭证分录结构的描述。

145

用友软件股份有限公司

11.1.2. 代码调用

WRITE 动作脚本或者SAVE动作脚本里面调用平台接口,参考CreatVouch.java

会计平台生成单据(nc501的一些bug):

1。代码部署完成后,登陆NC,入帐规则设置节点里,看不到新定义的系统类型,最后通过对比发现

自动生成的sql脚本有问题,用update dap_dapsystem set usebusitype=4 where module='demo' update sm_codetocode set dr=0 where dr is null 进行更正

2。凭证模板定义节点里看不到新的单据,最后执行脚本update bd_billtype set

146

用友软件股份有限公司

billstyle=130,isitem='Y',isroot='N' where pk_billtype='FY'进行更正

3。设置完成后,录入单据,能看到生成的实时凭证,但生成凭证时报错,没有找到控制规则,后问会计平台开发人员,新增单据类型后,要新建公司帐才能用,

只得通过脚本 insert into dap_controlrule (........) update dap_controlrule set pk_glorg=‘0001KJ10000000000017’ where pk_billtype=‘FY’ 完成建帐时

(这个错误502依然存在)

凭证生成节点查询生成的会计平台凭证

12. 单点登陆

内容概述

在广泛多样的产品集成场景中,基于界面的集成是非常重要的一类。NC待办事务消息集成到Portal和在第3方产品(包含Portal)中打开NC具体节点是最典型的需求。

例如,很多企业拥有自己的OA Portal,并且是企业领导和员工最常用的办公桌面。这时候,希望作为其整体信息系统一部分的NC产生的待办事务消息也可以及时出现在其Portal中并且相应角色可以直接点击处理就成为最常见的要求。企业还希望在相应角色的办公桌面上直接添加NC业务节点的链接,使得其领导或员工可以不登陆而进入到具体NC节点做相应业务。

与第3方产品集成应用时,也常常面对本产品界面嵌入对方产品的需求,例如双方相关

147

用友软件股份有限公司

单据的互相联查。

详细介绍

无论是代办事务的集成还是NC节点嵌入的集成,都需要完成关键的三步:

1与NC进行单点登录。

2通过页面Iframe(隐藏)登录进NC系统

3通过javascript调用iframe中的NC Applet提供的特定java方法,进行反射类调用。 注意事项:因为Iframe安全性特性,通过javascript访问Iframe有跨域问题,如果第三方服务和NC不是同一个域,则可能无法调用NC Applet 。

比如nc所在的机器是 nc.test.com, 其它web服务器所在的机器是jsp.test.com 那么,他们就有一个共同的上级域名:test.com

你在nc的首页面中,用javascript设置 document.domain = "test.com";

然后把jsp的域名配制成test.com, 这样两者就可以互相访问了。

如果在portal中,这个域名可以配置,在ierp/portal/system.properties中,将portal.appdomain 设置成这个域名就行。但是要求这两个机器必须真正有这个域名。或者你可以在本机上hosts文件中模拟出来。

12.1.1. 单点登陆

使用http GET或者POST方式,向NC servlet提交如下信息: -09-14&language=simpchn&usercode=z1

&pwd=1&accountcode=new502&pkcorp=1001

提交参数: accountcode=帐套编码

workdate=工作日期

language=登录语言

usercode=用户编码 pwd=密码 key=生成的唯一key。

其中,前五个参数是NC正常登录需要的。这里重点解释key参数。此参数是一个凭证码,

148

用友软件股份有限公司

一旦注册通过,将可以拿着此key在一定时间内直接登录NC(如10秒中,具体看NC设置)。因此,单点登录的客户端需要保证此key在NC设置的时间段内不会重复。

一旦注册完成,可直接使用 http://NC_IP/login.jsp?key=注册所使用key略过登录界面直接进入NC主界面。

Http get 方式注册例子:

public void connect(String urlString) {

try {

URL url = new URL(urlString);

connection = (HttpURLConnection)url.openConnection();

connection.connect();

System.out.println(connection.getClass());

} catch (MalformedURLException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

}

public void readContents() {

BufferedReader in = null;

try {

in = new BufferedReader(new InputStreamReader(connection.getInputStream()));

String inputLine;

while ((inputLine = in.readLine()) != null) {

System.out.println(inputLine);

}

} catch (IOException e) {

e.printStackTrace();

}

}

打开NC节点:

完成单点注册后,在第三方页面中通过一个iframe,将http://NC_IP/login.jsp?key=注册所使用key引入,此时界面应该已经隐藏载入并初始化。

这一步需注意的是:C Applet载入需要一定的时间,因此调用代码必须等待Applet完全载入完毕才可以进行调用。下面是一个Javascript 初始化iframe的代码

function initNCFrame()

{ var frameID = "ncf1";

var frame = frameID;

//if(frame == null)

{ frame = document.createElement("iframe");

frame.id = frameID;

149

用友软件股份有限公司

}; frame.style.position = "relative"; frame.style.left = "0"; frame.style.top = "0"; frame.style.width = 200; frame.style.height = 100; frame.frameBorder = 0; frame.width = 0; frame.height = 0; frame.desingMode="off" frame.src = "http://127.0.0.1/login.jsp?key=1234"; document.body.appendChild(frame); } return frame;

: 通过NC Applet调用NC的方法

第三方页面和Applet交互比较常用的一个方式是通过javascript进行调用。NC Applet为执行客户端类提供了一个基于反射调用的方法,可以传入客户端可得到的任何java类名和参数,applet负责进行反射调用。此方法调用方式为:

Applet.callNC(className,methodName, argStr);

其中,applet是javascript获得的applet对象。callNC是applet提供的方法。className为欲调用java类,methodName是欲调用方法,argStr为参数。

对于打开NC节点的常用操作,NC默认提供了Nc.ui.sm.webcall.OpenNCNode类的openNode方法。所以,客户端可以直接按如下方法调用

Applet.callNC(“nc.ui.sm.webcall.OpenNCNode”,“openNode”,“节点号”)

打开NC节点例子:

function openNCNodeTest(){

try{

var nf = document.getElementById("ncf1");

if(nf!=null){

}else{

alert("ncIFrame null");

}

var ncapplet = nf.contentWindow.document.applets["NCApplet"];

if(ncapplet!=null){

}else{

alert("ncapplet null");

}

ncapplet.callNC("nc.ui.sm.webcall.OpenNCNode","openNode","H00100");

}catch(error){

150

用友软件股份有限公司

}

};

12.1.2. 打开代办事项

还是通过JS脚本和NC Applet打交道。

第一步,查询出代办事宜,显示在页面上

第二步,打开代办事宜界面

因为JS调用NC Applet方法只能传递字符串参数,所以需要将查询出的多个代办事项VO转换成1个字符串,然后JS解析成字符串数组,显示在界面。

当打开代办事项时也是传递字符串,NC的方法将字符串解析成代办事项VO然后在打开对话框

public String[] getMessageStr(String urls,String pk_user,String pk_corp) {

Properties props = new Properties();

props.setProperty("SERVICEDISPATCH_URL",urls + "/ServiceDispatcherServlet");

IplatFormEntry p = (IplatFormEntry) NCLocator.getInstance(props).lookup(IplatFormEntry.class.getName());

MessageFilter filter = new MessageFilter();

HashMap<Integer, MessageFilter> hmFilters = new HashMap<Integer, MessageFilter>(); hmFilters.put(MessageVO.SPACE_IN_WORKLIST, filter);

MessageDateTimeVO msgAggVO = null;

try {

msgAggVO = p.getFilteredReceivedMsgs(pk_user,pk_corp, hmFilters);

} catch (BusinessException e) {

e.printStackTrace();

}

MessageVO[] msgs = msgAggVO.getWorkitems();

if (msgs == null || msgs.length == 0){

return null;

}

String title = null;

for (MessageVO msg : msgs) {

title = MessageVO.getMessageNoteAfterI18N(msg.getMessageNote());

msg.setMessageNote(title);

}

String[] str = new String[msgs.length];

for(int i=0;i<msgs.length;i++){

str[i] = createMessageStr(msgs[i]);

String[] infos = str[i].split(";");

createMessageVO(infos);

}

return str;

}

打开NC待办事务-打开界面代码:

151

用友软件股份有限公司

public void openMsgPanel(String messageVOInfo) {

UIPanel panel = Desktop.getApplet().getDesktopPanel().getMessagePanel();

FramePanel framePanel = (FramePanel) panel;

MessagePanel msgPanel = (MessagePanel) framePanel.getToftPanel();

System.out.println("传入的messageVO信息::" + messageVOInfo);

if (messageVOInfo == null || "".equals(messageVOInfo))

return;

String[] infos = messageVOInfo.split(";");

processStringArray(infos);

String messageType = infos[0];

MessageVO msg = createMessageVO(infos);

System.outif (messageType.trim().equals("workitem")) {

/* 强制在审批结束时以对话框形式打开. */

msg.setForceDialogOpen(true);

msgPanel.acceptWorkitem(msg);

} else if (messageType.trim().equals("notice"))

msgPanel.acceptBulletin(msg);

else if (messageType.trim().equals("prealarm"))

msgPanel.acceptPrealert(msg);

}

通过JS代码调用ncapplet.callNC("zq.web.tools.db.ncwebtools","openMsgPanel",parm);

13. NC开发webservice-Axis

内容概述

本章介绍如果通过Axis把NC方法发布成webservice

详细介绍

13.1.1. 发布webservice

Axis(Apache extensible Interaction system)是Apache项目组织的一个开源项目。前身是Apache SOAP,它通过如下方法来扩展了soap2.0的功能:

AXIS的关键功能和优势表现在速度(早期的SOAP的分析机制是基于DOM的,而AXIS是基于SAX的),灵活性(提供了在引擎中插入新扩展的功能,可以对头部信息的处理和系统管理进行定制,在WSDD中对服务,Handler对象和串行并行程序进行描述),面向组件

152

用友软件股份有限公司

展开(引入了链接chainable和Handler的概念),传输框架(SOAP可以建立在SMTP, FTP, HTTP等多种传输层协议上)。

Axis支持三种web service的部署和开发,分别为:

1、Dynamic Invocation Interface ( DII)

2、Dynamic Proxy方式

3、Stubs方式

? 准备插件:

下载 eclipse-wtp-all ,集成了webservice开发插件

下载eclipse-ncplugin nc开发插件,

下载axis2-1.4

以上下载可以到 下进行下载,jdk版本选择1.5以上

下载 axis1.4 解压缩把其webapps目录下axis放到nchome/hotweb下,其中的lib下jar包 要删除一些,不要和nchome/lib里的重复,

保留五个axis.jar,axis-ant.jar,saaj.jar,wsdl4j-1.5.1.jar,commons-discovery-0.2.jar就可以 ? 开发Webservice

创建一个Webservice服务。在eclipse中创建一个动态的web工程。New->Project->Dynamic Web Project。在Target Runtime中设置服务,这里选择 apache-tomcat-V5.5,并设置tomcat目录

153

用友软件股份有限公司

在工程的src下,写一个service类,比如:

public class test2 {

}

public String sayHi(String name)就是要调用的远程方法

在这个类的文件名上点击右键,选择”Web Services“->“Create Web Service”,就会出现下面的界面:

一路向导下一步,就可生成wsdl,wsdd,客户端代理类 public String sayHi(String name) { return "hi,"+name; }

154

用友软件股份有限公司

? 部署

类放到nchome\hotwebs\axis\WEB-INF\classes下。代码放到此可以直接调用nc的类 server-config.wsdd放到nchome\hotwebs\axis\WEB-INF。

也可以将源代码拷贝到nchome\hotwebs\axis下,改后缀java为jws

在浏览器输入http://127.0.0.1/axis/services/HelloWorld.jws

点击Click to see the WSDL,如果看到如下界面就表示你已经成功发布一个Web Service了,就这么简单,如果出现错误就表示你的配置错误,或者是你的web.xml有问题,或者是你的包引用有问题. ,不建议用jws方式发布。

测试发布:

在浏览器输入 http://127.0.0.1/axis/services/HelloWorld

如果出现如下界面表示webservice发布成功

155

用友软件股份有限公司

13.1.2. 客户端代码调用

156

用友软件股份有限公司

第四篇 附录

14. XML和EXCEL

内容概述

本章介绍XML和Excel文件的操作

详细介绍

14.1. 利用XmlUtils读取XML

常用接口说明

? 利用XmlUtils遍历XML

常用

157

用友软件股份有限公司

158

用友软件股份有限公司

159

用友软件股份有限公司

以NC的prop.xml文件为例来讲解利用XmlUtils来解析xml的过程。 获取根节点及其属性

? XML文件中的根节点

? 解析代码

?

输出结果

获取指定元素及其值

? 以webport为例。XML文件中的定义:

? 解析代码

160

用友软件股份有限公司

? 输出结果:

获得包含内容对应全部名称

从internalServiceArray元素中查找MutexService并输出它对应的类名称。 ? XML文件片断:

? 解析代码

? 输出结果

? 利用XmlUtils生成XML文档

161

用友软件股份有限公司

常用接口:

? 通过拷贝现有的XML文件,构造XML文档

Document对象如果是需要单独构建(如从数据库读数据),而不是从其他XML拷贝,构建Document对象,请参考Document构造的标准语法。 ? 打印输出

如果需要生成物理文件,上面文件的对应语句改为:

PrintWriter p = new PrintWriter(new File("C:\\1.xml"), true);

? 输出代码、输出结果

162

用友软件股份有限公司

14.2. Excel文件读写

? Excel读写概念

? 文件流 : 可使用包装类POIFSFileSystem, 或者FileInputStream

? 文件流类包装基本流数据。读取Excel时,需要根据Excel文件名称构造文件流,然后将文件流传入HSSFWorkBook构造子中。解决文件数据的获取。

读取:FileInputStream fs = new FileInputStream(m_fileName);

wb = new HSSFWorkbook(fs);

?后续使用wb操作Excel数据读取。

fs.close();//关闭文件流

写入:FileOutputStream out = new FileOutputStream("workbook.xls");

HSSFWorkbook wb = new HSSFWorkbook();

?构造相关HSSFSheet等对象

Wb.write(out);//将workbook对象写入文件流

out.close();//关闭文件流

? 重要提示:文件流不管是读取还是写入,用完即释放,否则资源泄漏容易导致后续文件读写错误。

163

用友软件股份有限公司

? Excel对象

描述 对应关键对象

Excel WorkBook 对应Excel工作簿(HSSFWorkBook),一个工作簿包含很多页(HSSFSheet),一页中包含多行(HSSFRow),一行中包含多个Cell(HSSFCell)

Excel WorkSheet 对应HSSFSheet

Excel Row 行 对应HSSFRow

Excel Cell 单元格 对应HSSFCell

? 使用注意的问题

? 程序代码变成时,行,单元格的索引是从0开始的。

? 读Excel文件一般有两种方式,通过Event API和普通API。

? 读Excel文件时,一种方式是通过索引,另外一种方式通过Iterator。通过iterator: 不知道Excel文件具体的数据行和单元格结束位置,通过Iterator可以动态过虑空行。

? 低版本的POI处理中文时,需要在代码中设置编码Encode为Unicode。

? Excel单元格每个单元格存在格式,有字符串型,数字型等,需要自己进行转换。

? 数据读取例程

看附带的范例程序,调试例子可以弄清最简单的Excel读写数据。附件是例子代码,非常简单,在main方法中存在三个例子的测试。

15. 多语言

内容概述

本章将介绍如何使开发的业务需求具备多语言功能

详细介绍

Nc是支持多语言开发的,多语言开发需要多语言文件,在nchome\resources\lang 目录

164

用友软件股份有限公司

下存放中文简体,繁体,英文3种多语言目录,目录下按照产品号分目录,然后是具体的多语言文件,

15.1.1. 生成资源文件 UPP400603R0-000000=请输入第

UPP400603R0-000001=行的

UPP400603R0-000002=调出公司\n

UPP400603R0-000003=调出组织\n

UPP400603R0-000004=调出仓库\n

UPP400603R0-000005=发货日期\n

UPP400603R0-000006=到货日期\n

UPP400603R0-000007=第

UPP400603R0-000008=行发货日期早于到货日期\n

UPP400603R0-000009=调拨量\n

UPP400603R0-000010=辅调拨量\n

UPP400603R0-000011=没有存货

UPP400603R0-000012=无法读取公司

UPP400603R0-000013=信息

UPP400603R0-000014=请设置公司

UPP400603R0-000015=的本位币

UPP400603R0-000016=的折本折辅汇率

UPP400603R0-000017=选择全部

UPP400603R0-000018=取消全部

UPP400603R0-000019=查询备料计划错误

UPP400603R0-000020=请输入查询条件

15.1.2. 代码调用

有了资源文件,代码中需要有需要使用中文的地方都需要按照下面代码来调用

nc.ui.ml.NCLangRes.getInstance() .getStrByID("common", "UC001-0000006")/* res "查询" */

165

用友软件股份有限公司

16. 补丁与安装盘

内容概述

本章介绍如何制作安装盘和打补丁

详细介绍

16.1. 安装盘结构

安装盘包含一个到多个产品,安装盘的目录结构如下图所示:

安装盘下面可以放一个到多个产品,表现形式上为一个目录。

目录的名称必须为产品的模块

166

用友软件股份有限公司

标识名称,如客户化为uap,

16.2. 产品结构

一个产品包含一个到多个模块。产品的目录结构为下图所示:

对于一个产品来说,其配置文件(setup.ini)中的内容为

code=10 产品编码

name=客户化 产品名称

version=5.0 产品版本号

disk.type=new 是否是全新安装,new为全新安装,patch为补丁安装

previous.generation.code=10 自身依赖的前一个版本号

required.related.module= 依赖的其他产品

16.3. 模块结构

模块下面包含着该模块相关的多个jar包,

运行安装程序,将解压模块下的所有jar包到指定的nchome目录下,形成ncv5的目录结构(如下图所示)。所以在压缩jar包时需要安装该目录结构进行压缩。

167

用友软件股份有限公司

配置文件setup.ini中配置着该模块的相关信息。

"code" * 该模块的编码

"name" * 该模块的名称

"version" * 该模块的版本号

"disk.type"

* 该模块安装盘的类型,

* new 表示全新的安装盘

* patch表示为补丁盘

"previous.generation.code" *依赖的前一个产品编码,目前主要用于客户化 "must.selected"

* 表示该模块是否必须被选中

168

用友软件股份有限公司

* 取值为true/false 或 y/n

* 默认为false 或 n

"preversion" * 该模块自身依赖的版本号

"required.related.module" * 依赖其它的模块

* 表示为[code,name, version1, version2,...]&[code,name, version1, version2,...]

"product.package" * 代码和文件包

"help.package";

* 帮助压缩文件的文件名或目录名

"db.create.script";

* 数据库建库脚本包

"dataupdateclass";

/**数据升级程序的类名。如果需要注册多个升级调整程序,可以在 dataupdateclass后面附加序数来指定,例如

dataupdateclass01= classname1

dataupdateclass02=classname2

dataupdateclass03=classname3

"bill.templet.script"

/**单据模板脚本压缩文件的文件名或目录名*/

"query.templet.script"

/**查询模板脚本压缩文件的文件名或目录名*/

"report.templet.script";

/**报表模板脚本压缩文件的文件名或目录名*/

"print.templet.script";

/**打印模板脚本压缩文件的文件名或目录名*/ "sys.templet.script";

/**默认模板脚本压缩文件的文件名或目录名*/ "bill.type.script";

/**单据类型脚本压缩文件的文件名或目录名*/

"busi.type.script";

/**业务类型脚本压缩文件的文件名或目录名*/

"system.type.script";

/**系统类型脚本压缩文件的文件名或目录名*/

"subj.class.script";

/**科目分类脚本压缩文件的文件名或目录名*/

"voucher.templet.script";

/**凭证模板脚本压缩文件的文件名或目录名*/

169

用友软件股份有限公司

"project.templet.script";

/**项目模板脚本压缩文件的文件名或目录名*/

"business.script";

/**产品组内脚本压缩文件的文件名或目录名*/

"menu.script";

/**菜单脚本压缩文件的文件名或目录名*/

"ml.script";

/**多语言脚本*/

"ddc.initdata";

/**数据字典初始化数据*/

"hasdynamictempletdata";

/** 是否有动态摸板数据*/

"need_deploy_ejb";

/** 是否需要重新部署ejb*/

"containproductcode";

/**包含的产品编码*/

“resourceupdateclass”

/** 产品代码复制时的代码调整注册类*/

详细也可参考ConfigKey接口里的说明。

我们在做安装盘的时候需要导出脚本,代码jar包和建库脚本(提供sql和oracle就可)以及其他的一些资源,将这些资源,jar包安装上面介绍在setup.ini中配置好,jar包要用zip压缩,安装盘制作最好找一个现有的产品的安装盘参考。

16.4. 制作补丁

代码打包可以从开发环境里通过MDE Tools导出,导出的jar包可以直接放到nchome\modules下,也可以将类手工打包,分别放入对应目录,目录介绍可参照第一章NC产品目录介绍。系统会优先加载classes下的补丁类,然后才到lib加载jar包,所以如果修改了几个类可以直接把编译好的类放到相应得classes下就可。

170

用友软件股份有限公司

NC很多设计,开发配置都存放在数据库中,为了能在其他服务器安装自己做单据等节点,需要将脚本导出,系统管理登陆,数据导出节点可以将各种脚本导出。

171

用友软件股份有限公司

目前大部分的二次开发成果,都是手工方式通过这两步“补到”标准产品上去的,即打开数据库执行脚本;把代码添加到产品代码Jar包里。带来的后果很严重:

过程不规范,只有直接执行者才知道当前用户系统加了哪些东西。

次数一多,即使直接执行者也弄不清到底打上了哪些功能、哪些版本的代码。

带来重复测试、比对文件日期、甚至比对源码的工作量;同时降低客户满意度。

无法耐受二次开发和实施顾问的人员变更。

以上存在的问题类同于标准产品升级维护过程中遇到的补丁管理,因此也需要提供二次开发安装盘/补丁盘安装工具,实现脚本自动执行、代码自动拷贝,使二次开发成果部署过程标准化和易实施,并可以记录安装日志;提供二次开发产品安装信息查询和显示,以便项目人员直观、确切地了解系统安装状况。

? 以上标准产品安装盘配置与升级技术描述也适用于行业产品和二次开发产品。新衍生模块开发成果(例如行业产品开发或大型的定制型项目开发)可以制作安装盘,大部分的二次开发成果只能以标准产品补丁盘方式制作

? 二次开发安装盘按照扩展代码的具体情况把jar包放置在同级产品代码目录的extension子目录下,例如针对收付模块进行的二次开发代码就放在收付产品目录的extension子目录下。标准产品在升级安装时不会覆盖该目录内容。

172

用友软件股份有限公司

? 建议规范:二次开发安装盘版本号可以参照产品补丁盘版本命名规范再加具体项目简称方式管理。例如:中国电信基于NC V5.011的二次开发成果盘版本号为NC V5.011版本号+ zgdx)。

? 二次开发安转盘只要把他的代码按照标准安装盘的做法进行相应的打包即可(code.jar,可以把code.jar当成nc_home目录),二次开发脚本也是这样一种方式。

17. 设计开发规范

内容概述

本章介绍NC中的SQL规范和JAVA规范

详细介绍

17.1. SQL规范

NC SQL编程规范

一、概述

本手册侧重于代码编写过程中SQL语句的编写规范问题,内容涉及书写风格、性能优化、多数据适配等方面。

文档中用★标示的内容为必须遵守的条例,其余的可视为建议。

二、书写风格

1. SQL语句全部使用小写。★

2. 引用字符时用单引号。如:update testable set idcol=’abcd’。 ★

3. 连接符或运算符or、in、and、=、<=、>=, +,- 等前后加上一个空格。

4. 严禁使用select * ??.形式的语句,必须指出select的具体字段,即select col1, col2,? from tablea where ?.★

5. 严禁使用 insert into table values(?,?,?),必须指出具体要赋值的字段,即 insert into tablea (col1, col2,?) values(?,?,?)★

6. SQL语句包含多表连接时,建议对每个表命名别名,对每个字段的使用都要带上表别名,即 select a.col1, a.col2, b.col3 from tablea a, tableb b where a.col4=b.col5

7. 避免隐含的类型转换。例如在where子句中numeric 型和int型的列的比较或相加。★

173

用友软件股份有限公司

8. 读取是指通过JDBC读到的数据格式,保存是指保存在VO中的数据格式,插入或者更新是指insert或者update语句中的数据格式。

a) 整型字段:读取时根据字段设置保存为Integer或者Long。

b) 数字型字段:读取为BigDecimal,并保存为UFDouble,插入或者更新时为BigDecimal。 c) 字符型字段:读取为String,并保存为String,插入或者更新为String。

d) 布尔型字段:读取为String(‘Y’ OR ‘N’),并保存为UFBoolean,插入或者更新时为String(‘Y’ OR ‘N’)。

e) 时间字段:读取为String,并保存为UFDateTime,插入或者更新时的时间格式由中间件统一处理,有单独需求的要申请后才能决定。

9. 在子查询中前后必须加上括号, select col1, col2 from tablea where col3 in ( select col4 from tableb where col4>0)★

10. 避免在where使用'1=1','1=2'这种表达式作为部分条件,如 select col1, col2 from tablea where 1=1 and col1 >0。

11. 禁止使用视图。★

三、性能优化

1. 尽量使用prepareStatement,利用预处理功能。

2. 在进行多条记录的增加、修改、删除时,建议使用批处理功能,批处理的次数以整个SQL语句不超过相应数据库的SQL语句大小的限制为准。

3. 建议每条SQL 语句中in中的元素个数在500以下,如果个数超过时,应拆分为多条SQL语句。禁止使用xx in(‘’,’’?.) or xx in(‘’,’’,’’)。★

4. 禁止使用or 超过 500,如 xx =’123’ or xx=’456’。 ★

5. 尽量不使用外连接。

6. 禁止使用not in 语句,建议用not exist。★

7. 禁止使用Union, 如果有业务需要,请拆分为两个查询。★

8. 禁止在一条SQL语句中使用3层以上的嵌套查询,如果有,请考虑使用临时表或中间结果集。★

9. 尽量避免在一条SQL语句中从>= 4个表中同时取数,对于仅是作为过滤条件关联,但不涉及取数的表,不参与表个数计算;如果必须关联4个或4个以上表,尽量采用子查询的方式。

10. 尽量避免使用order by和group by排序操作,因为大量的排序操作影响系统性能。如必

174

用友软件股份有限公司

须使用排序操作,尽量建立在有索引的列上。

11. 对索引列的比较,尽量避免使用NOT 或 !=,可以考虑拆分为几个条件。如col1 是索引列,条件col1 !=0 可以拆分为col1 >0 or col2 <0

12. 任何对列的操作都将导致表扫描,所以应尽量将数据库函数、计算表达式写在逻辑操作符右边。

13. 在对char类型比较时,建议不要使用rtrim()函数,应该在程序中将不足的长度补齐。

14. 用多表连接代替EXISTS子句。

15. 如果有多表连接时,应该有主从之分,并尽量从一个表取数, 如select a.col1, a.col2 from a join b on a.col3=b.col4 where b.col5 = ‘a’。

16. 在where子句中,如果有多个过滤条件,应将索引列或过滤记录数最多的条件应该放在前面。

17. 在使用Like时,建议Like 的一边是字符串,表列在一边出现。

四、多数据库的考虑

18. 字符串连接必须用“||”符号,不使用“+”。注意:在Oracle中一个null值与非null值连接,结果为非null值,在DB2和SqlServer中相反。使用isnull()对null转换为’’ 。★

19. 通配符不能使用‘[a-c]%’这种形式,应写成如:select col1, col2 from table_name where col1 like ‘[a]%’ OR col1 like ‘[b]%’ OR col1 like ‘[c]%’ 。★

20. 在Case when语句中只能出现 =、>=、<= 以及is null运算符,不能出现 <、>、<>、!=、以及is not null运算符。 否则在Oracle的decode函数无法表达。★

当必须使用 <, >, != ,is not null时,建议采用如下变通方法:

1)使用 !=时:例如 case when A!=B then e,

可改为 : case A=b then e1 else e (间接实现 A!=B)

2)使用 < 时:例如 case when A<B then e,

可改为 : case A<=b then case A=B then e1 else e (间接实现 A<B)

或 case A>=b then e1 else e (间接实现 A<B)

3)使用 > 时:例如 case when A>B then e,

可改为 : case A>=b then case A=B then e1 else e (间接实现 A>B)

或 case A<=b then e1 else e (间接实现 A>B)

4)使用 is not null 时:例如 case when A is not null then e,

可改为: case A is null then e1 else e (间接实现 A is not null)

175

用友软件股份有限公司

特别说明:当执行大数据量的操作时,sql Server 对 case when 的执行效率极低,甚至可能会死机,因此希望大家尽量不要使用case when。

21. 左连接的写法必须带“outer”关键字。例如: select f1 from t1 left outer t2 on t1.f1 = t2.f1;而不是: select f1 from t1 left t2 on t1.f1 = t2.f1。★

22. 只能使用以下函数,如要使用新的函数必须申报,审批后才能使用。函数:coalesce, cast, len, left, replace, right, substring, lower, upper, ltrim, rtrim, abs, acos, asin, atan, cos, ceiling, exp, floor, log, power, round, sign,sin, square, sqrt, tan, count, max, min, sum, avg。★

23. substring函数中起始位置为1,表示从头开始。★

24. 对于一些char/varchar的字段的值,即使是0,1,2?等值,也必须表达为’0’,’1’,’2’? ★

25. 在cast和convert语句中只支持到字符型、日期型和数字型的转换,且日期型只支持UFDate的格式,即’YYYY’-‘MM’-‘DD’ ★

26. 不能通过来percent n 限制查询结果集的记录数,也不能使用 select top n 的语句★

27. join 与on 必须严格匹配,不允许出现没有on的join。★

28. join?on 后面慎用 or,如果用到,请把or的范围用( )括起来

29. 不能使用select into 的格式★

30. 给某个字符型的列赋值时,如果其值含有单引号,例如:set col=’fsdf’fdsfdsf’sdf’?, 有两种解决方案:

1) 使用转意字符,将单引号写成’’,即 set col=’fsdf’’fdsfdsf’’sdf’?

2) 通过set的方式赋值,即:set col= ? ?

然后:setString(8,” ’fsdf’fdsfdsf’sdf’”)

17.2. java开发规范

软件开发涉及到各方面人员的交互、协作,为了有效地进行项目开发的沟通,完善代码的维护和交付,有必要在一个小组中采用统一的软件开发标准。一般来说,制定这样的标准有下列好处:

? 方便软件维护。据统计,80%的软件开发费用在维护,规范化的代码才方便维护,降低

176

用友软件股份有限公司

维护成本。

? 在软件的整个生命期内,期望一个编码人员从开始到该软件报废一致维护其代码是不现实的,必然需要不断地交付、协同

? 好的编码规范能够大大增强代码的可读性,便于开发人员快速的理解新代码。

? 任何产品都需要好的包装。我们可以把代码本身看作是一种产品,那么按照规范编程也是对这个“产品”的包装

? 规范化的代码也是软件质量的保证手段之一,也是软件过程能够流畅的基础。

我们每个人必须牢牢树立这样的观念:无论从时间跨度还是从工作量来说,一个软件系统生存期的大部分是维护,不是开发。你今天所编写的代码,会一直使用很多年,并且很有可能被其他人维护和改进。所以,我们必须努力写出“干净”和易读的代码。

注:本规范中加黑加下划线部分是强制执行规范,请严格遵守。

2.文件

? 属性文件后缀为properties,并且符合java中i18n的规范;

? 对于各产品模块自己的配置文件必须放置在自己模块的config目录下;

? 各个产品模块的图像文件放在webapps\nc_web\images目录下的自己子目录内; ? 各个产品模块自己的多语言文件放在NC_HOME\resources

? 文件的命名需要有一定的意义,尽量简短,名称符合操作系统的要求,没有特殊情况文件名称不能存在空格,对于普通的文件单词与单词之间采用下滑线进行。

3.命名规则

3.1基本的规则

? 字符集在26个英文字母、0到9的阿拉伯数字和下划线之中。Java中类、字段、方法、变量、常量尽量用字母表达,没有特别的理由不能用任何的其他字符

? 命名需要有一定的意义,推荐采用问题域中的术语命名,使命名在一定程度上是自描述的

? 命名尽量的短,如果命名太长,可以采用别名的方式,或者缩写来简化命名。缩写一定要有的意义,而且需要在整个项目中维护这些缩写的意义

? 名称缩写的规则(对于类名、字段名、变量名称、模块名称等适用)

177

用友软件股份有限公司

1) 删除所有的原音字母,压缩重复字母。如button,缩写为btn,

2) 如发生命名冲突,则在某一缩写中保留原音。如batton,为了不与button冲突,缩写为batn

? 不要用前导下划线,也不要在命名的末尾用下划线

3.2常量命名

? 所有的字符都必须大写。采用有意义的单词组合表达,单词与单词之间以“_”下划线隔开。

? 命名尽量简短,不要超过16个字符

程序开发中最好不要直接对literal进行工作,最好引入常量方式应用;只有在特别的情况下才能使用, 如在for循环中初始化变量时可直接用-1,0,1这些常量。

例:

public final int MAX_SIZE = 120;

public final int MAX_WIDTH = 100;

public final String PROPERTY_NAME= "menu" ;

3.3变量命名

变量的命名包括实例变量,静态变量,函数参数的命名。

? 避免在命名中采用数字,除非命名意义明确,程序更加清晰,对实例变量的命名中不应该有数字

? 变量名称是名词意义

? 采用有符合问题域意义的单词或单词组合。第一个单词全部小写,后续的每个单词采用首字母大写,其余小写(特殊单词除外,如URL)

? 命名尽量简短,不要超过16个字符

? 除了生命周期很短的临时变量外,避免采用单字符作为变量名,实例变量的命名不要用单字符。常用的单字符变量如整型用 i、j、 k、 m、 n字符型用c、d、 e,坐标用x、y、z。

? 在某些情况下,变量可能需要加上类型前缀,所有的类型前缀必须是小写,他与变量名称的实体部分没有任何间隔,实体部的每个单词都是首字母大写,其余字母小写(特殊单词除外如URL),类的全局变量强烈建议使用,一般的类型前缀如下:

类型前缀 类型 例子

178

用友软件股份有限公司

b

f

d Boolean、boolean bsingle 浮点数 fsize UFDouble dmoney

dt Date dtToday

c Character,、char cinput

obj OBJECT变量 ObjUser

str 字符串(String, StringBuffer) strFileName

i 整型数 iCount

aryName

ConnActiveConnection ary 数组 conn 连接

stmt Statement StmtFindUser

rs Resultset RsUsers

alData ArrayList al

Map map key_value_Map

Set set ValueSet

col Collection

msg 消息

err 错误

btn 按钮 colNames msgText errCode btnSubmit

? 不在特别的情况下,Java中不推荐采用前缀,而是推荐保持名称的语义

例:

public int width;

public String fileName;

public static ApplicationContext context;

3.4方法命名

命名多数为动词结构

? 采用有符合问题域意义的单词或单词组合。第一个单词采用小写,后续的每个单词采用首字母大写,其余小写(特殊字除外如URL),没有特别理由不用下划线作为分隔符 ? 在Java中对属性方法命名遵循JavaBean的标准:

179

用友软件股份有限公司

1) getter方法: get+属性名, 对boolean型采用is+属性名,有些特定的属性名用has, can代替is可能更好

2) setter方法: set+属性名

? 构造方法的命名与类名一致

如:

String getName();

string isStopped();

void connect();

3.5类和接口的命名

? 采用有符合问题域意义的单词或单词组合,每个单词的首字母大写,其余字母小写(特殊字除外如URL)

? 接口的第一个字符采用I

? 对与继承ValueObject对象的类,以VO结尾

例:

public class Fiugre

public interface FiugreContainer

public class StdFigure //std为Standard的缩写

3.6 EJB命名

? EJB远程接口与普通的类没有区别(EJB名称),本地接口如果需要区分,加后缀Local(EJB名称+Local)

如:

WorkflowEngine、WorkflowEngineLocal

? EJB远程 home接口,为EJB名称 + Home,如果为本地接口,命名为EJB名称+ LocalHome

如:

WorkflowEngineHome、WorkflowEngineLocalHome

180

用友软件股份有限公司

? EJB实现类在EJB名称,加后缀EJB或Bean,推荐用Bean作为后缀

如:

WorkflowEngineEJB或WorkflowEngineBean

? 只读的Entity Bean, EJB远程接口命名加后缀RO,如UserProfileRO,本地接口后缀为LocalRO,如PosRightsLocalRO

? EJB的JNDI名称为EJB的全名(即带包名)

如:

com.sinosoft.workflow.server.WorkflowEngine

com.sinosoft.workflow.server.WorkflowEngineLocal

3.7包的命名

? 采用逻辑上的层次结构,从而减少依赖

? 产品模块对外的接口定义放在nc.itf.模块名.xx

? 服务的实现类nc.impl.模块名.xx

? 后台业务类代码nc.bs.xx

? 值对象命名:nc.vo.模块名

? UI层命名:nc.ui.模块名

? 命名简短,常采用缩写

? 包名所有字符都为小写

? 不要用java, javax作为自定义包的前缀

4.注释规范

4.1 基本规则

? 注释应该使代码更加清晰易懂

? 注释要简单明了,只要提供能够明确理解程序所必要的信息就可以了。如果注释太复杂说明程序需要修改调整,使设计更加合理。

? 注释不仅描述程序做了什么, 还要描述为什么要这样做,以及约束

? 对于一般的getter、setter方法不用注释

? 注释不能嵌套

? 生成开发文档的需要用中文编写

4.2 Java中有三种注释方式说明

4.2.1文档注释 /** */

可以对用多行,一般用来对类、接口、成员方法、成员变量、静态字段、静态方法、常量进

181 、

用友软件股份有限公司

行说明。Javadoc可以用它来产生代码的文档。为了可读性,可以有缩进和格式控制。

文档注释常采用一些标签进行文档的特定用途描述,用于帮助Javadoc产生文档,常用的有: 标签 Used for 目的

@author name 类/接口 描述代码的作者,每个作者对应一个这样的标签

@deprecated 类

成员方法 说明该段API已经被废除

@exception name description

@throws name description 成员方法

每个异常一个对应一个这样的标签

@param name description 成员方法

一个这样的标签

@return description

@since 类/接口

成员方法 描述该段API开始的时间 成员方法 描述成员方法的返回值的意义 描述成员方法中的参数用途和意义,一个参数对应描述方法抛出的异常

@see ClassName 类/接口

成员方法

成员变量 用于引用特定的类描述,一般ClassName用包括包名的全名

类/接口 @see ClassName#memberfunction

成员方法

成员变量 用于引用特定的类的成员方法的描述,一般ClassName用包括包名的全名 @version text 类/接口 版本

@inheritDoc 类/接口

成员方法

4.2.2行注释 //

一次只能注释一行,一般用来简短的描述某一个局部变量,程序块的作用。

4.2.3块注释: /* */

可以用多行,一般用来对程序块、算法实现、类的实现进行说明。为了可读性,可以有缩进和格式控制。一般在行注释不能满足注释需要的时候采用。一般用来作为文件头、复杂算法

182 继承的文档

用友软件股份有限公司

的说明,方法体内的复杂过程说明等

4.3类/接口注释

类/接口描述,一般比较详细。按照常用的说明顺序排列,主要包括

? 类的主要说明,以。或.结束

? 类设计的目标,完成什么样的功能

? <Strong>主要的类使用</Strong>如何使用该类, 包括环境要求,如是否线程安全,并发性要求, 以及使用约束

? <Strong>已知的BUG</Strong>

? 描述类的修改历史:<Strong>修改人+日期+简单说明</Strong>

? @author作者、@version版本, @see参照,@since开始版本等信息如:

? 版本就以当时开发的NC产品的应用版本号为准

/**

* This class provides default implementations for the JFC <code>Action</code>

* interface. Standard behaviors like the get and set methods for

* <code>Action</code> object properties (icon, text, and enabled) are defined

* here. The developer need only subclass this abstract class and

* define the <code>actionPerformed</code> method.

* <p>

* <strong>Warning:</strong>

* Serialized objects of this class will not be compatible with

* future Swing releases. The current serialization support is appropriate

* for short term storage or RMI between applications running the same

* version of Swing. A future release of Swing will provide support for

* long term persistence.

*

* @version 1.41 02/02/00

* @author Georges Saab

* @see Action

*/

183

用友软件股份有限公司

为了使形成的文档可读性好,注释中经常带有缩进和格式控制。类描述放在类的类定义的紧前面,不能有任何的空行。

4.4变量注释

? 成员变量、类静态变量采用文档注释,对成员变量的注释通常包括:

1) 变量的意义

2) 变量的合法值域

3) 对并发访问的限制

如:

/**

* Web.xml文件中configServlet参数的UIAPP.xml initparam

*/

public final static String APP_CONFIG = "aaa.uiapp";

? 局部变量,如算法相关的变量采用块或行注释

如:

void func() {

int i; //用于循环计数

…………

}

? 参数变量注释一般用文档注释,并且用@param来说明为参数,一般包括:

1) 参数的用途

2) 对参数值范围的要求

4.5 方法注释

描述函数的功能,对成员方法,静态方法一般采用文档描述,特别是公开的方法。注释可以很详细,为了可读性强也可包含格式控制,如下面说明含有缩进:

/**

184

用友软件股份有限公司

* Here is a method comment with some very special

* formatting that I want indent(1) to ignore.*

*/

方法注释一般包括:

? 方法的主要说明,以。或.结束

? 描述方法完成什么样的功能,方法的目标,用该方法的原因

? 描述方法的使用方法,包括使用的环境要求,如前置条件,后置条件和并发性要求 ? 描述已知的bug

? 描述方法的修改历史:<Strong>修改人+日期+简单说明</Strong> (<修改人+日期+简单说明>)

? @param c elements to be inserted into this list.(参数说明)

? @return <tt>true</tt> if this list changed as a result of the call.(返回值说明)

? @throws NullPointerException if the specified Collection is null.(异常说明) ? @see如果重载方法必须参考父类的方法

? Eclips下采用Alt+Shift+J生成Javadoc说明方法的放回值((@return)

4.6 算法注释

算法描述指在实现级别的描述注释,如在方法内的注释,对类实现的注释,这样使得程序更加易懂,方便程序算法的修改和BUG的修复。一般采用块/行注释,对于简短的描述采用行注释,不要用文档注释。注释的主要内容包括:

? 某些局部变量的意义和用途

? 复杂的控制结构的注释,如循环,分枝,条件表达式。说明控制所要达到的目标 ? 复杂的代码段的描述,说明代码完成的功能,以及为什么这样做。

? 使用@ inheritDoc开始

4.7 修改记录

修改记录放在类的文件头说明中,一般为<修改人> + <修改日期> + <-> + <修改描述>。

5.编码规范

5.1基本原则

185

用友软件股份有限公司

? 一个程序文件最好不要超过2000行

? 尽可能缩小对象的作用域,这样对象的可见范围和生存期也都会尽可能地小

? 一个方法所完成的功能要单一,不同的功能封装为不同的方法.

? 尽可能的处理异常或转换异常,不要一味的包装异常

? 如果对象在某个特定范围内必须被清理(而不是作为垃圾被回收),请使用带有finally子句的try块,在finally子句中进行清理。

? 对于把一些逻辑相关的类组织在一起,可以考虑把一个类的定义放在另一个类的定义中,这种情况推荐使用内部类(比如界面层中的事件响应等)。内部类拥有所有外围类所有成员的访问权。

? 对成员变量的访问最好通过getter/setter方法,这样能够保证访问的合法性,以及代码调整 ? 优先选择接口而不是抽象类或具体类。如果你知道某些东西将成为基类,你应当优先把它们设计成接口;只有在必须放进方法定义或成员变量时,才把它修改为具体或抽象类。接口只和客户希望的动作有关(协议),而类则倾向于关注实现细节。

? 在处理可变String的时候要必须使用StringBuffer类,可变范围在5次以内可以使用String

? 使用java标准库提供的容器。精通他们的用法,将极大地提高工作效率。优先选择ArrayList来处理顺序结构,选择HashSet来处理集合,选择HashMap来处理关联数组,选择linkedList来处理堆栈和队列,它对顺序访问进行了优化,向List中间插入与删除的开销小,但随机访问则较慢。当使用前三个的时候,应该把他们向上转型为List、Set和Map,这样就可以在必要的时候以其它方式实现

? 数组是一种效率最高的存储和随机访问对象引用序列的方式,但是当创建了一个数组对象,数组的大小就被固定了,如果在空间不足时再创建新的数组进行复制,这样效率就比ArrayList开销大了。所以必须明确使用场景。

? 尽量使用”private”、”protected”关键字。一旦你把库的特征(包括类、方法、字段)标记为public,你就再也不可能去掉他们。在这种方式下,实现的变动对派生类造成的影响最小,在处理多线程问题的时候,保持私有性尤其重要,因为只有Private的字段才会受到保护,而不用担心被未受同步控制的使用所破坏。

? 采用类而不是对象引用静态变量和方法

? 使用UFBoolean必须采用

UFBoolean.valueof(true|false|y|n|Y|N)的形式进行构造

186

用友软件股份有限公司

? 禁止后台业务代码使用如下代码

try{

something()

}catch(Exception ex)

{}

new Exception()

5.2类编写规范

类的结构组织,一般按照如下的顺序:

1. 常量声明

2. 静态变量声明

3. 成员变量声明

4. 构造函数部分

5. Finalize部分

6. 成员方法部分

7. 静态方法部分

这种顺序是推荐的,在实际开发中可以按照一定的尺度修改,原则是程序更易读。如对方法的排序按照重要性,或按照字母顺序排列或按照方法之间的关系排列。

每个方法(包括构造与finalize)都是一个段。多个变量声明按照逻辑共同组成一个段,段与段之间以空行分隔。

类声明时,要指出其访问控制,一般为没有修饰符,public,和private。

方法与方法之间,大的部分之间都需要以空行隔离。

编写通用性的类时,请遵守标准形式。包括定义equals()、hasCode()、toString()、Clone(实现Cloneable接口),并实现Comparable和Serialiable接口

对于设计期间不需要继承的类,尽量使用final

5.3变量

? 对成员变量, 尽量采用private

? 每一个变量声明/定义占一行(参数变量除外),如:

int a;

int b;

比int a,b; 更容易读, 更容易查找bug

187

用友软件股份有限公司

? 局部变量在使用前必须初始化,一般在声明时初始化

? 变量的声明要放在程序块的开始位置

如:

void myMethod() {

int int1 = 0; // beginning of method block

if (condition) {

int int2 = 0; // beginning of "if" block

...

}

}

一种例外情况是在for语句中,定义声明不仅不占一行,还在表达式内部,完全采用Eclips生成,如:

for(int i = 0; i<100; i++)

? 数组的申明采用 <数据类型[] + 变量名>方式如:

char[] buffer;

而不是:

char buffer[];

5.4方法

? 对成员方法,不要轻易的采用public的成员变量。主要的修饰符有public, private, protected, 无

? 空方法中方法声明和函数体可都在一行。如: void func(){}

? 方法和方法之间空一行

? 方法的文档注释放在方法的紧前面,不能空一行。

? 避免过多的参数列表,尽量控制在5个以内,若需要传递多个参数时,当使用一个容纳这些参数的对象进行传递,以提高程序的可读性和可扩展性

? 方法中的循环潜套不能超过2层

? 对于设计期间不需要子类来重载的类,尽量使用final

? 每个方法尽量代码行数尽量不要超过100行(有效代码行,不包括注释),但必须保证逻辑的完整性

188

用友软件股份有限公司

5.5 语言使用及书写规范

? 避免变量的定义与上一层作用域的变量同名。

? 方法与方法之间用需要用一空行隔开

? 局部变量在使用时刻声明,局部变量/静态变量在声明时同时初始化

? 在与常数作比较时常数放在比较表达式的前面如:

if(“simpleCase”.equals(obj))…

if(null == obj)….

? return语句中,不要有复杂的运算。

? switch语句,需要一个缺省的分支

18. 开发常见问题与技巧

内容概述

本章将NC中常用的技巧和问题进行介绍

详细介绍

18.1. 环境变量类 nc.ui.pub.ClientEnvironment

环境变量类 nc.ui.pub.ClientEnvironment是开发中最常用到的类。

常量定义:

/** 用户类型常量 - 系统管理员。 */ public static final int SYSTEM_ADM = 1; /** 用户类型常量 - 帐套管理员。 */ public static final int ACCOUNT_ADM = 2; /** 用户类型常量 - 公司管理员。 */ public static final int CORP_ADM = 3; /** 用户类型常量 - 普通用户。 */ public static final int USER = 4;

/** 用户类型常量 - 超级用户。 */ public static final int SUPER_USER = 5; 常用环境变量列表

189

用友软件股份有限公司

190

用友软件股份有限公司

示例:

获得当前登录用户 UserVO m_user = ClientEnvironment.getInstance().getUser();

18.2. 发送待办消息

UAP发送待办消息方法

void nc.itf.uap.pf.IPFMessage.insertCommonMsg(CommonMessageVO cMsgVO) throws BusinessException

参数说明

cMsgVO 普通消息VO,结构定义如下:

public class CommonMessageVO extends ValueObject {

/** 消息内容 */

private String m_message = null;

/** 发送人PK */

private String m_sender = null;

/** 接收人pk */

private UserNameObject[] m_receiver = null;

/** 发送时间 */

private UFDateTime m_sendDate = null;

/** 标题 */

private String m_title = null;

191

用友软件股份有限公司

/**消息优先级*/

private int priority = MessagePriority.PRI_NORMAL(另外两个常量是

PRI_LOW;PRI_HIGH);

}

使用说明

该方法前后台均可使用,用于向指定的用户发送业务消息。执行效果为在消息中心的待办事务中插入一条普通消息,双击时弹出消息内容对话框。

18.3. 模板中下拉框的值

字符串的前缀有 I IX C CX S SX 六种代表不同的含义:

I 将下拉框的索引号作为整型返回

IX 将下拉框的索引号作为整型返回

C 将下拉框的索引号作为Char类型返回

CX 将下拉框的索引号作为Char类型返回

S 返回下拉框中显示的内容

SX 可设置返回值和显示内容的对应关系,选择某一个显示值则会返回该显示值对应的返回值 格式 “SX,*态=6,审核通过=7,审核不通过=9”

以上六种类型中两个字母的(IX、CX、SX)可通过“=”号设置对应关系,而剩下的类型会把整个字符串包括“=”号都显示出来。

比如可写:SX,提交=3,作废=4

18.4. 数据权限过滤

在启用数据权限后,我们查询时参照会显示拥有权限的数据,但如果不加条件,就会把所有数据查询出来,这样数据权限就没有作用了,这时就需要自己过滤数据权限。这里需要调用nc.itf.uap.rbac.IPowerManageQuery的相应方法。一般先判断是否启用某个数据项的权限,如果启用权限,就查询出具有权限的数据或者SQL自己进行过滤。如果是通过参照选择了条件,因为参照已经进行过滤,就不需要自己过滤。

192

用友软件股份有限公司

/**

* 根据用户PK、资源标识、组织类型、组织PK查询用户是否具有权限.

* 算法描述:

* 1.根据voUserPowerQuery的资源标识、组织主键可以查询资源是否启用权限控制。

* 2.如果资源没有启用权限控制,则直接返回true,退出此方法。

* 3.否则表示资源启用权限控制

* 3.1.根据用户PK、组织PK、资源标识查找出用户所委派的角色集没有进行权限控制的角色数

* 3.2.如果没有进行权限控制的角色数为0,则返回true,否则返回false */

boolean isUserHavePower(UserPowerQueryVO voUserPowerQuery,String resourceDataId)

/**

* 根据UserPowerQueryVO所提供的资源标识、用户PK、组织类型、组织PK,查询权限数据。

* 算法描述:

* 1.根据voUserPowerQuery可以查询用户是否启用权限控制

* 2.生成PowerResultVO实例,并设置此实例的权限控制标志

* 3.如果没有启用权限控制,则返回此实例,退出此方法

* 4.否则表示用户启用权限控制

* 4.1.通过其资源标识得到权限表

* 4.2.根据用户PK、组织类型、组织PK查找出用户委派的角色集所分配的权限集合

* 4.3.设置PowerResultVO实例的权限值,返回此实例,退出此方法

*/

PowerResultVO getUserPower(UserPowerQueryVO voUserPowerQuery)

/**

* 根据UserPowerQueryVO所提供的用户PK、资源标识、组织类型、组织PK,获得查询权限的sql。

* 算法描述:

* 1.根据voUserPowerQuery可以查询用户是否启用权限控制

* 2.如果没有启用权限控制,则返回null,退出此方法

* 3.否则表示用户启用权限控制

* 3.1.通过其资源标识得到权限表

* 3.2.根据用户PK、组织类型、组织PK,对用户所具有的权限集合拼写出SQL语句 */

String getSql4UserPower(UserPowerQueryVO vo)

UserPowerQueryVO类是参数类,其中resouceId必需保证正确,可参sm_powerresource

193

用友软件股份有限公司

表查询resouceId

public class UserPowerQueryVO extends ValueObject {

/**

* 用户PK

*/

private String userPK;

/**

* 权限资源的标识,功能权限为1,按钮权限为2,等等

*/

private int resouceId;

/**

* 公司类型为1,主体账簿类型为2,复合类型为3,默认为公司类型。

*/

private int orgTypeCode = IOrgType.COMPANY_TYPE;

/**

* 组织主键。

*/

private String orgPK;

/**

* 公司主键。

* 如果为公司类型,则表示orgPK;如果为主体账簿类型时,则还要提供公司主键,这样可以避免再根据主体账簿查找公司。

*/

private String corpPK;

/**

* 分配公司。一般不必要去设置,目前主要应用于查询集团的会计科目权限。

* 如果allocCorp不为空并且不等于corpPK,则表示查询分配allocCorp公司的那部分权限。

*/

private String allocCorp;

}

194