您的当前位置:首页正文

体系结构设计说明书

2021-05-02 来源:步旅网


文件标识 版 本 号 密 级 0.98 内部

App Suite产品 体系结构设计说明书

编制 审核 批准 日期 日期 日期

修订记录

版本编号

版本日期 修订人 说明

目 录

1 2 3 4

文档说明 ................................................................................................................................... 1 术语和缩略语 ........................................................................................................................... 1 主要功能概述 ........................................................................................................................... 4 体系结构设计约束条件 ........................................................................................................... 4 4.1 4.2 4.3 5 6

框架依赖 ................................................................................................................... 4 非功能要求 ............................................................................................................... 4 分布要求 ................................................................................................................... 4

设计准则和设计决策 ............................................................................................................... 5 核心需求描述 ........................................................................................................................... 6 6.1

功能性需求 ............................................................................................................... 6 6.1.1 6.1.2 6.1.3 6.2

系统平台管理员视图 ....................................................................................... 7 租户管理员视图 ............................................................................................... 8 租户用户视图 ................................................................................................. 10

非功能需求 ............................................................................................................. 12

7 8

概念模型 ................................................................................................................................. 12 设计模型 ................................................................................................................................. 20 8.1

子系统划分及概述 ................................................................................................. 20 8.1.1 8.1.2 8.1.3 8.1.4 8.1.5 8.1.6 8.1.7 8.2

平台管理 ......................................................................................................... 21 应用及对象管理 ............................................................. 错误!未定义书签。 用户管理及访问控制 ..................................................................................... 24 工作流管理 ..................................................................................................... 28 报表 ................................................................................. 错误!未定义书签。 多租户运行时服务 ......................................................................................... 29 标准应用组件 ................................................................................................. 43

通用的设计机制 ..................................................................................................... 60 8.2.1 8.2.2 8.2.3

数据缓存 ......................................................................................................... 60 事件通知 ......................................................................................................... 61 表现层的界面元素 ......................................................................................... 61

8.3 8.4

子系统接口 ............................................................................. 错误!未定义书签。 子系统实现类图 ..................................................................... 错误!未定义书签。 8.4.1 8.4.2 8.4.3 8.4.4

平台管理 ......................................................................... 错误!未定义书签。 应用及对象管理 ............................................................. 错误!未定义书签。 用户管理和访问控制 ..................................................... 错误!未定义书签。 多租户运行时 ................................................................. 错误!未定义书签。

I

8.4.5 8.4.6 8.4.7 8.5

工作流管理 ..................................................................... 错误!未定义书签。 报表 ................................................................................. 错误!未定义书签。 标准应用组件 ................................................................. 错误!未定义书签。

核心用例实现 ......................................................................... 错误!未定义书签。 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.5.6 8.5.7 8.5.8 8.5.9

平台管理员创建租户并分配租户资源 ......................... 错误!未定义书签。 租户用户登录系统 ......................................................... 错误!未定义书签。 租户管理员创建应用 ..................................................... 错误!未定义书签。 租户管理员创建对象 ..................................................... 错误!未定义书签。 租户管理员部署应用 ..................................................... 错误!未定义书签。 租户用户访问对象主页 ................................................. 错误!未定义书签。 租户用户创建新的对象实例 ......................................... 错误!未定义书签。 租户用户查询对象实例 ................................................. 错误!未定义书签。 租户用户修改新的对象实例 ......................................... 错误!未定义书签。

8.6 组件描述 ................................................................................. 错误!未定义书签。 8.6.1 8.6.2 8.6.3

构件综述 ......................................................................... 错误!未定义书签。 构件1 .............................................................................. 错误!未定义书签。 构件2 .............................................................................. 错误!未定义书签。

8.7 部署描述 ................................................................................................................. 61 8.7.1 8.7.2

网络拓扑图 ..................................................................................................... 61 节点功能及构件分布 ..................................................................................... 61

9 参考文献 ................................................................................................................................. 61

II

1 文档说明

本文档通过选取关键用例进行分析设计形成一个稳定的系统结构,指导所有用例的分析设计和实现。

本文档由开发经理负责编制,由产品组和公司技术专家进行评审。开发经理负责本文档的维护和修订。

本文档的预期读者是全体产品组/项目组成员和其他产品/项目的开发经理。

2 术语和缩略语

词汇名称 模型驱动架构 (Model driven Architecture) 表格 1 词汇表

词汇含义 由OMG定义的软件开发框架。MDA的关键之处是把建模语言当做编程语言来用,而不只是当作设计语言来用。从而提供生成率,改善质量,并使软件的生存期更长。MDA利用元数据建模,通过对商业模型的领域研究,进而定义相对核心的领域模型,抽象PIM(平台无关模型),之后根据不同的开发平台、应用平台转换成相应的PSM(平台相关模型)。 模型(Model) 云计算(Cloud computing) 模型,用精确定义的语言书写的系统的描述。 可以粗略地定义为根据需要使用在用户环境之外以服务形式提供的可伸缩计算资源。用户只使用需要的资源,只为使用的资源付费。在任何时候,在 Internet 上的任何地方,都可以访问 “云” 中的任何资源。不需要关心云中的资源在幕后是如何维护的。 多租户(Multi-tenancy) 一种所有用户和应用共享同一个一致的基础设施和应用实例的应用模型。 元数据(metadata) 元数据定义了App Suite支持的可配置的应用属性,包括应用的功能和界面表现。应用开发者可以通过修改应用元数据配置或创建新的应用。 标准应用 是App Suite平台内置的应用组件,可在多个租户的应用空间中共享,是面向特定应用领域的通用解决方案实现。 标准对象 随App Suite平台一起部署的已定义对象,是构成标准应用、工具组件的对象,特定的租户可以通过配置标准对象的属性,定制标准对象的行为和表现;也可以使用标准对象默认第1页

的行为和表现。 自定义应用 由租户自定义对象或定制的标准对象构成的定制的应用组件集合。 自定义对象(Custom object) 对象提供存储业务数据的结构,同时驱动界面元素,实现用户与业务数据的交互,如选项卡、页面上的字段布局和相关记录的列表。 应用开发者自定义的URL,用于集成第三方系统或自定义功能访问。 自定义链接(Custom link) 应用主页选项卡(Application Home 应用的起始选项卡页面,其中可以包含图表、快速创建菜单、Page) 对象选项卡(Tab) 当前的任务活动体系列表或者可以选择的其他标签页面。 导航对象访问的界面容器。选项卡是查看、编辑、或者访问特定对象的入口。对象选项卡包含一个已定义对象。当用户点击选项卡时,可导航到相应的对象主页。对象主页通常包含对象的各种搜索视图、结果列表、对象的最近访问历史、相关对象的创建菜单等内容。 一种自定义的选项卡,用户可以使用Web选项卡将对外部站点的访问集成到应用中。 在对象布局中的一个区域,用于放置一组和主对象相关的对象列表,可以通过列表中的连接导航到相关对象的详细页面。 在对象的详细信息查看和编辑界面中,组织对象的字段、自定义链接、相关列表以及其他组件。 查找布局(Search layout) 定义对象的查询对话框和查询结果列表的界面布局。查找布局通常位于对象的主页选项卡。查找布局定义的结果列表也应用在对象选项卡中的最近访问对象列表和对象搜索结果列表中。 在两个自定义对象关系中为实现多对多关系而构造的关联对象。 定义了两个对象间的一对多关系。在“详细”对象的属性中配置,创建从对象(子级或“详细信息”)与另一对象(父级或“主”)之间的父子关系类型。关系字段允许用户单击查找图标,以从弹出列表中选择值。主对象是列表中值的源。在主对象布局中,从对象以相关列表形式表现。 主详细关系可细分为1-*和{0,1}-*两类: a) 1-*的关系:在多方的关系字段是必填字段,并具有以下约束: 所有详细信息记录的关系字段必填。 一旦关系字段的值被保存,就无法更改。 详细信息记录的所有权和共享由主记录确定。 当用户删除主记录时,将删除所有详细信息记录。 第2页

Web选项卡(Web tab) 相关列表(Related List) 页面布局(Page Layout) 关联对象(Junction Object) 主详细关系(master-detail) b){0,1}-*关系:在多方的关系字段可以为空,不是必填字段。这种松散的关联关系也称为查找关系(lookup) 验证规则(Validation Rule) 简档(Profile) 定义了保存对象时需要遵守的业务规则。 简档定义了一类用户对系统的访问控制策略。包括用户可访问的应用、对象、对象属性、对象的操作、可使用的系统功能集等内容。一个用户只能被分配一个简档。系统中包括标准的简档定义和租户自定义的简档。标准简档在创建租户时由系统创建,不可修改。 组织默认共享规则 (Organization-wide defaults) 字段安全(Field Level Security) 对象安全 (Object Level Security) 记录级/行级安全 (Record Level Security) 共享规则 定义了管理员指定某类用户创建的对象可以授权给哪些用户查看或编辑的规则。共享规则是在组织默认共享规则基础上,面向特定用户开放的权限规则。 定义记录级安全规则时,可以指定高级角色能够查看和编辑下属所有的对象记录,而忽略已定义的对象访问的组织结构默认规则。 一组划分用户的逻辑方法,它可以是用户、其他用户组、用户角色限定的用户群的任意组合。 一组没有特定属主的对象记录集合。可以访问队列的用户能够查看队列中的对象,并指定对象的属主。 在租户应用内自动执行的过程,一个对象的审批过程定义了必须执行的若干个步骤,审批过程同时还指定了首次提交的操作以及每个步骤在批准或拒绝时必须执行的操作。 用于租户定义组织内用户对特定对象的基本访问控制的共享策略。 在用户的简档中,可以定义特定的对象属性字段的访问控制权限,包括隐藏、可见、只读和可编辑。 在用户的简档中可以定义指定对象的访问权限,包括查询、更新、新增、删除、导入、导出等,从而允许管理员可以配置某个对象的选项卡对某类用户不可见。 控制特定用户可以查看和编辑特定的对象记录的方法。 角色层次(Role hierarchy) 组(Group) 队列(Queue) 审批过程(Approval process) 时间依赖的工作流操作 特定的时间条件满足时,才执行的工作流操作。当工作流规(Time-dependent workflow Action) 则满足条件时,时间依赖的工作流操作可能触发任务、执行字段更新、或者执行向外部系统发送消息、发送邮件通知。 工作流操作(Workflow action) 工作流字段更新 (Workflow field update) 工作流队列(Workflow queue) 工作流规则(Workflow rule) 当工作流规则条件满足时,执行的邮件通知、字段更新、发送外部消息通知、或者任务触发等操作。 当工作流规则添加满足时,触发的更新特定对象字段的值工作流操作称为工作流字段更新。 基于工作流规则产生的工作流操作列表,其中包含一个或多个时间依赖的工作流操作。 工作流指令集的容器,包含激活工作流的条件以及条件满足时执行的特定任务、通知提醒、字段更新等操作。 第3页

