此文章将描述activiti的使用,activiti的集成,部署、启动、节点流转、驳回、批注等功能的基本使用。

目录

activiti的使用

背景

技术栈

参考

接口

先接入activiti吧

a、添加依赖

b、项目resources目录下新建activiti.cfg.xml

c、application.yml中srping下添加:

emm~~现在来绘制activiti流程图

1、绘制工具

2、我们会用到的图形

3、按照图形进行绘制,连线

4、设置process的id、name

5、设置每个节点的id、name

6、设置顺序流的name、condition

7、设置UserTask的候选人Canditate Users

8、生成xml、png文件

接口详解

1、创建数据库表

2、流程部署

3、流程删除

4、查询已部署的流程

5、启动流程

6、查询待处理的任务

7、查询处理中的任务

8、查询已处理的任务

9、任务处理(签收/退回/审核)

10、查询历史备注



activiti的使用

我把activiti集成在了spring-boot项目中,首先就是新建一个springboot项目,这里不再赘述springboot项目的搭建。

背景

在平常的业务开发中,遇到了一些审核流程,而且比较多,自己设计了几个数据库表,基本能满足自己的需求,但由于业务可能会越来越大,越来越复杂,就想到用activiti来解决我的问题,于是学习了activiti。

技术栈

springboot 1.X + mybatis 3.X + activiti6.0.0

参考

在学习过程中从网上找了一些博客进行参考,我也有一份电子书,文件太大就不上传了。

  1. 部署流程资源的三种方式 https://blog.csdn.net/zjx86320/article/details/50234707
  2. Activiti数据库表结构 https://blog.csdn.net/hj7jay/article/details/51302829
  3. IntelliJ IDEA安装Activiti插件并使用 https://blog.csdn.net/gozhuyinglong/article/details/80336765
  4. activiti 任务节点 处理人设置 https://blog.csdn.net/qq_30739519/article/details/51225067
  5. Activiti6实现自由跳转 https://segmentfault.com/a/1190000013952695 我应用此代码时加入了comment备注
  6. Activiti工作流的流转任务和结束任务 https://blog.csdn.net/liuming134/article/details/80453907
  7. Activiti添加批注(comment)信息 https://www.cnblogs.com/cxyj/p/3898535.html
  8. Activitivi之启动流程/完成任务的时候设置流程变量 https://www.cnblogs.com/shyroke/p/8000757.html
  9. Activiti任务认领 https://www.cnblogs.com/boulder/p/3658528.html
  10. Activiti之历史活动查询和历史任务查询和流程状态查询 https://www.cnblogs.com/shyroke/p/7994931.html

接口

我的项目完成了以下接口:

1、创建数据库表

2、流程部署

3、流程删除

4、查询已部署的流程

5、启动流程

6、查询待处理的任务

7、查询处理中的任务

8、查询已处理的任务

9、任务处理(签收/退回/审核)

10、查询历史备注

先接入activiti吧

6.0和5.21有什么区别?

在应用当中发现:

1)6.0删除了pvm包,ActivityImpl用不了了,实现节点跳转时就不能用这个了

别的区别,em~~~自己去看吧

a、添加依赖

<dependency><groupId>org.activiti</groupId><artifactId>activiti-spring-boot-starter-basic</artifactId><version>6.0.0</version>
</dependency>

b、项目resources目录下新建activiti.cfg.xml

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration"><property name="jdbcUrl" value="jdbc:mysql://10.10.30.31:3306/hare-arch-demo" /><property name="jdbcDriver" value="com.mysql.jdbc.Driver" /><property name="jdbcUsername" value="root" /><property name="jdbcPassword" value="rootroot" /><property name="databaseSchemaUpdate" value="true" /></bean></beans>

c、application.yml中srping下添加:

spring:jpa:show-sql: trueproperties:hibernate:dialect: org.hibernate.dialect.MySQL5Dialectformat_sql: trueuse_sql_comments: truehibernate:ddl-auto: update

emm~~现在来绘制activiti流程图

1、绘制工具

我用的是idea的actiBPM,虽然有点缺点,但是总归还能用,没有安装的请安装此plugin。

2、我们会用到的图形

1.StartEvent                开始事件

2.EndEvent                  结束事件

3.UserTask                   用户任务

4.ExclusiveAateway    排他网关

5.sequenceFlow         顺序流

其它的图形我没用到,有需要的小伙伴可以自己去研究~~

先上传一个成品截图:

这是我从实际业务中拿出来的流程图,我也做了牺牲了~

3、按照图形进行绘制,连线

4、设置process的id、name

点击bpmn画布空白处,即可看到属性设置,见上图

5、设置每个节点的id、name

点击每个节点,即可看到属性设置

6、设置顺序流的name、condition

点击每个连线,即可看到属性设置

condition的表达式格式为:${pass == true}

7、设置UserTask的候选人Canditate Users

结合业务,Canditate Users的表达式格式为:${face_audit},表示面审候选人,其他UserTask候选人可按照各自功能进行命名:

${face_audit}               面审

${final_first_audit}        终审1

${final_second_audit}  终审2审

${final_third_audit}      终审3审

${res_invest}               尽调

${loan_apply}              放款申请

${loan_audit}               放款审核

为什么设置Canditate Users?

为了结合业务,实现任务的节点的签收/退回,

当Canditate Users有值而assignee为空,则为待处理;

当Canditate Users有值而assignee不为空,则为处理中。

assignee为处理人。

8、生成xml、png文件

xml文件:直接复制demo.bpmn文件,并且把文件名改为demo.xml文件即可,可以以xml格式看到这个流程。

png文件:右键demo.xml,Diagrams-->show BPMN2.0 Designer,右键空白处-->Export to file 即可。

上传一张png给大家看:

好了,demo绘制完毕,接下来看代码~

接口详解

我贴出来的是service的代码,要看完整代码,请看文章末尾gitee地址。

