扩展Activiti工作流任务和属性

用过activiti的朋友都知道,activiti做工作流用起来非常方便,可以很容易的基于activiti开发出一个基础的OA流程,可以有多种任务,事件,网关提供给大家选择,想了解详细的,可以点击下方链接多了解,网上资料也特别多,这里不再赘述。

下面给出几个快速入门的链接:
咖啡兔的demo,英文版activti使用手册, 中文版用户手册

但是最近做了一个项目要求是:

  • 通过web访问的可视化可扩展的流程设计器
  • 可以定制任务节点
  • 可以扩展任务属性

这一下懵逼了,三个问题都不简单

首先,activiti虽然自带一个web设计器activiti modeler,但是如果要支持自定义任务节点和扩展节点属性,很难修改,而且修改之后activiti引擎并不识别。
然后就是我们扩展的任务节点和任务属性activiti引擎不识别的问题。

结果就是面对着activiti这个金矿却无从下手,而且如果要硬生生开发出一个activiti的新的任务节点,就得深入剖析activiti的代码,工作量和难度都非常大,最后只能决定曲线救国,看看activiti有没有什么现成的任务能支持扩展属性,如果有,这样就可以同时解决扩展属性的问题了,翻了翻用户手册,发现activiti有个任务节点叫ServiceTask,眼睛一亮这不就是我想要的么。ServiceTask参考

ServiceTask Description 描述

Java 服务任务用来调用外部 Java 类

XML representation 内容

有4钟方法来声明 java 调用逻辑:

  • 实现 JavaDelegate 或 ActivityBehavior
  • 执行解析代理对象的表达式
  • 调用一个方法表达式
  • 调用一直值表达式

执行一个在流程执行中调用的类, 需要在'activiti:class'属性中设置全类名,这个类设置后,流程执行到serviceTask这一步时就会自动调用这个java类。

<serviceTask id="javaService"  name="My Java Service Task" 
    activiti:class="com.yang.activiti.demo.service.ServiceTaskService" />

注意,如果使用了spring mvc框架,默认配置的 activiti:class 是不能通过注解注入类的,如果想要通过注解注入java类,需要使用如下语法

<serviceTask id="serviceTask" activiti:delegateExpression="${serviceTaskService}" />

serviceTaskService是一个实现了 JavaDelegate 接口的bean, 它定义在实例的 spring 容器中

serviceTask还可以注入多个参数

<serviceTask id="ServiceTaskService" 
    name="ServiceTaskService" 
    activiti:class="com.yang.activiti.demo.service.ServiceTaskService">
  <extensionElements>   
    <activiti:field name="param1">
        <activiti:string> Hello Worldactiviti:string>
    activiti:field>
  <activiti:field name="param2">
        <activiti:string> Hello Worldactiviti:string>
    activiti:field>
  extensionElements>        
serviceTask>

java后台com.yang.activiti.demo.service.ServiceTaskService

public class ServiceTaskService implements JavaDelegate {

  private Expression param1;
  private Expression param2;

  public void execute(DelegateExecution execution) {
    String value1 = (String) param1.getValue(execution);
    execution.setVariable("var1", new StringBuffer(value1).reverse().toString());

    String value2 = (String) param2.getValue(execution);
    execution.setVariable("var2", new StringBuffer(value2).reverse().toString());
  }
}

还有其他的参数属性去参照ServiceTask参考不得不说这个节点真的很灵活。


至此我发现了ServiceTask的两个重要特性:

1. 可以绑定自定义的java class(这不就是我想要的扩展自定义任务么)
2. 可以传递无限多个参数(这不就是我想要的扩展属性么)

基于ServiceTask可以有无限多的可能。
这样基本解决了以下两个大问题

  • 可以定制任务节点
  • 可以扩展任务属性

下面就剩下一个问题

  • 通过web访问的可视化可扩展的流程设计器

然后就继续调研,发现activiti modeler我是肯定用不了了,原因如下:

  • 因为要使用serviceTask扩展任务节点,就要涉及复制出多个serviceTask节点,结果发现复制出的serviceTask节点会将原生的serviceTask节点功能覆盖,也就是说只能同时存在一个serviceTask节点
  • 复制出来的serviceTask节点扩展属性,例如:param1,param2,activiti引擎根本不认识,会报错

所以不能用自带的activiti modeler,那么就得去寻找一个流程设计器替代品,替代品有如下要求:

  • 代码结构尽量简单
  • 可以将设计好的流程保存为格式化数据,例如json,xml等
  • 扩展性好
  • 好集成

找了老半天,有很多不错的设计器,但是都不太满足要求,最后还是万能的github帮了我,找到了一个大神开发的一款基于js的可拖拽流程设计器,可以将设计好的流程保存为json格式,双手附上链接LarryleWorkFlow,同时也谢谢作者wangyue20075,设计器的主页是这样子的:

扩展Activiti工作流任务和属性_第1张图片
设计器的主页.PNG

通过作者的工具类可以很容易的去扩展属性,扩展任务,然后将结果保存为json。

下面问题又来了:
保存的json activiti不认识
这个就需要我们自己去写activiti的task解释器了,将我们读取到的json解释成acitivi可以认识的xml,保存在数据库中,然后读取我们的xml去调用activiti的接口发布。

repositoryService.createDeployment() .name(workflowDesigner.getFlowId())
 .addString(processName, flowBpmnXml).deploy();

下面贴一段我的代码:

@RequestMapping("deployFlow/{flowId}")
    @ResponseBody
    public Map deployFlow(@PathVariable("flowId") String flowId){
        Map result = new HashMap();
        workflowDesigner workflowDesigner = workflowDesignerService.selectByPrimaryKey(flowId);
        String flowBpmnXml = workflowDesigner.getFlowBpmnXml();
        String processName = workflowDesigner.getFlowId() + ".bpmn20.xml";
        logger.debug("processName is : "+processName);
        try {
            Deployment deployment = repositoryService.createDeployment()
                                                     .name(workflowDesigner.getFlowId())
                                                     .addString(processName, flowBpmnXml).deploy();
            ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId());
            ProcessDefinition processDefinition = query.singleResult();
            result.put("code",1);
            result.put("message",processDefinition.getId());
        } catch (Exception e) {
            result.put("code",0);
            result.put("message",e.getMessage());
            logger.error(e.getMessage());
        }
        logger.debug(result.toString());
        return result;
    }

这样就完成了一个自定义任务的定义,创建,发布的过程,以上仅仅是个人的思路,欢迎大家讨论或提出意见。



作者:程序鱼
链接:http://www.jianshu.com/p/68c0034f8e56
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的:(JAVA)