工作流任务(Workflow task) 应用包(Package) 当工作流规则触发时,分配给特定用户的工作流操作即为工作流任务。 约定了每个租户自定义应用和对标准应用的扩展实现的名字空间。平台使用租户的应用包组织租户的自定义应用和对标准应用的定制。 3 主要功能概述

App Suite是由一个服务实例支持的多租户的呼叫中心应用系统,面向客户服务、电话营销、支持过程等典型的呼叫中心应用,每个企业用户可按需部署呼叫中心应用能力,定制自己的呼叫中心业务实现。

4 体系结构设计约束条件

4.1 框架依赖

App Suite基于成熟的Java EE应用框架搭建。应用MDA概念构建每个应用组件。使用应用模板+元数据的模型构造具体的应用。基于以下框架构造App Suite的应用开发环境和系统的运行环境,包括支持多租户能力的系统框架服务和满足特定租户需求的应用框架:

 Hibernate实现ORM以及多租户独立的持久化操作。  Spring实现轻量级的框架容器,完成对象和服务的注入。

 Struts2 实现开发环境和运行的环境的URL映射、Http协议解释、粗粒度控制逻辑、

加载过滤器和拦截器对特定方面的多租户能力实现,如多租户独立的安全、功能。  使用YUI脚本库辅助实现RIA表现层逻辑,用组件化的用户界面元素构造用户表

现。

4.2 非功能要求

 单应用服务器支持1000个在线用户。  每个Http请求响应时间小于3秒。  应用服务器支持在线升级。

 集群部署可以满足系统可伸缩性的要求;应用服务器实现负载均衡和集群。 4.3 分布要求

应用服务器和数据库服务器分别部署。应用服务器采用集群和负载均衡的方案部署,数据库服务器使用磁盘阵列,保证系统的高可靠性和伸缩性。

App Suite产品在单实例上能够支持多个租户的个性化应用需求,单实例服务可依赖于

第4页

集群和负载均衡实现租户数量的平滑增加。即遵循SaaS架构成熟度模型第四级模型作为标准部署应用组件和服务。如下图所示:

四个等级的SaaS成熟度模型。

5 设计准则和设计决策

多租户能力服务:以共享的服务完成各租户的访问隔离、对象的请求映射和控制流、数据访问服务;实现对象在表现层和控制层间的交互;元数据定义服务于应用和对象的定义和运行时环境。

标准应用组件和自定义应用组件的应用、对象、数据访问服务、控制、表现的组织形式:  应用:相关对象的集合,组织特定租户的相关对象的整合界面,确定对象选项卡的

组织。在表现层实现。

 对象:领域模型的具体体现。分为标准对象和自定义对象。

 标准对象为平台已定义的对象,每个租户在创建时都可拥有的对象定义,各租

户可增加标准对象的属性、修改对象的表现,但不能修改已存在的标准对象属性定义,不支持标准对象已实现的业务逻辑的配置。

 自定义对象在租户数据域内创建,定义表现和非标准的业务逻辑,在对象部署

后,不修改对象的数据定义,可以修改已创建属性的表现或在扩展保留域上定义新的属性,修改对象的表现。

 所有应用对象的持久化采用同样的值对象进行映射,它包含通用的标准字段和

自定义字段。在对象创建时仅创建一次。其中标准字段包括创建者、所有者、修改者、创建时间、修改时间等内容;自定义字段按类型分配,分为长短文本、日期时间等各30个,这样,所有对象定义在持久层被映射为内容一致的值对象和数据库表,仅仅是名称不同,对对象属性的定制操作被转换为对象字段的

第5页

元数据定义,配置操作不涉及持久层策略,减少配置操作对持久层实现的依赖。

 数据访问服务和控制:采用生成代码和应用引擎相结合的方式,基于框架的服务扩

展,应用引擎实现请求的多租户隔离和映射,导向到特定的前端控制对象和数据访问对象,实现领域模型限定的业务逻辑。

 表现层:系统内置表现的模板,完成通用的对象属性布局、相关列表布局、查找布

局、从对象属性到界面元素的转换、通用的服务操作控制导向、对象主页布局、应用主页布局。对象的布局支持通用的访问控制操作,包括:Create View、Edit View、Detail View、List View、Search View、Application Home Page、Domain Object Home Page。每个应用组件和对象都有一套生成完成的界面模板。标准组件的UI定义在多个租户间共享,租户可以修改标准组件的UI定义,租户修订后的UI定义覆盖标准组件的UI定义。界面使用选项卡组织应用对象,为了保证客户端性能,表现层选项卡支持懒加载,即仅当用户选择了特定的选项卡时,访问web server加载应用,而不是在选项卡创建时预先加载所有的对象选项卡。用户在不同的选项卡间切换时,可以保证未提交的数据不丢失。

 租户用户的身份认证:每个租户用户有唯一的系统账号,保存在系统的数据域中,

系统使用统一的认证服务认证租户用户的身份。租户用户的访问控制策略由每个租户的管理员限定,租户用户的访问控制策略保存在租户的数据域中。系统的License服务仅控制每个租户的各类型用户的在线用户数,如在线的租户管理员个数和在线的租户用户数,系统不会细分管理租户自定义的各类角色用户的在线用户数。  访问控制逻辑:访问控制逻辑作为系统中的一方面织入到每个请求的控制逻辑中,

访问控制逻辑包括应用的访问控制、对象操作的访问控制、对象数据域的访问控制、基于属主和角色树定义的记录级别的访问控制。暂时不支持自定义规则的访问控制策略。

6 核心需求描述

6.1

功能性需求

第6页

6.1.1 系统平台管理员

 注册租户:创建租户信息,产生租户标识,并为租户创建应用扩展空间和数据库空

间,创建租户管理员。系统保证租户标识和租户管理员账户的全局唯一性。应用扩展空间指预定义的一组目录结构,包括应用扩展路径、存放租户独立的配置文件、模板的路径、数据文件空间等内容。数据空间指一组租户独立的数据库模式(schema或catalog),用于持久化每个租户的应用数据和元数据定义。

 创建租户管理员账户:租户管理员为租户内部最高权限的用户,租户的用户由租户

管理员创建,被系统统一认证。每个租户仅有一个租户管理员账户。租户管理员账户由系统管理管理员创建租户时创建。

 注销租户:释放租户使用的资源,注销租户的各级用户账号。租户占用的资源包括

数据空间和应用扩展空间。

 重置租户管理员密码:平台管理员可以重置指定租户的租户管理员密码。可以按照

缺省规则生成一个密码,选择租户标识或租户管理员标识加密生成。

 性能监控:平台管理员可以查询系统中每个租户的在线用户数、查询登录历史、监

控系统资源的占用情况等信息。

 登录:登录操作面向系统中的全部用户。系统根据用户的账户信息确认用户身份的

合法性,根据用户的类型、简档、角色、用户所属用户组等信息加载访问控制策略,展现用户定制的应用,使得系统能够在用户登录后,控制用户在限定的权限内访问应用。如果用户的身份不合法,则拒绝使用系统。

 访问许可检查:应用访问许可检查包含在登录操作中,面向每个访问系统的用户。

系统根据每个租户申请的各种用户类型的许可数量管理租户在线用户数。系统管理

第7页

员可以查询或修改特定租户的授权许可。

6.1.2

租户应用开发者

租户开发者是租户中的超级用户,可以执行租户范围内的全部操作,包括系统的开发配置和管理配置。

 开发配置

 定义应用:维护租户可访问的对象集合的界面表现视图。  定义对象:定义对象的整体属性。

第8页

 定义对象字段:定义对象的细节属性。

 定义对象各类布局:描述对象针对各类操作的表现界面。

 定义对象关系:定义对象和相关对象的关联关系,定义一对一、一对多、多对

多的关联关系,并且定义是否需要在双方创建导航关系列表或属性链接。  定义选项卡:管理对象和应用,定义应用的构成。

 定义租户的字典数据:定义租户范围内对字典数据的定义,包括类型和相关子

类型的定义。先仅支持两级关系,反映到界面表现中,仅支持两级联动的级联列表,不支持更深层次的级联关系。

 管理租户用户:租户管理员可创建租户的用户,系统不限定每个租户可以创建

的用户数量,仅控制每个租户各类用户的在线用户数。租户用户的账户由系统统一认证,而租户用户的访问控制权限由租户管理员定义。

 管理租户用户组:由租户管理员创建,管理租户用户的逻辑组,可独立于用户

在组织机构中的角色职位。

 管理租户组织结构(角色):使用树型结构管理租户的组织结构,即角色。系

统可以通过定义组织结构,进行对象记录级的访问控制策略的实施。  管理租户的简档:为租户创建简档,为用户分配简档。

 定义简档控制的功能级访问控制:定义简档对应用、选项卡、对象操作、对象

布局、对象字段、用户功能、系统功能的访问控制策略。

 定义对象的共享规则:定义对象的共享规则,用于定义对象行级的访问控制。  工作流管理:系统能够定义一个审批流程的步骤和流转条件,能够参与每个步

骤的角色,与每个步骤相关的对象,以及每个步骤可填写的记录信息。并为特定的用户生成工作流任务和通知邮件。

 应用部署:鉴于当前的技术选型和积累,不支持应用的完全动态部署。系统的

开发环境和运行环境物理隔离,当租户系统管理员开发测试完成特定的应用组件后,可以提交发布,应用包含的类文件、配置文件、数据将被打包复制到运行环境中,部署后的应用,在运行环境中可进行UI定义的变更,不支持动态地添加新的功能。在集群环境中,可以采用备份服务与主服务配合,实现应用部署不会产生服务的中断。

 管理配置

 配置租户(企业)的Logo  配置租户(企业)的基本信息  发布公告

 定义应用的自定义链接

第9页

6.1.3 租户用户

第10页

 管理配置

 修改个人密码  更换应用表现皮肤  业务功能

 个人任务管理  查看公告通知

 数据管理:系统支持每个租户对象级数据的导入、导出、包含特定属性的批量

更新操作。实现租户用户级的数据维护。支持的数据格式包括cvs和excel格式的数据文件。数据文件的大小限定在每次10M以内。考虑支持文件打包压缩归档。导入和导出数据的范围可通过查找布局限定。

 报表:优先根据标准应用组件定义的报表实现每个对象的报表。如:客户个案

来源、交互类型、客户交互数量、客户解决方案访问频度、客户个案受理进程状态、平均响应时间、平均解决时间、潜在客户类型、潜在客户来源、潜在客户状态分布、座席管理的客户所有人数量、营销机会进展报告、营销机会的赢丢比率、营销机会成交统计等。在此之外,支持用户基于自定义对象创建报表,聚集条件可限定在时间范围、时间粒度、地区维度、用户组等方面。  工作流任务和事件:系统为每个用户生成待办的工作流任务列表和事件通知列

