osworkflow的使用

OSWorkflow是一个Java开源的工作流,使用Apache许可。OSWorkflow的最大特点是灵活,它所面向的使用对象是专业开发人员,如果最终用户想调整工作流,那是不太现实的。OSWorkflow的流程定义使用自己的xml格式,不遵守XPDL规范。
    在 http://www.opensymphony.com/osworkflow/下载OSWorkflow,本文使用的是2.8版本的。
1持久化
    安装包里有一个工作流示例,把osworkflow-2.8.0-example.war放到tomcat的webapps下面直接就可以看到效果了。但示例程序并没有对数据进行持久化,重启tomcat后数据就丢失了。OSWorkflow支持多种主流数据库,以下以mysql数据库为例,讲述如何把OSWorkflow的示例程序产生的数据保存到mysql数据库。
    1、在mysql数据库中执行建表脚本。
    在mysql数据库中建立一个数据库,如osworkflow,执行下载包中的src/etc/deployment/jdbc/mysql.sql,建立OSWorkflow所需要的数据库表。
    2、在应用的context中建立数据源。
    把mysql的jdbc驱动包放到tomcat的lib下面,建立一个数据源,代码如下:
auth="Container" 
type="javax.sql.DataSource" 
driverClassName="com.mysql.jdbc.Driver" 
url="jdbc:mysql://localhost:3306/osworkflow" 
username="root" 
password="" 
maxActive="10" 
maxIdle="5" 
maxWait="10000" />
    3、修改WEB-INF/classes下的配置文件。
    修改osuser.xml文件,修改后的文件内容如下:
 

     
     
        
         os_user 
         os_group 
         os_membership 
         username 
         passwordhash 
         groupname 
         username 
         groupname 
         jdbc/osworkflow 
        
        
         os_user 
         os_group 
         os_membership 
         username 
         passwordhash 
         groupname 
         username 
         groupname 
         jdbc/osworkflow 
        
        
         os_user 
         os_group 
         os_membership 
         username 
         passwordhash 
         groupname 
         username 
         groupname 
         jdbc/osworkflow 
        
     
     
     
     
    修改osworkflow.xml文件,修改后的文件内容如下:
 
     
     
   
     

          
     
     
     
     
                 select 1 as tb,  count(*)  as c1  
            from os_currentstep union  
            select 2 as tb, count(*) as c1 from os_historystep) as TabelaFinal"/> 
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
   

     
         
     
    增加文件propertyset.xml,内容如下:
 
    
     
     
         
         
         
         
         
         
         
         
         
         
         
     
    运行tomcat,对示例程序进行操作,就可以在mysql中看到数据了。OSWorkflow比较简单,也就用了10来个表,看一下就能明白这些表之间的关系。
2全局事务
    OSWorkflow中的示例程序使用BasicWorkflow,从文档上看这种方式不支持事务,这在实际应用时没有太大用处。但查看BasicWorkflow的源代码发现,这个类只是获取数据源,然后操作数据库,因为数据库连接默认的是自动提交的,这就造成了BasicWorkflow好像是不支持事务的。如果要实现工作流的事务,可以定义一个BasicWorkflow的子类来实现。也可以通过JOTM等分布式事务组件来实现事务,这种方式直接使用BasicWorkflow就可以。
    以下介绍OSWorkflow和JOTM集成的方法,实现事务功能。
    1、把需要的jar放到应用的lib下面。
    需要的jar包:howl.jar、jotm.jar、objectweb-datasource.jar、ow_carol.jar、xapool.jar。
    2、在应用的context中建立数据源。
    建立UserTransaction和数据源,代码如下:
auth="Container" 
type="javax.transaction.UserTransaction" 
factory="org.objectweb.jotm.UserTransactionFactory" 
jotm.timeout="180" /> 

factory="org.objectweb.jndi.DataSourceFactory" 
maxWait="5000" 
maxActive="300" 
maxIdle="2" 
username="root" 
password="" 
driverClassName="com.mysql.jdbc.Driver" 
url="jdbc:mysql://127.0.0.1:3306/osworkflow" 
/>
    3、对于需要持久化的工作流操作,在代码中置于事务之下。
    代码示例如下:
UserTransaction ut =DBUtil.getUserTransaction(); 
Connection conn = DBUtil.getConn(); 
boolean rollback = false; 
try { 
  ut.begin(); 

  //*********业务部分 

  //*********工作流部分 
  //新建工作流实例 
  Workflow wf = new BasicWorkflow(employeeName); 
  long wfid = wf.initialize("请假流程", 0, null); 

  //执行动作 
  wf.doAction(wfid, 8, null); 

catch (Exception e) { 
  rollback = true; 
  e.printStackTrace(); 
  throw e; 

finally { 
  if (ut != null && ut.getStatus() != Status.STATUS_NO_TRANSACTION) { 
    if (rollback) ut.rollback(); 
    else ut.commit(); 
  } 

  if (conn != null) conn.close(); 
}
    这样系统就可以支持事务了,如果业务数据放在一个单独的数据库,可以再配一个数据源,用业务的数据源进行业务数据的操作,这样也可以很好的工作。
3流程的图形化显示
    如果能够显示工作的流程,以及当前正在进行什么操作,这会给工作流系统增色不少。在OSWorkflow自带的示例程序中就有这样的功能,能够显示出一个流程图,并以红色边框表示下一步需要进行的操作。分析源代码可以看出,流程是保存为一个图片,图片中的一个步骤表示为一个方框,同时用一个xml文件记录图片中各个方框的位置,如左上角x、y坐标、宽度、高度,在程序运行的时候,从工作流系统查询出当前需要执行的步骤,然后从xml文件中检索出步骤所在方框的位置,在上面显示一个红色边框的矩形。
    以图形化的方式显示流程,原理很简单,但在做的时候需要画一个图片,并且把图片中方框的位置信息写到一个xml文件中,还是挺麻烦的。不知道OSWorkflow安装包中的流程设计器为什么不能运行,从网上下载了一个osworkflow PNG制作及生成lyt.xml文件的程序就可以运行,在这个设计器里面可以以图形化的方式设计流程,并可以导出流程图片,并有定义位置的lyt文件,比自己计算位置方便多了。但用设计器设计流程不太好用,好的做法是自己写流程的xml文件,然后在设计器里导出流程图片和位置lyt文件。这样在程序运行时,红色方框可能和图片上的对不上,可以对viewlivegraph.jsp中的偏移量进行调整,最终的效果还可以。
 

流程效果图
4常用的操作
    创建工作流实例:
Workflow wf = new BasicWorkflow((String) session.getAttribute("username")); 
long wfid = wf.initialize("请假流程", 0, null);
    设置、获取属性:
Workflow wf = new BasicWorkflow((String) session.getAttribute("username")); 
long wfId = Long.parseLong(request.getParameter("wfId")); 
wf.getPropertySet(wfId).setString("biz_id", id); 
String bizId = wf.getPropertySet(wfId).getString("biz_id");
    执行动作:
Workflow wf = new BasicWorkflow((String) session.getAttribute("username")); 
long wfId = Long.parseLong(request.getParameter("wfId")); 
int actionId = Integer.parseInt(request.getParameter("actionId")); 
wf.doAction(wfId, actionId, null);
    获取工作列表:
List workList = new ArrayList(); 
Workflow wf = new BasicWorkflow((String) session.getAttribute("username")); 
//创建查询条件 
FieldExpression statusExp = new FieldExpression(FieldExpression.STATUS, 
    FieldExpression.CURRENT_STEPS, FieldExpression.EQUALS, "Underway"); 
FieldExpression ownerExp = new FieldExpression(FieldExpression.OWNER, 
    FieldExpression.CURRENT_STEPS, FieldExpression.EQUALS, employeeName); 
FieldExpression wfExp = new FieldExpression(FieldExpression.NAME, 
    FieldExpression.ENTRY, FieldExpression.EQUALS, "请假流程"); 
FieldExpression stepExp = new FieldExpression(FieldExpression.STEP, 
    FieldExpression.CURRENT_STEPS, FieldExpression.NOT_EQUALS, 2); 
NestedExpression exp = new NestedExpression(new Expression[]{statusExp, ownerExp, wfExp, stepExp}, 
    NestedExpression.AND); 
WorkflowExpressionQuery expQuery = new WorkflowExpressionQuery(exp); 
//查询 
List workflows = wf.query(expQuery); 
//获取工作流实例相关信息 
for (Iterator iterator = workflows.iterator(); iterator.hasNext();) { 
    Long wfId = (Long) iterator.next(); 
    Map item = new HashMap(); 
    item.put("wfId", wfId); 
    item.put("wfName", wf.getWorkflowName(wfId)); 
    item.put("biz_id", wf.getPropertySet(wfId).getString("biz_id")); 
    WorkflowDescriptor wd = wf.getWorkflowDescriptor(wf.getWorkflowName(wfId)); 
    int[] actionIds = wf.getAvailableActions(wfId, null); 
    List actions = new ArrayList(); 
    for (int i=0; i         Map action = new HashMap(); 
        action.put("actionId", actionIds[i]); 
        action.put("actionName", wd.getAction(actionIds[i]).getName()); 
        actions.add(action); 
    } 
    item.put("actions", actions); 
    workList.add(item); 
}
    改变工作流实例状态:
Workflow wf = new BasicWorkflow((String) session.getAttribute("username")); 
long wfId = Long.parseLong(request.getParameter("wfId")); 
wf.changeEntryState(wfId, WorkflowEntry.COMPLETED);
    如果执行到某个动作整个流程都结束的时候,可以用上面的语句,如果在工作流定义的xml中设置action属性 finish="true" ,则工作流实例会自动关闭。

你可能感兴趣的:(osworkflow的使用)