1、创建数据库表

    /*** 创建数据库表* 根据配置文件activiti.cfg.xml创建ProcessEngine*/@Overridepublic void createProcessEngine() {ProcessEngineConfiguration cfg = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");ProcessEngine engine = cfg.buildProcessEngine();}

执行上述接口后,对应的数据库里会自动生成activiti相关的数据库表。

2、流程部署

需要传入参数deploymentName 部署名称,force是否强制部署,error是个map。

其中参数deploymentName为xml文件中process标签的id。

/*** 流程部署** @param deploymentName 流程部署名称* @param force          是否强制部署,true强制,false非强制* @param error*/@Overridepublic void deployProcess(String deploymentName, boolean force, ErrorInfo error) {//判断流程是否已存在Deployment deploymentExist = processEngine.getRepositoryService().createDeploymentQuery().deploymentName(deploymentName).singleResult();//流程已存在if (null != deploymentExist) {if (force) {error.msg = "流程已存在,进行强制部署。";//强制部署时,先删除原有的部署流程processEngine.getRepositoryService()//true:级联删除.deleteDeployment(deploymentExist.getId(), true);log.info("【%s】流程强制部署,删除部署id【%d】", deploymentName, deploymentExist.getId());} else {error.msg = "流程已存在,不更新部署";log.info("【%s】流程已存在,不更新部署", deploymentName);return;}}//流程不存在,直接部署Deployment deployment = processEngine.getRepositoryService().createDeployment().name(deploymentName).addClasspathResource("processes/" + deploymentName + ".bpmn").addClasspathResource("processes/" + deploymentName + ".png").deploy();error.msg += "流程已部署";log.info("流程已部署,部署名称:" + deploymentName + ",部署ID:" + deployment.getId() + ",部署时间:" + deployment.getDeploymentTime());}

3、流程删除

有流程部署,就会有流程删除,看代码:

/*** 删除流程定义** @param deploymentId 流程部署ID_* @param error*/@Overridepublic void deleteDeployment(String deploymentId, ErrorInfo error) {//流程定义名称String deploymentName = "";List<Deployment> deploymentList = processEngine.getRepositoryService().createDeploymentQuery().list();if (null != deploymentList && deploymentList.size() > 0) {for (Deployment de : deploymentList) {if (de.getId().equalsIgnoreCase(deploymentId)) {deploymentName = de.getName();break;}}}//级联删除流程processEngine.getRepositoryService().deleteDeployment(deploymentId, true);error.code = 1;error.msg = "流程定义[" + deploymentName + "]已级联删除";log.info("流程定义[%s]已级联删除", deploymentName);}

4、查询已部署的流程

已成功部署的流程定义会放在act_re_deployment里。

/*** 查询全部流程定义** @return*/@Overridepublic List<DeploymentDto> getDeploymentList() {//结果集List<DeploymentDto> list = new ArrayList<>();//deployment结果集List<Deployment> deploymentList = processEngine.getRepositoryService().createDeploymentQuery().list();if (null != deploymentList && deploymentList.size() > 0) {for (Deployment de : deploymentList) {DeploymentDto dto = new DeploymentDto();dto.setId(de.getId());dto.setName(de.getName());dto.setCreateTime(de.getDeploymentTime());list.add(dto);}}return list;}

5、启动流程

启动流程时,除了传业务所需的参数外,第一个节点所涉及到的参数变量也必须传,否则流程无法启动:

variables.put("face_audit", "faceAudit");

我把节点必传的参数写在了CarProcessCanditateUsersEnum.java

    /*** 启动流程** @param instanceKey 流程process的id,例:demo*/@Overridepublic ProcessInstance startProcess(String instanceKey, Map<String, Object> variables) {RuntimeService runtimeService = processEngine.getRuntimeService();//可根据id、key、message启动流程ProcessInstance myProcess_1 = runtimeService.startProcessInstanceByKey(instanceKey, variables);//流程实例IDlog.info("流程实例ID:" + myProcess_1.getId());//流程实例ProcessInstanceIdlog.info("流程实例ProcessInstanceId:" + myProcess_1.getProcessInstanceId());//流程实例ProcessDefinitionIdlog.info("流程实例ProcessDefinitionId:" + myProcess_1.getProcessDefinitionId());return myProcess_1;}

6、查询待处理的任务

我在activiti的使用中,UserTask任务用到了两个处理字段:Canditate Users 和 assignee

简单理解:当Canditate Users有值,assignee为null时,任务为待处理

    /*** 查询当前任务办理人的当前任务--待处理* <p>* 两个参数都不传,则查询所有节点待办任务** @param candidateUser 当前任务候选角色变量* @return*/@Overridepublic List<PersonnelTaskDto> pendingTask(String candidateUser) {//task list结果集List<Task> tasks = new ArrayList<>();//封装成dto listList<PersonnelTaskDto> personnelTaskDtoList = new ArrayList<>();if (StringUtils.isNotBlank(candidateUser)) {//与任务相关的Servicetasks = processEngine.getTaskService().createTaskQuery()//创建一个任务查询对象.taskCandidateUser(candidateUser).orderByTaskCreateTime().desc().list();} else {//查询所有待办任务//与任务相关的Servicetasks = processEngine.getTaskService().createTaskQuery()//创建一个任务查询对象.orderByTaskCreateTime().desc().list();}if (tasks != null && tasks.size() > 0) {for (Task task : tasks) {//待处理if (StringUtils.isBlank(task.getAssignee())) {PersonnelTaskDto entity = new PersonnelTaskDto();entity.setTaskId(task.getId());entity.setAssignee(task.getAssignee());entity.setTaskName(task.getName());entity.setCreateTime(task.getCreateTime());entity.setProcessInstanceId(task.getProcessInstanceId());personnelTaskDtoList.add(entity);}}}//将结果放到pageDtoreturn personnelTaskDtoList;}

7、查询处理中的任务

我在activiti的使用中,UserTask任务用到了两个处理字段:Canditate Users 和 assignee

简单理解:当Canditate Users有值,assignee也有值时,任务为处理中

    /*** 查询当前任务办理人的当前任务--处理中* <p> Constants.NODE_STATUS_HANDLING* 两个参数都不传,则查询所有节点处理中任务** @param candidateUser* @return*/@Overridepublic List<PersonnelTaskDto> handlingTask(String candidateUser) {//task list结果集List<Task> tasks = new ArrayList<>();//封装成dto listList<PersonnelTaskDto> personnelTaskDtoList = new ArrayList<>();TaskService taskService = processEngine.getTaskService();if (StringUtils.isNotBlank(candidateUser)) {//与任务相关的Servicetasks = taskService.createTaskQuery()//创建一个任务查询对象.taskCandidateUser(candidateUser).orderByTaskCreateTime().desc().list();} else {//查询所有待办任务//与任务相关的Servicetasks = taskService.createTaskQuery()//创建一个任务查询对象.orderByTaskCreateTime().desc().list();}if (tasks != null && tasks.size() > 0) {for (Task task : tasks) {//处理中if (StringUtils.isNotBlank(task.getAssignee())) {PersonnelTaskDto entity = new PersonnelTaskDto();entity.setTaskId(task.getId());entity.setAssignee(task.getAssignee());entity.setTaskName(task.getName());entity.setCreateTime(task.getCreateTime());entity.setProcessInstanceId(task.getProcessInstanceId());personnelTaskDtoList.add(entity);}}}return personnelTaskDtoList;}

8、查询已处理的任务

历史活动涉及到的表为act_hi_*

各种历史活动查询可参考资料:历史活动查询

我这里用了:

HistoryService historyService = processEngine.getHistoryService();

historyService.createHistoricActivityInstanceQuery()

可根据自己需求进行自行修改。

    /*** 查询已处理的任务** @param assignee 处理人* @return*/@Overridepublic List<PersonnelTaskDto> handledTask(String assignee) {//封装成dto listList<PersonnelTaskDto> personnelTaskDtoList = new ArrayList<>();HistoryService historyService = processEngine.getHistoryService();List<HistoricActivityInstance> list = new ArrayList<>();//处理人不为空时查询处理人所属的已处理任务if (StringUtils.isNotBlank(assignee)) {list = historyService.createHistoricActivityInstanceQuery().taskAssignee(assignee).finished().desc().list();} else {//处理人为空时查询所有已处理任务list = historyService.createHistoricActivityInstanceQuery().list();}if (null != list && list.size() > 0) {for (HistoricActivityInstance instance : list) {PersonnelTaskDto entity = new PersonnelTaskDto();entity.setTaskId(instance.getId());entity.setAssignee(instance.getAssignee());entity.setTaskName(instance.getActivityName());entity.setCreateTime(instance.getStartTime());entity.setProcessInstanceId(instance.getProcessInstanceId());personnelTaskDtoList.add(entity);}}return personnelTaskDtoList;}

9、任务处理(签收/退回/审核)

流程启动之后,整个流程会停留在第一个节点,以demo为例,会停留在【面审】

然后此节点的候选人进行任务签收

当有此节点权限的人签收此任务后,可以用代码禁止再被其他人签收(我这里没做)

    /*** 节点处理,0:审核,1:签收,2:退回** @param user* @param jumpToNodeDto* @param error*/@Overridepublic void handleNode(User user, JumpToNodeDto jumpToNodeDto, ErrorInfo error) {ActivitiServiceImpl impl = new ActivitiServiceImpl();//审核if (jumpToNodeDto.getIsClaim().equals(Constants.NODE_AUDIT)) {Map<String, Object> variables = prepareNodeJumpVaria(jumpToNodeDto);//流转impl.jumpToNode(jumpToNodeDto.isInOrder(), jumpToNodeDto.getTaskId(), jumpToNodeDto.getTargetFlowElementId(), jumpToNodeDto.getComment(), variables, error);} else {//签收/退回impl.claimActivity(jumpToNodeDto, user, error);}}

节点跳转,我这里做了顺序的的流转和跳转,因为在审核流程中任务有可能被驳回,也有可能最高权限的人一键审核通过。

跳转的代码,可以下载我的代码看一下,这里就不贴出来了。

    /*** 节点跳转/流转** @param isInOrder           是否是顺序执行,true:下一节点;false:任意节点(包括驳回和最高权限的审核通过)* @param taskId              任务id,对应act_ru_task中的ID_* @param targetFlowElementId 目标的节点id* @param comment             审批意见* @param variables           传入下一节点时所需参数*/public void jumpToNode(boolean isInOrder, String taskId, String targetFlowElementId, String comment, Map<String, Object> variables, ErrorInfo error) {//获取taskServiceTaskService taskService = processEngine.getTaskService();Task task = taskService.createTaskQuery().taskId(taskId).singleResult();if (StringUtils.isBlank(task.getAssignee())) {error.code = -1;error.msg = "任务未签收,不允许跳转/流转";return;}//当前任务节点顺序流转if (isInOrder) {//添加审批意见taskService.addComment(taskId, null, comment);try {taskService.complete(taskId, variables);} catch (Exception e) {error.code = -1;error.msg = "节点流转失败taskId[" + taskId + "]";e.printStackTrace();log.error("节点流转失败taskId[%s]", taskId);}error.code = 1;error.msg = "节点流转成功";}//任意节点if (!isInOrder) {if (StringUtils.isBlank(targetFlowElementId)) {error.code = -1;error.msg = "节点跳转targetFlowElementId不能为空";log.error(error.msg);return;}ActivitiJump activitiJump = new ActivitiJump();try {activitiJump.jump(taskId, targetFlowElementId, comment, variables);} catch (Exception e) {e.printStackTrace();log.error("节点跳转失败taskId[%s]", taskId);error.code = -1;error.msg = "节点跳转失败taskId[" + taskId + "]";}error.code = 1;error.msg = "节点跳转成功";}}

任务的签收和退回

    /*** 签收/退回任务** @param jumpToNodeDto* @param user* @param error*/public void claimActivity(JumpToNodeDto jumpToNodeDto, User user, ErrorInfo error) {TaskService taskService = processEngine.getTaskService();String isClaim = jumpToNodeDto.getIsClaim();//签收if (isClaim.equals(Constants.NODE_CLAIM)) {taskService.setAssignee(jumpToNodeDto.getTaskId(), user.getName());//添加备注taskService.addComment(jumpToNodeDto.getTaskId(), null, jumpToNodeDto.getComment());error.code = 1;error.msg = "签收成功";}//退回if (isClaim.equals(Constants.NODE_BACK)) {taskService.setAssignee(jumpToNodeDto.getTaskId(), null);taskService.addComment(jumpToNodeDto.getTaskId(), null, jumpToNodeDto.getComment());error.code = 1;error.msg = "退回成功";}}

10、查询历史备注

在节点流转/跳转、签收、退后等操作过程中,肯定会填写一些批注、原因,那么怎么查询这些批注呢?

要用HistoryService

   /*** 查询历史备注** @param candidateUser* @return*/public List<Comment> getHistoryTaskComments(String candidateUser) {List<Comment> taskComments = new ArrayList<>();HistoryService historyService = processEngine.getHistoryService();TaskService taskService = processEngine.getTaskService();List<HistoricTaskInstance> list = new ArrayList<>();//处理人不为空时查询处理人所属的已处理任务if (StringUtils.isNotBlank(candidateUser)) {list = historyService.createHistoricTaskInstanceQuery().taskCandidateUser(candidateUser).orderByHistoricTaskInstanceStartTime().desc().list();} else {//处理人为空时查询所有已处理任务list = historyService.createHistoricTaskInstanceQuery().orderByHistoricTaskInstanceStartTime().desc().list();}if (null != list && list.size() > 0) {for (HistoricTaskInstance instance : list) {String hisTaskId = instance.getId();List<Comment> comments = taskService.getTaskComments(hisTaskId);if (null != comments && comments.size() > 0) {taskComments.addAll(comments);}}}return taskComments;}

至此,基本讲述完了,贴上我的gitee代码:

https://gitee.com/dayydream/activiti.git

我只是一个小菜鸟,欢迎各位大神来沟通

activiti的使用相关推荐

  1. Activiti——流程执行历史记录(七)

    转自:http://blog.csdn.net/zjx86320/article/details/50363544 之前的几篇文章,为大家简单的介绍了部署流程定义.启动流程实例.查看和办理个人任务以及 ...

  2. Activiti——流程变量(六)

    Activiti--流程变量 转自:http://lib.csdn.net/article/java/66665?knId=268 流程变量在整个工作流中扮演很重要的作用.例如:请假流程中有请假天数. ...

  3. Activiti——工作流之流程实例、任务的执行(五)

    转自:http://profound-accumulation.iteye.com/blog/2244881 一.流程图   二.部署流程定义 /**部署请假流程(从zip)*/ @Test publ ...

  4. Activiti——数据表结构

    备注: 本文转自:http://blog.csdn.net/hj7jay/article/details/51302829 转载目的在于个人学习使用,如有涉及著作权相关问题,请联系本人,本人将第一时间 ...

  5. Activiti——管理流程定义(四)

    Activiti--管理流程定义 1.设计流程定义文档 1.1.流程图 1.2.bpmn文件 <?xml version="1.0" encoding="UTF-8 ...

  6. Activiti——工作流程-核心API(二)

    .1 ProcessEngine 说明: 1) 在Activiti中最核心的类,其他的类都是由他而来. 2) 产生方式: 在前面看到了两种创建ProcessEngine(流程引擎)的方式(http:/ ...

  7. Activiti——准备开发环境(一)

    准备材料下 activiti-5.17.0 1.添加Activiti5 的jar包或Maven依赖 Jar包方式 通过上述下载链接下载Activiti后,解压得到如下目录: 把libs的jar包添加到 ...

  8. 【应用篇】Activiti外置表单实例demo(四)

    在这里我想说的外置表单.是说我们将我们自己的jsp(.form,.html)等页面上传到工作流的数据库中,当任务运行到当前结点时.给我们像前台发送绑定好的表单. 此处是给表单绑定表单的过程 不允许为: ...

  9. Activiti 规则任务(businessRuleTask)

    Activiti 规则任务(businessRuleTask) 作者:邓家海 目前国内研究Activiti规则任务businessRuleTask)的文章在网上应该不超出3篇 小觑夜漫酒作伴,破晓黎明 ...

  10. activiti任务TASK

    一.概要 设计TASK的表主要是:ACT_RU_TASK,ACT_HI_TASKINST(见参考-activiti表): 任务主要有:人工任务(usertask),服务任务(servicetask)等 ...

最新文章

  1. RDKit | 定量评估类药性(QED)
  2. 浏览器支持java_为什么我下载了java并提示浏览器不支持j
  3. session outline for different culture
  4. 使用Buildroot为Nxp i.mx6ul制作文件系统
  5. 爬虫系列---Scrapy框架学习
  6. 自己动手写UI库——引入ExtJs(布局)
  7. MSP432P401R TI Drivers 库函数学习笔记(四)GPIO
  8. TensorFlow 学习指南 三、学习
  9. next.js 安装简易教程
  10. ai电磁组属于什么组_飞思卡尔智能车电磁组分区算法介绍
  11. Android ActionBar示例教程
  12. Android学习(五)—— Android初级控件
  13. 力扣-1232 缀点成线
  14. 南开大学2019年数学分析考研试题
  15. 实验3 黑盒测试:决策表法及测试用例设计
  16. 软连接和硬连接的区别
  17. 测试进阶篇之测试用例设计-百度云盘
  18. golang开发的准备 - gvm(go版本管理软件)的安装
  19. 基于SQLSERVER--数据库表的修复
  20. 10分钟了解BIM+GIS融合,常见BIM数据格式及特性

热门文章

  1. 数据增强功能工具,选项功能对照表
  2. Less的简单介绍、使用、语法
  3. 基于AT89C52单片机的温度检测报警设计
  4. mysql如何避免脏读_mysql避免脏读
  5. 用python做股票量化分析豆瓣_小白学 Python 爬虫(24):2019 豆瓣电影排行
  6. ElasticSearch Java API:Mget操作
  7. BeautifulSoup爬取豆瓣电影排名
  8. 电子商业承兑汇票到期怎么兑现
  9. react 全选_使用React的Hooks+ts实现全选和全不选?
  10. 银行自助设备详细介绍(三)——取款机