用osworkflow写一个请假例子
osworkflow扩展非常容易,跟我们的应用结合起来使用也很容易。假设一个请假流程:员工请假,需要经过部门经理和人力资源部经理两人共同审批,只有当两人都许可时才通过,任一人驳回就失效,也就是一个and split和and Join流程,并且我们附加一个要求,当发送请假请求、许可和驳回这几个操作时都将发送一条消息给相应的用户。
流程定义文件如下:
<!DOCTYPE workflow PUBLIC "-//OpenSymphony Group//DTD OSWorkflow 2.7//EN"
"http://www.opensymphony.com/osworkflow/workflow_2_7.dtd">
<workflow>
<initial-actions>
<action id="0" name="开始">
<pre-functions>
<function type="class">
<arg name="class.name">
com.opensymphony.workflow.util.Caller
</arg>
</function>
</pre-functions>
<results>
<unconditional-result old-status="Finished"
status="Underway" step="1" owner="${caller}" />
</results>
</action>
</initial-actions>
<steps>
<step id="1" name="填假单">
<external-permissions>
<permission name="permA">
<restrict-to>
<conditions type="AND">
<condition type="class"><!--流程处于Underway状态(流程已经启动)-->
<arg name="class.name">
com.opensymphony.workflow.util.StatusCondition
</arg>
<arg name="status">Underway</arg>
</condition>
<condition type="class">
<arg name="class.name">
com.opensymphony.workflow.util.AllowOwnerOnlyCondition
</arg>
</condition>
</conditions>
</restrict-to>
</permission>
</external-permissions>
<actions>
<action id="1" name="送出">
<restrict-to>
<conditions type="AND">
<condition type="class"><!--流程处于Underway状态(流程已经启动)-->
<arg name="class.name">
com.opensymphony.workflow.util.StatusCondition
</arg>
<arg name="status">Underway</arg>
</condition>
<condition type="class">
<arg name="class.name">
com.opensymphony.workflow.util.AllowOwnerOnlyCondition
</arg>
</condition>
</conditions>
</restrict-to>
<pre-functions>
<function type="class">
<arg name="class.name">
com.opensymphony.workflow.util.Caller
</arg>
</function>
</pre-functions>
<results>
<unconditional-result old-status="Finished"
split="1" status="Queued">
<post-functions>
<function type="class">
<arg name="class.name">
net.rubyeye.leavesys.service.workflow.SendRemindInfFunction
</arg>
<arg name="groupName">
AND (GROUPNAME='dept_manager' or
GROUPNAME='comp_manager')
</arg>
<arg name="content">
you have leavemsg to
check!please check it!
</arg>
</function>
</post-functions>
</unconditional-result>
</results>
</action>
</actions>
</step>
<step id="2" name="部门经理批假单">
<actions>
<action id="2" name="准许">
<restrict-to>
<conditions>
<condition type="class">
<arg name="class.name">
com.opensymphony.workflow.util.OSUserGroupCondition
</arg>
<arg name="group">dept_manager</arg>
</condition>
</conditions>
</restrict-to>
<pre-functions>
<function type="class">
<arg name="class.name">
com.opensymphony.workflow.util.Caller
</arg>
</function>
<function type="beanshell">
<arg name="script">
propertySet.setString("action1",
"success");
</arg>
</function>
</pre-functions>
<results>
<unconditional-result old-status="Finished"
status="Queued" join="1" owner="${caller}" />
</results>
</action>
<action id="3" name="驳回">
<restrict-to>
<conditions>
<condition type="class">
<arg name="class.name">
com.opensymphony.workflow.util.OSUserGroupCondition
</arg>
<arg name="group">dept_manager</arg>
</condition>
</conditions>
</restrict-to>
<pre-functions>
<function type="class">
<arg name="class.name">
com.opensymphony.workflow.util.Caller
</arg>
</function>
<function type="beanshell">
<arg name="script">
propertySet.setString("action1",
"fail");
</arg>
</function>
</pre-functions>
<results>
<unconditional-result old-status="Finished"
status="Queued" join="2" owner="${caller}" />
</results>
</action>
</actions>
</step>
<step id="3" name="公司经理批假单">
<actions>
<action id="4" name="准许">
<restrict-to>
<conditions>
<condition type="class">
<arg name="class.name">
com.opensymphony.workflow.util.OSUserGroupCondition
</arg>
<arg name="group">comp_manager</arg>
</condition>
</conditions>
</restrict-to>
<pre-functions>
<function type="class">
<arg name="class.name">
com.opensymphony.workflow.util.Caller
</arg>
</function>
<function type="beanshell">
<arg name="script">
propertySet.setString("action2",
"success");
</arg>
</function>
</pre-functions>
<results>
<unconditional-result old-status="Finished"
status="Queued" join="1" owner="${caller}" />
</results>
</action>
<action id="5" name="驳回">
<restrict-to>
<conditions>
<condition type="class">
<arg name="class.name">
com.opensymphony.workflow.util.OSUserGroupCondition
</arg>
<arg name="group">dept_manager</arg>
</condition>
</conditions>
</restrict-to>
<pre-functions>
<function type="class">
<arg name="class.name">
com.opensymphony.workflow.util.Caller
</arg>
</function>
<function type="beanshell">
<arg name="script">
propertySet.setString("action2",
"fail");
</arg>
</function>
</pre-functions>
<results>
<unconditional-result old-status="Finished"
status="Queued" join="2" owner="${caller}" />
</results>
</action>
</actions>
</step>
<step id="4" name="停止" />
</steps>
<splits>
<split id="1">
<unconditional-result old-status="Finished" status="Queued"
step="2" />
<unconditional-result old-status="Finished" status="Queued"
step="3" />
</split>
</splits>
<joins>
<join id="1">
<conditions type="AND">
<condition type="beanshell">
<arg name="script">
<![CDATA[
"Finished".equals(jn.getStep(2).getStatus()) &&
"Finished".equals(jn.getStep(3).getStatus())&&"success".equals(propertySet.getString("action1"))&&
"success".equals(propertySet.getString("action2"))
]]>
</arg>
</condition>
</conditions>
<unconditional-result old-status="Finished" status="Queued"
step="4"/>
</join>
<join id="2">
<conditions type="OR">
<condition type="beanshell">
<arg name="script">
<![CDATA[
"Finished".equals(jn.getStep(2).getStatus()) &&"fail".equals(propertySet.getString("action1"))
]]>
</arg>
</condition>
<condition type="beanshell">
<arg name="script">
<![CDATA[
"Finished".equals(jn.getStep(3).getStatus())&&"fail".equals(propertySet.getString("action2"))
]]>
</arg>
</condition>
</conditions>
<unconditional-result old-status="Finished" step="4"
status="Queued">
<post-functions>
<function type="class">
<arg name="class.name">
net.rubyeye.leavesys.service.workflow.SendRemindInfFunction
</arg>
<arg name="groupName">
AND GROUPNAME='employee'
</arg>
<arg name="content">
you leveamsg is fail!!!
</arg>
</function>
</post-functions>
</unconditional-result>
</join>
</joins>
</workflow>
请注意,我们在许可或者通过的时候propertySet.setString("action2",......),propertySet.setString("action3",......),然后在join点判断,如果两个都是success,流程结束;如果一个是fail,就发送一个消息给员工。
发送消息的function像这样:
import java.sql.SQLException;
import java.util.Map;
import net.rubyeye.leavesys.domain.RemindInf;
import net.rubyeye.leavesys.service.ManagerFactory;
import com.opensymphony.module.propertyset.PropertySet;
import com.opensymphony.workflow.FunctionProvider;
import com.opensymphony.workflow.WorkflowException;
public class SendRemindInfFunction implements FunctionProvider {
public void execute(Map transientVars, Map args, PropertySet ps)
throws WorkflowException {
String groupName = (String) args.get("groupName");
String content = (String) args.get("content");
RemindInf remindInf = new RemindInf();
remindInf.setContent(content);
try {
ManagerFactory.getRemindService().addRemindInfByGroupName(
groupName, remindInf);
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
文章转自庄周梦蝶 ,原文发布时间5.17
得到两个参数groupName和content(消息内容),调用业务对象发送消息。
完整代码下载在《LeaveSystem》
代码用到了自己过去写的一个MVC框架和持久层,对此有兴趣的参考这三篇文章:
《设计自己的MVC框架》
《设计模式之事务处理》
《使用Annotation设计持久层》
如果仅仅是想了解osworkflow的应用,建议您跑下流程,读读相关几个业务类(LeaveServiceImpl.java,SendRemindInfFunction.java,service包下)即可。解压缩后的文件可以直接导入myeclipse工程,部署在tomcat下,数据库用的是oracle。跑起来以后可以用3个用户登录,test是雇员组,dennis是部门经理组,jordan是公司经理,都不需要密码。写的比较简单,只是实验性质,见谅。
我认为使用osworkflow,只要了解了它的表结构和主要原理,根据你的业务需要结合几张主要表(os_wfentry,os_currentstep,os_historystep等)合理设计数据库和业务流程,可以省去过去为每个业务流程对象创建的一大堆flag(标志,目前的流程状态)的累赘,充分利用工作流的威力。比如为部门经理和人力资源部经理显示不同的需要审批的假单列表,只要结合os_historystep表进行联合查询,部门经理的应该是执行了未执行acion2,step在3的;而人力资源部经理得到的同样是step在3,action未执行3的。
手痒痒,很想把去年为一家公司写的绩效考核系统改写一下,当时设计的一个contract对象拥有7,8个flag来标志合约状态(直接上级审核,人力资源评价,KPI评价等),搞的非常混乱,而且流程写死在代码里,如果以后要改变考核流程,只有重新写过一套。不过那家公司是国有企业,每年的固定的预算费用一定要花掉,反正大家一起赚国家的钱嘛。
用osworkflow写一个请假例子相关推荐
- 写一个饿汉单例模式的例子_你写的单例模式,能防止反序列化和反射吗?
推荐学习 "23种设计模式知识要点"都没读通过,还有脸说摸不清搞不懂? 玩转JAVA筑基之Netty.并发编程与设计模式,打好基础备战春招 前言 说起单例模式,相信大家都不会陌生. ...
- 如何写一个简单java接口的例子(内容详细,适合初学者)
这里说一个简单的java接口的小例子(一个接口类,两个实现类) 先新建一个动态web工程: 我的项目目录是这样子的(接口写完之后目录) 先在test0609_test1包下new 一个interfac ...
- 【微博SDK调用逻辑】微博SDK的调用逻辑,最好自己还是写一个例子,试一下!!!...
逻辑是这样的,谢谢给我讲东西的开发哥哥,嘻嘻~~~ 1.点击微博登录,SDK会打开微博客户端,然后点击登陆(如果已经登录了会出现一个当前app跟微博交互的图片界面,然后提示"正在获取授权信息 ...
- python 请假审批系统_菜鸟也要懂点设计模式|用Python设计一个请假模式
很多同学学Python一段时间了,但是总感觉自己的写代码不好维护,或者时间长了一旦增加需求或者需要扩展功能,发现自己写的代码就是一团糟!尽管也代码不断的重构了,好像也遵循了PEP8的风格,为啥代码量一 ...
- 一个请假单流程的实现(struts2.1.8+spring2.5+hibernate3集成jbpm4.3
先说明这个只是一个例子而已,简单的介绍了一些写法,你真的理解了以后完全可以写出比这个更好的代码来. 网上随便找了个请假的流程图,在此先谢谢提供图片的人: 使用jbpm工具画出流程图,中文好像是乱码,所 ...
- 大神教你如何给脚本写一个守护进程
在我们日常运维中,写脚本监控一个进程是比较常见的操作,比如我要监控mysql进程是否消失,如果消失就重启mysql. 用下面这段代码就可以实现: #!/bin/shDate=` date '+%c'` ...
- php日历如何写,如何写一个好看的实用的日历
本文发布在我的博客如何写一个日历组件 许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者.众所周知,虽然javascript中关于时间的API有不少,我们可以通过方法单独 ...
- 正则表达式限定长度_自己写一个通用的邮箱正则表达式
今天把正则又复习了一遍,为了加深记忆,自己写一个邮箱的正则表达式 咱们先来看几个合法的邮箱地址 hd33322@nat123.com maksim.kim.82@d-link.ua vova_laza ...
- SAP MM采购定价过程的一个简单例子
SAP MM采购定价过程的一个简单例子 本文以一个简单的例子阐述了SAP MM模块中采购定价的基本原理.本例中,假定采购订单里输入的是含税采购价,然后系统自动计算出物料最终的采购价格(含税价-税额=采 ...
最新文章
- mysql字符串相加函数concat()
- hashMap死循环
- 【Android 插件化】Hook 插件化框架 ( Hook 实现思路 | Hook 按钮点击事件 )
- 在Windows操作系统下,由操作系统分配的内存就叫做堆
- 3.3.1网络原理数据链路层之差错控制(检错编码和纠错编码)-(奇偶校验码、CRC循环冗余码、海明码)
- c语言怎么在win7上运行,C语言做的中国象棋,分享,问怎么在WIN7下运行
- java学习(117):list迭代器和包含方法
- 分组数据方差公式_连续变量假设检验 之 单因素方差检验
- ajax跨域,json,jsonp
- Canvas递归画一棵树
- 神剑轩辕java,上古十大神剑有哪些 有一把居然是专门用来弑君杀父的
- 【java】JavaFX从零开始实现拼图小游戏
- webpack-dev-server的代理(proxy)
- 小白终是踏上了这条不归路----小文的mysql学习笔记(6)----连接查询-----等值连接、非等值连接、自链接、外连接、交叉连接
- 485、CAN、单总线、SPI、I2C的概念,特点,协议,使用方法及通信方式,还有它们之间的区别
- 楼层部分的计算机术语大全,计算机术语(大全)
- Collection的概念
- 什么是边缘节点服务?
- 电脑版微信防撤回怎么设置?
- 破解mifare Classic(M1)非接触式射频IC卡--Mifare crack Hack 笔记一