用osworkflow寫一個(gè)請(qǐng)假例子
Posted on 2007-03-02 16:07 dennis 閱讀(12308) 評(píng)論(26) 編輯 收藏 所屬分類: java 、工作流update:這個(gè)例子是不當(dāng)?shù)?,更合適的例子請(qǐng)自己上javaeye上搜索個(gè)帖子。源碼俺早就丟了,請(qǐng)不要再發(fā)郵件給我,謝謝。
osworkflow擴(kuò)展非常容易,跟我們的應(yīng)用結(jié)合起來使用也很容易。假設(shè)一個(gè)請(qǐng)假流程:?jiǎn)T工請(qǐng)假,需要經(jīng)過部門經(jīng)理和人力資源部經(jīng)理兩人共同審批,只有當(dāng)兩人都許可時(shí)才通過,任一人駁回就失效,也就是一個(gè)and split和and Join流程,并且我們附加一個(gè)要求,當(dāng)發(fā)送請(qǐng)假請(qǐng)求、許可和駁回這幾個(gè)操作時(shí)都將發(fā)送一條消息給相應(yīng)的用戶。
流程定義文件如下:
請(qǐng)注意,我們?cè)谠S可或者通過的時(shí)候propertySet.setString("action2",......),propertySet.setString("action3",......),然后在join點(diǎn)判斷,如果兩個(gè)都是success,流程結(jié)束;如果一個(gè)是fail,就發(fā)送一個(gè)消息給員工。
發(fā)送消息的function像這樣:
得到兩個(gè)參數(shù)groupName和content(消息內(nèi)容),調(diào)用業(yè)務(wù)對(duì)象發(fā)送消息。
完整代碼下載在《LeaveSystem》
代碼用到了自己過去寫的一個(gè)MVC框架和持久層,對(duì)此有興趣的參考這三篇文章:
《設(shè)計(jì)自己的MVC框架》
《設(shè)計(jì)模式之事務(wù)處理》
《使用Annotation設(shè)計(jì)持久層》
如果僅僅是想了解osworkflow的應(yīng)用,建議您跑下流程,讀讀相關(guān)幾個(gè)業(yè)務(wù)類(LeaveServiceImpl.java,SendRemindInfFunction.java,service包下)即可。解壓縮后的文件可以直接導(dǎo)入myeclipse工程,部署在tomcat下,數(shù)據(jù)庫(kù)用的是oracle。跑起來以后可以用3個(gè)用戶登錄,test是雇員組,dennis是部門經(jīng)理組,jordan是公司經(jīng)理,都不需要密碼。寫的比較簡(jiǎn)單,只是實(shí)驗(yàn)性質(zhì),見諒。
我認(rèn)為使用osworkflow,只要了解了它的表結(jié)構(gòu)和主要原理,根據(jù)你的業(yè)務(wù)需要結(jié)合幾張主要表(os_wfentry,os_currentstep,os_historystep等)合理設(shè)計(jì)數(shù)據(jù)庫(kù)和業(yè)務(wù)流程,可以省去過去為每個(gè)業(yè)務(wù)流程對(duì)象創(chuàng)建的一大堆flag(標(biāo)志,目前的流程狀態(tài))的累贅,充分利用工作流的威力。比如為部門經(jīng)理和人力資源部經(jīng)理顯示不同的需要審批的假單列表,只要結(jié)合os_historystep表進(jìn)行聯(lián)合查詢,部門經(jīng)理的應(yīng)該是執(zhí)行了未執(zhí)行acion2,step在3的;而人力資源部經(jīng)理得到的同樣是step在3,action未執(zhí)行3的。
手癢癢,很想把去年為一家公司寫的績(jī)效考核系統(tǒng)改寫一下,當(dāng)時(shí)設(shè)計(jì)的一個(gè)contract對(duì)象擁有7,8個(gè)flag來標(biāo)志合約狀態(tài)(直接上級(jí)審核,人力資源評(píng)價(jià),KPI評(píng)價(jià)等),搞的非?;靵y,而且流程寫死在代碼里,如果以后要改變考核流程,只有重新寫過一套。不過那家公司是國(guó)有企業(yè),每年的固定的預(yù)算費(fèi)用一定要花掉,反正大家一起賺國(guó)家的錢嘛。
osworkflow擴(kuò)展非常容易,跟我們的應(yīng)用結(jié)合起來使用也很容易。假設(shè)一個(gè)請(qǐng)假流程:?jiǎn)T工請(qǐng)假,需要經(jīng)過部門經(jīng)理和人力資源部經(jīng)理兩人共同審批,只有當(dāng)兩人都許可時(shí)才通過,任一人駁回就失效,也就是一個(gè)and split和and Join流程,并且我們附加一個(gè)要求,當(dāng)發(fā)送請(qǐng)假請(qǐng)求、許可和駁回這幾個(gè)操作時(shí)都將發(fā)送一條消息給相應(yīng)的用戶。
流程定義文件如下:
<?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狀態(tài)(流程已經(jīng)啟動(dòng))-->
<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狀態(tài)(流程已經(jīng)啟動(dòng))-->
<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="部門經(jīng)理批假單">
<actions>
<action id="2" name="準(zhǔn)許">
<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="公司經(jīng)理批假單">
<actions>
<action id="4" name="準(zhǔn)許">
<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>
<!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狀態(tài)(流程已經(jīng)啟動(dòng))-->
<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狀態(tài)(流程已經(jīng)啟動(dòng))-->
<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="部門經(jīng)理批假單">
<actions>
<action id="2" name="準(zhǔn)許">
<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="公司經(jīng)理批假單">
<actions>
<action id="4" name="準(zhǔn)許">
<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>
請(qǐng)注意,我們?cè)谠S可或者通過的時(shí)候propertySet.setString("action2",......),propertySet.setString("action3",......),然后在join點(diǎn)判斷,如果兩個(gè)都是success,流程結(jié)束;如果一個(gè)是fail,就發(fā)送一個(gè)消息給員工。
發(fā)送消息的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();
}
}
}
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();
}
}
}
得到兩個(gè)參數(shù)groupName和content(消息內(nèi)容),調(diào)用業(yè)務(wù)對(duì)象發(fā)送消息。
完整代碼下載在《LeaveSystem》
代碼用到了自己過去寫的一個(gè)MVC框架和持久層,對(duì)此有興趣的參考這三篇文章:
《設(shè)計(jì)自己的MVC框架》
《設(shè)計(jì)模式之事務(wù)處理》
《使用Annotation設(shè)計(jì)持久層》
如果僅僅是想了解osworkflow的應(yīng)用,建議您跑下流程,讀讀相關(guān)幾個(gè)業(yè)務(wù)類(LeaveServiceImpl.java,SendRemindInfFunction.java,service包下)即可。解壓縮后的文件可以直接導(dǎo)入myeclipse工程,部署在tomcat下,數(shù)據(jù)庫(kù)用的是oracle。跑起來以后可以用3個(gè)用戶登錄,test是雇員組,dennis是部門經(jīng)理組,jordan是公司經(jīng)理,都不需要密碼。寫的比較簡(jiǎn)單,只是實(shí)驗(yàn)性質(zhì),見諒。
我認(rèn)為使用osworkflow,只要了解了它的表結(jié)構(gòu)和主要原理,根據(jù)你的業(yè)務(wù)需要結(jié)合幾張主要表(os_wfentry,os_currentstep,os_historystep等)合理設(shè)計(jì)數(shù)據(jù)庫(kù)和業(yè)務(wù)流程,可以省去過去為每個(gè)業(yè)務(wù)流程對(duì)象創(chuàng)建的一大堆flag(標(biāo)志,目前的流程狀態(tài))的累贅,充分利用工作流的威力。比如為部門經(jīng)理和人力資源部經(jīng)理顯示不同的需要審批的假單列表,只要結(jié)合os_historystep表進(jìn)行聯(lián)合查詢,部門經(jīng)理的應(yīng)該是執(zhí)行了未執(zhí)行acion2,step在3的;而人力資源部經(jīng)理得到的同樣是step在3,action未執(zhí)行3的。
手癢癢,很想把去年為一家公司寫的績(jī)效考核系統(tǒng)改寫一下,當(dāng)時(shí)設(shè)計(jì)的一個(gè)contract對(duì)象擁有7,8個(gè)flag來標(biāo)志合約狀態(tài)(直接上級(jí)審核,人力資源評(píng)價(jià),KPI評(píng)價(jià)等),搞的非?;靵y,而且流程寫死在代碼里,如果以后要改變考核流程,只有重新寫過一套。不過那家公司是國(guó)有企業(yè),每年的固定的預(yù)算費(fèi)用一定要花掉,反正大家一起賺國(guó)家的錢嘛。