表。用户可通过访问列表,完成相关的工作任务和事件,驱动流程的执行。  文档管理:

 高级座席管理的文档:用户根据文档的类型、子类型、组织文档的目录结

构,系统记录上传文档的标题、关键字、属主、上传时间,支持用户基于这些属性检索查询相应的文档。这样的文档管理实现类似知识库的文档管理。

 普通座席管理的文档:普通座席可以针对特定的对象记录上传与此相关的

文档。辅助任务的处理。

 客户服务:管理客户基本信息、联系人信息、交互历史、相关活动和事件历史。

实现客户信息查询、支持屏幕弹出。

 个案和解决方案:个案是与一个客户交互相关的业务记录。记录了交互涉及的

业务类型、处理记录、相关产品信息、交易记录等信息。一个具有典型意义的个案可以转换为解决方案。普通座席可以提交个案作为待审核的解决方案,高级座席审核后,可以将其作为可公开的解决方案,供座席参考。座席处理个案时,可以查询和参考解决方案与客户沟通。解决方案可以根据个案属性构建,支持查询。

 营销活动:特定完成营销目的活动跟踪,系统支持营销活动的创建、营销目标

客户名单导入或选择、名单的分配,形成业务机会。

 业务机会:跟踪每个营销活动业务机会的进展,记录业务机会的处理过程。

第11页

 产品管理:定义租户的产品目录,产品报价,可将产品信息关联到特定的营销

活动和业务机会中。

6.2

非功能需求

Web应用支持集群部署。选择支持集群配置的Web服务器,从而实现系统的集群和负载均衡部署。

7 概念模型

7.1 7.1.1

系统概念视图 用户视图

从使用系统的用户角度看,系统可以划分为租户域、系统域以及租户域和系统域共同依赖的多租户能力框架。在系统域,平台级的管理员负责分配租户应用资源,包括工作空间、账户许可;监控租户的在线使用情况。在租户域,每个租户中的用户在各自的工作空间中访问租户应用,执行业务操作,管理租户域内的应用和配置。

第12页

7.1.2 元数据驱动的应用实现

概念模型设计时应用配置和设计工具用户角色配置用户界面报表定制流程配置应用访问控制领域模型定义OpportunitiesCampaignAccountContactCase运行时租户应用实例多租户管理Report租户账户租户许可WorkflowSLA监控租户域管理可配置多租户运行时元数据服务多域扩展租户简档/应用定义/配置数据应用组件在线部署 为了支持多租户环境下的应用可配置,平台被划分为设计时和运行时两个部分。当平台的租户管理员创建了一个租户,并为其分配了工作空间后,系统的开发者角色就可以使用应用配置工具和安全管理工具配置租户的应用。

在设计时,应用开发者在租户的应用空间中配置业务对象、对象关系、业务对象的用户界面、工作流规则、用户对应用的访问控制策略、业务报表;应用配置数据、用户和安全策略被保存在租户的存储空间中。设计时根据模型定义,将模型定义转换为可部署在运行时中执行的应用代码或运行时解释应用需要的配置数据。

在运行时,租户的业务用户使用已部署的应用组件执行定制应用。在运行时,租户的管理员也可以使用在线配置工具修订设计时定义的应用,包括管理用户、角色、用户对应用的访问控制策略、已部署的应用的界面布局、字典数据等配置信息;相对于设计时刻的配置,运行时的在线配置是为了适应不同的租户对同一标准应用组件的细微差异的定制,是在已部署的应用扩展点上进行的重新配置。运行时与设计时配置的区别主要表现在以下几个方面:

 用户区别:运行时配置面向租户的普通用户;设计时配置面向租户应用开发者。  配置参与的应用生命周期不同:设计时配置指应用部署前的配置,运行时配置指应

用部署后的配置,因此配置操作的频度不同。

 配置范围的区别:运行时配置限定在应用表现、业务规则、安全策略、用户账户方

面的配置。设计时配置没有范围限定,可包含特定的应用开发定制、新应用和对象的创建。

第13页

系统维护应用模型在设计时和运行时与应用实例代码的一致性,保证应用的即时可用。 运行时元数据访问接口:为运行时标准工具组件或应用组件提供访问租户应用配置的接口,通过元数据访问接口,标准应用组件、工具组件能够了解当前租户用户可访问的应用和对象、它们的界面表现配置、安全策略、以及在安全策略限定下的应用配置。 7.1.3

系统逻辑视图

自定义应用任务提醒客户基本信息交互历史解决方案应用组件平台配置应用在线配置个案…应用模板工作流引擎报表引擎应用解释器安全,license,数据隔离,认证,鉴权多租户Runtime元数据管理报表定义对象及应用定义工作流定义用户管理及访问定义租户管理系统管理平台管理

