谈谈你在OA项目中主要负责的模块,并简单的说一下它们的功能。
答:我呢,在项目中主要负责了权限管理模块,从初期的需求分析,到概念模型的设计都是我全权负责的,这个项目的权限是细化到操作的,这个是我觉得比较有分量的地方,以往我做过的一些权限都是限制在模块层,所以它的概念模型的设计和认证就比较复杂一些,大体来讲主要包括2个方面,一个是授权、另一个就是认证。
授权: 其实说明白点,我认为权限其实就是一种关联,它的内在关系是谁对某种资源进行某种操作,比如说某用户拥有对某模块进行某种操作的权限,实际上就是将用户、操作的模块、具体的操作关联起来,这也就是我们经常说的ACL访问控制列表,当初设计ACL表的时候,我们跟用户谈的是基于CRUD操作的一些个限制,当我基于这个需求设计ACL表结构时我的做法是将4种操作分别映射成C、R、U、D4个字段来表示这4个操作过程,但随着项目的开发的深入,并不断的和客户进行交互之后,客户提出需要加一些其他的限制,那么这个时候我就在考虑了,如果我还是将其他操作以单独字段添加到ACL表中的话,就得去更改ACL表结构,那么这个时候我就在寻求一种能一劳永逸解决这种问题的办法,我首先想到的是抽出一个字段来表示所有操作,这样做的话,如果后期再需要添加一些操作的话我就不用去更改ACL表结构了,并能使我的认证操作更便捷、更统一化,它的关键是操作字段的类型选择问题,起先想到用字符串来标识所有操作,这样在认证的时候只要遍历这个字符串就能够得到相应的权限了,但这个项目对性能的要求是比较高的,而权限的认证又是随时随地的,也就是说权限的认证会频繁发生,那么如果用字符串来表示操作的话,在认证时我们每次要将字符串转化成字符数组,然后进行遍历,拿到相应的操作位来确定权限,很明显这样在性能上并不是太好,所以我想到了位操作,我们都知道对位的操作要比对String类型操作效率快的多,而且int类型在计算机中是占32位的,所以我最后拿出的方案是用一个int类型的变量来代表所有的操作,这样它能够支持32种操作,对于一般的应用而言是足够了,而且对于授权和认证我们可以通过简单的按位或、按位与操作来解决。
关于权限这块,大家如果不理解前面的话也可以对照下面的例子来理解.
一般的权限大多都是控制到模块的,但控制到操作的大部分也是用如下方式:
很明显,同一个用户对同一个模块的限制有多少种就会有多少条记录,那么遍历的时候效率明显不好,为了提高效率
我们会这样做(设计之初)
这样做解决了多条记录的问题,但是不知道大家有没有发现,这样是不便于扩展的,也就是说如果再要加一条限制的
话我们可能要在ACL表再加入一字段来代表该限制,但是,一旦当数据库表设计好了之后,一般是不允许再次更改的,
因为要尽量设计出能够通用的表,那么接下来我们是这样做的.
这样做既解决了多条记录的问题,又解决了扩展不易的问题,但这么做还存在一个问题,那就是认证和授权时候会相
当麻烦,大家都知道权限的认证是即时的,也就是随时随地都需要认证的,那么认证操作肯定会非常频繁,上面ACL表
的permission字段的设计在认证时需要将其先转化成字符数组,然后遍历这个数组,拿到相应的操作符,并来判断其
有没有这个权限,授权时也是相当麻烦的,你得根据一定的规则拼成类似于(X_X_X_X)这样的字符串,很显然从效率的
角度去考虑这样也不符合要求.
最终的方案
我们用int来表示权限,int占32位也就是说支持32个操作的扩展,而且这样做,在认证和授权方面会非常的快速(位
操作速度是非常快的),我们只需要通过简单的按位或和按位与来完成授权和认证了.
这就是权限这块的东西了,你从最初的那么多个不足到最后的比较完美的实现不就是你遇到的困难和你最后的解决
方案吗?呵呵
认证:整个项目的认证包括2个方面,一个是当用户登陆时,需要拿到该用户所有拥有读取权限的模块列表,另一个
是当用户对某个资源模块进行某种操作之前需要认证其是否有该权限,对于本系统而言,是允许存在特权用户的,
也就是说,不仅能将角色赋予给用户,而且也能将权限直接赋予给用户。这样在认证的时候就存在冲突问题,主要
体现在2个方面。
第一种冲突
问题:当认证时该以用户直接赋予的权限为准还是应该以该用户拥有的角色所拥有的权限为准。
比如说,直接赋予给用户的权限表明用户拥有对某模块进行读取操作的权限,而该用户本身拥有的角色中却不
允许对该模块进行读取操作,那么我们进行认证的时候是该以用户直接赋予的特权为准还是以用户拥有的角色中的
权限为准呢?记得很清楚,由于是我负责这个模块,所以当初做需求时是跟着项目经理一起做的,通过和客户的沟
通基本上确定了2种结论,一种是,有些客户认为,既然是特权用户,那么当然应该以特权用户为准了.另一些客
户则认为,所谓特权用户是在特殊的情况下赋予的权限,所以应该以通用的角色中的权限为准。
解决方案:我不应该在程序中写死就是以特权用户为准,对于我现在要做的就是如何将这种灵活性留给客户去
操作,后来的解决办法是在给某个特权用户赋予特殊权限的时候有一个选择,就是继承和不继承的选择,也就是说,
如果继承,那么我们应该以角色中的权限为准,如果不继承,那么就是以特权用户特有的权限为准,这样的话就能
够根据客户操作时的意愿来确定以哪种权限为准了,很好的解决了这种冲突问题。
第二种冲突
问题:角色的冲突问题
本系统是允许用户拥有多个角色的,那么角色中的权限肯定也会存在冲突问题,当发生冲突的时候应该以哪个
角色的权限为准的呢?这里面就有一个出发点的问题。
举一个 很简单的例子,对于总经理角色和管理员角色而言,在对公文进行审批操作的时候我们理应以总经理角
色为准,但当对文件柜进行整理时我们就应该以管理员角色为准。
解决方案:很明显这种情况是不确定的,也就是说也需要做一个灵活的实现,而不是写死在程序中,同样站在客户
角度来考虑我们应该把这种灵活性的控制交给客户来抉择,所以在用户和角色之间添加了一个优先级概念,这样当
客户给某一用户赋予某个角色的时候就能够根据实际情况来分配角色的优先级,彻底的将灵活性交给了用户。
工作流模块
另外我也参与了工作流模块的设计,在本系统中工作流的关键实际上就是公文的流转,其实呢,很多软件都说支持工
作流,其实大部分是以一种硬编码的形式将有限个流程写死在程序中的,而本系统则真正做到了支持用户自定义流程的功能。对于工作流引擎的实现,我认为它的关键就是在如何解析用户自定义的流程,也就是能够根据用户自己定义的流程创建出相应的流程规则。
本系统中的关键业务是体现在以下几个方面
?
? 公文的创建(不太重要) 公文的提交(将公文提交给下一个人)
当用户进行提交公文操作时能够手动的选择流程的走向,当公文创建开始到最后公文流转结束,是将每一步
的流程走向都交给客户去选择,而不是写在程序中,我们做到了根据用户选择的流程走向选择相应的流程进
行流转。
? 查询待审公文列表
当某个用户登陆系统之后,能够查询到等待该用户审批的所有公文列表
? 浏览审批历史记录
用户可以浏览审批过的公文信息
其实每一步的实现也是一种关联的体现,比如当创建公文的时候,需要将公文和创建者相关联,当流程提交时需要建
立公文和审批者之间的关联
,以便能够实现查询待审公文列表的功能。
应用JBPM实现以上业务
首先进行流程定义,也就是通过流程设计器来定义流程,定义好流程之后,我们要进行部署也就是将流程实例保存在数据库中
?
?
? 之后是创建公文 接着是根据流程定义创建流程实例,并将公文和流程实例互相绑定。 如何完成提交的呢?流程实例的创建需要某个特定的流程定义,而流程定义是某种流程规则的定义,而流程
实例则是这种规则的体现.
JBPM中的关键主要是流程定义和流程实例的概念,另外一个就是关于怎么样将JBPM和系统集成起来,那么在流程定
义和流程执行的概念中,需要区分流程定义和流程执行的区别,定义呢,其实主要就是通过各种节点、线,实际上就相当于一个流程图,把这个流程图用对象模型表达出来,所谓定义其实就是把规则用某种语言,在JBPM中叫JPDL,用这种语言把它定义出来,它是一个XML,这种语言定义了一些XML中一些个元素,这些元素里面可以嵌套什么样的元素,这些元素可以有什么样的属性等等等等类似这样一些基本的规则,而流程执行所面对的是一个流程实例的概念,一定要创建一个实例,通过这个实例来执行流程,其实就是图的执行,我们可以通过signal从一个节点转向到下一个节点,在创建一个流程实例的时候(根据流程定义创建相应的实例),某一个实例是按照相应的规则来创建的,在流程实例中包含了一些数据信息,这种数据信息当然就是流程实例变量,流转从一个环节转向另一个环节,通过在旁边创建一个Token对象,通过Token的引用或者说一个指向发生改变,就叫做执行,Token开始是指向起点的,调用signal就转向到下一个节点,这样就表示流程执行到下一个节点了,在下一个节点该干一些什么事情,就是由节点本身来决定的,一步一步的往下走,如果找到那些比如说Fork节点,它就会在当前Root Token下面去创建多个子Token,通过各个子Token的signal来触发流程往下走,这就是一个大概的流程走向。
如果我们将JBPM集成到系统中应该去怎么做,总体来讲应该有2个部分,第一个就是做一些准备工作,所谓的准备
就是设计好流程,将流程部署到数据库中去,第二个部分是做流转,根据定义好的流程,创建出公文,然后将公文进行流转,也就是从一个人手上流转到另一个人手上,如何流转呢?我们通过JBPM的流程实例来记录一些信息,把这些信息从一个节点转移到另一个节点。因此我们创建好流程实例之后就会将公文的ID保存在流程实例中,然后我们触发JBPM的流程实例从一个节点转到另一个节点,这样就相当于将一个公文从一个人手上转到另外一个人手上,那么在创建公文的同时,我们要将公文和流程实例互相的绑定在一起,这样会更加容易使得我们开发起来更加方便一些,因为互相绑定之后,我们可以通过公文,可以得到这个公文对应的流程实例是什么,通过流程实例我们就可以得到这个公文现在所处的位置是什么,然后通过流程实例可以得到公文,这个是很显然的,这些流程信息就是应该和流程实例绑定在一起,不能说流程实例里什么也没有,那么就失去了流转的意义了,所以应该把一些个有意义的信息放到流程实例中,这些有意义的信息可以是公文,也可以是一些别的信息,比如一些关键的变量(有条件的流转等)。
第二篇:OA项目总结
组织机构管理模块
请描述一下你做的组织机构管理模块
描述思路:
1、 组织机构模块的基本需求
a) 本模块主要管理公司、子公司、部门、岗位、员工的信息
b) 公司下面可以创建子公司、部门
c) 部门下面可以创建子部门、岗位或员工
d) 岗位下面可以创建员工(即员工可以属于某个岗位)
e) 公司、部门、岗位、员工形成一棵组织机构树,要求使用树型方式来展现和管理
2、 组织机构的总体设计思路
a) 公司、部门、岗位、员工可以看成同一种类型:Party
b) 在Party上实现树型结构(父子关系)
c) 其它类型:公司、部门、岗位、员工均继承Party(请画出类图)
3、 组织机构的实现技巧
a) 利用jQuery的jsTree实现组织机构树
b) 利用jQuery的treeTable实现列表(AJAX、查询、分页)
c) 在组织机构树中显示公司、部门、岗位的信息,点击公司、部门、岗位,则可以显示其详细信息,及其下面的所有员工(利用hibernate filter避免在树上显示员工信息)
d) 为了显示某个公司或部门(包括其下级机构)下面的所有员工,我们设计了一个sn,这个sn根据组织机构的树型结构来取值,通过它便可以方便实现查询需求。 e) 利用TreadLocal实现分页参数的传输
f) 利用VO设计模式适应客户端对数据格式的特殊要求
4、 我们这个设计的优点在哪里
a) 通过树的方式来管理,一目了然,层次清楚
b) TheadLocal设计模式的运用大大降低了分页查询逻辑的封装处理
c) 抽象出Party来,便于对所有的组织机构实体进行统一的管理(比如方便我们后面的权限管理模块把所有Party统一对待)
5、 我们这个设计的缺点在哪里
a) 没有实现员工的调动管理(从一个部门调到另外一个部门),此功能在项目二期实现!
b) 员工不允许跨部门(即一个员工只能属于一个部门,而不能同时属于多个部门) c) 在模型上没有规定哪些类型的Party只能放在哪些类型的Party下面,比如,在一般的需求中,岗位下面肯定是不能挂一个公司的。我们针对这种需求,是通过具体的代码逻辑来实现的,而没有办法在一个地方去统一定义这种规则。 i. 如果要实现这些逻辑的统一定义,可以参考“责任模式”!
权限管理模块
请描述一下你做的权限管理模块
描述思路:
1、 权限管理的基本需求
a) 系统后台有很多菜单项,同时各个页面上也有很多功能按钮,客户要求我们的系统
要能够控制这些菜单项的访问权限,也可以控制到具体每个功能按钮的访问权限 b) 客户要求建立角色的概念(参考RBAC),能够自由定制不同的角色,角色和用户
之间是多对多的。
c) 权限可以授予角色,然后把角色分配给用户,这样用户就拥有了角色的权限
d) 权限也可以授予某个部门、某个岗位,这样在这些部门或岗位下面的用户就拥有了
这些部门和岗位的权限
e) 客户还要求权限也能直接授予用户,这样即使拥有相同的角色、相同的部门、相同
的岗位,用户的权限也可以是不同的
f) 这样,用户自身被授予的权限、用户拥有的角色的权限、用户所属部门或岗位的权
限这些要素联合起来判断,才能最终决定用户的权限。
g) 因为用户的权限可能从多个角色或部门、岗位中继承下来,而这些角色、部门或岗
位的授权极有可能会有冲突,比如一个角色的授权是允许访问,而另外一个角色的授权是拒绝访问,客户要求,如果出现这种情况,就以拒绝为准,即不允许访问。
2、 权限管理的总体设计思路
a) 因为权限可以被授予用户、角色、部门、岗位等等,我们称之为权限控制的“主体”,
我们定义了一个接口Principal用来表示主体的概念,用户、角色、部门、岗位等均实现这个接口
b) 我们要控制菜单项以及各种功能按钮的访问,我们称这些菜单项和各种功能按钮为
权限控制的“资源”,定义了一个SysResource接口来表示资源的概念。
c) 菜单项是一种资源;而各种功能按钮最终其实是要访问后台的某个类的某个方法,
因此我们把Action类看成是一种资源(称为“操作资源”),各种功能按钮则对应了这个类里面的各种方法,我们把这些方法看成是这种资源的各种操作。
d) 我们定义了一个ACL用来表示哪些资源的哪些操作被授予了哪些主体,ACL中的
主要属性包括:主体类型(principalType)、主体ID(principalId)、资源类型(resourceType)、资源ID(resourceId)、操作状态(aclState),其中操作状态是int类型,在Java中,一个int有32位(bit),我们定义资源的时候,把这个资源对应的操作映射到某一位上,规定在这一位上取1表示允许执行那个操作,而取0表示不允许执行那个操作。
e) 这样,在授权的时候,我们直接改变相应操作的状态位的取值即可;在认证的时候,
直接判断相应操作状态位的取值
3、 权限管理的实现技巧
a) 在实现上,对于授权,我们界面上用jQuery和jQuery的插件jsTree来呈现菜单树,
在菜单树的前面显示一个CheckBox框,打勾表示允许,打叉表示拒绝;同时也做了一些右键点击显示上下文菜单,方便客户执行各种功能
b) jsTree没有打叉这种显示方式,为了满足我们的要求,所以对jsTree插件做了一些
扩展(主要是修改它的js文件和css文件、图片等),以便能支持更强大的显示方式。
c) 因为我们把系统中的各种Action类及其方法,看成是各种资源及其操作,为了方
便管理,我们利用Spring提供的API搜索具备某些特征的Action类及其方法(特定的命名及特定的注解),将这些信息插入数据库,这样便可以将其用于授权和认证。
d) 在认证的时候,我们实现了两种方式的认证:
i. 第一是根据授权,能够把没有授权的菜单项屏蔽,也能够把没有授权的功能按
钮屏蔽;
ii. 第二,因为第一种认证方式会有一些安全性问题,比如客户可以绕过功能按钮,
直接在浏览器输入某个功能的地址,为了避免这种问题,我们在后台也做了认证,根据当前请求的是哪个类的哪个方法,编写拦截器,判断当前登录用户是否具备这个权限,如果没有这个权限,就不允许执行这个操作!
e) InitService和XML
f) 自定义注解,利用Springde的API扫描类(大概说出一两个类名)
4、 我们这个设计的优点在哪里
a) 因为抽象出了主体和资源这两个概念,核心的授权和认证代码依赖于这两个概念,
而不是具体的哪个主体或资源。所以,能够更灵活的支持主体和资源的扩展,比如假设以后客户还想要给用户分组,按照分组来给用户授权,那么只需要实现一个新的主体类型即可,核心的授权和认证的代码无需变化。
b) 权限控制的粒度更细,因为我们用一个int来表示操作的允许状态,这就意味着,
我们能支持在某个资源上的至多32种操作,在设计上无需做变化。一个资源上的操作一般不会超过32种操作,一般来说也就是添加、更新、删除、查询,以及在这个基础上更加细分的一些操作而已,很少会超过32种操作。即使是极端情况,超过了32种操作,那么我们的核心设计也无需变动,无非就是把int换成一个long类型即可(支持64种操作)。
c) 我们还能支持细粒度的操作权限继承关系:
i. 比如针对“公司管理”这种资源,假设它有六种操作:添加公司信息、删除公
司信息、更新公司信息、查询公司信息、添加子公司、删除子公司;我们可以把这些权限授予比如“张三”这个用户。在授权的时候,我们可以细化到这种程度:
1. 明确规定:允许张三查询公司信息、更新公司信息
2. 明确规定:不允许张三添加公司信息、删除公司信息
3. 至于张三是否能执行添加子公司和删除子公司这些操作,我们可以不做明
确规定,而是由其所拥有的角色,或其所属的部门、岗位的权限来决定,
这称为“权限的继承关系”,针对这种需求,在ACL中,我们设计了一个
额外的属性:aclTriState,用来表示某种操作的权限是否是继承下来的。
5、 我们这个设计的缺点在哪里
a) 角色之间没有考虑父子关系,如果考虑父子关系的话,会更加便于授权,比如假设
有一个角色为“普通员工”,另外一个角色是“档案管理员”,如果把普通员工看成
是档案管理员的父角色,则意味着档案管理员这个角色的权限将可以继承普通员工中的权限(为什么没有实现这个设计呢,客户认为没有必要,因为系统中的角色数量比较少,如果这样设计的话,反而会增加客户操作的难度,无需过度设计) b) 我们还没有实现更细粒度的数据级的权限控制,比如,我们目前通过权限控制系统
无法实现如下需求:规定张三可以查看所有部门的员工信息,但只能对本部门的员工信息执行添加、删除和修改操作。没有实现的原因是:客户目前这方面的需求还不是很多,因此,没有必要在权限控制系统中实现。实现上述需求,我们是将这些逻辑写到了具体的代码中,而没有通过权限控制系统进行统一的定义。这也是大部分权限控制系统的实现策略。
工作流模块
请描述一下你做的工作流模块
描述思路:
1、 工作流模块的基本需求
a) 请描述
2、 工作流模块的总体设计思路
a) 把JBPM嵌入OA系统(如何实施的?具体过程?大概有哪些配置?)
b) 表单管理、流程管理、WorkEntity、WorkApprove、EntityProperty(动态表单)
3、 工作流模块的实现技巧
a) 引入jbpmeditor之后,对它做了一些定制开发(支持中文,动态表单的关联) b) 其它?
4、 我们这个设计的优点在哪里
a) 对JBPM的扩展
i. 自定义JBPM变量解释器
ii. 可以给角色、部门、岗位分配任务,抛弃了JBPM中简单的User-Group这种
组织结构模型,使用了OA中的组织结构模型
iii. 实现了自由流(如何实现的?)
iv. 利用自定义节点实现了会签的决策(如何实现的?)
b) 动态表单设计方案
5、 我们这个设计的缺点在哪里
a) 在流程定义的界面上,没有实现会签节点的定义
b) 在动态表单设计界面上,无法直接添加一些动态的组件(比如无法通过拖拽的方式
添加一个人员列表等等)
c) 没有实现流程的监控