文章目录
画工作流
idea集成插件Flowable BPMN visualizer,这个插件可以画工作流,先在目录创建一个xxx.bpmn20.xml的文档,此文档可以放在resource下面,后期肯定和前端联调,前端可以集成bpmn.js进行勾画工作流。
画的工作流是BPMN2.0结构,里面包含了多种类型,分别为:事件,顺序流,网关,任务,子流程与调用活动,事务与并发,流程启动认证,数据对象。
如果不是空事件启动的话,在拒绝的情况下重新指回发起流程节点,带有参数的启动则不会重新填写参数,会直接到下一次审核。
如果空事件启动,下一个用户任务启动的情况下,可以把拒绝的箭头指回到填写审核信息发起重新走流程。
工作流整体流程,审批流程
部署流程-》启动流程-》发起申请-》审批-》存档-》结束
联调流程
1.部署流程
2.获取当前登陆人启动流程发起申请,此处可以有两种,1.无参数启动流程事件,下一个在用户任务在提交申请参数。2.带参数启动流程,在启动的时候直接包含数据列表,下一步到审批流程。
3.查看当前人未结束的流程,此处对应的为无参数启动,目的为了找到当前任务id和流程实例的processInstanceId
4.不带参数的发起流程,下一步需要写申请,带上参数的请求,进行执行任务
5.审批(执行任务),审批有两种方式,1.查询当前的流程,获取下边的任务进行审批。2.查询当前人的审批列表,展示任务列表,对任务单独审批
6.查看需要审批的内容
7.查看流程图,可以看执行的过程图,展示的为image图片
具体代码如下:
1.部署流程
部署流程有5中实现方式,分别为
1.使用文件流部署工作流
@GetMapping("/deployInputStream")
public void deploy(@RequestParam("file") MultipartFile multipartFile, @RequestParam("name") String name) {
try {
Deployment deployment = repositoryService.createDeployment()
.addInputStream(multipartFile.getOriginalFilename(), multipartFile.getInputStream())
.name(name)
.deploy();
// 输出部署的一些信息
System.out.println("流程部署ID:"+ deployment.getId());
System.out.println("流程部署名称:"+ deployment.getName());
System.out.println("流程部署成功");
} catch (IOException e) {
System.out.println("流程部署失败,文件验证失败,流程图有错误:"+ e.getMessage());
throw new RuntimeException(e);
}
}
2.使用classPath进行部署工作流
@GetMapping("/deployClasspath")
public void deployClasspath(@RequestParam("name") String name) {
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("processes/leave.bpmn20.xml")
.name(name)
.deploy();
// 输出部署的一些信息
System.out.println("流程部署ID:"+deployment.getId());
System.out.println("流程部署名称:"+deployment.getName());
System.out.println("流程部署成功");
}
3.使用压缩文件zipStream进行部署工作流
/**
* 部署流程(使用压缩文件zipStream进行部署工作流)
* 支持批量部署多个 BPMN 文件。适合一次性部署多个流程定义。
* 需要将 BPMN 文件打包为 ZIP 格式。
*/
@GetMapping("/deployZipStream")
public void deployZipStream(@RequestParam("file") MultipartFile multipartFile, @RequestParam("name") String name) {
Deployment deployment = null;
try {
deployment = repositoryService.createDeployment()
.addZipInputStream(new ZipInputStream(multipartFile.getInputStream()))
.deploy();
System.out.println("流程部署ID:"+ deployment.getId());
System.out.println("流程部署名称:"+ deployment.getName());
System.out.println("流程部署成功");
} catch (IOException e) {
System.out.println("流程部署失败,文件验证失败,流程图有错误:"+ e.getMessage());
throw new RuntimeException(e);
}
}
4.使用纯文本格式(text)进行部署工作流
/**
* 部署流程(使用纯文本格式(text)进行部署工作流)
*
* 如果 XML 字符串较大,可能会占用较多内存。
*/
@GetMapping("/deployText")
public void deployText(@RequestBody Map<String, Object> map) {
// 文件的全名称
String resourceName = (String) map.get("resourceName");
// 符合流程图的xml文件规范
String flowableText = (String) map.get("flowableText");
// 流程图的名称
String name = (String) map.get("name");
try {
Deployment deployment = repositoryService.createDeployment()
.addString(resourceName, flowableText)
.name(name)
.deploy();
// 输出部署的一些信息
System.out.println("流程部署ID:"+ deployment.getId());
System.out.println("流程部署名称:"+ deployment.getName());
System.out.println("流程部署成功");
} catch (Exception e) {
System.out.println("流程部署失败,文件验证失败,流程图有错误:"+ e.getMessage());
throw new RuntimeException(e);
}
}
5.使用字节数组进行部署工作流
/**
* 部署流程(使用字节数组进行部署工作流)
* 直接使用字节数组部署,适合从二进制数据加载 BPMN 文件。性能较高,适合处理大文件。
* 如果和前端联调,前端画图生成的话,然后传入后端进行部署流程图使其生效,使用此方法较为合适,他的灵活度和性能都属于较高的
* 如果bpmn文件较小的话,就是用addString或者addInputStream方法,如果文件较大的话,就使用addBytes方法
* 批量部署的话,使用addZipInputStream方法
*/
@GetMapping("/deployBytes")
public void deployBytes(@RequestParam("file") MultipartFile multipartFile, @RequestParam("name") String name) {
try {
Deployment deployment = repositoryService.createDeployment()
.addBytes(multipartFile.getOriginalFilename(), multipartFile.getBytes())
.name(name)
.deploy();
// 输出部署的一些信息
System.out.println("流程部署ID:"+ deployment.getId());
System.out.println("流程部署名称:"+ deployment.getName());
System.out.println("流程部署成功");
} catch (Exception e) {
System.out.println("流程部署失败,文件验证失败,流程图有错误:"+ e.getMessage());
throw new RuntimeException(e);
}
}
2.启动流程
2.1 无参数启动流程
identityService.setAuthenticatedUserId设置发起人也就是当前用户的id,在act_hi_procinst表中的start_user_id_字段中看到发起人id
@PostMapping("/start-process")
public void startProcess(@RequestBody Map<String, Object> map) {
try {
identityService.setAuthenticatedUserId("xiaochen");
// 获取map里流程定义的key
String processKey = (String) map.get("processKey");
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processKey);
System.out.println("流程定义的id = " + processInstance.getProcessDefinitionId());
System.out.println("流程实例的id = " + processInstance.getId());
} catch (Exception e) {
e.printStackTrace();
} finally {
identityService.setAuthenticatedUserId(null);
}
}
2.2 带有参数启动流程
@PostMapping("/lnitiate-application")
public void initiateApplication(@RequestBody Map<String, Object> map) {
String processKey = (String) map.get("processKey");
// 获取请求的参数
Map<String, Object> paramMap = (Map<String, Object>) map.get("paramMap");
identityService.setAuthenticatedUserId("xiaochen");
runtimeService.startProcessInstanceByKey(processKey, paramMap);
}
3.查看当前用户还未结束的流程
@PostMapping("/unfinished-process")
public void unfinishedProcess(@RequestBody Map<String, Object> map) {
String assignee = (String) map.get("assignee");
List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().startedBy(assignee).list();
for (ProcessInstance processInstance : list) {
System.out.println("流程定义的id = " + processInstance.getProcessDefinitionId());
System.out.println("ProcessInstanceId = " + processInstance.getProcessInstanceId());
}
}
4.不带参数的发起流程
@PostMapping("/apply-with-parameters")
public void applyWithParameters(@RequestBody Map<String, Object> map) {
String processKey = (String) map.get("processKey");
String processInstanceId = (String) map.get("processInstanceId");
LinkedHashMap paramMap = (LinkedHashMap) map.get("paramMap");
List<Task> tasks = taskService.createTaskQuery()
.processDefinitionKey(processKey).processInstanceId(processInstanceId)
.list();
for (Task task : tasks) {
taskService.complete(task.getId(), paramMap);
System.out.println("流程定义的id = " + task.getProcessDefinitionId());
System.out.println("流程实例的id = " + task.getProcessInstanceId());
System.out.println("任务id = " + task.getId());
System.out.println("任务名称 = " + task.getName());
System.out.println("流程定义的id = " + task.getProcessDefinitionId());
}
}
5.审批
5.1 根据流程审批
@PostMapping("/approve")
public void approve(@RequestBody Map<String, Object> map) {
String processKey = (String) map.get("processKey");
// 获取审批人
String assignee = (String) map.get("assignee");
// 获取参数
LinkedHashMap<String, Object> paramMap = (LinkedHashMap) map.get("paramMap");
// 获取审批状态是true还是false,添加审批备注
boolean approved = (boolean) paramMap.get("approved");
List<Task> list = taskService.createTaskQuery().processDefinitionKey(processKey).taskAssignee(assignee).list();
for (Task task : list) {
taskService.addComment(task.getId(), task.getProcessInstanceId(), assignee + (approved ? "通过" : "不通过"));
// 执行任务
taskService.complete(task.getId(), paramMap);
}
}
5.2 单独审批
5.2.1 查询当前人的待审批列表
@PostMapping("/select-todo-task-list")
public void selectTodoTaskList(@RequestBody Map<String, Object> map) {
try {
String assignee = (String) map.get("assignee");
String processKey = (String) map.get("processKey");
if (assignee == null || assignee.trim().isEmpty()) {
System.out.println("assignee不能为空");
}
List<Task> tasks;
if (processKey != null && !processKey.trim().isEmpty()) {
tasks = taskService.createTaskQuery()
.taskAssignee(assignee)
.processDefinitionKey(processKey)
.list();
} else {
tasks = taskService.createTaskQuery()
.taskAssignee(assignee)
.list();
}
// 日志记录
for (Task task : tasks) {
System.out.println("流程定义的id = " + task.getProcessDefinitionId());
System.out.println("流程实例的id = " + task.getProcessInstanceId());
System.out.println("任务id = " + task.getId());
}
} catch (Exception e) {
System.out.println("查询待审批任务列表时发生异常" + e);
System.out.println("系统错误,请稍后再试");
}
}
5.2.2 单独审批
@PostMapping("/approveTaskId")
public void approveTaskId(@RequestBody Map<String, Object> map) {
String taskId = (String) map.get("taskId");
String processInstanceId = (String) map.get("processInstanceId");
// 获取当前审批人
String assignee = (String) map.get("assignee");
// 获取参数
LinkedHashMap<String, Object> paramMap = (LinkedHashMap) map.get("paramMap");
// 获取审批状态是true还是false,添加审批备注
boolean approved = (boolean) paramMap.get("approved");
taskService.addComment(taskId, processInstanceId, assignee + (approved ? "通过" : "不通过"));
// 执行任务
taskService.complete(taskId, paramMap);
}
5.3 查看需要审批的内容
@PostMapping("/select-task-content")
public void selectTaskContent(@RequestBody Map<String, Object> map) {
String taskId = (String) map.get("taskId");
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
System.out.println(task);
}
6.查看流程图
@GetMapping("/genProcessDiagram")
public void genProcessDiagram(HttpServletResponse httpServletResponse, @RequestParam String processId) throws IOException {
// 获得当前活动的节点
String processDefinitionId = "";
boolean b = historyService.createHistoricProcessInstanceQuery().finished()
.processInstanceId(processId).count() > 0;
if (b) {// 如果流程已经结束,则得到结束节点
HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).singleResult();
processDefinitionId = pi.getProcessDefinitionId();
} else {// 如果流程没有结束,则取当前活动节点
// 根据流程实例ID获得当前处于活动状态的ActivityId合集
ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
processDefinitionId = pi.getProcessDefinitionId();
}
List<String> highLightedActivitis = new ArrayList<String>();
// 获得活动的节点
List<HistoricActivityInstance> highLightedActivitList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processId).orderByHistoricActivityInstanceStartTime().asc().list();
for (HistoricActivityInstance tempActivity : highLightedActivitList) {
String activityId = tempActivity.getActivityId();
highLightedActivitis.add(activityId);
}
List<String> flows = new ArrayList<>();
//获取流程图
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
// 设置支持中文的字体
String activityFontName = "SimSun"; // 宋体
String labelFontName = "SimSun"; // 宋体
String annotationFontName = "SimSun"; // 宋体
InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", highLightedActivitis, flows, activityFontName,
labelFontName, annotationFontName, engconf.getClassLoader(), 1.0, true);
OutputStream out = null;
byte[] buf = new byte[1024];
int legth = 0;
try {
out = httpServletResponse.getOutputStream();
while ((legth = in.read(buf)) != -1) {
out.write(buf, 0, legth);
}
} catch (IOException e) {
e.getMessage();
} finally {
IOUtils.closeQuietly(out);
IOUtils.closeQuietly(in);
}
}
结果如下: