Java开源工作流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中的偏移量进行调整,最终的效果还可以。
 

Java开源工作流OSWorkflow常见问题_第1张图片

流程效果图
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" ,则工作流实例会自动关闭。

你可能感兴趣的:(编程开发)