flowable集成flowable及其运行示例spring boot后端

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、前期准备流程文件,可参考我之前的文章

flowable

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、注意:关于流程实例,当发起流程后,有两个实例,一个是流程实例,一个是主执行实例。

相关推荐
代码不停1 小时前
Spring IoC&DI
java·后端·spring
我是一颗柠檬1 小时前
【Redis】数据类型详解Day2(2026年)
数据库·redis·后端·缓存
KANGBboy1 小时前
java知识二(数组)
java·开发语言·python
爱笑的源码基地1 小时前
智慧班牌源码:从后端SpringBoot到前端Vue2的全栈实现
java·大数据·云计算·源码·程序代码·智慧校园源码·智慧班牌源码
土狗TuGou1 小时前
SQL内功笔记 · 第7篇:CTE&临时表&递归
数据库·笔记·后端·sql·mysql
XiYang-DING1 小时前
【Spring】日志
java·数据库·spring
Reisentyan2 小时前
[Pro]GoLang Learn Data Day 5
开发语言·后端·golang
雪度娃娃2 小时前
转向现代C++——优先选用删除函数而非private未定义函数
java·jvm·c++