App Framework (Hibernate,Spring,Struts2,YUI…从系统分层的角度看,各个子系统的依赖关系如上图所示:系统使用统一的开发框架为各个子系统提供了实现的基础,开发框架基于MVC各层应用的工具包封装了一组接口和抽象类实现,各个子系统构建的基础;系统中面向用户的应用通过在线配置工具配置生成,系统管理这些配置数据,在运行时解释形成租户的定制应用;平台实现了多租户应用环境的支撑,能够在一套应用实例中管理多个租户的个性化应用。 7.2 应用的概念模型 7.2.1

领域模型

App Suite依赖于代表领域模型概念的对象来构建应用系统,实现从用户需求到应用模型的映射。

 应用和对象:在App Suite平台中,对象提供存储数据的结构,它还驱动界面元素,

允许用户与数据交互,如选项卡、页面上的字段布局和相关记录的列表。由于任何

第14页

对象都可对应于一个选项卡,而一组功能内聚的选项卡的有序集合构成应用程序,因而对象是在平台上创建的应用程序的核心。

 业务逻辑实现:系统支持每个业务对象的维护操作,包括标准的CRUD操作、定

制的查询视图、对象关系完整性操作。支持特定的领域对象的业务逻辑控制。  业务对象的关系:业务对象间的组合或聚合关系可以通过应用定义工具来描述,系

统支持用户定义业务对象间的关系,包括一对一关系和一对多关系;多对多的关系可通过先定义关联对象,然后建立三个对象间的两个一对多的关系来表达。对于一对多的关系,可细分为1-*和{0,1}-*,即强制依赖关系和非强制依赖关系。  标准工具组件:平台通过标准工具组件实现跨越多个应用实体的通用功能,如对象

搜索、任务提醒、创建对象快捷菜单、最近访问历史、自定义链接、系统公告、报表定制工具、工作流定义及待审批项目等,它们依赖于租户部署的应用配置,实例化每个工具组件的具体功能,完成与应用对象和系统对象间的协作,实现具体的业务功能。

7.2.2

表现模型

 应用的界面组织:表现层利用选项卡容器组织应用主页和对象主页以及它们之间的导航

关系,即系统的一级功能菜单。选项卡容器构成了应用用户界面的内容区域。应用的主页和对象主页分别是选项卡容器中独立的选项卡。用户界面的基本结构如下图所示:一级菜单采用使用选项卡定义,即为对象选项卡或主页选项卡。

广告位置,logo,应用菜单,换肤操作,登录信息1菜单1 菜单2 菜单3 菜单4 菜单5 菜单6 子菜单1 子菜单2子菜单3 子菜单4子菜单5 子菜单63子菜单1子菜单2子菜单3子菜单4菜单1 菜单2菜单3 菜单4菜单5 菜单62菜单1 子菜单1 子菜单2菜单2 菜单3菜单4 菜单5功能区域1功能区域2功能区域3功能区域4菜单1 菜单2 菜单3 菜单4 主要工作界面采用上,左右布局。左边可以收缩。适当补充对话框,弹出窗口这样的界面。

区域1:包括设置菜单,广告,应用选择(有默认),用户信息提示。

第15页

区域2:任何界面组件,前提是可以容纳下。 区域3:任何界面组件,前提是可以容纳下。

 对象的表现:对象的表现包括对象详细信息的布局、对象列表集合的布局、对象的查询

布局。详细信息布局应用于对象的编辑和详细查看类操作,对象详细信息的布局采用表格布局策略统一规范对象属性的表现。对象列表集合布局采用数据表格方式定义支持服务器分页的表现布局。对象的查询布局包括对查询条件和查询结果的表现。

绑定对象3界面布局对象1标签A标签B标签C标签D相关列表列1列2列3列41*属性D(主键)……字段A属性A字段B字段C字段D属性B属性C属性D(关联外键)1*对象2属性1属性2属性3…….  对象详细信息布局:使用网格布局风格定义对象的属性在用户界面中的布局。如上

图所示对象1的属性A、属性B、属性C在界面中的布局。根据功能不同,详细信息布局可细分为编辑布局、创建布局、详细信息查看布局。

 对象关系的表现:对象的关系在表现层可定义为主-详细关系。它们分别用于关系

对象中相关各方对关联对象的访问导航。

 关系字段:应用于一对多关系中多方对一方的引用,关系字段具有只读属性,可以通过查找关联对象的实例来获得相应的外键值。表示查找关系的外键字段在布局中通常以一组组合的界面元素来表现,即字段标签+只读关联对象记录名+查找链接构成,如上图所示对象1属性D在布局中的表现。

 相关列表:应用于一对多关系中一方对多方数据关联关系表现,通常以相关列表形式表现,列表是通过以一方对象中的关联属性和关系属性在当前对象实例中的值查询获得,系统可以定义列表中需要表现的列和排序规则。如上图所示对象2在对象1布局中的表现。相关列表中除了包含关联对象的属性外,还包括对列表中的记录行进行操作的导航链接。

 对象的搜索布局的表现:定义了查询指定对象的条件和查询结果的列表布局,包括

显示查询结果的字段、排序方式、展现格式和在列表中的显示顺序以及对列表中的记录行进行操作的导航链接。

 对象查找带回布局:定义了查询被关联对象时的界面布局,包括查询条件定义和查

第16页

询结果列表的表现定义,它作为一个组合的界面组件,支持用户选中查询结果列表中的一行记录后,返回选中的记录功能。

 关联对象的组合表现:当对象之间定义为多对一的关系或一对一的关系时,在多对

一关系的多方或一对一中的任意一方对象可在对象详细布局中组合关联对象的属性。其中外键的表现是必须在对象创建的布局中存在,关联对象的其他属性可以以只读字段形式出现在主对象的详细布局中。它们的值可以通过“查找-带回”查询对话框获得,从而实现对外键的维护。如下图所示:

对象1布局标签A标签B标签C对象2标签A标签B标签C字段A字段B字段C字段A字段B字段C1对象2属性A属性B属性C1对象1属性A属性B属性C11对象3属性A属性B属性C对象3标签A标签B标签C字段A字段B字段C 7.2.3

安全模型

App Suite采用基于角色的权限分配策略来定义每个用户对系统的访问控制策略,通过角色和简档定义了每个用户对系统功能级访问的权限、对象实例的字段级访问控制权限、对象记录行级的访问控制权限,能够满足不同控制粒度的安全需求。如下图所示,简档、角色、用户和用户组构成系统中定义应用的用户数据角色安全策略的基本元素。

第17页

角色•组织层次结构•共享规则•应用访问权限•选项卡访问权限•对象操作权限•布局分配•字段级访问控制权限•用户信息•分配用户角色•分配用户简档简档用户用户组•相关一组用户

 角色:描述了用户在组织结构中的层次关系,用于定义对象记录的共享规则以及共

享规则在处于层次结构中的上下级角色用户间的传递规则。

 简档:描述了一类用户对应用、选项卡、对象布局、对象操作功能、对象字段、系

统管理功能、用户功能等方面的访问控制权限的分配。限定了用户在功能方面的访问控制权限。

 用户:用户可由租户内部的管理账户来创建和维护,系统平台提供管理接口保证租

户管理的用户账户能够与系统平台同步,使得系统能够在多租户环境下,实现对每个租户用户的身份认证。每个用户通过分配一个角色和一个简档来定义对系统的访问权限。

 用户组:为了方便授权,增强应用的灵活性,可以选择一组工作职责相近的用户作

为一个用户组来进行管理。租户的管理员可以创建用户组并指定用户组的成员。 通过角色和简档,既可支持应用功能级的访问控制权限,又可支持数据级的访问控制权限。数据级访问控制可以细分为行级访问控制和对象字段级访问控制,其中字段级访问控制以对象为单位在简档中定义用户对每个对象字段的读写访问控制权限;而行级访问在用户访问具体对象时根据对象的属主和系统定义的共享规则确定用户对特定对象实例的可访问性。共享规则可以根据租户用户的组织结构,向上级传递。

系统的安全策略作为独立的方面跨越垂直存在的所有功能和数据访问,运行时服务将根据当前用户配置的权限进行在不同应用层次中进行控制。

 表现层:对于功能级的访问控制权限,系统根据当前登录用户的访问权限展现其工

作界面,仅展现用户有访问权限的应用、选项卡、对象操作功能以及可见的数据域。  控制层:运行时服务在控制层实现访问拦截器,在请求派发给目标服务前通过拦截

每个请求操作,验证用户请求的合法性,实现对功能级访问控制的后端支持。

第18页

 服务层:在对象实例返回给表现层之前,运行时服务解释对象的字段级安全策略,

过滤对当前用户不可见的对象字段;在请求提交给数据访问对象前,运行时服务解释对象字段级安全策略,过滤对当前用户不可见和只读的对象字段的更新操作。  持久层过滤器:数据的访问控制策略作为持久化实现的一个方面插入到数据访问逻

辑中,在数据访问服务中插入解释了对象共享规则的行级数据过滤器。

综上,系统的安全控制策略在用户角色数据安全管理工具中配置,而在运行时服务中解释生效。

7.3 应用模型转换到运行时应用

App Suite平台使用MDA的方法定义应用的模型、支持应用模型到运行期代码的转换。平台使用元数据和用户权限配置数据描述应用,定义应用的访问控制策略、使用应用的用户及角色、以及基于业务对象的工作流程规则,并将这些定义部署到运行环境中,构成特定租户可执行的应用实例。

定义应用、生成应用、以及部署应用的过程如下图所示:

应用管理工具在配置和部署应用时完成从元数据描述的应用到可运行应用代码的转换;在编辑和修改应用时,完成从元数据描述到应用配置模型的转换,特殊的定制用户可以基于生成的应用扩展自己的实现,应用管理工具能够保证模型定义和生成代码间的增量一致性。

生成的代码遵循特定的规则,可以在系统运行时框架内执行。用户在设计期使用应用配置工具定义应用、对象、对象字段、对象布局、对象主页、应用主页,并生成运行时代码,部署到运行环境中,立即生效。系统按照分层的体系结构,基于框架提供的支持,按照分层的体系结构,分别生成表现层界面代码(JSP文件和JS脚本)、控制层代码(Action类)、服务层(扩展服务接口代码)代码、持久化对象(PO类和Hibernate映射文件)。生成的应用按照系统内置的规则,在租户的应用空间中以应用包的形式来组织租户自定义的应用和对象,以及租户对系统已部署的标准应用和对象的界面的重新配置。

模型到代码的转换通过模板组织,模板定义了应用模型转换为各层代码的规则。 平台定义了应用部署的规则,对生成的代码执行编译,将可运行的应用包发布到租户的应用空间中,实现应用的部署。租户的应用空间中包含以下内容:

第19页

系统及共享应用空间App Suite应用标准组件标准应用租户初始化数据用户、角色、简档租户应用空间租户应用包标准应用自定义界面自定义应用用户界面自定义应用实现标准应用元数据自定义应用元数据数据库服务器

应用服务器8 设计模型

8.1

子系统划分及概述

根据系统的概念模型,划分为以下几个子系统:

第20页

 平台管理(PlarformManagement)  应用管理(AppManagement)

 用户管理和访问控制(User Role Data Security)  工作流管理(Workflow)  报表定制和报表生成(Report)  多租户运行时(Multi-tenancy Runtime)  标准组件(Components)  标准应用组件(AppModules) 8.1.1 8.1.1.1

平台管理 租户管理

8.1.1.1.1 子系统描述

平台管理员完成对租户的完整的生命周期管理,包括租户用户账户、租户的资源、租户的使用许可。租户的使用许可按在线并发用户计算,按用户类型分别计算:租户管理员

第21页

(administrator)、租户应用开发者(developer)、高级租户用户(supervisor)、普通用户(agent),其中后三种是租户域的用户可使用的许可。

租户管理服务与数据访问在平台域内集中管理,只有平台管理员拥有访问这些功能的权限。 8.1.1.2 8.1.1.2.1

系统管理 子系统描述

 系统监控和告警

系统提供一些运行时监控数据,使得租户管理员能够了解系统的运行状况和租户对系统资源的占用情况:系统监控主要包含以下指标:

 各租户实时在线用户数  各租户用户登录记录查询  各租户和用户账户统计  系统数据库资源占用统计  系统已分配工作空间统计  关键服务的监控  事件告警  应用发布和备份

为平台管理员提供部署租户应用的接口。  应用数据备份

提供系统级数据备份的解决方案。 8.1.1.3 8.1.1.4 8.1.1.5

子系统类图 子系统关键用例 子系统接口

租户管理接口:

 租户注册与注销:  租户License授权接口:

 注册租户用户:当平台管理员创建新的租户用户时,访问平台的租户管理接口,

注册租户用户名称和认证密码。  修改租户用户密码:  重置租户管理员密码: 监控接口:

 租户与用户统计查询(快照信息)

第22页

 租户在线用户数查询 8.1.1.6

约束和假设

假设租户管理员在创建租户时,仅能看到一个逻辑的服务域,等待创建的租户均部署在同一服务域内,系统按照以下指标设计每个逻辑服务域的支持能力:

 1000个租户用户  500个租户

 每个租户工作空间<200M  每个租户的数据库空间:<1G  每个租户自定义对象数<50

 每个租户的在线历史数据保留时长:6个月

在当前实现中,暂时不考虑多平台管理,以及根据租户的服务等级需求实现系统域的逻辑划分,从而实现租户性能的隔离。

8.1.2 8.1.2.1

应用设计器 子系统描述

通过定制向导引导租户管理员创建合法的应用和对象,基于系统中的描述应用的元数据模型生成应用的定义,并根据应用定义生成应用组件代码。应用开发环境支持应用和对象的定义数据和设计模型间的相互转换。

用户使用定制向导定义应用和对象的属性,包括它们的数据模型和表现布局;当用户在编辑环境中完成对应用或对象的定义或修改,保存设计模型时,应用生成环境将访问元数据服务生成可打包的应用组件,包括配置数据、表现模板、自定义对象相关类字节码;并按照应用组件部署的约定组织这些生成的数据和文件。

当用户需要变更已存在的应用和对象的定义时,生成环境将应用定义转换为可编辑的设计模型,用户可以对已存在应用和对象进行修改。并重新生成应用代码和定义。 8.1.2.1.1 应用和对象配置

定义应用:定义应用的名称、应用的表现风格、应用的主页布局 定义对象:对象的基本属性,对象级界面元素和风格、对象的主页布局。

定义对象字段: 对象的每个属性的详细定义,包括属性的类型、合法性检查规则、界面元素的类型

定义对象各类布局及布局的表现容器(选项卡、对话框、新窗口、Portlet):描述对象

第23页

在执行各种标准操作时的界面布局以及打开布局页面的界面容器。

定义对象关系:定义对象间的一对多关系和一对一关系依赖,表现为相关列表定义和查找关系定义

定义选项卡:定义对象组件容器-选项卡的表现属性,以及承载的对象主页。 8.1.2.1.2 字典数据定义

租户定义对象属性时,对于枚举类型的属性,可定义对象属性值取自系统管理的字典数据。租户管理员可以定义租户内部可见的字典数据,定义枚举类型值、子类型值,用于初始化下拉列表数据和级联下拉列表数据。 8.1.2.1.3

应用动态部署

在当前实现中,对于新的应用组件的部署,租户管理员定制完成应用后,由平台管理员部署到应用生产环境。利用生产环境的集群特征,实现应用的在线升级。对于已部署的应用组件,面向租户管理员,仅提供界面的重新定制功能,仅支持在已部署的应用对象中增加有限数量的属性。

后续版本的实现中,可以考虑采用动态语言实现应用的热部署。 8.1.2.2 8.1.2.3 8.1.2.4

8.1.3 8.1.3.1

用户管理及角色数据安全控制 子系统描述 子系统接口 子系统类图

子系统关键用例实现

 租户组织结构和角色:系统使用树型的组织结构定义角色,组织结构树中的每个节点均

由一个角色来定义。角色用于控制记录级的访问策略。

 租户的用户组:用于定义一组用户,便于访问权限的分配或统计数据分组。

 简档配置:简档作为可分配给特定租户用户的权限描述文件,限定了特定用户群的可访

问的应用集合、应用中的对象集合、对象的操作控制、对象的属性集合、属性的操作权限(R/W)、特定的界面布局中的记录类型、管理功能权限。系统通过访问元数据服务获得租户域内的应用、对象、对象的操作、对象字段、选项卡、系统中可配置权限的管理功能,根据业务需求定义一组用户对这些元素的访问权限集合。 其中管理功能包括:

第24页

数据导入导出的功能、查看报表的功能、租户管理设置功能等内容。

 租户用户管理:每个租户的用户账户由租户管理员管理。租户管理员创建了租户用户后,

租户用户的信息保存在租户数据库中,同时,租户用户的账户信息注册到平台的数据域中。在平台域和租户域同步保存租户用户的账户,可以简化应用的实现,一方面,便于实现统一的身份认证,另一方面,便于租户应用能够方便地访问到用户的账户信息。在平台域,保存租户的用户名称和密码;在租户域,保存租户用户除密码外的其他信息。系统在创建用户时分配用户的角色和简档。

 共享规则定义:定义用户对每个对象的记录级访问控制策略。对象所有者可以通过共享

规则将其拥有的对象访问权限授权給其它用户。所有者和共享者使用组类型的用户来描述,即用户组、角色、角色及其下属。 8.1.3.2

子系统接口

租户用户简档信息查询:获取指定用户的简档,用于确定特定用户的访问控制权限:用户登录时,安全服务从租户管理配置子系统中获取特定租户用户的简档信息

租户对象共享规则查询(可缓存):系统启动时,系统启动类从租户管理配置子系统中获取配置的对象的共享规则,并提供查询方法供其他子系统使用。

用户信息查询 用户组信息查询 用户组织结构信息查询 8.1.3.3

子系统类图

实体类图

简档实体类定义:简档实体类是简档配置的持久层实现,描述了构成简档的各个要素间的关系。

第25页

class builder-profile-modelProfile- - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + serialVersionUID: long = 1530946583 {readOnly}profileId: Longname: Stringremark: Stringdeletable: BooleanfunctionEditable: BooleanProfile() : voidProfile(Long) : voidProfile(String) : voidgetProfileId() : LongsetProfileId(Long) : voidgetName() : StringsetName(String) : voidsetProfileObjects(Set) : voidhashCode() : intequals(Object) : booleangetTabs() : SetsetTabs(Set) : voidgetEntityDescription() : StringgetObjectDescription() : StringgetObjectID() : SerializablegetProfileObjects() : SetgetRemark() : StringsetRemark(String) : voidgetProfileApps() : SetsetProfileApps(Set) : voidclone(String) : ProfilegetFunctions() : SetsetFunctions(Set) : voidisDeletable() : BooleangetDeletable() : BooleansetDeletable(Boolean) : voidgetFunctionEditable() : BooleansetFunctionEditable(Boolean) : voidgetProfileApp(String) : ProfileAppgetTabByName(String) : ProfileTabgetProfileObject(String) : ProfileObjectgetFunction(String) : ProfileFunctiongetProfileObjectByName(String) : ProfileObjectProfileObject- - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + creatable: Booleandeletable: Booleaneditable: Booleanprofile: ProfileprofileObjectId: Longreadable: Booleanobject: MockObjectBaseHibernateObjectjava.io.Serializable BaseHibernateObjectjava.io.Serializablejava.lang.Comparable BaseHibernateObjectMockObject- - - - - - - - - - + + + + + -object+ + + + + + + + + -object+ + + + + + + + + + + + + + serialVersionUID: long = 1113696588 {readOnly}objectId: Longname: Stringlabel: Stringfields: SetdefRecordSharing: Bytetype: BytedefaultFieldId: LongshareRules: Setqueues: SetMockObject() : voidMockObject(String) : voidgetFields() : SetsetFields(Set) : voidgetObjectId() : LongsetObjectId(Long) : voidgetName() : StringsetName(String) : voidgetEntityDescription() : StringgetObjectDescription() : StringgetObjectID() : SerializablegetQueues() : SetsetQueues(Set) : voidgetShareRules() : SetsetShareRules(Set) : voidgetCommonShareRules() : SetgetManualShareRules() : SetgetReadWriteRules() : SetgetDefRecordSharing() : BytesetDefRecordSharing(Byte) : voidgetLabel() : StringsetLabel(String) : voidgetType() : BytesetType(Byte) : voidhashCode() : intequals(Object) : booleangetDefaultFieldId() : LongsetDefaultFieldId(Long) : void-object-profileObjects-profileBaseHibernateObjectjava.io.Serializablejava.lang.ComparableProfileTab- - - + + + + + + + + + + + + + + + + + + + + visible: Booleanprofile: Profiletab: MockTabProfileTab() : voidProfileTab(Profile, MockTab, Boolean) : voidProfileTab(Profile, MockTab) : voidgetVisible() : BooleansetVisible(Boolean) : voidgetProfile() : ProfilesetProfile(Profile) : voidgetTab() : MockTabsetTab(MockTab) : voidgetEntityDescription() : StringgetObjectDescription() : StringgetObjectID() : Serializableclone(Profile) : ProfileTabgetId() : LonggetLabel() : StringgetName() : StringhashCode() : intequals(Object) : booleancompareTo(ProfileTab) : intcompareTo(Object) : int-profile-tabs-profileApps-profile-profile-functionsProfileObject() : voidProfileObject(Profile, MockObject) : voidclone(Profile) : ProfileObjectequals(Object) : booleangetCreatable() : BooleangetDeletable() : BooleangetEditable() : BooleangetEntityDescription() : StringgetFieldsConfig() : SetgetLayouts() : SetgetObject() : MockObjectgetObjectDescription() : StringgetObjectID() : SerializablegetProfile() : ProfilegetProfileObjectId() : LonggetReadable() : BooleanhashCode() : intsetAccess(Boolean, Boolean, Boolean, Boolean) : voidsetCreatable(Boolean) : voidsetDeletable(Boolean) : voidsetEditable(Boolean) : voidsetFieldsConfig(Set) : voidsetLayouts(Set) : voidsetObject(MockObject) : voidsetProfile(Profile) : voidsetProfileObjectId(Long) : voidsetReadable(Boolean) : voidgetObjectLabel() : StringgetHomepage() : ProfileObjectLayoutgetAddpage() : ProfileObjectLayout-profileObjectgetDetailpage() : ProfileObjectLayoutgetListpage() : ProfileObjectLayoutgetLookuppage() : ProfileObjectLayout-fieldConfiggetRelationpage() : ProfileObjectLayoutgetUpdatepage() : ProfileObjectLayoutgetLayout(Byte) : ProfileObjectLayoutcompareTo(ProfileObject) : intcompareTo(Object) : intBaseHibernateObjectMockHome- - - - - + + + + + + + + + + + + + + homepageId: Longobject: MockObjectlabel: Stringname: Stringtype: ByteMockHome() : voidgetEntityDescription() : StringgetObjectDescription() : StringgetObjectID() : SerializablegetLabel() : StringsetLabel(String) : voidgetName() : StringsetName(String) : voidgetType() : BytesetType(Byte) : voidgetHomepageId() : LongsetHomepageId(Long) : voidgetObject() : MockObjectsetObject(MockObject) : void-object-objectBaseHibernateObjectMockField-layouts- - - - - - - + + + + + + + + + + + + + + + + + + + serialVersionUID: long = 459622395 {readOnly}fieldId: Longobject: MockObjecttype: Integerlabel: Stringname: StringentityAttr: StringsetEntityAttr(String) : voidMockField() : voidMockField(MockObject, String) : voidgetEntityDescription() : StringgetObjectDescription() : StringgetObjectID() : SerializablegetFieldId() : LongsetFieldId(Long) : voidgetObject() : MockObjectsetObject(MockObject) : voidgetType() : IntegersetType(Integer) : voidgetLabel() : StringsetLabel(String) : voidgetName() : StringsetName(String) : voidgetEntityAttr() : StringhashCode() : intequals(Object) : boolean-fieldBaseHibernateObjectjava.io.Serializablejava.lang.ComparableProfileAppBaseHibernateObjectjava.io.SerializableProfileFunction- - - - + + + + + + + + + + + + + + + + + serialVersionUID: long = 939672374 {readOnly}enabled: Booleanprofile: Profilefunction: FunctiongetEnabled() : BooleansetEnabled(Boolean) : voidgetProfile() : ProfilesetProfile(Profile) : voidgetFunction() : FunctionsetFunction(Function) : voidProfileFunction() : voidProfileFunction(Profile, Function, Boolean) : voidisEnable() : booleangetEntityDescription() : StringgetObjectDescription() : StringgetObjectID() : Serializableclone(Profile) : ProfileFunctiongetId() : LonggetLabel() : StringhashCode() : intequals(Object) : boolean- - - - - + + + + + + + + + + + + + + + + + + + + + + + + objectLayoutId: Longprofile: Profileapp: MockAppvisible: BooleandefaultApp: BooleangetVisible() : BooleansetVisible(Boolean) : voidgetProfile() : ProfilesetProfile(Profile) : voidgetApp() : MockAppsetApp(MockApp) : voidProfileApp() : voidProfileApp(Profile, MockApp, Long) : voidgetObjectLayoutId() : LongsetObjectLayoutId(Long) : voidgetEntityDescription() : StringgetObjectDescription() : StringgetObjectID() : Serializableclone(Profile) : ProfileAppgetId() : LonggetLabel() : StringgetName() : StringgetDefaultApp() : BooleansetDefaultApp(Boolean) : voidgetLayoutId() : LonghashCode() : intequals(Object) : booleancompareTo(ProfileApp) : intcompareTo(Object) : int-tabBaseHibernateObjectjava.lang.ComparableMockTab- - - - - + + + + + + + + + + + + + + + serialVersionUID: long = 157784004 {readOnly}tabId: Longname: Stringlabel: Stringobject: MockObjectMockTab() : voidMockTab(MockObject, String) : voidgetTabId() : LongsetTabId(Long) : voidgetName() : StringsetName(String) : voidgetEntityDescription() : StringgetObjectDescription() : StringgetObjectID() : SerializablegetObject() : MockObjectsetObject(MockObject) : voidgetLabel() : StringsetLabel(String) : voidcompareTo(MockTab) : intcompareTo(Object) : int-tab-profileObjectBaseHibernateObjectMockLayout- - - - - - - + + + + + + + + + + + + + + + + + + layoutId: Longlabel: Stringname: Stringtype: Bytedefination: StringlayoutDefination: LayoutDefinationobject: MockObjectgetObject() : MockObjectsetObject(MockObject) : voidMockLayout() : voidMockLayout(Long) : voidgetEntityDescription() : StringgetObjectDescription() : StringgetObjectID() : SerializablegetLayoutId() : LongsetLayoutId(Long) : voidgetLabel() : StringsetLabel(String) : voidgetName() : StringsetName(String) : voidgetType() : BytesetType(Byte) : voidgetDefination() : StringsetDefination(String) : voidgetLayoutDefination() : LayoutDefination-layoutBaseHibernateObjectjava.io.Serializablejava.lang.ComparableProfileObjectLayout- - - - + + + + + + + - + + ~ + + + + + + + + + + + + + + + + + profileObject: ProfileObjectobjectLayoutId: LonghomePageId: Longlayout: MockLayoutHOME_PAGE: Byte {readOnly}LIST_PAGE: Byte {readOnly}RELATION_LIST_PAGE: Byte {readOnly}DETAIL_PAGE: Byte {readOnly}UPDATE_PAGE: Byte {readOnly}ADD_PAGE: Byte {readOnly}LOOK_UP: Byte {readOnly}type: ByteProfileObjectLayout() : voidProfileObjectLayout(ProfileObject, Long, Byte) : voidgetProfileObject() : ProfileObjectsetProfileObject(ProfileObject) : voidgetObjectLayoutId() : LongsetObjectLayoutId(Long) : voidgetType() : BytesetType(Byte) : voidequals(Object) : booleanhashCode() : intgetEntityDescription() : StringgetObjectDescription() : StringgetObjectID() : Serializableclone(ProfileObject) : ProfileObjectLayoutgetLayout() : MockLayoutsetLayout(MockLayout) : voidgetHomePageId() : LongsetHomePageId(Long) : voidcompareTo(ProfileObjectLayout) : intcompareTo(Object) : intBaseHibernateObjectjava.io.Serializablejava.lang.ComparableProfileObjectField- - - - - + + + + + + + + + + + + + + + + + + + + + + + + + serialVersionUID: long = 1102944033 {readOnly}id: ProfileObjectFieldIdaccessLevel: ByteprofileObject: ProfileObjectfield: MockFieldgetProfileObject() : ProfileObjectsetProfileObject(ProfileObject) : voidgetField() : MockFieldsetField(MockField) : voidProfileObjectField() : voidProfileObjectField(ProfileObjectFieldId) : voidProfileObjectField(ProfileObject, MockField, Byte) : voidProfileObjectField(ProfileObjectFieldId, Byte) : voidgetId() : ProfileObjectFieldIdsetId(ProfileObjectFieldId) : voidgetAccessLevel() : BytesetAccessLevel(Byte) : voidgetEntityDescription() : StringgetObjectDescription() : StringgetObjectID() : Serializableclone(ProfileObject) : ProfileObjectFieldisReadonly() : BooleanisInvisible() : BooleanisVisible() : BooleanisReadWrite() : BooleanhashCode() : intequals(Object) : booleancompareTo(ProfileObjectField) : intgetAccessLabel() : StringcompareTo(Object) : int-appBaseHibernateObjectMockApp- - - - - - + + + + + + + + + + + + + + + + + serialVersionUID: long = 871445215 {readOnly}appId: Longname: Stringlabel: Stringicon: StringappTabs: SetgetAppId() : LongsetAppId(Long) : voidgetName() : StringsetName(String) : voidgetIcon() : StringsetIcon(String) : voidMockApp() : voidMockApp(String) : voidgetEntityDescription() : StringgetObjectDescription() : StringgetObjectID() : SerializablegetAppTabs() : SetsetAppTabs(Set) : voidgetLabel() : StringsetLabel(String) : voidhashCode() : intequals(Object) : booleanMockAppTab- - - - - - + + + + + + + + + + + + + + + + + serialVersionUID: long = -2043650027 {readOnly}id: AppTabIdapp: MockApptab: MockTaborder: ShortdisplayType: ByteBaseHibernateObjectjava.lang.Comparable-appMockAppTab() : voidMockAppTab(MockApp, MockTab, Short, byte) : voidgetApp() : MockAppsetApp(MockApp) : voidgetTab() : MockTabsetTab(MockTab) : voidgetOrder() : ShortsetOrder(Short) : voidgetDisplayType() : BytesetDisplayType(Byte) : voidgetEntityDescription() : StringgetObjectDescription() : StringgetObjectID() : SerializablecompareTo(MockAppTab) : intgetId() : AppTabIdsetId(AppTabId) : voidcompareTo(Object) : int 用户管理实体类:定义了租户的用户、组织结构(角色)和用户组,以及它们间的构成关系。

第26页

共享规则:定义了租户用户访问对象的共享规则。其中,共享规则类“ObjectEShare”的SHARE_TYPE属性定义了共享规则中共享对象所有者和共享对象访问者的用户类型,即用户组、角色、角色及其下属的所有可能的组合类型。

第27页

class sharerules BaseHibernateObjectjava.io.SerializableObjectEShare- - - - - - - - - - - - objectShareId: Longobject: MockObjectreadOnly: BooleanruleId: LongshareType: IntegerofferGroup: GroupsharerGroup: GroupofferRole: RolesharerRole: RoleofferUser: UsersharerUser: UserdataId: LonggetOfferUser() : UsersetOfferUser(User) : voidgetShareType() : IntegersetShareType(Integer) : voidgetOfferGroup() : GroupsetOfferGroup(Group) : voidgetSharerGroup() : GroupsetSharerGroup(Group) : voidgetOfferRole() : RolesetOfferRole(Role) : voidgetSharerRole() : RolesetSharerRole(Role) : voidgetReadOnly() : BooleansetReadOnly(Boolean) : voidObjectEShare() : voidObjectEShare(MockObject, Integer) : voidObjectEShare(MockObject, Integer, Boolean) : voidObjectEShare(Long) : voidObjectEShare(MockObject, Boolean) : voidgetObjectShareId() : LongsetObjectShareId(Long) : voidgetObject() : MockObjectsetObject(MockObject) : voidgetRuleId() : LongsetRuleId(Long) : voidhashCode() : intequals(Object) : booleangetGroupOffers() : SetgetRoleOffers() : SetgetRolesOffers() : SetgetOffers() : SetgetUserOffer() : SetgetSharers() : SetgetRolesSharers() : SetgetRoleSharers() : SetgetGroupSharers() : SetgetSharerUser() : UsersetSharerUser(User) : voidisManualShare() : booleangetDataId() : LongsetDataId(Long) : voidgetEntityDescription() : StringgetObjectDescription() : StringgetObjectID() : Serializable BaseHibernateObjectjava.io.SerializableRole- - - - - - - + + + + + + + + + + + + + + + + + + + + - + - + + + + serialVersionUID: long = -1947225924 {readOnly}roleId: Longname: Stringsuperior: Rolejuniors: Setusers: Setgroups: SetRole() : voidRole(String) : voidRole(String, Role) : voidgetName() : StringsetName(String) : voidgetSuperior() : RolesetSuperior(Role) : voidgetJuniors() : SetsetJuniors(Set) : voidequals(Object) : booleanhashCode() : inttoString() : StringgetUsers() : SetgetAllUsers() : SetsetUsers(Set) : voidgetGroups() : SetsetGroups(Set) : voidgetRoleId() : LongsetRoleId(Long) : voidgetAllSuperiors(boolean) : SettravelUp(Role) : SetgetAllJuniors(boolean) : SettravelDown(Role) : SetgetIsLeaf() : BooleangetEntityDescription() : StringgetObjectDescription() : StringgetObjectID() : Serializable-superiorBaseHibernateObjectjava.io.SerializableGroup- - - - + + + + + + + + + + + + + + + + + + groupId: Longname: StringgroupRoles: Setusers: SetgetUsers() : SetsetUsers(Set) : void-sharerGroupgetGroupRoles() : SetsetGroupRoles(Set) : void-offerGroupGroup() : voidGroup(Long) : voidGroup(String) : voidgetGroupId() : LongsetGroupId(Long) : voidgetName() : StringsetName(String) : voidhashCode() : intequals(Object) : booleangetAllRoles() : SetgetAllUsers() : SetgetEntityDescription() : StringgetObjectDescription() : StringgetObjectID() : Serializable+ + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + - + - - - + + + + + + + + -sharerRole-offerRole 8.1.3.4 8.1.4 8.1.4.1 8.1.4.2

运行时元数据和配置访问服务 子系统描述 子系统接口

子系统关键用例实现

运行时元数据服务为系统在运行期提供简档、应用定义、对象定义、对象字段定义、租户用户信息、用户角色(组织结构)信息、用户组配置信息等查询服务。通常是限定在当前用户简档中已分配的应用、对象、对象操作和对象字段、系统功能和用户功能。

读取当前登录用户的简档。简档定义了用户对应用的访问权限,包括选项卡可见性、简档对布局的访问权限、对象的操作权限、对象字段的访问控制权限、

读取当前登录用户可见的应用。应用配置定义当前用户对应用的访问权限和应用的基本

第28页

属性,返回应用的概要信息,包括应用的可见性、应用的名称(显示标签)、应用标识、应用主页标识等信息。

读取当前登录用户可见的对象,包括简档对对象的可访问性、对象的名称(显示标签)、对象标识。

读取指定对象的字段集合,包括对象已定义字段的名称、字段标识、字段的类型、字段对当前用户简档的可访问性。

读取当前登录用户所在组织的全部用户标识和用户登录名称

读取当前登录用户所在组织的角色(组织结构)定义 读取当前登录用户所在组织已定义的用户组名称和用户组标识 8.1.4.3 8.1.4.4 8.1.5

子系统类图

子系统关键用例实现 多租户运行时服务

多租户的基础服务实现了SaaS模式应用需要的基础设施,这些基础设施包括:  安全服务:完成多租户的访问的安全隔离性。提供访问许可验证和身份认证及鉴权。  租户数据隔离性的实现机制:将租户数据隔离性从每个应用逻辑中剥离出来,为多租户

共享的应用实例维护数据空间在租户上下文间的隔离。

 统一的应用组件模板:使用统一的表现层界面元素和界面布局构造一致的应用组件模

板。通过标准化的模板抽象业务对象的行为。最大化复用已验证的应用组件服务实现。  应用组件的服务框架:包括一组通用实现机制,由一组接口和接口的部分实现构成。涉

及典型的分层web应用的控制层、业务逻辑实现层、持久化策略。如URL Mapping规则、统一的Action、Service、DAO、POJO基类、自动生成领域对象、以及各层自定义类的装配和打包部署等方面的基础实现。 8.1.5.1 8.1.5.1.1

安全服务 子系统描述

 租户用户登录  租户用户身份认证  租户License控制

 租户用户访问控制策略的加载

第29页

 登录日志

 租户用户的访问控制服务

每个租户的访问权限在登录时通过元数据服务加载到租户用户的上下文中。租户用户的访问控制服务作为一个独立的方面织入到租户用户的每个请求中。每个租户登录时的身份认证由系统域的租户管理完成,权限规则由租户管理员在租户域内定义,访问权限在租户登录时,通过访问元数据服务获得,保存在租户会话的上下文中。访问控制服务验证每个请求的合法性。

访问控制根据粒度可以划分为:应用级、对象级、对象字段级、对象记录级等几个层次。访问控制服务以一个安全过滤器插入到每个请求的控制逻辑中,完成应用级、对象级访问控制;对象字段级的访问控制由表现层解释实现;对象记录级访问控制则在持久化数据访问策略中作为一个数据访问的过滤器来实现。 8.1.5.1.2

子系统接口

用户登录接口:用于被第三方应用集成。 在线用户查询接口。

依赖接口:租户的license申请与释放、访问控制策略查询、租户对象共享规则查询。

第30页

8.1.5.1.3 子系统类图

8.1.5.1.4

子系统关键用例实现

 租户用户登录

第31页

 租户用户访问控制

8.1.5.2 8.1.5.2.1

多租户的数据隔离(Helpdesk已实现) 子系统描述

每个租户使用独立的一套数据库模式,保证数据的隔离性。应用在运行时根据当前用户的租户属性,切换到租户自己的数据空间中,使用唯一的应用实例执行租户定制的业务逻辑。平衡在数据访问的安全性和系统资源利用率,各个租户的请求共享访问同一个数据源的数据库连接池,即系统不为每个租户创建独立的数据库访问账户,但通过应用控制保证租户数据访问的独立性。

第32页

数据源使用Spring依赖注入机制配置,应用的基础框架在租户登录到系统后,根据用户所属的租户信息动态地创建面向租户的Session Factory,使得每个租户的数据库访问映射到自己的逻辑数据库中(schema/catalog)。 约束和假设:

为了简化管理的复杂度,在集群和负载均衡的环境中,多租户的应用实例与数据库服务间存在一对一的对应关系,即一套应用实例仅访问一个数据库服务;而一个数据库服务也仅服务于一套应用实例。 8.1.5.2.2

子系统接口

租户数据隔离的数据库访问。 8.1.5.2.3

子系统类图

第33页

8.1.5.2.4 子系统关键用例实现

8.1.5.3 8.1.5.3.1

应用解释器 子系统描述

 表现层框架

在应用创建时,应用生成环境为应用生成了可以被框架管理的表现模板和业务数据,在运行时刻,多租户能力框架负责将模板和数据合并,动态生成体验唯一的用户界面。这些表现层模板主要有:

 应用主页:是一组对象导航模板,定义了用户登录到系统后可访问的标签页面

组合。一个系统中可包含多个应用,每个应用有一个主页。用户登录后展现的主页为用户的缺省应用主页。

 对象主页:导航到应用主页中特定的标签页即为对象的主页,对象的主页由对

象的查询视图区和由缺省对象查询视图生成的对象导航列表、对象相关访问快捷菜单构成。通过对象的主页,用户可以定位到具体的对象实体,从而完成对具体的对象实例及其相关信息的操作。  与对象操作相关的各类布局视图:

 对象详细查看布局  对象编辑布局  对象创建布局  对象关系布局  对象查询布局  对象列表布局

表现层页面模板基于布局的定义,结合当前用户的权限数据,生成最终用户可访问的用

第34页

户界面。

 统一的前端控制器

使用struts提供的动态方法调用机制实现每个租户用户对本组织部署的应用中的特定对象的特定URL请求到具体租户应用的action对象的映射,利用通配符定义的Action Mapping配置,通过通配请求中的租户标识、对象名称和操作名称,使用通用的struts配置完成请求到具体action实例的映射。

后端服务与表现层的数据交换使用PO类实现,表现层利用struts支持的OGNL策略,基于已定义的模板,合成对象的界面。

 通用的Action、Service、DAO、PO与领域相关的Action、PO

系统提供Action、Service的接口定义和抽象实现,作为应用组件的控制层与服务层的实现模板,集成用户自定义的具体的Action和Service类,实现通用的服务逻辑在不同的领域对象间的复用。

具体的Action和Service类派生框架中的缺省实现,它们仅实现领域模型中特定的请求(create、update、search、list(pagination)、delete之外的请求),装配具体领域对象(POJO);实现模板方法中的钩子方法,从而扩展定制每个应用组件相关的业务逻辑。 8.1.5.3.2 8.1.5.3.3

子系统接口 子系统类图

 应用、对象主页导航类图

第35页

class 应用、对象首页导航Action RuntimeAction- - - - - - - + + + + + + destination: StringappName: StringobjectName: StringshortcutMenuShowMode: Stringapps: Maptabs: ListportalService: IPortalServiceopenAppIndexPage() : StringopenObjIndexPage() : StringopenSetupMenu() : StringgetTenantPackage() : StringgetAppPageId() : StringgetObjPageId() : StringActionSupportBaseAction# # # # # # # # # # # addError(Exception, String) : voidaddError(string) : voidaddError(Exception) : voidaddMsg(String) : voidbuildError(Exception, String) : voidgetActionName() : StringgetApplication() : MapgetBean(string) : ObjectgetContext() : ActionContextgetSession() : MapgetUserInfo() : UserInfoTabVo- - - - tabId: LongtabName: StringtabLabel: StringobjectName: String«interface»IPortalService+ getPortalParam(IUser, Integer, String) : PortalParam  对象CRUD操作类图

第36页

第37页

8.1.5.3.4 子系统关键用例实现

 租户用户应用切换

 进入对象主页

第38页

 创建自定义对象

第39页

 删除自定义对象

第40页

 修改自定义对象

第41页

 查询自定义对象

第42页

 查看自定义对象

8.1.6

标准工具组件

标准工具组件是指可以布局到应用主页中的通用组件,它们实现相对独立的应用功能,

第43页

但同时与系统中部署的标准应用对象或自定义对象以及系统配置的访问控制策略间存在一定的联系。如对象创建的快捷菜单、任务提醒工具、主页中的自定义链接、公告栏、对象智能搜索工具等。 8.1.6.1

新建快捷菜单

新建快捷方式为用户快速创建一个业务对象提供了快捷菜单。系统为租户管理员提供了定制这个快捷菜单的管理工具。租户管理员可以配置新建对象快捷菜单的表现形式,即以完全显示的列表菜单形式表现或者以固定大小的下拉列表方式表现。可以将快捷菜单以组件形式拖拽到对象的主页或应用的主页中。

下拉列表方式:展开后的表现

=>

直接以列表形式展现快捷菜单。

第44页

快捷菜单中的菜单项由对象图标、对象名称和对象的新建导航构成,点击链接后导航到指定对象的标签页中,加载对象快捷创建布局。对象的图标、名称以及快速创建的布局在对象定义时确定,新建快捷菜单收集系统中已定义了快速创建的布局对象信息,构造快捷创建菜单。构建快捷创建菜单时需要考虑对“快速创建对象”的URL构造规则,考虑运行时对有些租户使用自定义的标准对象的快捷创建布局,而有些租户使用标准的快捷创建布局的不同情况的处理,生成合适的导航链接。

租户可访问的快捷菜单取决于租户的简档授权,租户仅能访问已授权的对象创建链接。 8.1.6.1.1 8.1.6.1.2

第45页

子系统类图

子系统关键用例实现

8.1.6.2 任务提醒(区别于工作流任务)

用户基于特定的对象记录、客户及联系人创建的定时任务或活动的通知提醒,定义任务的执行时间、执行者、提醒方式、任务的主题、任务的优先级、任务的状态。和任务类似的对象有事件、活动、备忘录,它们在实际应用中存在细微的差别。在当前产品定义中,任务涵盖了这三种实体,综合了事件、活动、任务和备忘录的全部特征,统一定义为任务组件。这些任务不同于工作流中定义的工作流任务,它们有自己的任务状态、处理期限。

用户可以从两个途径进入任务的创建:具有活动跟踪列表的对象;应用主页中的任务列表。当一个任务和对象相关时,可以出现在对象的待处理活动列表中,任务关闭后,从主页的任务列表中消失,如果存在关联对象,则存档到对象活动历史列表中。

任务包含以下属性:被分配者、任务主题、任务状态(事件提醒、未开始、执行中、已完成、推迟)、开始时间、到期时间、提醒时间、优先级、注释、*邮件通知、相关项、联系人电话、电子邮件,以及联系人查询框。

用户也可以创建周期性的任务,系统根据定义的任务执行频度定期生成任务提醒、创建新的任务,并根据频度指定开始时间和到期时间。

其中的主题是对任务的简单分类,包括邮件、电话、发送报价、其他、信函等;电话和电子邮件是在确定了联系人后,从联系人信息中获得。任务的优先级有高、中、低三种。任务有明确的到期日和一个具体的提醒时间。

当任务可周期性执行时,可以根据选择的时间间隔指定具体的日期,系统辅助用户选择合适的日期,不同时间频度有相应的配置界面。周期性任务在原型阶段不实现。

第46页

8.1.6.2.1 8.1.6.2.2

子系统类图

子系统关键用例实现

第47页

8.1.6.3 对象的最近访问历史

或者

记录最近浏览过的对象的链接。最近访问对象定义为当前用户访问过的最近10个对象记录。在对象最近访问中包含对象的图标、对象的记录值、以及指向具体对象实体的URL。

当用户访问一个对象的详细信息时,更新对象访问历史,包括界面的更新和持久化数据的更新。用户再次登录系统时,能够浏览到累积的访问历史。 8.1.6.3.1 8.1.6.3.2

8.1.6.4

对象搜索工具 子系统类图

子系统关键用例实现

对象搜索工具基于当前登录用户的简档可访问的对象实现搜索功能,对象搜索工具实现了对象的快速搜索,可支持模糊匹配,可限定搜索对象的类型,可搜索的对象字段是各类文本型字段,对象搜索工具根据每个对象可用于搜索的属性构造查询条件,访问每个对象的查询服务,搜索的结果根据搜索对象的搜索布局定义表现查询结果列表。如果搜索工具检索到关键字在多个对象中都存在查询结果,搜索工具会将搜索结果分别按对象搜索布局依次展现。

第48页

8.1.6.4.1 8.1.6.4.2

8.1.6.5

子系统类图

子系统关键用例实现

自定义链接

租户管理员或有权限的高级用户可配置放置在应用主页中的一组链接,用于快速访问外部相关地址。自定义链接作为标准工具组件可布局在应用的主页中。 8.1.6.5.1 8.1.6.5.2

8.1.6.6

公告 子系统类图

子系统关键用例实现

租户管理员或有权限的高级用户可向租户域内的所有用户发布公告。公告作为标准组件可配置在应用的主页布局中,用户登录到系统后,可以看到已发布的公告通知。 8.1.6.6.1 8.1.6.6.2

8.1.7

开发框架 子系统类图

子系统关键用例实现

开发框架作为系统构建的基础框架提供了分层架构的各层封装,相应的,开发框架依赖于以下Spring2.5、Hibernate3、struts2、YUI、Apache Commons API等Open Source框架,实现各层通用功能。系统遵循成熟的分层架构构建。

8.1.8 8.1.8.1 8.1.8.1.1

通用自定义应用服务 工作流 子系统描述

工作流的典型应用有两种,一个是工作流规则,另一个是批准过程。工作流规则

第49页

(workflow rule)是一组工作流指令的容器。它包含激活这个工作流的条件,以及在满足这个规则的条件时应该执行的任务、警告和字段更新。每个工作流规则必须基于在定义规则时选择的一个对象。这个对象影响到可用来设置工作流激活条件的字段。批准过程用于指定批准一个新记录(对象实例)所需的一系列步骤。每个步骤允许一个指定的批准人接受或拒绝记录。这些步骤可以应用于过程中的所有记录,也可以只应用于满足特定条件的记录。与工作流相似,批准过程也允许指定操作,比如发送电子邮件警告、更新字段值或分配任务,这些操作应该在批准记录、拒绝记录或者记录首次提交等待批准时执行。

工作流规则与批准过程使用不同的解释引擎解释工作流指令。而构成工作流指令的功能组件是可复用的。

工作流中的关键用例:

8.1.8.1.2

子系统关键用例实现

8.1.8.1.2.1 批准过程

批准过程实现了由系列操作构成的业务活动,每个执行步骤由不同的系统用户参与完成。使用批准过程能够实现典型的呼叫中心客户服务或主动营销活动中的工单流转业务。与其他工作流工具相比,App Suite的批准过程具有以下关键特征:

 批准过程解释引擎可跟踪审批过程的执行  支持定义批准过程中每个步骤的批准或拒绝操作  支持拒绝后可终止流程或回退上一步

一个完整的批准过程的生命周期由定义->初始化->执行->结束几个阶段构成。

第50页

 定义过程

批准过程和步骤的定义过程包括以下四个部分: 批准过程和步骤的定义(Setup Approval Process)

1. 开发人员创建业务流程

2. 选择需要创建业务流程的已定义的对象

3. 定义业务流程的过滤条件,确定哪些对象的实例将触发执行批准过程。 4. 定义业务流程的第一个审批者。 5. 定义批准者是否可编辑待批准的记录

6. 定义批准相关的界面布局:选择在审批界面中展现的对象属性和是否生在对象详

细布局中成审批历史列表。系统会在定制的审批布局中添加审批过程自身必须的属性,如:审批意见、审批者(系统自动填写、只读显示)、审批时间(系统自动填写,只读显示) 7. 定义初始提交者

8. 定义初始提交后的工作流操作:记录锁定+工作流操作(字段更新或创建任务) 9. 保存业务流程定义。 注:

初始提交操作:初始提交操作是用户初次提交待批准记录时发生的操作。默认情况下,

第51页

锁定记录的操作在初始提交时会自动运行。初始提交操作可以包含任意批准操作,例如电子邮件或短信报警、字段更新、任务。例如,初始提交操作可以将自定义批准状态字段更新为“进行中”。

记录锁定:记录锁定是防止用户编辑记录(无论字段级安全或共享设置如何)的过程。系统将自动锁定等待批准的记录。用户必须具有给定对象的“修改所有”对象级权限或“修改所有数据”权限才可编辑锁定记录。默认情况下,初始提交操作、最终批准操作、最终拒绝操作和调回操作相关列表包含记录锁定操作。不能为初始提交和调回操作编辑这一默认操作。

创建批准步骤(Setup Approval Step)

1. 选择过程,创建过程的初始步骤

2. 定义步骤的过滤条件:选择所有对象实例都进入批准步骤或指定条件。通过选择工

作流绑定的对象属性取值配置对象实例的过滤条件

3. 选择步骤的批准人:批准人可是具体的用户,用户组、角色、可以定义为自动选择,

也可以定义为允许手工选择批准人。

第52页

4. 设置拒绝的类型:最终拒绝或回退上一步 5. 定义批准步骤的拒绝操作或批准操作

定义最终拒绝操作、最终批准操作、回调操作

定义最终拒绝操作、最终批准操作和回调操作的过程与定义一般的批准步骤中的操作是一致,只是这些操作触发的位置比较特别:

最终批准操作:最终批准操作是记录的所有必要批准均获得批准后发生的操作。最终批准操作可以包含电子邮件报警、字段更新、任务或出站消息。例如,最终批准操作可以将状态更改为“已批准”,或发送电子邮件通知。

最终拒绝操作:最终拒绝操作是在批准人拒绝请求,并且请求进入最终拒绝阶段时发生的操作。最终拒绝操作可以包含电子邮件报警、字段更新、任务或出站消息。例如,最终拒绝操作可以将状态更改为“已拒绝”,发送一个电子邮件通知,解除记录锁定以便用户可以进行编辑以重新提交。

调回操作:调回操作是在调回提交的批准请求时发生的操作。默认情况下,解锁记录的操作在调回时会自动运行。调回操作可以包含电子邮件报警、字段更新、任务或消息。例如,调回操作可将请求的状态从“进行中”更改为“未提交”。

批准过程的激活与顺序设置

批准过程定义完成后,管理员激活批准过程。

激活批准过程后,系统为相关的自定义对象创建审批历史列表,并可在应用主页中配置待审批任务。

当系统配置了多个批准过程时,可以定义他们之间的执行顺序。一个对象实例按照审批顺序只进入一个审批流程。

 批准过程初始化

批准过程的初始化是指批准流程的初始提交操作的执行过程,提交后未处理的过程可以执行回调操作。批准过程的初始化由初始提交操作触发。

第53页

 批准过程执行

第54页

执行者查看批准过程的待审批任务,从待审批的任务列表中选择分配给自己的待审批任务开始执行。批准过程的解释引擎根据批准过程的定义,触发相应的动作,或自动执行操作,修改状态,或生成工作流任务,或者新的待审批任务,推动参与工作流执行的各个用户执行工作流分配的任务。

 批准过程结束

第55页

工作流结束即执行最终的批准或否决操作,完成工作流的执行。

8.1.8.1.2.2 工作流规则

//TBD

8.1.8.1.2.3 工作流中的基础设施

工作流操作:工作流操作是定义在流程中的活动组件。通过配置不同条件下的执行的工作流操作,实现工作流的执行。系统已定义的工作流操作有:工作流任务、对象的字段更新、邮件通知、短信通知、发起Web Service调用等操作。每种工作流操作都有其各自的属性,可在定义批准过程或工作流规则时定义。

NN工作流条件评估服务:条件评估服务根据流程定义的过滤条件,对即将进入批准过程、

流程步骤或者触发工作流规则的对象实例(记录)进行评估,判定当前的对象实例是否触发

第56页

定义执行条件Y规则条件Y工作工作工作流工作流 工作流步骤或工作流规则的执行。 8.1.8.1.3

子系统类图

参考WFMC对工作流产品的功能划分,如下图所示:

App Suite的工作流实现主要由以下功能组件构成:

批准过程与步骤定义(Approval Process Definition):面向系统中的应用开发人员或平台管理员,实现了定义与租户的业务流程相关的批准过程和步骤的工具,并为工作流解释引擎提供服务接口,外部服务可以访问接口获得批准过程、指定的步骤、以及步骤的关系的详细定义。

工作流规则定义(Workflow Rule Definition):面向应用开发人员或平台管理员,实现定义工作流规则的用户接口,并为工作流规则的解释引擎提供服务接口。

批准过程引擎(Approval Process Engine):根据批准过程的定义,解释执行批准过程中定义的评估条件,并驱动执行相应的工作流操作,为参与审批过程的用户生成待审批的任务和工作流任务。

工作流规则引擎(Workflow Rule Engine):根据工作流规则的定义,解释执行工作流规则定义中的评估条件,执行工作流规则中定义的操作:生成工作流任务、字段更新、邮件或短信告警、WEB Service调用等操作。

第57页

工作流操作(Workflow Action):配置在批准过程或工作流规则中的执行步骤中的操作,包括发送通知、创建任务、更新字段、发送邮件或短信、Web Service调用等操作。优先实现创建任务和更新字段这两个操作。

审批任务监控与执行触发(Workflow Activity):过程执行解释器生成待审批任务后,用户通过待审批任务列表执行待审批的操作,系统能够提供特定的审批流程执行情况的监控,形成基于任务完成状态的统计结果,查询超期的任务。

对象条件评估服务(Rule Evaluation Service):作为一个工具服务,帮助过程引擎或工作流规则引擎评估计算当前的记录是否满足指定的条件,以便决定当前的记录是否会触发流程定义中已定义的操作。

待审批任务(Approval Process Task):待审批任务是由工作流引擎生成的需要人工参与才能够驱动工作流执行的工作条目,每个用户的待审批任务作为一个可配置的组件列表配置到应用的主页中,被用户查看并选择执行审批操作。选择具体的审批任务后,用户可以在已定义的批准过程布局中查看和审批任务相关的对象,并填写审批意见,提交驱动批准过程的流转。其中,用户在批准过程布局中可查看的对象属性遵循当前用户的简档定义中对对象的访问权限的限定。

工作流规则主要类图:

批准过程的关键类图

第58页

第59页

8.1.8.1.4 与其他子系统的接口依赖

8.1.8.2

报表

//TBD 8.2 8.2.1

通用的设计机制 数据缓存

分布在各个子系统中相对静态、访问频度较高的数据,如租户配置的字典数据、对象的共享规则、用户的组织结构(角色)。这些数据在运行环境中,读操作多于写操作,为了提高系统的性能,减少数据访问和网络调用的开销,它们适于采用缓存的方式来管理。它们在系统启动时,被系统加载到内存中,当数据修改时,通过更新接口刷新内存中的数据,同时将变更持久化到数据库中。 系统使用通用的机制保证缓存数据的读取和更新安全;以及在并发环境下的访问效率。可以采用下面的方法来管理这些缓存数据:

 使用支持CAS机制的容器管理缓存数据,实现安全发布。  缓存数据支持懒加载。

第60页

8.2.2 事件通知

系统中存在一些需要异步执行的任务,如工作流待办事项和任务提醒、可能的第三方应用集成(短信网关或短信Modem集成)、系统事件告警等,对于这些异步的消息事件,通过创建相关主题的消息队列,应用Spring(MDP)和Resin内置(JMS实现)的消息机制完成。 8.2.3

定时任务

定时任务使用Spring框架已集成的Quartz实现不同定时策略的任务执行。 8.2.4

表现层的界面元素

利用App Framework封装的YUI界面组件,简化表现层实现。这些界面组件包括:数据表格、对话框、信息提示、弹出窗口、控制按钮、树型菜单、级联下拉列表等。 8.3

部署描述 单服务域部署 多服务域部署 8.3.1 8.3.2

网络拓扑图

节点功能及构件分布

9 参考文献

10 附件

《客户化的应用程序界面说明》 《运行时应用解释器规则说明》 《App Suite数据库设计说明》

第61页

因篇幅问题不能全部显示,请点此查看更多更全内容