??? osworkflow扩展非常容易,跟我们的应用结合起来使用也很容易。假设一个请假流程:员工请假,需要经过部门经理和人力资源部经理两人共同审批,只有当两人都许可时才通过,任一人驳回就失效,也就是一个Or Split和Or Join的流程,并且我们附加一个要求,当发送请假请求、许可和驳回这几个操作时都将发送一条消息给相应的用户。
??? 流程定义文件如下:
<?xml?version="1.0"?encoding="UTF-8"??>
<!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像这样:
package?net.rubyeye.leavesys.service.workflow;
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();
????????}
????}
}
得到两个参数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评价等),搞的非常混乱,而且流程写死在代码里,如果以后要改变考核流程,只有重新写过一套。不过那家公司是国有企业,每年的固定的预算费用一定要花掉,反正大家一起赚国家的钱嘛。
posted on 2007-03-02 16:07
dennis 阅读(244)
评论(3) 编辑 收藏 引用 所属分类:
java 、
工作流