1、安装maven依赖
bash
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>7.2.0</version>
</dependency>
2、yml配置文件
bash
spring:
servlet:
multipart:
max-file-size: 500MB
max-request-size: 600MB
threads:
virtual:
enabled: true
#配置数据源
datasource:
#MySQL
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/flowable_test?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: root
password: xxxxxx
hikari:
max-lifetime: 70000
flowable:
# 开启定时任务JOB
async-executor-activate: false
# 在引擎启动时,会自动更新数据库架构
database-schema-update: true
3、开启异步线程池
bash
package com.example.flowable_eng.config;
import jakarta.servlet.annotation.WebServlet;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
public class AnsycConfig {
@Bean("applicationTaskExecutor")
public ThreadPoolTaskExecutor applicationTaskExecutor() {
ThreadPoolTaskExecutor executor=new ThreadPoolTaskExecutor();
//此方法返回可用处理器的虚拟机的最大数量; 不小于1
int core= Runtime.getRuntime().availableProcessors();
executor.setCorePoolSize(core);//设置核心线程数
executor.setMaxPoolSize(core * 2 + 1);//设置最大线程数
executor.setKeepAliveSeconds(120);//除核心线程外的线程存活时间
executor.setQueueCapacity(120);//如果传入值大于0,底层队列使用的是LinkedBlockingQueue,否则默认使用SynchronousQueue
executor.setThreadNamePrefix("thread-default-execute");//线程名称前缀
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());//设置拒绝策略,抛出 RejectedExecutionException来拒绝新任务的处理。
// executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//设置拒绝策略,使用主线程
// executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());//设置拒绝策略,直接丢弃掉
// executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());//设置拒绝策略,丢弃最早的未处理的任务请求。
return executor;
}
}
4、前期准备流程文件,可参考我之前的文章
5、关于流程部署接口及其实现
1)新建接口IFlowableDeployService
java
package com.example.flowable_eng.service;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import java.util.List;
public interface IFlowableDeployService {
//部署流程
String depolyFlow();
//删除流程部署
String removeDepolyFlow(String deploymentId);
//挂起流程定义
String suspendFlowByKey(String key);
//激活流程定义
String activateFlowByKey(String key);
//获取最新部署记录
Deployment getDeployment(String deploymentId);
//查询流程定义
List<ProcessDefinition> getProcessDefinitionList();
}
2)实现类FlowableDeployServiceImpl
java
package com.example.flowable_eng.service.impl;
import com.example.flowable_eng.service.IFlowableDeployService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.*;
import org.flowable.engine.impl.DeploymentQueryImpl;
import org.flowable.engine.impl.persistence.deploy.DeploymentManager;
import org.flowable.engine.impl.persistence.entity.*;
import org.flowable.engine.repository.*;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Slf4j
public class FlowableDeployServiceImpl implements IFlowableDeployService {
@Resource
@Lazy
private RepositoryService repositoryService;
@Override
@Transactional(rollbackFor = Exception.class)
public String depolyFlow() {
//部署流程
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("bpmn/请假流程.bpmn20.xml").deploy();
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.deploymentId(deployment.getId()).singleResult();
log.info("流程定义ID:{},版本号:{}", processDefinition.getId(),processDefinition.getVersion());
return "OK";
}
@Override
@Transactional(rollbackFor = Exception.class)
public String removeDepolyFlow(String deploymentId) {
//删除流程部署
repositoryService.deleteDeployment(deploymentId);
return "OK";
}
@Override
@Transactional(rollbackFor = Exception.class)
public String suspendFlowByKey(String key) {
//挂起流程定义
// log.info("挂载状态:{}",repositoryService.createProcessDefinitionQuery()
// .processDefinitionKey(key).singleResult().isSuspended());
// repositoryService.suspendProcessDefinitionByKey(key);
// log.info("挂载状态:{}",repositoryService.createProcessDefinitionQuery()
// .processDefinitionKey(key).singleResult().isSuspended());
repositoryService.suspendProcessDefinitionById(key);
return "OK";
}
@Override
@Transactional(rollbackFor = Exception.class)
public String activateFlowByKey(String key) {
//激活流程定义
// log.info("挂载状态:{}",repositoryService.createProcessDefinitionQuery()
// .processDefinitionKey(key).singleResult().isSuspended());
// repositoryService.activateProcessDefinitionByKey(key);
// log.info("挂载状态:{}",repositoryService.createProcessDefinitionQuery()
// .processDefinitionKey(key).singleResult().isSuspended());
repositoryService.activateProcessDefinitionById(key);
return "OK";
}
@Override
public Deployment getDeployment(String deploymentId) {
//查询最新的部署记录
return repositoryService.createDeploymentQuery()
.deploymentId(deploymentId)
.latest().singleResult();
}
@Override
public List<ProcessDefinition> getProcessDefinitionList() {
return repositoryService.createProcessDefinitionQuery()
.processDefinitionKeyLike("*")
.list();
}
}
6、运行时接口及其实现类
1)接口IFlowableRuntimeService
java
package com.example.flowable_eng.service;
public interface IFlowableRuntimeService {
//开始流程
String startProcess(String processKey);
//执行流程
String executeProcess(String processInstanceId);
//唤醒触发流程实例
String processTrigger(String processInstanceId);
}
2)实现类FlowableRuntimeServiceImpl
java
package com.example.flowable_eng.service.impl;
import com.example.flowable_eng.listener.MyUserTaskListener;
import com.example.flowable_eng.service.IFlowableRuntimeService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.IdentityService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Map;
@Service
@Slf4j
public class FlowableRuntimeServiceImpl implements IFlowableRuntimeService {
@Resource
@Lazy
private RuntimeService runtimeService;
@Resource
@Lazy
private TaskService taskService;
@Resource
@Lazy
private IdentityService identityService;
@Override
@Transactional(rollbackFor = Exception.class)
public String startProcess(String processKey) {
Map<String,Object> variableMap=Map.of("myUserTaskListener",new MyUserTaskListener());
//方式1
ProcessInstance processInstance=runtimeService.startProcessInstanceByKey(processKey,variableMap);
// ProcessInstance processInstance=runtimeService.createProcessInstanceBuilder()
// .processDefinitionId(processKey).name("simple flow").start();
log.info("流程实例ID:{},流程定义ID:{},流程实例名称:{}",processInstance.getId(),
processInstance.getProcessDefinitionId(),processInstance.getName());
//给任务指派人员
Task task = taskService.createTaskQuery()
.processInstanceId(processInstance.getId()).singleResult();
taskService.setAssignee(task.getId(),"admin");
return processInstance.getProcessInstanceId();
}
@Override
public String executeProcess(String processInstanceId) {
Task task = taskService.createTaskQuery()
.processInstanceId(processInstanceId).singleResult();
taskService.complete(task.getId(),"admin");
return "OK";
}
@Override
@Transactional(rollbackFor = Exception.class)
public String processTrigger(String processInstanceId) {
//执行实例
Execution execution=runtimeService.createExecutionQuery()
.processInstanceId(processInstanceId).onlyChildExecutions()
.singleResult();
runtimeService.trigger(execution.getId());
return "OK";
}
}
7、任务接口及其实现类
1)接口IFlowableTaskService
java
package com.example.flowable_eng.service;
import org.flowable.task.api.Task;
import java.util.List;
public interface IFlowableTaskService {
List<Task> getFlowableTaskList(String userId);
}
2)实现类FlowableTaskServiceImpl
java
package com.example.flowable_eng.service.impl;
import com.example.flowable_eng.service.IFlowableTaskService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.TaskService;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
@Slf4j
public class FlowableTaskServiceImpl implements IFlowableTaskService {
@Resource
@Lazy
private TaskService taskService;
@Override
public List<Task> getFlowableTaskList(String userId) {
String processInstanceId="c650b4be-3bc5-11f1-8598-84a93e7930d9";
TaskQuery taskQuery=taskService.createTaskQuery().processInstanceId(processInstanceId);
Task task = taskQuery.singleResult();
//设置办理人
taskService.setAssignee(task.getId(),userId);
//设置评论
taskService.addComment(task.getId(),processInstanceId,"测试评论");
taskService.complete(task.getId(),userId);
//下一步
Task nextTask = taskService.createTaskQuery()
.processInstanceId(processInstanceId).singleResult();
if(nextTask!=null){
taskService.addCandidateUser(nextTask.getId(),userId);
taskService.addCandidateUser(nextTask.getId(),"zhangming");
}
// taskService.claim(task.getId(),userId);//候选人认领任务
return new ArrayList<>();
}
}
8、历史记录接口及其实现类
1)接口IFlowableHistoryService
java
package com.example.flowable_eng.service;
import java.util.Map;
public interface IFlowableHistoryService {
Map<String, Long> getTableInfoMap();
}
2)实现类FlowableHistoryServiceImpl
java
package com.example.flowable_eng.service.impl;
import com.example.flowable_eng.service.IFlowableHistoryService;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.HistoryService;
import org.flowable.engine.ManagementService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
@Service
@Slf4j
public class FlowableHistoryServiceImpl implements IFlowableHistoryService {
@Resource
@Lazy
private HistoryService historyService;
@Resource
@Lazy
private ManagementService managementService;
@Override
public Map<String, Long> getTableInfoMap() {
List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
.list();
list.forEach(v -> {
log.info("任务id:{},任务名称:{}",v.getId(),v.getName());
});
return Map.of("res",1000L);
}
}
9、身份管理接口及其实现类
1)接口IFlowableIdentityService
java
package com.example.flowable_eng.service;
import java.util.List;
import java.util.Map;
public interface IFlowableIdentityService {
//新建用户
String insertFlowUser(Map<String,String> userBody);
//查询用户
String queryFlowUser();
//更新用户
String updateFlowUser(Map<String,String> userBody);
//根据id删除用户
String removeFlowUser(String userId);
//新建用户组
String insertFlowGroup(Map<String,String> params);
//查询用户组
List<Map<String,String>> getFlowGroupList(Map<String,String> params);
//更新用户组
String updateFlowGroup(Map<String,String> params);
//删除用户组
String removeFlowGroup(String groupId);
//将用户添加到用户组
String addUserToGroup(String userId,String groupId);
//将用户从用户组移除
String removeUserToGroup(String userId,String groupId);
}
2)实现类FlowableIdentityServiceImpl
java
package com.example.flowable_eng.service.impl;
import com.example.flowable_eng.service.IFlowableIdentityService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.exceptions.PersistenceException;
import org.flowable.engine.IdentityService;
import org.flowable.idm.api.Group;
import org.flowable.idm.api.GroupQuery;
import org.flowable.idm.api.User;
import org.flowable.idm.api.UserQuery;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@Service
@Slf4j
public class FlowableIdentityServiceImpl implements IFlowableIdentityService {
@Resource
private IdentityService identityService;
@Override
@Transactional(rollbackFor = Exception.class)
public String insertFlowUser(Map<String,String> userBody) {
try {
User user = identityService.newUser(userBody.get("id"));
user.setFirstName(userBody.get("firstName"));
user.setLastName(userBody.get("lastName"));
user.setEmail(userBody.get("email"));
user.setDisplayName(userBody.get("displayName"));
user.setTenantId(userBody.get("tenantId"));
user.setPassword(userBody.get("password"));
identityService.saveUser(user);
}catch (PersistenceException ex){
ex.printStackTrace();
throw new RuntimeException("不得重复");
}
return "OK";
}
@Override
public String queryFlowUser() {
UserQuery userQuery=identityService.createUserQuery();
List<User> users=userQuery.userDisplayNameLike("%明%").list();
users.forEach(v->{
System.out.println(v.getDisplayName());
System.out.println(v.getFirstName());
System.out.println(v.getLastName());
});
System.out.println(userQuery.count());
User user1=identityService.createUserQuery().userId("12344321").singleResult();
System.out.println(user1.getDisplayName());
return "OK";
}
@Override
@Transactional(rollbackFor = Exception.class)
public String updateFlowUser(Map<String,String> userBody) {
User user=identityService.createUserQuery().userId(userBody.get("id")).singleResult();
user.setPassword(userBody.get("password"));
user.setEmail(userBody.get("email"));
user.setDisplayName(userBody.get("displayName"));
user.setTenantId(userBody.get("tenantId"));
user.setFirstName(userBody.get("firstName"));
user.setLastName(userBody.get("lastName"));
//更新密码
identityService.updateUserPassword(user);//更新用户,同时修改密码
// identityService.saveUser(user);//更新用户,但跨过密码字段
return "OK";
}
@Override
@Transactional(rollbackFor = Exception.class)
public String removeFlowUser(String userId) {
identityService.deleteUser(userId);
return "OK";
}
@Override
@Transactional(rollbackFor = Exception.class)
public String insertFlowGroup(Map<String, String> params) {
try {
Group group=identityService.newGroup(params.get("groupId"));
group.setName(params.get("name"));
group.setType(params.get("type"));
identityService.saveGroup(group);
}catch (PersistenceException ex){
ex.printStackTrace();
throw new RuntimeException("不得重复");
}
return "OK";
}
@Override
public List<Map<String, String>> getFlowGroupList(Map<String, String> params) {
GroupQuery groupQuery=identityService.createGroupQuery()
.groupNameLike("%"+params.get("name")+"%");
//groupQuery.listPage(1,10);//分页查询
System.out.println("数量");
System.out.println(groupQuery.count());
// System.out.println(groupQuery.listPage(0,10));
return groupQuery.list().stream().map(v->{
Map<String,String> map=new LinkedHashMap<>();
map.put("id",v.getId());
map.put("name",v.getName());
map.put("type",v.getType());
return map;
}).toList();
}
@Override
@Transactional(rollbackFor = Exception.class)
public String updateFlowGroup(Map<String, String> params) {
Group group=identityService.createGroupQuery()
.groupId(params.get("groupId")).singleResult();
group.setType(params.get("type"));
group.setName(params.get("name"));
identityService.saveGroup(group);
return "OK";
}
@Override
@Transactional(rollbackFor = Exception.class)
public String removeFlowGroup(String groupId) {
identityService.deleteGroup(groupId);
return "OK";
}
@Override
@Transactional(rollbackFor = Exception.class)
public String addUserToGroup(String userId, String groupId) {
identityService.createMembership(userId,groupId);
return "OK";
}
@Override
@Transactional(rollbackFor = Exception.class)
public String removeUserToGroup(String userId, String groupId) {
identityService.deleteMembership(userId,groupId);
return "OK";
}
}
10、执行监听器
1)定义ExecutionListener接口的实现类
java
package com.example.flowable_eng.listener;
import org.flowable.common.engine.impl.interceptor.Command;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
public class MyUserTaskExecutionListener implements ExecutionListener {
@Override
public void notify(DelegateExecution execution) {
System.out.println("执行监听器");
System.out.println("活动id");
System.out.println(execution.getCurrentActivityId());
System.out.println("活动名称");
System.out.println(execution.getCurrentActivityName());
System.out.println("事件名称");
System.out.println(execution.getEventName());
System.out.println("**********");
}
}
2)然后以流程变量的形式传入,建议选择委托表达式
11、任务监听器
1)实现TaskListener接口的实现类
java
package com.example.flowable_eng.listener;
import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
import org.flowable.engine.delegate.TaskListener;
import org.flowable.task.service.delegate.DelegateTask;
public class MyUserTaskListener implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
System.out.println(delegateTask.getEventName());
System.out.println(delegateTask.getTaskDefinitionKey());
System.out.println(delegateTask.getName());
System.out.println("******");
}
}
2)然后以流程变量的形式传入,建议选择委托表达式
12、全局事件监听器
1)实现FlowableEventListener接口的实现类
java
package com.example.flowable_eng.listener;
import org.flowable.common.engine.api.delegate.event.*;
import org.flowable.engine.delegate.event.FlowableActivityEvent;
public class GlobalEventListener implements FlowableEventListener {
@Override
public void onEvent(FlowableEvent event) {
FlowableEventType eventType = event.getType();
System.out.println("事件类型");
System.out.println(eventType);
if (event instanceof FlowableEngineEntityEvent engineEntityEvent) {
String processInstanceId = engineEntityEvent.getProcessInstanceId();
System.out.println("流程实例Id");
System.out.println(processInstanceId);
} else if (event instanceof FlowableActivityEvent flowableActivityEvent) {
System.out.println("活动实例id");
System.out.println(flowableActivityEvent.getActivityId());
}
System.out.println("******");
}
//在onEvent方法出现异常时,如果返回false则忽略,否则向上传递
@Override
public boolean isFailOnException() {
return true;
}
@Override
public boolean isFireOnTransactionLifecycleEvent() {
return false;
}
@Override
public String getOnTransaction() {
return "";
}
}
2)全局注册
java
package com.example.flowable_eng.config;
import com.example.flowable_eng.listener.GlobalEventListener;
import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent;
import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType;
import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.engine.delegate.ExecutionListener;
import org.flowable.spring.SpringProcessEngineConfiguration;
import org.flowable.spring.boot.EngineConfigurationConfigurer;
import org.flowable.spring.boot.ProcessEngineConfigurationConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.*;
import java.util.stream.Collectors;
@Configuration
public class FlowableConfig {
//全局事件监听器注册配置
@Bean
public EngineConfigurationConfigurer<SpringProcessEngineConfiguration> flowableEngineConfigurer() {
return configuration -> {
//监听全部类型的事件
// List<FlowableEventListener> listeners = new ArrayList<>();
// listeners.add(new GlobalEventListener());
// configuration.setEventListeners(listeners);
//监听指定类型的事件
Map<String, List<FlowableEventListener>> typedListenerMap = new HashMap<>();
List<String> listenerTypes=List.of(FlowableEngineEventType.PROCESS_STARTED.toString(),FlowableEngineEventType.PROCESS_COMPLETED.toString());
List<FlowableEventListener> listeners = List.of(new GlobalEventListener());
// FlowableEngineEventType.TASK_CREATED,FlowableEngineEventType.TASK_COMPLETED
typedListenerMap.put(listenerTypes.parallelStream().collect(Collectors.joining(",")), listeners);
configuration.setTypedEventListeners(typedListenerMap);
configuration.setEnableEventDispatcher(true);//是否开启事件监听器
configuration.setEnableDatabaseEventLogging(false);//日志监听器
};
}
}
13、注意:关于流程实例,当发起流程后,有两个实例,一个是流程实例,一个是主执行实例。