一. Activiti相关概念
1. Activiti介绍
Activiti是基于Apache许可的开源BPM平台,创始人Tom Baeyens原是JBPM架构师,可以理解为与JBPM出自同一祖师爷。它提供了Eclipse插件,开发可以通过插件直接绘制业务流程图。基于Spring,ibatis等框架,并在此之上构建了非常清晰的开发框架。是由Alfresco软件发布的业务流程管理(BPM)框架,它是覆盖了业务流程管理、工作流、服务协作等领域的一个开源的、灵活的、易扩展的可执行流程语言框架。 本文基于Activiti7的Activiti Core,基于Spring Boot做简单学习总结。(Activiti最新版本向微服务这边靠齐了,并分Activiti Core与Activiti Cloud两块,Activiti Cloud还没研究)
2. 核心类
2.1 ProcessEngine
流程引擎的抽象,可以通过此类获取需要的所有服务。
2.2 服务(Service)类
通过ProcessEngine获取,Activiti将不同生命周期的服务封装在不同Service中,包括定义、部署、运行。通过服务类可获取相关生命周期中的服务信息。
2.2.1 TaskService
流程运行过程中,每个任务节点的相关操作接口,如complete,delete,delegate等。
2.2.2 RepositoryService
流程定义和部署相关的存储服务。
2.2.3 RuntimeService
流程运行时相关的服务,如根据流程好启动流程实例startProcessInstanceByKey。
2.2.3 HistoryService
历史记录相关服务接口。
2.3 CommandContextIntercepter或CommandExecutor
Activiti使用命令模式作为基础开发模式,如Service中调用的各个方法都对应相应的命令对象。Service将请求委托给命令对象,命令对象来命令接受者,接受者接收后执行并返回结果。而CommandContextIntercepter的作用是拦截所有命令,并在命令前后执行一些公共方法。
2.4 核心业务对象
org.activiti.engine.impl.persistence.entity包下的类,包括Task,ProcessInstance,Execution等。会根据不同职责实现相应接口的方法(如需要持久化则继承PersistentObject接口),与传统的实体类不同。
3. 上下文组件(Context)
用来保存生命周期比较长,全局性的信息,类似Application,主要包括如下三类。
3.1 CommandContext
命令上下文,保存每个命令必要的资源,如持久化需要的session。
3.2 ProcessEngineConfigurationImpl
流程引擎相关配置信息,整个引擎全局的配置信息,如数据源DataSource等。该对象为单例,在流程引擎创建的时候初始化。
3.3 ExecutionContext
持有ExecutionEntity对象。
4. 持久化组件
Activiti使用ibatis作OR映射,并在此基础上增加设计了自己的持久化框架。在流程引擎创建时初始化。顶层接口Session、SessionFactory。Session有两个实现类:DbSqlSession,负责sql表达式的执行。AbstractManager负责对象的持久化操作。SessionFactory有两个实现类:DbSqlSessionFactory负责DbSqlSession相关操作,GenericManagerFactory负责AbstractManager相关操作。
5. Event-Listener组件
Activiti允许客户代码介入流程执行,提供了事件监听组件。监听的事件类型可以分为TaskListener、JavaDelegate、Expression、ExecutionListener。ProcessEngineConfigurationImpl持有DelegateInterceptor的某个实例,方便调用handleInvocation。
6. Cache组件
DbSqlSession中有cache的实现,Activiti基于List和Map来做缓存。如查询时先查缓存,没有则直接查询并放入缓存。
7. 异步执行组件
Activiti可以执行任务,JobExecutor为启核心类,JobExecutor包含三个主要属性:JobAcquisitionThread,BlockingQueue,ThreadPoolExecutor。方法ProcessEngines在引擎启动时调用JobExecutor.start,JobAcquisitionThread 线程即开始工作,其run方法不断循环执行AcquiredJobs中的job,执行一次后线程等待一定时间直到超时或者JobExecutor.jobWasAdded方法,因为有新任务而被调用。
8. PVM:Process Virtal Machine
二. Eclipse插件安装:
三. 项目搭建
1. 新建Spring Boot工程
2. 引入Activiti相关依赖
在pom属性中定义版本号,并添加Activiti相关依赖:
7.0.56
org.activiti.dependencies
activiti-dependencies
${activiti-dependencies.version}
import
pom
org.activiti
activiti-spring-boot-starter
由于Activiti默认使用H2数据库,所以需添加H2数据库支持(这里使用此SpringBoot版本默认1.4.197):
com.h2database
h2
出现错误:Missing artifact org.activiti:activiti-spring-boot-starter:jar:7.0.56

添加私服仓库地址:
alfresco
Activiti Releases
https://artifacts.alfresco.com/nexus/content/repositories/activiti-releases/
true

错误消失。
3. 创建流程图
4. 启动工程
5. 修改配置
在正常使用中,一般系统会有自己的数据库,而不会采用默认内存的H2数据库,这里以MySQL为例。修改application.yml。
5.1 添加MySQL依赖
mysql
mysql-connector-java
5.2 修改数据库
spring: 数据库连接信息 datasource: # 数据源配置 url: jdbc:mysql://127.0.0.1:3306/activity?useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: root driver-class-name: com.mysql.jdbc.Driver # SQLException: XAER_INVAL: Invalid arguments (or unsupported command)问题 xa: properties: pinGlobalTxToPhysicalConnection: true useServerPrepStmts: true
5.3 Activiti相关配置
# 参考配置https://www.cnblogs.com/liaojie970/p/8857710.html
activiti:
# 自动建表
database-schema: ACTIVITI
database-schema-update: true
history-level: full
db-history-used: true
5.4 附上application.yml完整配置:
# 服务配置
server:
display-name: actdemo
port: 8085
# Spring相关配置
spring:
数据库连接信息
datasource:
# 数据源配置
url: jdbc:mysql://127.0.0.1:3306/activity?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 888
driver-class-name: com.mysql.jdbc.Driver
# SQLException: XAER_INVAL: Invalid arguments (or unsupported command)问题
xa:
properties:
pinGlobalTxToPhysicalConnection: true
useServerPrepStmts: true
thymeleaf:
mode: HTML
encoding: utf-8
# 禁用缓存
cache: false
application:
# 注册应用名
name: actdemo
mvc:
# 静态资源路径
static-path-pattern: /static/
# 参考配置https://www.cnblogs.com/liaojie970/p/8857710.html
activiti:
# 自动建表
database-schema: ACTIVITI
database-schema-update: true
history-level: full
db-history-used: true
5.5 启动工程
6. 编写实例
本例子使用Thymeleaf做前端页面展示(SpringBoot推荐使用),并创建控制器Controller调用工作流接口与前端交互。
6.1 引入Thymeleaf依赖,(前端使用Thymeleaf的配置已经在application.yml中)
org.springframework.boot
spring-boot-starter-thymeleaf
6.2 创建Controller控制器
创建启动流程方法,主要代码如下
/ * 启动请假流程
* @return String 流程实例ID * @author FRH * @time 2018年12月10日上午11:03:36 * @version 1.0 */ @RequestMapping(value="/start") @ResponseBody public String start() { // xml中定义的ID String instanceKey = "leaveProcess"; logger.info("开启请假流程..."); // 设置流程参数,开启流程 Map
map = new HashMap
(); map.put("jobNumber","A1001"); map.put("busData","bus data"); ProcessInstance instance = runtimeService.startProcessInstanceByKey(instanceKey, map);//使用流程定义的key启动流程实例,key对应helloworld.bpmn文件中id的属性值,使用key值启动,默认是按照最新版本的流程定义启动 logger.info("启动流程实例成功:{}", instance); logger.info("流程实例ID:{}", instance.getId()); logger.info("流程定义ID:{}", instance.getProcessDefinitionId()); //验证是否启动成功 //通过查询正在运行的流程实例来判断 ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery(); //根据流程实例ID来查询 List
runningList = processInstanceQuery.processInstanceId(instance.getProcessInstanceId()).list(); logger.info("根据流程ID查询条数:{}", runningList.size()); // 返回流程ID return instance.getId(); }
6.3 流程跟踪与流程图展示
Activiti流程图展示,使用流程图生成器,本例生成的流程图在页面使用如下方式展示即可:
引入相关工具包,版本使用默认版本7.0.65
org.activiti
activiti-image-generator
调用输出流程图
/ * 查看当前流程图
* @param instanceId 流程实例 * @param response void 响应 * @author FRH * @time 2018年12月10日上午11:14:12 * @version 1.0 */ @ResponseBody @RequestMapping(value="/showImg") public void showImg(String instanceId, HttpServletResponse response) { /* * 参数校验 */ logger.info("查看完整流程图!流程实例ID:{}", instanceId); if(StringUtils.isBlank(instanceId)) return; /* * 获取流程实例 */ HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(instanceId).singleResult(); if(processInstance == null) { logger.error("流程实例ID:{}没查询到流程实例!", instanceId); return; } // 根据流程对象获取流程对象模型 BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId()); /* * 查看已执行的节点集合 * 获取流程历史中已执行节点,并按照节点在流程中执行先后顺序排序 */ // 构造历史流程查询 HistoricActivityInstanceQuery historyInstanceQuery = historyService.createHistoricActivityInstanceQuery().processInstanceId(instanceId); // 查询历史节点 List
historicActivityInstanceList = historyInstanceQuery.orderByHistoricActivityInstanceStartTime().asc().list(); if(historicActivityInstanceList == null || historicActivityInstanceList.size() == 0) { logger.info("流程实例ID:{}没有历史节点信息!", instanceId); outputImg(response, bpmnModel, null, null); return; } // 已执行的节点ID集合(将historicActivityInstanceList中元素的activityId字段取出封装到executedActivityIdList) List
executedActivityIdList = historicActivityInstanceList.stream().map(item -> item.getActivityId()).collect(Collectors.toList()); /* * 获取流程走过的线 */ // 获取流程定义 ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition(processInstance.getProcessDefinitionId()); List
flowIds = ActivitiUtils.getHighLightedFlows(bpmnModel, processDefinition, historicActivityInstanceList); /* * 输出图像,并设置高亮 */ outputImg(response, bpmnModel, flowIds, executedActivityIdList); } / *
输出图像
* @param response 响应实体 * @param bpmnModel 图像对象 * @param flowIds 已执行的线集合 * @param executedActivityIdList void 已执行的节点ID集合 * @author FRH * @time 2018年12月10日上午11:23:01 * @version 1.0 */ private void outputImg(HttpServletResponse response, BpmnModel bpmnModel, List
flowIds, List
executedActivityIdList) { InputStream imageStream = null; try { imageStream = processDiagramGenerator.generateDiagram(bpmnModel, executedActivityIdList, flowIds, "宋体", "微软雅黑", "黑体", true, "png"); // 输出资源内容到相应对象 byte[] b = new byte[1024]; int len; while ((len = imageStream.read(b, 0, 1024)) != -1) { response.getOutputStream().write(b, 0, len); } response.getOutputStream().flush(); }catch(Exception e) { logger.error("流程图输出异常!", e); } finally { // 流关闭 StreamUtils.closeInputStream(imageStream); } }
流程图工具类ActivitiUtils
package com.mypro.activiti.utils; import java.util.ArrayList; import java.util.List; import org.activiti.bpmn.model.BpmnModel; import org.activiti.bpmn.model.FlowNode; import org.activiti.bpmn.model.SequenceFlow; import org.activiti.engine.history.HistoricActivityInstance; import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity; / * Activiti工作流工具类
* @author FRH * @time 2018年12月10日上午11:26:02 * @version 1.0 */ public class ActivitiUtils { / * 获取流程走过的线
* @param bpmnModel 流程对象模型 * @param processDefinitionEntity 流程定义对象 * @param historicActivityInstances 历史流程已经执行的节点,并已经按执行的先后顺序排序 * @return List
流程走过的线 * @author FRH * @time 2018年12月10日上午11:26:19 * @version 1.0 */ public static List
getHighLightedFlows(BpmnModel bpmnModel, ProcessDefinitionEntity processDefinitionEntity, List
historicActivityInstances) { // 用以保存高亮的线flowId List
highFlows = new ArrayList
(); if(historicActivityInstances == null || historicActivityInstances.size() == 0) return highFlows; // 遍历历史节点 for (int i = 0; i < historicActivityInstances.size() - 1; i++) { // 取出已执行的节点 HistoricActivityInstance activityImpl_ = historicActivityInstances.get(i); // 用以保存后续开始时间相同的节点 List
sameStartTimeNodes = new ArrayList
(); // 获取下一个节点(用于连线) FlowNode sameActivityImpl = getNextFlowNode(bpmnModel, historicActivityInstances, i, activityImpl_); // FlowNode sameActivityImpl = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstances.get(i + 1).getActivityId()); // 将后面第一个节点放在时间相同节点的集合里 if(sameActivityImpl != null) sameStartTimeNodes.add(sameActivityImpl); // 循环后面节点,看是否有与此后继节点开始时间相同的节点,有则添加到后继节点集合 for (int j = i + 1; j < historicActivityInstances.size() - 1; j++) { HistoricActivityInstance activityImpl1 = historicActivityInstances.get(j);// 后续第一个节点 HistoricActivityInstance activityImpl2 = historicActivityInstances.get(j + 1);// 后续第二个节点 if (activityImpl1.getStartTime().getTime() != activityImpl2.getStartTime().getTime()) break; // 如果第一个节点和第二个节点开始时间相同保存 FlowNode sameActivityImpl2 = (FlowNode) bpmnModel.getMainProcess().getFlowElement(activityImpl2.getActivityId()); sameStartTimeNodes.add(sameActivityImpl2); } // 得到节点定义的详细信息 FlowNode activityImpl = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstances.get(i).getActivityId()); // 取出节点的所有出去的线,对所有的线进行遍历 List
pvmTransitions = activityImpl.getOutgoingFlows(); for (SequenceFlow pvmTransition : pvmTransitions) { // 获取节点 FlowNode pvmActivityImpl = (FlowNode) bpmnModel.getMainProcess().getFlowElement(pvmTransition.getTargetRef()); // 不是后继节点 if(!sameStartTimeNodes.contains(pvmActivityImpl)) continue; // 如果取出的线的目标节点存在时间相同的节点里,保存该线的id,进行高亮显示 highFlows.add(pvmTransition.getId()); } } //返回高亮的线 return highFlows; } / *
获取下一个节点信息
* @param bpmnModel 流程模型 * @param historicActivityInstances 历史节点 * @param i 当前已经遍历到的历史节点索引(找下一个节点从此节点后) * @param activityImpl_ 当前遍历到的历史节点实例 * @return FlowNode 下一个节点信息 * @author FRH * @time 2018年12月10日上午11:26:55 * @version 1.0 */ private static FlowNode getNextFlowNode(BpmnModel bpmnModel, List
historicActivityInstances, int i, HistoricActivityInstance activityImpl_) { // 保存后一个节点 FlowNode sameActivityImpl = null; // 如果当前节点不是用户任务节点,则取排序的下一个节点为后续节点 if(!"userTask".equals(activityImpl_.getActivityType())) { // 是最后一个节点,没有下一个节点 if(i == historicActivityInstances.size()) return sameActivityImpl; // 不是最后一个节点,取下一个节点为后继节点 sameActivityImpl = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstances.get(i + 1).getActivityId());// 找到紧跟在后面的一个节点 // 返回 return sameActivityImpl; } // 遍历后续节点,获取当前节点后续节点 for (int k = i + 1; k <= historicActivityInstances.size() - 1; k++) { // 后续节点 HistoricActivityInstance activityImp2_ = historicActivityInstances.get(k); // 都是userTask,且主节点与后续节点的开始时间相同,说明不是真实的后继节点 if("userTask".equals(activityImp2_.getActivityType()) && activityImpl_.getStartTime().getTime() == activityImp2_.getStartTime().getTime()) continue; // 找到紧跟在后面的一个节点 sameActivityImpl = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstances.get(k).getActivityId()); break; } return sameActivityImpl; } }
6.4 附上DemoController完整代码
package com.mypro.activiti.controller; import java.io.InputStream; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.activiti.bpmn.model.BpmnModel; import org.activiti.engine.HistoryService; import org.activiti.engine.RepositoryService; import org.activiti.engine.RuntimeService; import org.activiti.engine.TaskService; import org.activiti.engine.history.HistoricActivityInstance; import org.activiti.engine.history.HistoricActivityInstanceQuery; import org.activiti.engine.history.HistoricProcessInstance; import org.activiti.engine.impl.RepositoryServiceImpl; import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity; import org.activiti.engine.runtime.ProcessInstance; import org.activiti.engine.runtime.ProcessInstanceQuery; import org.activiti.engine.task.Task; import org.activiti.image.ProcessDiagramGenerator; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import com.mypro.activiti.utils.ActivitiUtils; import com.mypro.activiti.utils.StreamUtils; / * Activiti控制器
* @author FRH * @time 2018年12月10日上午9:30:18 * @version 1.0 */ @Controller @RequestMapping("/demo") public class DemoController { private static final Logger logger = LoggerFactory.getLogger(DemoController.class); / 流程定义和部署相关的存储服务 */ @Autowired private RepositoryService repositoryService; / 流程运行时相关的服务 */ @Autowired private RuntimeService runtimeService; / 节点任务相关操作接口 */ @Autowired private TaskService taskService; / 流程图生成器 */ @Autowired private ProcessDiagramGenerator processDiagramGenerator; / 历史记录相关服务接口 */ @Autowired private HistoryService historyService; / * 跳转到测试主页面
* @return String 测试主页面
* @author FRH
* @time 2018年12月10日上午11:12:28
* @version 1.0
*/
@RequestMapping(value="/toIndex.html")
public String toTestPage() {
return "/index";
}
/
* 跳转到上级审核页面
* @return String 上级审核页面 * @author FRH * @time 2018年12月5日下午2:31:42 * @version 1.0 */ @RequestMapping(value="/toLeave") public String employeeLeave() { return "/employeeLeave"; } / * 启动请假流程(流程key即xml中定义的ID为leaveProcess)
* @return String 启动的流程ID * @author FRH * @time 2018年12月10日上午11:12:50 * @version 1.0 */ @RequestMapping(value="/start") @ResponseBody public String start() { /* * xml中定义的ID */ String instanceKey = "leaveProcess"; logger.info("开启请假流程..."); /* * 设置流程参数,开启流程 */ Map
map = new HashMap
(); map.put("jobNumber","A1001"); map.put("busData","bus data"); ProcessInstance instance = runtimeService.startProcessInstanceByKey(instanceKey, map);//使用流程定义的key启动流程实例,key对应helloworld.bpmn文件中id的属性值,使用key值启动,默认是按照最新版本的流程定义启动 logger.info("启动流程实例成功:{}", instance); logger.info("流程实例ID:{}", instance.getId()); logger.info("流程定义ID:{}", instance.getProcessDefinitionId()); /* * 验证是否启动成功 */ //通过查询正在运行的流程实例来判断 ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery(); //根据流程实例ID来查询 List
runningList = processInstanceQuery.processInstanceId(instance.getProcessInstanceId()).list(); logger.info("根据流程ID查询条数:{}", runningList.size()); /* * 返回流程ID */ return instance.getId(); } / *
查看当前流程图
* @param instanceId 流程实例 * @param response void 响应 * @author FRH * @time 2018年12月10日上午11:14:12 * @version 1.0 */ @ResponseBody @RequestMapping(value="/showImg") public void showImg(String instanceId, HttpServletResponse response) { /* * 参数校验 */ logger.info("查看完整流程图!流程实例ID:{}", instanceId); if(StringUtils.isBlank(instanceId)) return; /* * 获取流程实例 */ HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(instanceId).singleResult(); if(processInstance == null) { logger.error("流程实例ID:{}没查询到流程实例!", instanceId); return; } // 根据流程对象获取流程对象模型 BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId()); /* * 查看已执行的节点集合 * 获取流程历史中已执行节点,并按照节点在流程中执行先后顺序排序 */ // 构造历史流程查询 HistoricActivityInstanceQuery historyInstanceQuery = historyService.createHistoricActivityInstanceQuery().processInstanceId(instanceId); // 查询历史节点 List
historicActivityInstanceList = historyInstanceQuery.orderByHistoricActivityInstanceStartTime().asc().list(); if(historicActivityInstanceList == null || historicActivityInstanceList.size() == 0) { logger.info("流程实例ID:{}没有历史节点信息!", instanceId); outputImg(response, bpmnModel, null, null); return; } // 已执行的节点ID集合(将historicActivityInstanceList中元素的activityId字段取出封装到executedActivityIdList) List
executedActivityIdList = historicActivityInstanceList.stream().map(item -> item.getActivityId()).collect(Collectors.toList()); /* * 获取流程走过的线 */ // 获取流程定义 ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition(processInstance.getProcessDefinitionId()); List
flowIds = ActivitiUtils.getHighLightedFlows(bpmnModel, processDefinition, historicActivityInstanceList); /* * 输出图像,并设置高亮 */ outputImg(response, bpmnModel, flowIds, executedActivityIdList); } / *
员工提交申请
* @param request 请求 * @return String 申请受理结果 * @author FRH * @time 2018年12月10日上午11:15:09 * @version 1.0 */ @RequestMapping(value="/employeeApply") @ResponseBody public String employeeApply(HttpServletRequest request){ /* * 获取请求参数 */ String taskId = request.getParameter("taskId"); // 任务ID String jobNumber = request.getParameter("jobNumber"); // 工号 String leaveDays = request.getParameter("leaveDays"); // 请假天数 String leaveReason = request.getParameter("leaveReason"); // 请假原因 /* * 查询任务 */ Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); if(task == null) { logger.info("任务ID:{}查询到任务为空!", taskId); return "fail"; } /* * 参数传递并提交申请 */ Map
map = new HashMap
(); map.put("days", leaveDays); map.put("date", new Date()); map.put("reason", leaveReason); map.put("jobNumber", jobNumber); taskService.complete(task.getId(), map); logger.info("执行【员工申请】环节,流程推动到【上级审核】环节"); /* * 返回成功 */ return "success"; } / *
跳转到上级审核页面
* @return String 页面 * @author FRH * @time 2018年12月5日下午2:31:42 * @version 1.0 */ @RequestMapping(value="/viewTask") public String toHigherAudit(String taskId, HttpServletRequest request) { /* * 获取参数 */ logger.info("跳转到任务详情页面,任务ID:{}", taskId); if(StringUtils.isBlank(taskId)) return "/higherAudit"; /* * 查看任务详细信息 */ Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); if(task == null) { logger.info("任务ID:{}不存在!", taskId); return "/higherAudit"; } /* * 完成任务 */ Map
paramMap = taskService.getVariables(taskId); request.setAttribute("task", task); request.setAttribute("paramMap", paramMap); return "higherAudit"; } / *
跳转到部门经理审核页面
* @param taskId 任务ID * @param request 请求 * @return String 响应页面 * @author FRH * @time 2018年12月6日上午9:54:34 * @version 1.0 */ @RequestMapping(value="/viewTaskManager") public String viewTaskManager(String taskId, HttpServletRequest request) { /* * 获取参数 */ logger.info("跳转到任务详情页面,任务ID:{}", taskId); if(StringUtils.isBlank(taskId)) return "/manageAudit"; /* * 查看任务详细信息 */ Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); if(task == null) { logger.info("任务ID:{}不存在!", taskId); return "/manageAudit"; } /* * 完成任务 */ Map
paramMap = taskService.getVariables(taskId); request.setAttribute("task", task); request.setAttribute("paramMap", paramMap); return "manageAudit"; } / *
上级审核
* @param request 请求 * @return String 受理结果 * @author FRH * @time 2018年12月10日上午11:19:44 * @version 1.0 */ @ResponseBody @RequestMapping(value="/higherLevelAudit") public String higherLevelAudit(HttpServletRequest request) { /* * 获取请求参数 */ String taskId = request.getParameter("taskId"); String higherLevelOpinion = request.getParameter("sug"); String auditStr = request.getParameter("audit"); logger.info("上级审核任务ID:{}", taskId); if(StringUtils.isBlank(taskId)) return "fail"; /* * 查找任务 */ Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); if(task == null) { logger.info("审核任务ID:{}查询到任务为空!", taskId); return "fail"; } /* * 设置局部变量参数,完成任务 */ Map
map = new HashMap
(); map.put("audit", "1".equals(auditStr) ? false : true); map.put("higherLevelOpinion", higherLevelOpinion); taskService.complete(taskId, map); return "success"; } / *
部门经理审核
* @param request 请求 * @return String 受理结果 * @author FRH * @time 2018年12月10日上午11:20:44 * @version 1.0 */ @ResponseBody @RequestMapping(value="/divisionManagerAudit") public String divisionManagerAudit(HttpServletRequest request) { /* * 获取请求参数 */ String taskId = request.getParameter("taskId"); String opinion = request.getParameter("sug"); String auditStr = request.getParameter("audit"); logger.info("上级审核任务ID:{}", taskId); if(StringUtils.isBlank(taskId)) return "fail"; /* * 查找任务 */ Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); if(task == null) { logger.info("审核任务ID:{}查询到任务为空!", taskId); return "fail"; } /* * 设置局部变量参数,完成任务 */ Map
map = new HashMap
(); map.put("audit", "1".equals(auditStr) ? false : true); map.put("managerOpinion", opinion); taskService.complete(taskId, map); return "success"; } / *
查看任务
* @param request 请求 * @return String 任务展示页面 * @author FRH * @time 2018年12月10日上午11:21:33 * @version 1.0 */ @RequestMapping(value="/toShowTask") public String toShowTask(HttpServletRequest request) { /* * 获取请求参数 */ List
taskList = taskService.createTaskQuery().list(); if(taskList == null || taskList.size() == 0) { logger.info("查询任务列表为空!"); return "/task"; } /* * 查询所有任务,并封装 */ List
7. 效果

看出Activiti默认使用Spring的security,添加配置,关闭安全认证,如下:
# 关闭activiti登录验证 security: basic: enabled: false

附上首页/index.html代码,其它页面相比比较简单:
首页
流程实例ID:
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/178056.html原文链接:https://javaforall.net
