activiti初使用
这周开始使用activiti工作流。任务要求:做一个二级审批流程(可驳回)
遇到的一些问题:
- IDEA集成activiti,2019版本的IDEA插件商店和别的版本不同。
- bpmn会出现乱码问题,需要更改IDEA的相关配置文件
- activiti操作数据库会出现乱码问题,需要在activiti.cfg.xml中URL那里配置编码信息
- activiti.cfg.xml必须在资源根路径下,看它的源码是这样规定的,也就是要在resources下
- activiti是有官网的
- 看不懂官网上7的教程
- 5,6版本有官方教程和API,在官网首页的下部
- 5,6版本的activiti和7差异较大
- 7版本的activiti整合spring boot的时候是默认集成spring security。所以启动项目会被拦截到一个登录页面上面。需要去关闭security的配置。或者更换版本。
- 看官方API的时候,查找某个方法很麻烦,其实API有个index的索引,里面可以直接用CTRL+F来搜索相关方法。
- spring boot的控制器层的类,注解失效,是因为把启动类的路径放的过深,这样自动装配没法扫描到这些类,它只会扫描本包下的类。
- gson的使用,因为传回前端的key是无规律的。所以不知道怎么拿数据。最后直接把整段json展示在文本域中,没有进行处理。
最开始跟着网上的教程手把手教你如何玩转Activiti工作流_Cs_hnu_scw的博客-CSDN博客_activiti工作流
以及B站视频黑马程序员java教程最新工作流引擎Activiti7基础到进阶,Activiti和Spring框架、SpringBoot整合_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili
跟着敲的一些基础的测试用例,大概对activiti的工作流程有所了解,使用activiti对固定的工作流程进行CRUD会很方便,尤其是OA系统。但是对activiti的各个表之间的关系还是不够熟悉。以及流程引擎的各种常用API不熟练。
然后试着去若依官网找扩展项目activiti的时候,没能成功运行起来相关的activiti开源项目。
其中vue前后端分离版本。缺少node_module,原因是没下载相关包,需要npm install。因为为了减少项目大小,所以一般都会把这个包删掉。只要package.json存在就可以,类似pom.xml文件。
最后前端写一些表单和后端进行交互。
参考:
Activiti工作流几种驳回方式的实现与比较 - kongbin - 博客园
测试用例代码
public class ActivitiDemo {
/**
* 流程定义部署
*/
@Test
public void createProcess(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deploy = repositoryService.createDeployment()
.addClasspathResource("diagrams/evection.bpmn")
.addClasspathResource("diagrams/evection.png")
.name("出差申请")
.deploy();
System.out.println("流程部署id:" + deploy.getId());
System.out.println("流程部署名称:" + deploy.getName());
}
/**
* 启动流程实例
*/
@Test
public void startProcess(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myEvention");
System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());
System.out.println("流程实例id:" + processInstance.getId());
System.out.println("当前活动id:" + processInstance.getActivityId());
}
/**
* 任务负责人查询自己需要处理的任务
*/
@Test
public void findPersonalTaskList(){
String assignee = "zhangsan";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
List<Task> list = taskService.createTaskQuery()
.processDefinitionKey("myEvention")
.taskAssignee(assignee)
.list();
for (Task task : list){
System.out.println("流程实例id:" + task.getProcessInstanceId());
System.out.println("任务id:" + task.getId());
System.out.println("任务负责人:" + task.getAssignee());
System.out.println("任务名称:" + task.getName());
}
}
/**
* 负责人查询待办任务,选择任务进行处理,完成任务
*/
@Test
public void completTask(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery()
.processDefinitionKey("myEvention")
.taskAssignee("jerry")
.singleResult();
taskService.complete(task.getId());
}
/**
* 查询流程相关信息,包含流程定义,流程部署,流程定义版本
*/
@Test
public void queryProcessDefinition(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
List<ProcessDefinition> definitionList = processDefinitionQuery.processDefinitionKey("myEvention")
.orderByProcessDefinitionVersion()
.desc()
.list();
for (ProcessDefinition processDefinition : definitionList){
System.out.println("流程定义 id="+processDefinition.getId());
System.out.println("流程定义 name="+processDefinition.getName());
System.out.println("流程定义 key="+processDefinition.getKey());
System.out.println("流程定义 Version="+processDefinition.getVersion());
System.out.println("流程部署ID ="+processDefinition.getDeploymentId());
}
}
/**
* 流程删除
*/
@Test
public void deleteDeployment(){
String deploymentId = "1";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
repositoryService.deleteDeployment(deploymentId);
}
/**
* 启动流程实例,添加businessKey
*/
@Test
public void addBusinessKey(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myEvention", "10001");
System.out.println("业务id==" + processInstance.getBusinessKey());
}
/**
* 查询流程实例
*/
@Test
public void queryProcessInstance(){
String processDefinitionKey = "myEvention";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
List<ProcessInstance> list = runtimeService
.createProcessInstanceQuery()
.processDefinitionKey(processDefinitionKey)//
.list();
for (ProcessInstance processInstance : list) {
System.out.println("----------------------------");
System.out.println("流程实例id:"
+ processInstance.getProcessInstanceId());
System.out.println("所属流程定义id:"
+ processInstance.getProcessDefinitionId());
System.out.println("是否执行完成:" + processInstance.isEnded());
System.out.println("是否暂停:" + processInstance.isSuspended());
System.out.println("当前活动标识:" + processInstance.getActivityId());
}
}
/**
* 审批驳回
*/
@Test
public void reject() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
HistoryService historyService = processEngine.getHistoryService();
RuntimeService runtimeService = processEngine.getRuntimeService();
RepositoryService repositoryService = processEngine.getRepositoryService();
String taskId = "20002";//这里根据你自己的taskid来写
Map variables = new HashMap<>();
//获取当前任务
HistoricTaskInstance currTask = historyService.createHistoricTaskInstanceQuery()
.taskId(taskId)
.singleResult();
//获取流程实例
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId(currTask.getProcessInstanceId())
.singleResult();
//获取流程定义
ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
.getDeployedProcessDefinition(currTask.getProcessDefinitionId());
if (processDefinitionEntity == null) {
System.out.println("不存在的流程定义。");
}
//获取当前activity
ActivityImpl currActivity = ((ProcessDefinitionImpl) processDefinitionEntity)
.findActivity(currTask.getTaskDefinitionKey());
//获取当前任务流入
List<PvmTransition> histTransitionList = currActivity
.getIncomingTransitions();
//清除当前活动出口
List<PvmTransition> originPvmTransitionList = new ArrayList<PvmTransition>();
List<PvmTransition> pvmTransitionList = currActivity.getOutgoingTransitions();
for (PvmTransition pvmTransition : pvmTransitionList) {
originPvmTransitionList.add(pvmTransition);
}
pvmTransitionList.clear();
//查找上一个user task节点
List<HistoricActivityInstance> historicActivityInstances = historyService
.createHistoricActivityInstanceQuery().activityType("userTask")
.processInstanceId(processInstance.getId())
.finished()
.orderByHistoricActivityInstanceEndTime().desc().list();
TransitionImpl transitionImpl = null;
if (historicActivityInstances.size() > 0) {
ActivityImpl lastActivity = ((ProcessDefinitionImpl) processDefinitionEntity)
.findActivity(historicActivityInstances.get(0).getActivityId());
//创建当前任务的新出口
transitionImpl = currActivity.createOutgoingTransition(lastActivity.getId());
transitionImpl.setDestination(lastActivity);
}else
{
System.out.println("上级节点不存在。");
}
variables = processInstance.getProcessVariables();
// 完成任务
List<Task> tasks = taskService.createTaskQuery()
.processInstanceId(processInstance.getId())
.taskDefinitionKey(currTask.getTaskDefinitionKey()).list();
for (Task task : tasks) {
taskService.complete(task.getId(), variables);
historyService.deleteHistoricTaskInstance(task.getId());
}
// 恢复方向
currActivity.getOutgoingTransitions().remove(transitionImpl);
for (PvmTransition pvmTransition : originPvmTransitionList) {
pvmTransitionList.add(pvmTransition);
}
}
}
前端index.html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/jquery-3.6.0.min.js"></script>
</head>
<body>
<form>
<div>
<div>
<label >事项名称:</label>
<div>
<input id="event" type="text" placeholder="请输入事项名称">
</div>
</div>
<div>
<label>请假原因:</label>
<div>
<textarea id="reason" type="text" placeholder="请输入请假原因"></textarea>
</div>
</div>
<div >
<label >是否报销:</label>
<div>
<label>
<input type="checkbox" value="yes" id="inlineCheckbox1">是</label>
</div>
</div>
<div >
<label >出行方式:</label>
<div >
<select class="form-control" id="way">
<option value="飞机">飞机</option>
<option value="动车">动车</option>
</select>
</div>
</div>
<div >
<label >申请人:</label>
<div >
<input id="name" type="text" placeholder="请输入申请人">
</div>
</div>
<button id="btnSubmit">提交</button>
</div>
</form>
<button id="queryEvent" onclick="queryEventPage()">查询</button>
<button id="startEvent" onclick="startEvent()">开启</button>
<script type="text/javascript">
var url = "../activiti/create";
var startUrl = "../activiti/start";
var params;
$(function(){
$("#btnSubmit").click(function () {
var event = $("#event").val();
var reason = $("#reason").val();
var isPaid = $("#inlineCheckbox1").val();
var way = $("#way").val();
var name = $("#name").val();
params = {
event: event,
reason: reason,
isPaid : isPaid,
way : way,
name: name
}
console.log(params)
$.post(url, params, function () {
alert("你已经成功提交申请")
})
})
})
function queryEventPage() {
window.location.href = "query.html"
}
function startEvent() {
$.get(startUrl, function () {
alert("你已经成功开启审批流程")
})
}
</script>
</body>
</html>
query.html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/jquery-3.6.0.min.js"></script>
</head>
<body>
<form>
<input type="text" id="queryName" />
</form>
<button id="btnQuery">查询</button>
<textarea id="queryResult"></textarea>
<form>
<input type="text" id="completeId">
</form>
<button id="btnComplete">选择任务完成</button>
<button id="btnReturn">驳回指定任务</button>
<script>
var queryUrl = "../activiti/query";
var completeUrl = "../activiti/complete";
var returnUrl = "../activiti/return"
var name;
var id;
$(function(){
$("#btnQuery").click(function () {
name = $("#queryName").val();
$.ajax({
type : "POST", //提交方式
url : queryUrl,//路径
data : {
name : name
},//数据,这里使用的是Json格式进行传输
success : function(result) {//返回数据根据结果进行相应的处理
console.log(result)
$("#queryResult").val(result)
}
});
})
$("#btnComplete").click(function () {
id = $("#completeId").val();
$.ajax({
type : "POST", //提交方式
url : completeUrl,//路径
data : {
id : id
},//数据,这里使用的是Json格式进行传输
success : function() {//返回数据根据结果进行相应的处理
alert("已完成"+id)
}
});
})
$("#btnReturn").click(function () {
id = $("#completeId").val();
$.ajax({
type : "POST", //提交方式
url : returnUrl,//路径
data : {
id : id
},//数据,这里使用的是Json格式进行传输
success : function(result) {//返回数据根据结果进行相应的处理
alert("已驳回"+id + result)
}
});
})
})
</script>
</body>
</html>
后台控制器层代码
@RestController
@RequestMapping("/activiti")
public class ActivitiController {
/**
* 流程定义部署
*/
@RequestMapping("/create")
public void createProcess(Event event){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deploy = repositoryService.createDeployment()
.addClasspathResource("diagrams/evection.bpmn")
.addClasspathResource("diagrams/evection.png")
.name(event.getEvent())
.deploy();
System.err.println(deploy);
}
/**
* 启动流程实例
*/
@RequestMapping("/start")
public void startProcess(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myEvention");
}
/**
* 任务负责人查询自己需要处理的任务
*/
@RequestMapping("/query")
public String queryProcess(@Param("name") String name){
String assignee = name;
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
List<Task> list = taskService.createTaskQuery()
.processDefinitionKey("myEvention")
.taskAssignee(assignee)
.list();
System.err.println(list);
Map<String, String> map = new HashMap<>();
for (Task task : list){
map.put(task.getId(), task.getName());
}
return new Gson().toJson(map);
}
/**
* 负责人查询待办任务,选择任务进行处理,完成任务
*/
@RequestMapping("/complete")
public void completTask(@Param("id") String id){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
taskService.complete(id);
}
/**
* 驳回功能
* @param id
*/
@RequestMapping("/return")
public String rollBackWorkFlow(String id) {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
HistoryService historyService = processEngine.getHistoryService();
RuntimeService runtimeService = processEngine.getRuntimeService();
RepositoryService repositoryService = processEngine.getRepositoryService();
try {
Map<String, Object> variables;
// 取得当前任务.当前任务节点
HistoricTaskInstance currTask = historyService
.createHistoricTaskInstanceQuery().taskId(id)
.singleResult();
// 取得流程实例,流程实例
ProcessInstance instance = runtimeService
.createProcessInstanceQuery()
.processInstanceId(currTask.getProcessInstanceId())
.singleResult();
if (instance == null) {
return "ERROR";
}
variables = instance.getProcessVariables();
// 取得流程定义
ProcessDefinitionEntity definition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
.getDeployedProcessDefinition(currTask
.getProcessDefinitionId());
if (definition == null) {
return "ERROR";
}
// 取得上一步活动
ActivityImpl currActivity = ((ProcessDefinitionImpl) definition)
.findActivity(currTask.getTaskDefinitionKey());
//也就是节点间的连线
List<PvmTransition> nextTransitionList = currActivity
.getIncomingTransitions();
// 清除当前活动的出口
List<PvmTransition> oriPvmTransitionList = new ArrayList<PvmTransition>();
//新建一个节点连线关系集合
List<PvmTransition> pvmTransitionList = currActivity
.getOutgoingTransitions();
//
for (PvmTransition pvmTransition : pvmTransitionList) {
oriPvmTransitionList.add(pvmTransition);
}
pvmTransitionList.clear();
// 建立新出口
List<TransitionImpl> newTransitions = new ArrayList<TransitionImpl>();
for (PvmTransition nextTransition : nextTransitionList) {
PvmActivity nextActivity = nextTransition.getSource();
ActivityImpl nextActivityImpl = ((ProcessDefinitionImpl) definition)
.findActivity(nextActivity.getId());
TransitionImpl newTransition = currActivity
.createOutgoingTransition();
newTransition.setDestination(nextActivityImpl);
newTransitions.add(newTransition);
}
// 完成任务
List<Task> tasks = taskService.createTaskQuery()
.processInstanceId(instance.getId())
.taskDefinitionKey(currTask.getTaskDefinitionKey()).list();
for (Task task : tasks) {
taskService.claim(task.getId(), task.getAssignee());
taskService.complete(task.getId(), variables);
historyService.deleteHistoricTaskInstance(task.getId());
}
// 恢复方向
for (TransitionImpl transitionImpl : newTransitions) {
currActivity.getOutgoingTransitions().remove(transitionImpl);
}
for (PvmTransition pvmTransition : oriPvmTransitionList) {
pvmTransitionList.add(pvmTransition);
}
return "SUCCESS";
} catch (Exception e) {
return "ERROR";
}
}
}