- 浏览: 117763 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
lufazhi:
楼主,是否可以将源码分享,谢谢,小弟初次接触nutz不太理解, ...
基于Nutz与ExtJs的快速开发 -
qazxcdews:
jbpm不是使用hibernate吗?你是怎么将Nutz与jb ...
ExtJS+Nutz+JBPM实现一个简单的请假流程 -
kk63643813:
代码很经典,楼主你很强,代码思路也很好,求源码,谢谢17146 ...
使用Nutz+ExtJS+JBPM4.4实现会签 -
qinboss:
...
jbpm4表结构(1) -
han0917:
hello,我想问下我使用XBlink序列化对象为xml的时候 ...
最近的一点计划
会签的例子依然采用Nutz+ExtJS+JBPM来实现。
这里只讲讲会签的实现,其他细节可以参考这篇文章http://pangwu86.iteye.com/blog/1114082
#######################邪恶的分割线#######################
首先介绍下什么是会签
会签
会签是撰拟公文的过程中,主办单位主动与有关单位协商并核签的一种办文程序,一般当公文的内容涉及本单位的多个部门或与其他单位有关时,需要进行会签。会签根据对象的不同分为内部会签和外部会签。内部会签用于与本单位内部的各有关部门进行协商并核签;外部会签用于与外单位的有关部门进行协商并核签;二者的性质相同,但处理形式不同。
在管理系统中的会签流程,例如公司职员离职、大学生毕业离校都要在不同的部门去签字确认,这里去哪个部门签字没有顺序之分,但所有部门签字完毕后才可以离职或离校。
会签的情况会有很多中,根据复杂程度,一般可以分为单步会签(只有一个活动处理会签任务),以及多步会签(由多个任务组成的)
这里只介绍下常见的,也是业务中最常遇到的单步会签。
单步会签常见有4种情况:
- 一票否决制——参加会签的用户中任何一个人不同意,会签活动就会结束,进去会签否决,全部同意,则进入会签通过
- 一票通过制——与一票否决完全相反
- 按比例通过——等全部参加会签的用户提交任务后,根据会签意见,按照比例(比如少数服从多数)决定下面的转移
- 意见收集制——等全部参加会签的用户提交完意见后(这里就是一个收集意见的作用而已),会签结束,进入下一个节点
这里要说一下,在查找会签的资料时,yy269兄的http://yy629.iteye.com/blog/660701与phoenix.clt兄的http://phoenix-clt.iteye.com/blog/428242这两篇文章给了很大的启发,后面的实现也借鉴了他们的一些好的思想,需要的朋友可以去看一看。
下面的部分将会讲述如何实现一个动态会签(会签人数,人员,会签规则都可以自由设定)
好,接下来看一下今天举得这个申请经费的例子:
贴一下jpdl.xml文件
<?xml version="1.0" encoding="UTF-8"?> <process name="jingfeishenqing" xmlns="http://jbpm.org/4.4/jpdl"> <description><![CDATA[ 经费申请,大于30万需要老总们会签(采用一票否决制) ]]></description> <!-- 会签决策实现类 --> <variable name="calc.countersignCalculatorImpl" type="string"> <string value="org.nutz.jbpm.countersign.impl.AllAgreeSign" /> </variable> <!-- 以下三个参数只有按百分比策略才会用到,可以根据需要来设定 --> <!-- 最小同意数 --> <variable name="calc.minAgreeSize" type="int"> <int value="2"/> </variable> <!-- 最小同意比例(请设定一个在0-1之间的数字) --> <variable name="calc.minAgreePercent" type="float"> <float value="0.6"/> </variable> <!-- 是否使用按比例(true为按照比例,false为按照人数) --> <variable name="calc.userPercent" type="boolean"> <false/> </variable> <start g="81,8,48,48" name="start1"> <transition g="-60,13" name="申请经费" to="申请经费" /> </start> <task assignee="${employee}" form="countersign/applyfor.jsp" g="304,65,92,52" name="申请经费"> <transition name="金额判断" to="判断1" g="-69,-22" /> </task> <decision expr="#{money > 300000 ? '大于30万' : '小于等于30万'}" g="190,144,48,48" name="判断1"> <transition g="-39,14" name="大于30万" to="领导会签" /> <transition g="-80,-21" name="小于等于30万" to="财务部拨款" /> </decision> <task form="countersign/countersign.jsp" g="302,183,92,52" name="领导会签"> <assignment-handler class="org.nutz.jbpm.countersign.CountersignAssignment"> </assignment-handler> <transition g="-79,-11" name="会签结果判断" to="会签判断" /> </task> <decision expr="#{agree == true ? '同意' : '不同意'}" g="325,293,48,48" name="会签判断"> <transition g="-13,-26" name="同意" to="财务部拨款" /> <transition g="-50,-22" name="不同意" to="申请驳回" /> </decision> <task g="68,291,92,52" name="财务部拨款"> <transition g="-33,-10" name="拨款" to="拨款完毕" /> </task> <end g="91,400,48,48" name="拨款完毕" /> <end g="327,398,48,48" name="申请驳回" /> </process>
可以说会签的难点就是如何在一个任务中,实现由多个人去完成。
JBPM4中提供了建立子任务的API,这一点就提供了一个思路.
那就是在进入这个任务后,给相应的会签人员建立对应的子任务,然后等待他们完成子任务后,该会签任务设定为完成,流程向下流转。
下面这段配置就是会签任务,可以看到,与普通task不同的是,添加一个assignment-handler属性,同时指定了一个java类
<task form="countersign/countersign.jsp" g="302,183,92,52" name="领导会签"> <assignment-handler class="org.nutz.jbpm.countersign.CountersignAssignment"> </assignment-handler> <transition g="-79,-11" name="会签结果判断" to="会签判断" /> </task>
这里的作用就是,在流程进入到这个节点时,会执行你指定的这个类
这个类的要求是,实现AssignmentHandler接口
public class CountersignAssignment implements AssignmentHandler
查看这个接口,会发现需呀实现一个assign方法
/** interface to delegate {@link Task} or {@link Swimlane} assignment. * * @author Tom Baeyens */ public interface AssignmentHandler extends Serializable { /** sets the actorId and candidates for the given task. */ void assign(Assignable assignable, OpenExecution execution) throws Exception; }
下面给出ME的一个实现:
public class CountersignAssignment implements AssignmentHandler { public void assign(Assignable assignable, OpenExecution execution) throws Exception { // 获得实例ID String pid = execution.getProcessInstance().getId(); // 获得当前的主任务 Task task = JbpmUtil.taskService.createTaskQuery().processInstanceId(pid) .activityName(execution.getName()).uniqueResult(); // 创建子任务 createSubTasks(task); // 获得会签决策(通过jpdl配置文件中配置的属性) String className = (String) JbpmUtil.taskService.getVariable(task.getId(), "calc.countersignCalculatorImpl"); // 通过会签决策工厂生产获得决策对象 CountersignCalculator calculator = CountersignCalculatorFactory .makeCountersignCalculator(className); // 如果是按比例通过的话,需要设定通过人数,或者比例 SetCalculatorVars(calculator, task.getId()); // TODO 这里用户采用一个模拟的方式,以后可以通过要整合的系统提供的API 获得用户名字列表 CountersignInfo countersignInfo = CountersignInfoFactory.makeCountersignInfo(getUsers(), calculator); // 记录当前的主任务与会签信息 Map<String, Object> vars = new HashMap<String, Object>(); vars.put("parentTaskId", task.getId()); vars.put("countersignInfo", countersignInfo); JbpmUtil.taskService.setVariables(task.getId(), vars); return; } private void SetCalculatorVars(CountersignCalculator calculator, String taskId) { // 只有按比例会签决策需要设定参数 if (calculator instanceof PercentAgreeSign) { // 获取参数 Object minAgreeSize = JbpmUtil.taskService.getVariable(taskId, "calc.minAgreeSize"); Object minAgreePercent = JbpmUtil.taskService.getVariable(taskId, "calc.minAgreePercent"); Object userPercent = JbpmUtil.taskService.getVariable(taskId, "calc.userPercent"); // 设定参数 PercentAgreeSign calc = (PercentAgreeSign) calculator; if (null != minAgreeSize) { calc.setMinAgreeSize((Integer) minAgreeSize); } if (null != minAgreePercent) { calc.setMinAgreePrecent((Float) minAgreePercent); } if (null != userPercent) { calc.setUserPercent((Boolean) userPercent); } } } private void createSubTasks(Task task) { // OpenTask才有createSubTask方法,Task接口是没有的 OpenTask oTask = (OpenTask) task; // 这个对象非常重要,没有它,通过子任务无法跟主任务获得联系 Execution execution = JbpmUtil.executionService.findExecutionById(task.getExecutionId()); // 获得所有的参与者 for (String assignee : getUsers()) { TaskImpl subTask = (TaskImpl) oTask.createSubTask(); subTask.setAssignee(assignee); subTask.setName(task.getName()); subTask.setFormResourceName(task.getFormResourceName()); // 这句话是关键 只有设定同样的实例 子任务才能获得主任务设定的变量 subTask.setExecution((ExecutionImpl) execution); JbpmUtil.taskService.addTaskParticipatingUser(task.getId(), assignee, Participation.CLIENT); } } private List<String> getUsers() { return CountersignAction.users; } }
代码中注释解释的很详细了,这里就不再复述了,这段代码相关参数,可以参照上面的jpdl.xml中的变量设置。
下面介绍下上面代码中的CountersignInfo类与CountersignCalculator类
CountersignInfo
/** * 会签信息 * */ public interface CountersignInfo extends Serializable { /** * 用户下达会签结论 * * @param user * @param conclusion * @return */ public boolean sign(String user, Conclusion conclusion); /** * 获取会签人员列表 * * @return */ public List<String> getUsers(); /** * 获取会签会议结论 * * @return */ public Conclusion getConclusion(); /** * 是否全部人员都已签完 * * @return */ public boolean isAllSigned(); /** * 获取特定用户的会签结论 * * @param userId * @return */ public Conclusion getUserConclusion(String userId); /** * 获取所有用户的会签结论 * * @return */ public Map<String, Conclusion> getConclusions(); /** * 获取会签结论计算方式 * * @return */ public CountersignCalculator getConclusionCalculator(); }
可以通过这个API获得当前会签的所有相关信息。
CountersignCalculator
/** * 会签决策 * */ public interface CountersignCalculator extends Serializable { /** * 计算会签结果 * * @param info * @return */ public Conclusion calculate(CountersignInfo info); }
这里就只有一个方法,就是通过会签信息,计算出当前的会签结果,这个接口的实现类,你就可以在里面根据业务来进行实现,比如说实现上面提到的单步会签的常见的四种情况(后面会给出实现类)。
还有一个会签结果的枚举类,这个可以根据你的需要自己定制,这里给出ME的方案
Conclusion
/** * 会议结论定义 * */ public enum Conclusion implements Serializable { // 通过 AGREE, // 否决 DENY, // 弃权 ABSTAIN, // 继续(会签没有结束) CONTINUE; public static Conclusion getConclusion(String conclusion) { if (AGREE.toString().equals(conclusion)) { return Conclusion.AGREE; } else if (DENY.toString().equals(conclusion)) { return Conclusion.DENY; } else if (ABSTAIN.toString().equals(conclusion)) { return Conclusion.ABSTAIN; } else if (CONTINUE.toString().equals(conclusion)) { return Conclusion.CONTINUE; } return Conclusion.AGREE; } }
下面给出几个实现类,给大家做个参考:
首先是会签决策实现类:
一票否决制
/** * 一票否决制(全票通过制) * */ public class AllAgreeSign implements CountersignCalculator { public Conclusion calculate(CountersignInfo info) { // 是否有否决票 for (Entry<String, Conclusion> entry : info.getConclusions().entrySet()) { if (entry.getValue() == Conclusion.DENY) { // 一旦出现否决票,立刻作为否决处理 return Conclusion.DENY; } } if (info.isAllSigned()) { // 所有票投完了 return Conclusion.AGREE; } return Conclusion.CONTINUE; } public String toString() { return "采用一票否决制,只要有一票否决,则会签不通过。"; } }
同理大家可以如法炮制一票通过制。
至于按比例,按人数是如何实现的,这里就不给出例子了,留给大家留一个思考的空间。
下面是会签信息的实现类:
默认会签信息实现
public class CountersignInfoDefaultImpl implements CountersignInfo { private List<String> users; private boolean isAllSigned = false; private Map<String, Conclusion> results = new HashMap<String, Conclusion>(); private CountersignCalculator countersignCalculator; public CountersignInfoDefaultImpl(List<String> users, CountersignCalculator countersignCalculator) { this.users = users; this.countersignCalculator = countersignCalculator; } /** * 用户提交决策 * * @param user * @param conclusion * @return */ public synchronized boolean sign(String user, Conclusion conclusion) { if (!users.contains(user)) { return false; } results.put(user, conclusion); if (results.size() == users.size()) { isAllSigned = true; } return true; } // *********接口实现*********** public List<String> getUsers() { // 不允许修改 return Collections.unmodifiableList(users); } public Conclusion getConclusion() { return countersignCalculator.calculate(this); } public boolean isAllSigned() { return isAllSigned; } public Conclusion getUserConclusion(String userId) { return results.get(userId); } public Map<String, Conclusion> getConclusions() { return Collections.unmodifiableMap(results); } public CountersignCalculator getConclusionCalculator() { return countersignCalculator; } }
最后说一下,在会签时,要做的一些处理,这里只给思路,源码就不放了。
- 根据当前任务(子任务)获得主任务
- 调用CountersignInfo的sign方法,进行会签,然后完成子任务。
- 调用CountersignInfo.getConclusion方法,判断是否会签结束
- 如果会签结束,完成主任务,流程继续向下流转
评论
恩,没明白你想问什么问题
我参考了你的代码,之后在子流程提交这块我想获得一个监听提交的时候始终是失败的.
由于缺少完整代码,对于刚开始写会签的代码比较困难。谢谢
我的邮箱是lwei20000@163.com
上面的代码看了,但是一些个工厂类,工具类啥的没有,所以看不太清。
恩,没明白你想问什么问题
请看4楼
还有LZ在CountersignAssignment类中
private List<String> getUsers() { return CountersignAction.users; }的CountersignAction是怎么得到的
希望解惑,非常感谢!
这里的getUsers()方法的意思是你可以根据你的系统特点,通过各种方式,拿到这个用户列表就好了
CountersignAction.users 实际上就是ME在CountersignAction这个类中定义的一个String列表
例如 List<String> users = new ArrayList<String>{'user1','user2'};
还有LZ在CountersignAssignment类中
private List<String> getUsers() { return CountersignAction.users; }的CountersignAction是怎么得到的
希望解惑,非常感谢!
发表评论
-
MySQL关于Timestamp类型的一个要注意的地方
2011-11-02 19:18 1870使用Nutz提供的建表功能。 测试类: @Tab ... -
JBPM4注意事项
2011-07-04 17:35 1435学习过程中遇到的几个问题,记录一下 常见错 ... -
ExtJS+Nutz+JBPM实现一个简单的请假流程
2011-07-04 16:26 10170学习了一段时间的JBPM工作流,根据网上一个很常见的请假的例子 ... -
jbpm4表结构(2)
2011-06-28 12:03 1390流程历史数据表 JBPM4_HIST_ACT ... -
jbpm4表结构(1)
2011-06-28 11:57 3222了解JBPM是如何运作的,还是要从表结构下手,真正 ... -
基于Nutz与ExtJs的快速开发
2011-06-11 16:01 5159这里对Nutz与ExtJs都进行二次封装,使前后台代码尽可能的 ... -
Nutz+ExtJS示例教程——后台Service实现
2011-02-20 16:56 4648后台的结构图如下: 这里 ... -
Nutz+ExtJS示例教程——数据库设计
2011-02-19 19:15 2064因为这里只是个简单的Demo,所以设计上就简单点了。 ... -
Nutz+ExtJS示例教程——搭建开发环境
2011-02-14 13:28 4845这里介绍下,开发环境 ... -
Nutz+ExtJS示例教程——预告篇
2011-01-08 00:21 7553最近一直在新项目,决定采用全新的架构 ...
相关推荐
**Nutz+ExtJS示例教程——后台Service实现** Nutz和ExtJS是两种不同的技术栈,它们在Web开发中有着各自的应用。Nutz是一款基于Java的轻量级框架,它提供了全面的Web开发解决方案,包括ORM、AOP、IOC等。而ExtJS则是...
在本项目中,"企业级应用项目,springmvc+nutz+redis+rabbitmq+quartz+shiro",开发者采用了一系列高级技术构建了一个具备高可扩展性和低耦合度的系统,旨在提供一个适用于有一定Java基础的学习者进行实践和进阶的...
标题中的“国内技术强强联手之Nutz+KindEditor+LHGDialog+My97DatePicker”揭示了四个关键的IT技术组件,它们在中国的技术社区中被广泛使用,并且经常一起集成到项目中以提供强大的功能。现在,我们将深入探讨这些...
4. **Nutz与ExtJs的整合**:讲解如何将Nutz作为后台服务,与ExtJs前端进行有效地通信,实现数据的动态加载和界面的实时更新。 5. **实战案例**:可能包含一些实际项目中的应用场景,如创建一个CRUD(创建、读取、...
在本项目中,`dao层`的实现将基于Nutz,通过其提供的注解和API来实现对数据库的操作,如增删改查等。 再来看Beetl,这是一款高性能的Java模板引擎,它的设计目标是提高开发效率,减少模板代码。Beetl语法简洁,支持...
【basecms(nutz+easyui)】是一款基于Nutz框架和EasyUI前端库构建的CMS(内容管理系统)项目。此系统充分利用了EasyUI的组件化特性,为用户提供了一个直观、简洁且功能丰富的管理界面,而Nutz作为后端开发框架,确保...
每次项目验收写文档是一个很凌乱的事情,作为一个程序员,应该是用技术解决问题。当然有很多工具也可以实现。比如PDman就可以导出word或者pdf文档。 这个案例主要是学习springboot...以及使用nutz poi第三方工具的使用
SpringMVC+Nutz框架介绍.docxSpringMVC+Nutz框架介绍.docxSpringMVC+Nutz框架介绍.docxSpringMVC+Nutz框架介绍.docxSpringMVC+Nutz框架介绍.docxSpringMVC+Nutz框架介绍.docxSpringMVC+Nutz框架介绍.docxSpringMVC+...
SpringMVC+Nutz框架介绍.pdfSpringMVC+Nutz框架介绍.pdfSpringMVC+Nutz框架介绍.pdfSpringMVC+Nutz框架介绍.pdfSpringMVC+Nutz框架介绍.pdfSpringMVC+Nutz框架介绍.pdfSpringMVC+Nutz框架介绍.pdfSpringMVC+Nutz框架...
可以自动生成数据库脚本,生成代码项目,数据库文档生成
在Nutz+jCasbin的环境中,你可以根据业务需求定义各种条件,如用户属性、时间、地点等,来决定用户是否能执行特定操作,增强了权限控制的灵活性和适应性。 3. **策略定义**:jCasbin使用一种声明式的策略语言,称为...
NutzWk 2.0.x 试验版(不建议使用) NutzWk 1.0.x 传统版(velocity 支持IE6) 注:_velocity后缀为同时支持beetl和velocity两种模板引擎版本 QQ交流群: 68428921 在线演示地址 ====== 基于Nutz的开源企业级开发...
7. **使用Nutz Redis API**:集成完成后,就可以在代码中使用Nutz Redis提供的API进行数据操作,例如: ```java import org.nutz.dao.Dao; import org.nutz.integration.jedis.JedisHolder; public class ...
### Nutz 使用手册知识点概述 #### 一、Nutz 框架简介 - **背景与定位**:Nutz 是一款旨在提高 Java Web 开发效率的轻量级框架集。随着脚本语言在 Web 开发领域的兴起,Java 开发者面临开发效率低下等问题。Nutz ...
在"nutz框架使用手册.zip"中,我们可以预期找到关于Nutz框架全面的学习资源,从基础概念到高级用法,帮助开发者从零开始掌握Nutz平台的开发技能。手册可能包含以下主要知识点: 1. **Nutz IOC**:Nutz IOC是Nutz...
DAO接口则包含了如`selectById`、`insert`、`updateById`、`deleteById`等常见操作,这些方法的实现是基于Nutz的Ioc(依赖注入)和Aop(面向切面编程)功能,使得代码简洁而高效。 Nutz Codematic的压缩包文件"**...
《ztree与nutz在实际应用中的简单使用详解》 在IT行业中,高效地管理和操作数据是至关重要的。zTree和Nutz都是在这方面提供强大支持的工具。zTree是一款基于JavaScript的灵活、强大的树状菜单插件,而Nutz则是一个...
在本教程中,我们将深入探讨如何使用Nutz 1.b.38版本进行数据库表的CRUD操作。 首先,Nutz的核心组件Nutz DAO(Data Access Object)提供了与数据库交互的能力。通过简单的API,开发者可以轻松地实现对数据库的读写...