较早的⼯作流是jBPM,这是⼀个由Java实现的企业级流程引擎,是JBoss公司开发的产品之⼀。jBPM 的创建者是Tom Baeyens,这个⼤佬后来离开了JBoss,并加⼊到Alfresco,并推出了基于jBPM4的开源⼯作流系统Activiti,⽽jBPM则在后续的代码中完全放弃了jBPM4的代码。
从这个过程中也能看出来,jBPM 在发展过程中,由于意⻅相左,后来变成了两个jBPM和Activiti。然⽽戏剧的是,Activiti5没搞多久,从Activiti中⼜分出来⼀个Camunda,Activiti继续发展,⼜从中分出来⼀个Flowable。
现在市⾯上主流的流程引擎就⼀共有三个:Activiti、Flowable、Camunda这三个各有特点:
1.Activiti ⽬前是侧重云,他⽬前的设计会向Spring Cloud、Docker 这些去靠拢 。
2.Flowable 核⼼思想还是在做⼀个功能丰富的流程引擎⼯具,除了最最基础的⼯作流,他还提供了很多其他的扩展点,我们可以基于 Flowable 实现出许多我们想要的功能。
3.Camunda 相对于前两个⽽⾔⽐较轻量级,Camunda 有⼀个⽐较有特⾊的功能就是他提供了⼀个⼩巧的编辑器,基于 bpmn.io 来实现的。如果 你的项⽬需求是做⼀个轻巧的、灵活的、定制性强的编辑器,⼯作流是嵌⼊式的,那么可以选择 Camunda 。
基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
项目地址:https://github.com/YunaiV/ruoyi-vue-pro 视频教程:https://doc.iocoder.cn/video/ 以简单的请假流程为例:
一个流程图主要包含四个方面:
在一个流程图中肯定要有的是开始事件和结束事件,就是上图中的圆圈,此外还有一些中间事件,边界事件等。
连线是将事件,任务,网关等连在一起的线条,一般情况下都是普通连线,有的会有一些条件,比如上图中从网关出来的连线需要根据请假申请的审批结果确定走那一条连线
这个任务并不需要处理额外的事,流程到这一步就自动停下来了,需要人工点一下,推动流程继续向下执行。
一般用来吧消息发送给外部参与者
一般由系统自动完成,我们需要自定义一个类,可以在这个自定义的类里面完成自己想要做的事,比较灵活
一个自动化活动,当流程执行到脚本任务时,自动执行相应的脚本
用于为那些需要人工参与者完成的工作建模
服务主要分为两大类
用户任务: 一般表示人工需要介入的事情,比如是否同意,或者一些表单输入,需要让人工完成,一般用户任务和表单结合在一起,用户任务需要用户向引擎提交一个完成任务的动作,否则流程会暂停在这里等待。服务任务: 服务任务会自动执行,调用服务任务的时候,可以是一个javabean,也可以是一个类的全限定名,也可以是一个远程rest服务,流程会自动执行服务任务。也叫排他性网关,这种网关只有一个有效出口
这种网关有多个出口,只要满足条件,都会执行
事件网关是通过中间事件驱动,它在等待的事件发生后才会触发决策,基于事件的网关允许基于事件做出决策
并行网关一般是成对出现的,如果有一些任务可以并行执行,那么可以用并行网关
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
项目地址:https://github.com/YunaiV/yudao-cloud 视频教程:https://doc.iocoder.cn/video/ idea 创建spring boot 项目相信大家都很熟练了,就不再赘述了,因为flowable需要用到数据库,所以需要引入mysql和mybatis依赖
引入flowable依赖
<dependency > <groupId > org.flowablegroupId > <artifactId > flowable-spring-boot-starterartifactId > <version > 6.7.2version >dependency >
默认情况下,位于resources/processes
目录下的历程都会被自动部署
配置数据库连接信息,项目启动会自动初始化数据库(建表,初始化流程信息),流程引擎运行时候的数据也会被保存到数据库中。
spring: datasource: driverClassName: com.mysql.jdbc.Driver url: jdbc:mysql://ip:port/process?useSSL=false&useUnicode=true&characterEncoding=utf-8 username: username password: pw
可以集成flowableUI画,也可以使用idea插件
本文使用Flowable BPMN visualizer
插件画流程图
在processes目录下新建流程文件
本文新建的为ask_for_leave.bpmn20.xml
.bpmn20.xml 是固定后缀
在文件上右击,选择View BPMN(Flowable) Diagram就可以可视化的绘制流程图了
如果需要新添加一个流程图元素,则需要右键,根据需要选择即可
我画的流程图如下:
1、首先根据业务流程把各个流程画出并链接起来,开始事件–>员工的用户任务(员工发起请假流程)–>组长用户任务(组长审批是否同意)–>组长审批网关(如果不同意,则发送失败提示并结束流程,如果同意进入经理审批任务)–> 经理审批任务(经理审批是否同意)–> 组长审批网关(如果不同意,则发送失败提示并结束流程,如果同意结束流程)
2、员工用户任务配置:需要注意的点在于需要配置Assignee(办理人)属性,该属性一般为员工id
3、组长审批 用户任务 和 经理审批用户任务的配置和员工的类似,办理人都需要指定为用户ID
4、组长审批网关和经理审批网关我们使用互斥网关,因为在审批的时候只能是同意或者不同意,其他没有特殊配置
5、组长审批通过连线:需要配置条件表达式,用来判断什么情况下走这个连线,我们配置表达式为 ${var:equals(checkResult,“通过”)}
,这个地方的表达式是el表达式,会自动计算,checkResult是在组长审批的用户任务中,表单提交的数据
6、发送失败提示 服务任务:服务任务会自动执行,所需要指定class 这个类需要自己实现接口
自动生成的流程定义文件
<definitions xmlns ="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd ="http://www.w3.org/2001/XMLSchema" xmlns:flowable ="http://flowable.org/bpmn" xmlns:bpmndi ="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc ="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi ="http://www.omg.org/spec/DD/20100524/DI" typeLanguage ="http://www.w3.org/2001/XMLSchema" expressionLanguage ="http://www.w3.org/1999/XPath" targetNamespace ="http://www.flowable.org/processdef" > <process id ="ask_for_leave" name ="ask_for_leave" isExecutable ="true" > <startEvent id ="sid-3cb4e010-243b-401b-9ad3-4a1f8ecf35d7" /> <userTask id ="sid-c60eebb9-3a5b-48f9-963c-d0b064344fad" name ="请假" flowable:assignee ="#{leaveTask}" > <documentation > 员工请假documentation > userTask > <sequenceFlow id ="sid-ff0c2afe-1c1c-4e2f-b2eb-5083c5fadb41" sourceRef ="sid-3cb4e010-243b-401b-9ad3-4a1f8ecf35d7" targetRef ="sid-c60eebb9-3a5b-48f9-963c-d0b064344fad" /> <userTask id ="sid-dafc35fa-fa0f-49af-9f46-7074fa5a60ab" name ="组长审批" flowable:assignee ="#{zuzhangTask}" /> <sequenceFlow id ="sid-32a2a643-9ce6-44f3-bb94-f9df3d97c49b" sourceRef ="sid-c60eebb9-3a5b-48f9-963c-d0b064344fad" targetRef ="sid-dafc35fa-fa0f-49af-9f46-7074fa5a60ab" /> <exclusiveGateway id ="sid-c03f8946-a6cd-4e38-881a-70d450e32748" name ="组长审批网关" /> <sequenceFlow id ="sid-bbed6467-cc35-41d2-ad08-2c3b17b8ca83" sourceRef ="sid-dafc35fa-fa0f-49af-9f46-7074fa5a60ab" targetRef ="sid-c03f8946-a6cd-4e38-881a-70d450e32748" /> <sequenceFlow id ="sid-afe09a37-7634-4166-8617-68d5f35edef7" sourceRef ="sid-c03f8946-a6cd-4e38-881a-70d450e32748" targetRef ="sid-c9544983-0465-43e0-b6fc-1dbd0f1e0687" name ="组长审批通过" > <conditionExpression xsi:type ="tFormalExpression" > ${var:equals(checkResult,"通过")}conditionExpression > sequenceFlow > <sequenceFlow id ="sid-df2ad71d-6aa1-4d43-a9f9-bbdad8687e3a" sourceRef ="sid-c03f8946-a6cd-4e38-881a-70d450e32748" targetRef ="sid-e720a425-9f57-4a42-9833-b5f4f0175840" name ="组长审批拒绝" > <conditionExpression xsi:type ="tFormalExpression" > ${var:equals(checkResult,"拒绝")}conditionExpression > sequenceFlow > <userTask id ="sid-c9544983-0465-43e0-b6fc-1dbd0f1e0687" name ="经理审批" flowable:assignee ="#{manageTask}" /> <exclusiveGateway id ="sid-970d87f2-84d0-4603-ae25-163a0ae7ca53" name ="经理审批网关" /> <sequenceFlow id ="sid-ffa6dd8b-ae8d-47a5-a2ff-45d25e58dcac" sourceRef ="sid-c9544983-0465-43e0-b6fc-1dbd0f1e0687" targetRef ="sid-970d87f2-84d0-4603-ae25-163a0ae7ca53" /> <serviceTask id ="sid-e720a425-9f57-4a42-9833-b5f4f0175840" flowable:exclusive ="true" name ="发送失败提示" isForCompensation ="true" flowable:class ="com.xx.process.service.LeaveFailService" /> <endEvent id ="sid-f158c31d-d760-4a06-bb4a-6ff8b156d2fb" /> <sequenceFlow id ="sid-6e2fc1e3-43be-4768-96f5-d9c7861cbce7" sourceRef ="sid-e720a425-9f57-4a42-9833-b5f4f0175840" targetRef ="sid-f158c31d-d760-4a06-bb4a-6ff8b156d2fb" /> <sequenceFlow id ="sid-c90c5e3e-e5c2-40f0-8324-44d548de0ef2" sourceRef ="sid-970d87f2-84d0-4603-ae25-163a0ae7ca53" targetRef ="sid-e720a425-9f57-4a42-9833-b5f4f0175840" name ="经理审批拒绝" > <conditionExpression xsi:type ="tFormalExpression" > ${var:equals(checkResult,"拒绝")}conditionExpression > sequenceFlow > <endEvent id ="sid-ea363fd0-f4ad-4537-9faf-a9349aac16f1" /> <sequenceFlow id ="sid-5cad8e7b-8ee3-4e34-b94f-920a362f578d" sourceRef ="sid-970d87f2-84d0-4603-ae25-163a0ae7ca53" targetRef ="sid-ea363fd0-f4ad-4537-9faf-a9349aac16f1" name ="经理审批通过" > <conditionExpression xsi:type ="tFormalExpression" > ${var:equals(checkResult,"通过")}conditionExpression > sequenceFlow > process > <bpmndi:BPMNDiagram id ="BPMNDiagram_ask_for_leave" > <bpmndi:BPMNPlane bpmnElement ="ask_for_leave" id ="BPMNPlane_ask_for_leave" > <bpmndi:BPMNShape id ="shape-013aa23c-13e6-466e-942b-6a1a308eeda7" bpmnElement ="sid-3cb4e010-243b-401b-9ad3-4a1f8ecf35d7" > <omgdc:Bounds x ="-2235.0" y ="-1200.0" width ="30.0" height ="30.0" /> bpmndi:BPMNShape > <bpmndi:BPMNShape id ="shape-10dbd0c8-a3b1-4a9e-b214-5c506e80fd1d" bpmnElement ="sid-c60eebb9-3a5b-48f9-963c-d0b064344fad" > <omgdc:Bounds x ="-2145.0" y ="-1224.9999" width ="100.0" height ="80.0" /> bpmndi:BPMNShape > <bpmndi:BPMNEdge id ="edge-97bf72f7-edcb-4813-9e03-73bc597d1492" bpmnElement ="sid-ff0c2afe-1c1c-4e2f-b2eb-5083c5fadb41" > <omgdi:waypoint x ="-2205.0" y ="-1185.0" /> <omgdi:waypoint x ="-2145.0" y ="-1184.9999" /> bpmndi:BPMNEdge > <bpmndi:BPMNShape id ="shape-df2f6c22-1d44-4180-94fb-87753f871822" bpmnElement ="sid-dafc35fa-fa0f-49af-9f46-7074fa5a60ab" > <omgdc:Bounds x ="-1945.0" y ="-1225.0001" width ="100.0" height ="80.0" /> bpmndi:BPMNShape > <bpmndi:BPMNEdge id ="edge-e0d1746e-e6b5-481a-a492-83881d2a9c22" bpmnElement ="sid-32a2a643-9ce6-44f3-bb94-f9df3d97c49b" > <omgdi:waypoint x ="-2045.0" y ="-1184.9999" /> <omgdi:waypoint x ="-1945.0" y ="-1185.0001" /> bpmndi:BPMNEdge > <bpmndi:BPMNShape id ="shape-6e0e9d80-5884-4ca5-847d-d3e555005c51" bpmnElement ="sid-c03f8946-a6cd-4e38-881a-70d450e32748" > <omgdc:Bounds x ="-1735.0" y ="-1205.0" width ="40.0" height ="40.0" /> bpmndi:BPMNShape > <bpmndi:BPMNEdge id ="edge-9dbfbe2b-c839-44eb-b74b-fceee48631b7" bpmnElement ="sid-bbed6467-cc35-41d2-ad08-2c3b17b8ca83" > <omgdi:waypoint x ="-1845.0" y ="-1185.0001" /> <omgdi:waypoint x ="-1735.0" y ="-1185.0" /> bpmndi:BPMNEdge > <bpmndi:BPMNShape id ="shape-1ff96c95-d96d-4241-9d0f-85414bbb3859" bpmnElement ="sid-c9544983-0465-43e0-b6fc-1dbd0f1e0687" > <omgdc:Bounds x ="-1570.0" y ="-1224.9999" width ="100.0" height ="80.0" /> bpmndi:BPMNShape > <bpmndi:BPMNEdge id ="edge-f8f6488f-354a-490c-9d22-1f57e9a654d4" bpmnElement ="sid-afe09a37-7634-4166-8617-68d5f35edef7" > <omgdi:waypoint x ="-1695.0" y ="-1185.0" /> <omgdi:waypoint x ="-1632.5" y ="-1185.0" /> <omgdi:waypoint x ="-1570.0" y ="-1184.9999" /> bpmndi:BPMNEdge > <bpmndi:BPMNShape id ="shape-bb52e23c-ee53-4073-9b74-c5dca8459100" bpmnElement ="sid-970d87f2-84d0-4603-ae25-163a0ae7ca53" > <omgdc:Bounds x ="-1395.0" y ="-1205.0" width ="40.0" height ="40.0" /> bpmndi:BPMNShape > <bpmndi:BPMNEdge id ="edge-6e5e32bc-5b44-41f5-97e6-458c1aa7b7f3" bpmnElement ="sid-ffa6dd8b-ae8d-47a5-a2ff-45d25e58dcac" > <omgdi:waypoint x ="-1470.0" y ="-1184.9999" /> <omgdi:waypoint x ="-1395.0" y ="-1185.0" /> bpmndi:BPMNEdge > <bpmndi:BPMNShape id ="shape-26269b4b-a620-4e2f-a463-145fdfd8c0b1" bpmnElement ="sid-e720a425-9f57-4a42-9833-b5f4f0175840" > <omgdc:Bounds x ="-1764.9999" y ="-1055.0" width ="100.0" height ="80.0" /> bpmndi:BPMNShape > <bpmndi:BPMNShape id ="shape-47431d28-2f8b-4b2c-81e0-19dc832d1880" bpmnElement ="sid-f158c31d-d760-4a06-bb4a-6ff8b156d2fb" > <omgdc:Bounds x ="-1910.0" y ="-1030.0" width ="30.0" height ="30.0" /> bpmndi:BPMNShape > <bpmndi:BPMNEdge id ="edge-cfc9460b-eaf6-44ee-9baa-300e89b18f4d" bpmnElement ="sid-6e2fc1e3-43be-4768-96f5-d9c7861cbce7" > <omgdi:waypoint x ="-1764.9999" y ="-1015.0" /> <omgdi:waypoint x ="-1880.0" y ="-1015.0" /> bpmndi:BPMNEdge > <bpmndi:BPMNEdge id ="edge-46d26639-0c9b-40da-b5ec-10678783920b" bpmnElement ="sid-c90c5e3e-e5c2-40f0-8324-44d548de0ef2" > <omgdi:waypoint x ="-1375.0" y ="-1165.0" /> <omgdi:waypoint x ="-1375.0" y ="-1015.0" /> <omgdi:waypoint x ="-1664.9998" y ="-1015.0" /> bpmndi:BPMNEdge > <bpmndi:BPMNShape id ="shape-cfc8c0f0-f529-4023-83a6-e8635533be1b" bpmnElement ="sid-ea363fd0-f4ad-4537-9faf-a9349aac16f1" > <omgdc:Bounds x ="-1200.0" y ="-1200.0" width ="30.0" height ="30.0" /> bpmndi:BPMNShape > <bpmndi:BPMNEdge id ="edge-5c22485e-bc92-4af7-b814-6f384c98ba5d" bpmnElement ="sid-5cad8e7b-8ee3-4e34-b94f-920a362f578d" > <omgdi:waypoint x ="-1355.0" y ="-1185.0" /> <omgdi:waypoint x ="-1200.0" y ="-1185.0" /> bpmndi:BPMNEdge > <bpmndi:BPMNEdge id ="edge-eb5ecc69-91e8-4e50-81e2-14123d77ee2d" bpmnElement ="sid-df2ad71d-6aa1-4d43-a9f9-bbdad8687e3a" > <omgdi:waypoint x ="-1715.0" y ="-1165.0" /> <omgdi:waypoint x ="-1714.9999" y ="-1055.0" /> bpmndi:BPMNEdge > bpmndi:BPMNPlane > bpmndi:BPMNDiagram >definitions >
@Slf 4j@Component public class LeaveFailService implements JavaDelegate { @Override public void execute (DelegateExecution delegateExecution) { log.info("审批不通过{}" , delegateExecution.getCurrentActivityId()); } }
需要实现 JavaDelegate接口;在执行到服务任务的时候,就会自动调用这个方法,在这个方法中我们可以做一些自定义的业务逻辑
为了方便查看流程执行到那一步了,故增加该接口查看
开启流程的时候会生成一个流程id,使用该流程ID可查询流程进行到那一步了
/** * LeaveController * * @Description : * @Author : wangyubiao * 标签属性 ... * 网关:... * @Date 2023/5/12 13:26 * @since 1.0.0 */ @RestController public class LeaveController { @Autowired RuntimeService runtimeService; @Autowired RepositoryService repositoryService; @Autowired ProcessEngine processEngine; @GetMapping ("/pic" ) public void showPic (HttpServletResponse resp, String processId) throws Exception { ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); if (pi == null ) { return ; } List executions = runtimeService .createExecutionQuery() .processInstanceId(processId) .list(); List activityIds = new ArrayList<>(); List flows = new ArrayList<>(); for (Execution exe : executions) { List ids = runtimeService.getActiveActivityIds(exe.getId()); activityIds.addAll(ids); } /** * 生成流程图 */ BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId()); ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration(); ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator(); InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png" , activityIds, flows, engconf.getActivityFontName(), engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0 , false ); OutputStream out = null ; byte [] buf = new byte [1024 ]; int legth = 0 ; try { out = resp.getOutputStream(); while ((legth = in.read(buf)) != -1 ) { out.write(buf, 0 , legth); } } finally { if (in != null ) { in.close(); } if (out != null ) { out.close(); } } } }
查询结果:
import lombok.extern.slf4j.Slf4j;import org.flowable.engine.RuntimeService;import org.flowable.engine.TaskService;import org.flowable.engine.runtime.ProcessInstance;import org.flowable.task.api.Task;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.ActiveProfiles;import java.util.HashMap;import java.util.List;import java.util.Map;@SpringBootTest @Slf 4j@ActiveProfiles ("dev" )class ProcessApplicationTests { @Autowired RuntimeService runtimeService; @Autowired TaskService taskService; // 员工id public static final String yuangongId = "yuangongID_3" ; // 员工id public static final String zuzhangId = "zuzhangId_3" ; // 员工id public static final String manageId = "manageId_3" ; @Test void contextLoads () { } /** * 开启一个请假流程 */ @Test void askForLeave () { HashMap map = new HashMap<>(); map.put("leaveTask" , yuangongId); // 开启流程的key,就是流程定义文件里 process 标签的id ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("ask_for_leave" , map); // 设置一些参数 runtimeService.setVariable(processInstance.getId(), "name" , "javaboy" ); runtimeService.setVariable(processInstance.getId(), "reason" , "休息一下" ); runtimeService.setVariable(processInstance.getId(), "days" , 10 ); log.info("创建请假流程 processId:{}" , processInstance.getId()); } /** * 员工提交请假 */ @Test void submitToZuZhang () { // 员工查找到自己的任务,然后提交给组长审批 List list = taskService.createTaskQuery().taskAssignee(yuangongId).orderByTaskId().desc().list(); for (Task task: list) { log.info("任务 ID:{};任务处理人:{};任务是否挂起:{}" , task.getId(), task.getAssignee(), task.isSuspended()); Map map = new HashMap<>(); //提交给组长的时候,需要指定组长的 id map.put("zuzhangTask" , zuzhangId); taskService.complete(task.getId(), map); } } /** * 组长批准请假 */ @Test void zuZhangApprove () { List list = taskService.createTaskQuery().taskAssignee(zuzhangId).orderByTaskId().desc().list(); for (Task task: list) { if ("组长审批" .equals(task.getName())) { log.info("任务 ID:{};任务处理人:{};任务是否挂起:{}" , task.getId(), task.getAssignee(), task.isSuspended()); Map map = new HashMap<>(); //提交给组长的时候,需要指定组长的 id map.put("manageTask" , manageId); map.put("checkResult" , "通过" ); map.put("zuzhangTask" , zuzhangId); try { taskService.complete(task.getId(), map); } catch (Exception e) { e.printStackTrace(); log.error("组长审批失败{} {}" , task.getId(), task.getAssignee()); } } } } /** * 经理审批通过 */ @Test void managerApprove () { List list = taskService.createTaskQuery().taskAssignee(manageId).orderByTaskId().desc().list(); for (Task task: list) { log.info("经理 {} 在审批 {} 任务" , task.getAssignee(), task.getId()); Map map = new HashMap<>(); map.put("checkResult" , "通过" ); taskService.complete(task.getId(), map); } } /** * 经理审批不通过 */ @Test void managerNotApprove () { List list = taskService.createTaskQuery().taskAssignee(manageId).orderByTaskId().desc().list(); for (Task task: list) { log.info("经理 {} 在审批 {} 任务" , task.getAssignee(), task.getId()); Map map = new HashMap<>(); map.put("checkResult" , "拒绝" ); taskService.complete(task.getId(), map); } } }
这是因为本地没有默认的字体,安装字体或者修改配置解决
import org.flowable.spring.SpringProcessEngineConfiguration;import org.flowable.spring.boot.EngineConfigurationConfigurer;import org.springframework.context.annotation.Configuration;/** * FlowableConfig * * @Description : * @Author : wangyubiao * @Date 2023/5/15 15:16 * @since 1.0.0 */ @Configuration public class FlowableConfig implements EngineConfigurationConfigurer <SpringProcessEngineConfiguration > { @Override public void configure (SpringProcessEngineConfiguration springProcessEngineConfiguration) { springProcessEngineConfiguration.setActivityFontName("宋体" ); springProcessEngineConfiguration.setLabelFontName("宋体" ); springProcessEngineConfiguration.setAnnotationFontName("宋体" ); } }
流程开始后,流程配置信息已经持久化了,修改流程定义文件,只会影响还没开始的流程,不会对已经开始的流程造成影响