Activiti工作流之实现一个简单的流程审批

该代码在上一篇博客的基础上开发。

Activiti工作流入门

1.绘制bpmn流程图

在resources目录下新建一个diagram文件夹来存放我们绘制的bpmn流程图

由于我的IDEA中已经安装了actiBPM插件,所以我们可以直接创建

 

然后利用IDEA中提供的组件来绘制流程图

 

为了方便测试,对应的3个流程处理的人员分别为zhangsan,lisi,wangwu。

我们可以点击对应的流程,在Assignee中指定任务负责人。

 

2.将bpmn转为png图片

在IDEA中将bpmn格式的后缀改为.xml

 

 

导出png图片,最终效果如下:

 

3.部署流程定义

部署流程定义就是要将上边绘制的图形即流程定义(.bpmn)部署在工作流程引擎 activiti 中,方法 如下:

/**
 *  流程定义的部署
 *  背后影响的表:
 *      act_re_deployment: 部署信息
 *      act_re_procdef: 流程定义
 *      act_ge_bytearray: 流程定义的bpmn文件和png文件
 */
public class ActivitiDeployment {
    public static void main(String[] args) {
        //1.创建ProcessEngineer对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2.获取repositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //3.部署对象
        Deployment deploy = repositoryService.createDeployment()
                //添加bpmn资源
                .addClasspathResource("diagram/holiday.bpmn")
                //添加图片文件资源
                .addClasspathResource("diagram/holiday.png")
                .name("请假申请流程")
                .deploy();
        //4.输出部署的一些信息
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
    }
}

我们还可以用zip压缩包部署

@Test
public void deployProcessByZip() {
        //1.创建ProcessEngineer对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2.获取repositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();
        //3.定义zip输入流
        InputStream inputStream = this.getClass() .getClassLoader() .getResourceAsStream(
            " diagram/holiday.zip");
        //4.部署对象
        ZipInputStream zipInputStream = new ZipInputStream(inputStream);
        Deployment deploy = repositoryService.createDeployment()
            .addZipInputStream(zipInputStream)
        //5.输出部署的一些信息
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
}

4.启动一个流程实例

流程定义部署在 activiti 后就可以通过工作流管理业务流程了,也就是说上边部署的请假申请流程可以使用了。

针对该流程,启动一个流程表示发起一个新的请假申请单,这就相当于 java 类与 java 对象的关 系,类定义好后需要 new 创建一个对象使用,当然可以 new 多个对象。对于请假申请流程,张三发起一个请假申请单需要启动一个流程实例。

/**
 * 启动流程实例(前提是完成了流程定义的部署工作)
 *
 * 背后影响的表:
 *      act_hi_actinst: 已完成的活动信息
 *      act_hi_identitylink: 参与者信息
 *      act_hi_procinst: 流程实例
 *      act_hi_taskinst: 任务实例
 *      act_ru_execution: 执行表
 *      act_ru_identitylink: 参与者信息
 *      act_ru_task: 任务
 */
public class ActivitiStartInstance {
    public static void main(String[] args) {
        //1.创建ProcessEngineer对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //2.获取runtimeService
        RuntimeService runtimeService = processEngine.getRuntimeService();
        //3.创建流程实例
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("holiday");
        //4.输出实例的相关信息
        System.out.println("流程部署id:" + processInstance.getDeploymentId());//null
        System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());//holiday:1:4
        System.out.println("流程实例id:" + processInstance.getId());//2501
        System.out.println("流程活动id:" + processInstance.getActivityId());//null
    }
}

5.任务查询

流程启动后,各任务的负责人就可以查询自己当前需要处理的任务,查询出来的任务都是该用户的待办任务。

/**
 * 查询当前用户的任务列表
 */
public class ActivitiTaskQuery {
​
    //wangwu完成自己任务列表的查询
    public static void main(String[] args) {
        //1.得到ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
​
        //2.得到TaskService对象
        TaskService taskService = processEngine.getTaskService();
​
        //3.根据流程定义的key,负责人assignee来实现当前用户的任务列表查询
        Task task = taskService.createTaskQuery()
                .processDefinitionKey("holiday")
                .taskAssignee("zhangsan")
                .singleResult();
​
        //4.任务列表的展示
        System.out.println("流程实例ID:" + task.getProcessInstanceId());//2501
        System.out.println("任务ID:" + task.getId());  //2505
        System.out.println("任务负责人:" + task.getAssignee());//zhangsan
        System.out.println("任务名称:" + task.getName());//填写请假申请单
​
    }

6.任务处理

任务负责人查询待办任务,选择任务进行处理,完成任务。

/**
 * 处理当前用户的任务
 * 背后操作的表:
 *   act_hi_actinst
     act_hi_identitylink
     act_hi_taskinst
     act_ru_identitylink
     act_ru_task
 */
public class ActivitiCompleteTask {
​
    //查询当前用户wangwu的任务并处理掉
    public static void main(String[] args) {
        //1.得到ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
​
        //2.得到TaskService对象
        TaskService taskService = processEngine.getTaskService();
​
        //3.查询当前用户的任务
        Task task = taskService.createTaskQuery()
                .processDefinitionKey("holiday")
                .taskAssignee("zhangsan")
                .singleResult();
​
        //4.处理任务,结合当前用户任务列表的查询操作的话,任务ID:task.getId()
        taskService.complete(task.getId());
​
        //5.输出任务的id
        System.out.println(task.getId());
    }
}

在处理过程中可以实时观察代码中标明的表的变化,下面列出了一些表的数据变化:

比如在zhangsan填写完请假申请单后act_hi_actinst表的变化

流程到了部门经理审批这一步,由于部门经理还没有处理,end_time为null

 

全部完成后的效果:

 

act_ru_task表,可以发现每处理一步,都会将处理完的数据删除掉,然后当前的数据为待处理的。等lisi和wangwu都处理完,没有任务后,该表的数据会为空。

 

全部完成后的效果:

 

7.流程定义查询

/**
 * 查询流程定义信息
 */
public class QueryProcessDefinition {
​
​
    public static void main(String[] args) {
        //1.得到ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
​
        //2.创建RepositoryService对象
        RepositoryService repositoryService = processEngine.getRepositoryService();
​
        //3.得到ProcessDefinitionQuery对象,可以认为它就是一个查询器
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
​
        //4.设置条件,并查询出当前的所有流程定义   查询条件:流程定义的key=holiday
        //orderByProcessDefinitionVersion() 设置排序方式,根据流程定义的版本号进行排序
        List<ProcessDefinition> list = processDefinitionQuery.processDefinitionKey("holiday")
                .orderByProcessDefinitionVersion()
                .desc().list();
​
        //5.输出流程定义信息
        for(ProcessDefinition processDefinition :list){
            System.out.println("流程定义ID:"+processDefinition.getId());
            System.out.println("流程定义名称:"+processDefinition.getName());
            System.out.println("流程定义的Key:"+processDefinition.getKey());
            System.out.println("流程定义的版本号:"+processDefinition.getVersion());
            System.out.println("流程部署的ID:"+processDefinition.getDeploymentId());
​
        }
    }
}

输出信息如下:

流程定义ID:holiday:1:4
流程定义名称:请假流程
流程定义的Key:holiday
流程定义的版本号:1
流程部署的ID:1

8.流程定义删除

/**
 * 删除已经部署的流程定义
 *
 * 背后影响的表:
 *      act_re_deployment: 部署信息
 *      act_re_procdef: 流程定义
 *      act_ge_bytearray: 流程定义的bpmn文件和png文件
 */
public class DeleteProcessDefinition {
​
    /**
     * 注意事项:
     *     1.当我们正在执行的这一套流程没有完全审批结束的时候,此时如果要删除流程定义信息就会失败
     *     2.如果公司层面要强制删除,可以使用repositoryService.deleteDeployment("1",true);
     *     //参数true代表级联删除,此时就会先删除没有完成的流程结点,最后就可以删除流程定义信息  false的值代表不级联
     *
     * @param args
     */
    public static void main(String[] args) {
        //1.得到ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
​
        //2.创建RepositoryService对象
        RepositoryService repositoryService = processEngine.getRepositoryService();
​
        //3.执行删除流程定义  参数代表流程部署的id
        repositoryService.deleteDeployment("1");
    }
}

9.流程定义资源查询

通过流程定义对象获取流程定义资源,获取 bpmn 和 png。

/**
 * 需求:
 * 1.从Activiti的act_ge_bytearray表中读取两个资源文件
 * 2.将两个资源文件保存到路径:   /Users/apple/diagram/
 *
 * 技术方案:
 *     1.第一种方式使用actviti的api来实现
 *     2.第二种方式:其实就是原理层面,可以使用jdbc的对blob类型,clob类型数据的读取,并保存
 *        IO流转换,最好commons-io.jar包可以轻松解决IO操作
 *
 * 真实应用场景:用户想查看这个请假流程具体有哪些步骤要走?
 *
 */
public class QueryBpmnFile {
​
    public static void main(String[] args) throws IOException {
        //1.得到ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
​
        //2.得到RepositoryService对象
        RepositoryService repositoryService = processEngine.getRepositoryService();
​
        //3.得到查询器:ProcessDefinitionQuery对象
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
​
        //4.设置查询条件
        processDefinitionQuery.processDefinitionKey("holiday");//参数是流程定义的key
​
        //5.执行查询操作,查询出想要的流程定义
        ProcessDefinition processDefinition = processDefinitionQuery.singleResult();
​
        //6.通过流程定义信息,得到部署ID
        String deploymentId = processDefinition.getDeploymentId();
​
        //7.通过repositoryService的方法,实现读取图片信息及bpmn文件信息(输入流)
        //getResourceAsStream()方法的参数说明:第一个参数部署id,第二个参数代表资源名称
        //processDefinition.getDiagramResourceName() 代表获取png图片资源的名称
        //processDefinition.getResourceName()代表获取bpmn文件的名称
        InputStream pngIs = repositoryService
                .getResourceAsStream(deploymentId,processDefinition.getDiagramResourceName());
        InputStream bpmnIs = repositoryService
                .getResourceAsStream(deploymentId,processDefinition.getResourceName());
​
        //8.构建出OutputStream流
        OutputStream pngOs =
                new FileOutputStream("/Users/apple/"+processDefinition.getDiagramResourceName());
​
        OutputStream bpmnOs =
                new FileOutputStream("/Users/apple/"+processDefinition.getResourceName());
​
        //9.输入流,输出流的转换  commons-io-xx.jar中的方法
        IOUtils.copy(pngIs,pngOs);
        IOUtils.copy(bpmnIs,bpmnOs);
        //10.关闭流
        pngOs.close();
        bpmnOs.close();
        pngIs.close();
        bpmnIs.close();
​
    }
}

10.流程历史信息的查看

即使流程定义已经删除了,流程执行的历史信息通过前面的分析,依然保存在 activiti 的 act_hi_*相关的表中。所以我们还是可以查询流程执行的历史信息,可以通过 HistoryService 来查看相关的历史记录。

/**
 * 需求:
 * 历史数据的查看
 */
public class HistoryQuery {
​
    public static void main(String[] args) throws IOException {
        //1.得到ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
​
        //2.得到HistoryService
        HistoryService historyService = processEngine.getHistoryService();
​
        //3.得到HistoricActivitiInstanceQuery对象
        HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
​
        historicActivityInstanceQuery.processInstanceId("2501");//设置流程实例的id
​
        //4.执行查询
        List<HistoricActivityInstance> list = historicActivityInstanceQuery
                .orderByHistoricActivityInstanceStartTime().asc().list();//排序StartTime
​
        //5.遍历查询结果
        System.out.println("=============================");
        for (HistoricActivityInstance instance : list) {
            System.out.println(instance.getActivityId());
            System.out.println(instance.getActivityName());
            System.out.println(instance.getProcessDefinitionId());
            System.out.println(instance.getProcessInstanceId());
            System.out.println("=============================");
        }
    }
}

输出信息如下:

=============================
_holiday
请假流程
holiday:1:4
2501
=============================
_3
填写请假申请单
holiday:1:4
2501
=============================
_4
部门经理审批
holiday:1:4
2501
=============================
_5
总经理审批
holiday:1:4
2501
=============================
_6
结束
holiday:1:4
2501
=============================
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值