SpringBoot整合Flowable/Activiti

SpringBoot版本: 2.0.1.RELEASE

Flowable版本: 6.3.1

Activiti版本: 6.0.0

一.添加pom依赖

    因为之前我整合的时候有报错关于sqlsession的错误,后面查询文章才发现flowable要排除掉mybatis,又没说具体排除哪一个,所以我这干脆全部排除了

<!-- Flowable dependencies -->
            <dependency>
                <groupId>org.flowable</groupId>
                <artifactId>flowable-spring-boot-starter</artifactId>
                <version>6.3.1</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.mybatis</groupId>
                        <artifactId>mybatis</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>org.flowable</groupId>
                <artifactId>flowable-engine</artifactId>
                <version>6.3.1</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.mybatis</groupId>
                        <artifactId>mybatis</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>org.flowable</groupId>
                <artifactId>flowable-spring</artifactId>
                <version>6.3.1</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.mybatis</groupId>
                        <artifactId>mybatis</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>org.flowable</groupId>
                <artifactId>flowable-rest</artifactId>
                <version>6.3.1</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.mybatis</groupId>
                        <artifactId>mybatis</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>org.flowable</groupId>
                <artifactId>flowable-cmmn-spring</artifactId>
                <version>6.3.1</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.mybatis</groupId>
                        <artifactId>mybatis</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>org.flowable</groupId>
                <artifactId>flowable-dmn-spring</artifactId>
                <version>6.3.1</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.mybatis</groupId>
                        <artifactId>mybatis</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>

<!--activiti modeler start-->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-json-converter</artifactId>
            <version>6.0.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.activiti</groupId>
                    <artifactId>activiti-bpmn-model</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

二.yml配置flowable/Activiti相关配置项

  至于层级关系,都是和spring同级的,我一般放在mybatis配置项下面,类似下面这样

  flowable:
    #关闭定时任务JOB
    async-executor-activate: false
    #  将databaseSchemaUpdate设置为true。当Flowable发现库与数据库表结构不一致时,会自动将数据库表结构升级至新版本。
    database-schema-update: true




  # activiti 模块
  activiti:
    # 解决启动报错:class path resource [processes/] cannot be resolved to URL because it does not exist
    check-process-definitions: false
    # 检测身份信息表是否存在
    db-identity-used: true
    # 默认为false
      # false:项目启动时,如果数据库中没有表将抛出异常(上线后使用)
      # true:项目启动时,如果数据库中没有表将自动生成(开发和测试时使用)
    database-schema-update: true

 三.数据库配置项中url添加&nullCatalogMeansCurrent=true配置

        因为我之前用过activiti工作流,如果不加这个配置工作流会默认查询整个数据库连接下所有的库,只要发现有相关的act表就会认为已经自动生成了. 导致你在A库有了工作流的表之后想在B库再去自动生成就会发现生成不了.加上这个配置就可以了,不知道flowable影不影响,我都习惯给加上了

#  nullCatalogMeansCurrent=true
#  因为mysql使用schema标识库名而不是catalog,因此mysql会扫描所有的库来找表,
#  如果其他库中有相同名称的表,activiti就以为找到了,本质上这个表在当前数据库中并不存在。
#  解决办法就是在数据库链接的配置后面加上 nullCatalogMeansCurrent=true,标识之搜索当前链接的库。
url: jdbc:mysql://192.168.*.*:3306/flowable?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true

四.启动项目 自动生成数据表

        这个会根据flowable的版本而来 实际可能不一致 我的flowable版本是6.3.1,生成了66张表

Activiti版本是6.0.0,生成了28张表

一些常用的需要关注的表的含义(注明了注释)

 

五.IDEA中安装Flowable/Activiti插件

        安装插件: Flowable BPMN visualizer / Activiti BPMN visualizer

        然后在resources目录下新建processes目录

        右键新建一个基于BOMN 2.0协议的文件

        绘制流程图 

 

        注意: flowable/Activiti都会将处于processes目录下的符合后缀名要求的文件自动部署

                 不想要这个功能你可以修改目录名或者查询网站搜索下相关的关闭命令

六.工作流提供的几个Service

Flowable和Activiti都给我们提供了几个Service

因为本身Flowable的团队就是从Activiti团队中过来的,所以Service的命名及使用基本都是一致的,会一个就会另一个

    // 运行时执行管理Service
    @Autowired
    private RuntimeService runtimeService;

    // 工作流任务管理Service
    @Autowired
    private TaskService taskService;

    // 管理流程定义Service
    @Autowired
    private RepositoryService repositoryService;

    // 核心类 可以理解为流程引擎对象
    @Autowired
    private ProcessEngine processEngine;

    // 历史管理Service
    @Autowired
    private HistoryService historyService;

七.常用方法

因为几乎所有业务都需要用到"PROC_INST_ID_" 也就是 "流程实例Id"

以及当前任务id-TASK_ID

所以我建议把这两个id都放在业务表中和你的业务表一对一关联(一般都是一个业务开一个流程实例)

1.动态部署

(提供一个文件,通过repositoryService创建部署对象去读取xml文件的内容来自动部署)

部署完之后ACT_RE_DEPLOYMENT,ACT_RE_PROCDEF两个表中会有数据

MultipartFile file; // 提供一个二进制文件对象
Deployment deployment = null;
        try{
            DeploymentBuilder deploymentBuilder =
                    repositoryService.createDeployment()
.name(Objects.requireNonNull(file.getOriginalFilename()).substring(0, file.getOriginalFilename().indexOf(".bpmn20.xml")))
                            .addInputStream(file.getOriginalFilename(),
                                    file.getInputStream());
            deployment = deploymentBuilder
                            .deploy();
        }catch (Exception e){
            e.printStackTrace();
            throw new CustomException("文件部署失败");
        }


// 部署完后可以获取部署ID
// 根据部署ID查询流程定义
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).singleResult();
System.out.println("流程【"+processDefinition.getName()+"】部署成功, 部署ID为: "+processDefinition.getDeploymentId()+"流程定义Key为: "+processDefinition.getKey());

2.流程启动

Map<String, Object> variables = new HashMap<>();

        variables.put("startUser", SecurityUtils.getLoginUser().getUser().getUserId().toString());
        variables.put("data", processInit.getData());
        variables.put("remark", processInit.getRemark());

        ProcessInstance processInstance = null;

        try{
            // 根据部署ID查询流程定义
            ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(processInit.getDeployId()).singleResult();

            //启动流程实例,同时还要指定业务标识businessKey  项目Id
            //第一个参数:是指流程定义key
            //第二个参数:业务标识businessKey
            processInstance = runtimeService.startProcessInstanceByKey(
                    processDefinition.getKey(),processInit.getWorkId().toString(),variables
            );

            runtimeService.setProcessInstanceName(processInstance.getId(),processDefinition.getName());

        启动后ACT_RU_EXECUTION会看到流程实例当前执行的节点概况,包括历史节点和当前时节点

PROC_INST_ID_是流程实例Id 

 

这两个表也可以看到实例相关节点信息

 

3.执行下一任务节点并添加审核备注

核心方法为: 

taskService.complete(task.getId());

需要注意的是:如果没有执行人,需要先认领任务而后才去审核任务

SysUser user = SecurityUtils.getLoginUser().getUser();
        String taskId; // 当前任务Id
        String processInstanceId; // 流程实例Id
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        String businessKey = processInstance.getBusinessKey(); // 流程实例的业务Id-businessKey

        // 获取当前待办任务
        Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).taskId(taskId).singleResult();
        if(task == null){
            throw new CustomException(CustomExceptionEnums.DATA_NOT_FOUND);
        }

        String assignee = task.getAssignee();
        if(StringUtils.isEmpty(assignee)){
            // 如果没有执行人 需要先认领任务
            taskService.claim(task.getId(),user.getUserId().toString());
        }
        if(StringUtils.isNotEmpty(processApproved.getRemark())){
            // 添加审批备注
            taskService.addComment(taskId, processInstanceId, ActivityCommentType.APPROVED_REMARK.getType(), processApproved.getRemark());
        }
        // 完成当前任务
        taskService.complete(task.getId());

 通过后可通过taskService获取下一个任务节点Id

// 获取下一个任务ID
List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstanceId).list();

4.获取待办/已办

因为Activiti和Flowable中并没有获取待办任务和已办任务的直接方法可以调用

所以需要我们自己写sql语句来获取

需要用到以下的表

待办任务所需

"ACT_RU_TASK"运行时任务节点表

"ACT_RU_IDENTITYLINK"运行时流程人员表

"ACT_HI_PROCINST"历史流程实例表

已办任务所需

"ACT_HI_TASKINST"历史任务节点表

"ACT_HI_PROCINST"历史流程实例表

然后我自己通过union将结果合并,并通过task_status来区分待办和已办

-- 待办和已办union all查询
select * from
(
select 0 as task_status,
RES.ID_ as task_id,RES.NAME_ as task_name,RES.CREATE_TIME_ as start_time,null as end_time,RES.PROC_INST_ID_ as process_instance_id,RES.ASSIGNEE_ as assignee,P.BUSINESS_KEY_  as business_key ,P.NAME_ as process_instance_name ,I.TYPE_ as type,I.USER_ID_ as user_id, I.GROUP_ID_ as group_id ,RES.TASK_DEF_KEY_ as task_def_key
from ACT_RU_TASK RES 
left join ACT_RU_IDENTITYLINK I on I.TASK_ID_ = RES.ID_ 
left join ACT_HI_PROCINST P on P.PROC_INST_ID_ = RES.PROC_INST_ID_ 

						
						
						UNION ALL
						
select 1 as task_status,
RES.ID_ as task_id,RES.NAME_ as task_name,RES.START_TIME_ as start_time,RES.END_TIME_ as end_time,RES.PROC_INST_ID_ as process_instance_id,RES.ASSIGNEE_ as assignee,P.BUSINESS_KEY_  as business_key ,P.NAME_ as process_instance_name ,null as type,null as user_id, null as group_id,RES.TASK_DEF_KEY_ as task_def_key
from ACT_HI_TASKINST RES 
left join ACT_HI_PROCINST P on P.PROC_INST_ID_ = RES.PROC_INST_ID_  and RES.END_TIME_ is not null
)v

然后可以通过条件查询,比如"执行人","执行部门","任务节点定义key"等来进行查询

(task_status : 待办/已办)

(assignee : 执行人Id)

(task_def_key : 任务节点定义key)

(type : 表示候选用户 

  • candidate: 表示候选用户或用户组。在任务尚未被领取时,这些用户或用户组可以领取任务。
  • participant: 表示任务的参与者。通常情况下,当任务被领取后,参与者就是具体执行任务的用户。
  • owner: 表示任务的所有者。在某些情况下,任务可能会指定一个所有者,通常是在任务创建时指定,这个所有者有特殊权限或责任来处理任务。

)

(group_id  : 部门Id)

(start_time : 任务节点生成时间)

(end_time : 任务节点完成时间)

比如以下的where条件可以用作待办任务的筛选查询

WHERE v.task_status = 0 and v.assignee = '1'  and v.task_def_key=  'sid-5db27d85-b516-4784-8b58-0f5c9e1c3235' or (v.assignee is null and v.type = 'candidate' and (v.user_id = '1' or v.group_id IN ( '土整中心','123' ) )) order by v.start_time desc

比如以下的where条件可以用作已办任务的筛选查询 

WHERE v.task_status = 1 and v.assignee = '1' and v.task_def_key=  'sid-8abc3887-40c5-49c2-b8c0-b4d3fdefb7a0' and v.end_time is not null order by v.end_time desc


5. 通过taskId获取该任务的备注

/**
     * 通过taskId获取该任务的备注
     * @param taskId 任务Id
     * @param commentType 备注类型
     * @return 备注详情
     */
    @Override
    public List<Comment> getCommentByTaskId(String taskId,String commentType){
        if(StringUtils.isNotEmpty(commentType)){
            // 带有type筛选
            return taskService.getTaskComments(taskId, commentType);
        }
        return taskService.getTaskComments(taskId);
    }

6.查询截止目前可驳回的节点列表

我的逻辑是查询当前已完成的用户任务,不包括"开始"节点(因为"开始"节点不是用户任务)

然后有一些特殊情况需要处理:

        比如多次驳回,因为每一次驳回实际上都是将当前任务节点完成然后再加一条"目标驳回任务节点"用作下一个节点

        比如多次驳回之后取最新的节点,不可能出现可驳回列表中出现两个key相同的节点,这不符合逻辑

/**
     * 查询截止目前可驳回的节点列表
     * @param processInstanceId 流程ID
     * @return 结果
     */
    @Override
    public List<ActHistoricActivityInstanceVo> getAllActInstByInstanceIdToSimple(String processInstanceId,String taskDefKey){
        // 只要用户任务
        // 目前已完成的用户任务
        List<HistoricActivityInstance> userTask = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().activityType("userTask").finished().list();

        // 流程定义时的用户任务
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        String processDefinitionId = processInstance.getProcessDefinitionId();
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult();
        // 定义时的所有节点
        Collection<FlowElement> flowElements = repositoryService.getBpmnModel(processDefinitionId).getMainProcess().getFlowElements();
        List<ActHistoricActivityInstanceVo> userTasks = new ArrayList<>();

        // 循环
        for (HistoricActivityInstance historicActivityInstance : userTask) {

            for (FlowElement flowElement : flowElements) {
                if (flowElement instanceof UserTask) {
                    UserTask definitionUserTask = (UserTask) flowElement;
                    String activityName = definitionUserTask.getName();
                    String activityId = definitionUserTask.getId();
                    String activityTaskDefKey = definitionUserTask.getId();
                    // 可以查看其他用户任务属性,如Assignee、Candidate Users、Candidate Groups等

                    // 获取任务定义对象信息
                    // 入参taskDefKey对应的对象
                    SysProcessTaskDef processTaskDef = sysProcessTaskDefMapper.selectSysProcessTaskDefById(taskDefKey);
                    // 当前循环体中taskDefKey对应的对象
                    SysProcessTaskDef currentTaskDef = sysProcessTaskDefMapper.selectSysProcessTaskDefById(activityTaskDefKey);
                    if(currentTaskDef.getSort() >= processTaskDef.getSort()){
                        // 不能驳回到后面的任务去(防止二次提交后可驳回的任务列表乱套)
                        continue;
                    }

                    // 如果Id匹配 就加入自定义集合返回
                    if(activityId.equals(historicActivityInstance.getActivityId()) && !activityTaskDefKey.equals(taskDefKey)){

                        ActHistoricActivityInstanceVo activityInstanceVo = new ActHistoricActivityInstanceVo();

                        activityInstanceVo.setActivityId(activityId);
                        activityInstanceVo.setActivityName(activityName);
                        // 对重复的跳过 (针对多次驳回导致存在多个相同节点的情况)
//                        if(userTasks.contains(activityInstanceVo)) continue;
                        ActHistoricActivityInstanceVo actHistoricActivityInstanceVo = userTasks.stream().
                                filter(u -> u.getActivityId().equals(activityInstanceVo.getActivityId())).findAny().orElse(null);
                        if(actHistoricActivityInstanceVo != null && actHistoricActivityInstanceVo.getStartTime().compareTo(historicActivityInstance.getStartTime()) < 0){
                            // 存在并且时间早于这一次就删除 (针对多次驳回导致存在多个相同节点的情况,取最新的节点审核情况)
                            userTasks.remove(actHistoricActivityInstanceVo);
                        }
                        // 转换赋值
                        BeanUtils.copyProperties(historicActivityInstance, activityInstanceVo);
                        // 获取type为isFillSteps的comment(是否为填报步骤:提交填报时的那个步骤)
                        List<Comment> comments = taskService.getTaskComments(activityInstanceVo.getTaskId(), "isFillSteps");
                        if(comments != null && comments.size() > 0){
                            activityInstanceVo.setFillSteps(true);
                        }
                        userTasks.add(activityInstanceVo);
                    }
                }
            }
        }
        if(userTasks.size() > 0){
            userTasks = userTasks.stream().sorted(Comparator.comparing(ActHistoricActivityInstanceVo::getStartTime)).collect(Collectors.toList());
        }
        return userTasks;
    }

 

7.驳回到指定节点

提供流程实例Id,当前任务Id,驳回目标任务Id



    /**
     * 驳回到指定节点
     * @param actRollbackIo 驳回对象
     */
    @Override
    @Transactional(rollbackFor = Throwable.class,propagation = Propagation.REQUIRES_NEW)
    public void rejectToNode(ActRollbackIo actRollbackIo){
        String processInstanceId = actRollbackIo.getProcessInstanceId();
        String currentTaskId = actRollbackIo.getTaskId(); // 当前任务
        String targetTaskId = actRollbackIo.getTargetTaskId(); // 驳回目标任务

        //  获取该流程所有的活动实例
        List<HistoricActivityInstance> hisActivityList = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(processInstanceId).list();

        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        String processDefinitionId = processInstance.getProcessDefinitionId();
        //  当前任务
        Task currentTask = taskService.createTaskQuery().taskId(currentTaskId).singleResult();

        //  驳回目标任务
        HistoricTaskInstance targetTask = historyService.createHistoricTaskInstanceQuery().finished().taskId(targetTaskId).singleResult();

        if(currentTask == null || targetTask == null){
            throw new CustomException(CustomExceptionEnums.MISSING_DATA_ERROR);
        }

        try{
            //  当前活动
            HistoricActivityInstance currentActivity = hisActivityList.stream().filter(e -> currentTask.getId().equals(e.getTaskId())).collect(Collectors.toList()).get(0);
            //  驳回目标活动
            HistoricActivityInstance targetActivity = hisActivityList.stream().filter(e -> targetTask.getId().equals(e.getTaskId())).collect(Collectors.toList()).get(0);

            //  获取xml文件对象
            BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);

            //  获取驳回目标活动节点
            FlowNode targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(targetActivity.getActivityId());
            //  获取当前活动节点
            FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivity.getActivityId());

            //  临时保存当前活动的原始方向
            List<SequenceFlow> originalSequenceFlowList = new ArrayList<>();
            originalSequenceFlowList.addAll(currentFlowNode.getOutgoingFlows());
            //  清理活动方向
            currentFlowNode.getOutgoingFlows().clear();

            //  建立新方向
            SequenceFlow newSequenceFlow = new SequenceFlow();
            newSequenceFlow.setId("newSequenceFlowId");
            newSequenceFlow.setSourceFlowElement(currentFlowNode);
            newSequenceFlow.setTargetFlowElement(targetFlowNode);
            List<SequenceFlow> newSequenceFlowList = new ArrayList<>();
            newSequenceFlowList.add(newSequenceFlow);
            //  当前节点指向新的方向
            currentFlowNode.setOutgoingFlows(newSequenceFlowList);

            //  完成当前任务
            taskService.claim(currentTaskId,SecurityUtils.getLoginUser().getUser().getUserId().toString());
            taskService.complete(currentTaskId);

            //  重新查询当前任务
            Task nextTask = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
            String assignee = (StringUtils.isNull(actRollbackIo.getAssignee())) ? targetTask.getAssignee() : actRollbackIo.getAssignee().toString();
            if (null != nextTask) {
                System.out.println("最新任务=="+nextTask);
                taskService.setAssignee(nextTask.getId(), assignee);
            }else{
                throw new CustomException(CustomExceptionEnums.OPERATION_FAILED);
            }

            //  恢复原始方向
            currentFlowNode.setOutgoingFlows(originalSequenceFlowList);
}

8.撤回 删除流程

    /**
     * 撤回 删除流程
     * @param processInstanceId 流程实例Id
     * @param fillId 任务填报Id
     * @param message 撤回备注信息
     */
    @Override
    @Transactional(rollbackFor = Throwable.class)
    public int revoke(String processInstanceId,Long fillId,String message){
        runtimeService.deleteProcessInstance(processInstanceId, message);
        historyService.deleteHistoricProcessInstance(processInstanceId);
        return landProjectFillService.cleanProcessInstance(fillId);
    }

后续有新的方法再来补充

### 回答1: Spring Boot整合Flowable的教程可以分为以下几个步骤: 1. 引入依赖 在pom.xml文件中添加以下依赖: ``` <dependency> <groupId>org.flowable</groupId> <artifactId>flowable-spring-boot-starter</artifactId> <version>6.6.</version> </dependency> ``` 2. 配置数据源 在application.properties文件中配置数据源: ``` spring.datasource.url=jdbc:mysql://localhost:3306/flowable?useUnicode=true&characterEncoding=utf8&useSSL=false spring.datasource.username=root spring.datasource.password=root spring.datasource.driver-class-name=com.mysql.jdbc.Driver ``` 3. 配置Flowable 在application.properties文件中配置Flowable: ``` # 配置Flowable的数据库表前缀 spring.flowable.database-schema-update=true spring.flowable.database-schema=flowable spring.flowable.database-schema-update=true ``` 4. 编写流程定义 在resources目录下创建一个名为processes的文件夹,用于存放流程定义的bpmn文件。例如,创建一个名为leave.bpmn的文件,内容如下: ``` <?xml version="1." encoding="UTF-8"?> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:flowable="http://flowable.org/bpmn" targetNamespace="http://activiti.org/bpmn20" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd" expressionLanguage="http://www.w3.org/1999/XPath" typeLanguage="http://www.w3.org/2001/XMLSchema"> <process id="leave" name="请假流程"> <startEvent id="start" name="开始"/> <userTask id="apply" name="申请请假"/> <sequenceFlow id="flow1" sourceRef="start" targetRef="apply"/> <endEvent id="end" name="结束"/> <sequenceFlow id="flow2" sourceRef="apply" targetRef="end"/> </process> </definitions> ``` 5. 编写流程服务 创建一个名为ProcessService的服务类,用于启动流程实例: ``` @Service public class ProcessService { @Autowired private RuntimeService runtimeService; public void startProcess(String processDefinitionKey) { runtimeService.startProcessInstanceByKey(processDefinitionKey); } } ``` 6. 编写控制器 创建一个名为ProcessController的控制器类,用于处理请求: ``` @RestController public class ProcessController { @Autowired private ProcessService processService; @PostMapping("/startProcess") public void startProcess() { processService.startProcess("leave"); } } ``` 7. 启动应用程序 运行Spring Boot应用程序,访问http://localhost:808/startProcess即可启动流程实例。 以上就是Spring Boot整合Flowable的教程,希望对你有所帮助。 ### 回答2: SpringBootSpring框架的一款快速开发框架,而Flowable则是一款基于Activiti的轻量级工作流引擎。SpringBoot整合Flowable可以快速开发出支持业务流程的应用程序。 1. 创建SpringBoot项目 首先,我们需要创建一个SpringBoot项目。可以使用Spring官网提供的Spring Initializr快速创建。 2. 添加Flowable依赖 在pom.xml文件中添加Flowable的依赖。 ``` <dependency> <groupId>org.flowable</groupId> <artifactId>flowable-spring-boot-starter</artifactId> <version>6.3.1</version> </dependency> ``` 3. 配置Flowable 在application.yml配置文件中添加Flowable相关配置。 ``` flowable: database-schema-update: true history-level: full id-generator: uuid jdbc-url: jdbc:mysql://localhost:3306/flowable-spring-boot?useUnicode=true&characterEncoding=utf-8&useSSL=false jdbc-username: root jdbc-password: root rest: enabled: true base-path: /flowable-rest ``` 其中,jdbc-url为数据库连接地址,jdbc-username和jdbc-password为连接数据库的用户名和密码。 4. 创建业务流程定义 在src/main/resources目录下创建bpmn和png文件,用于定义业务流程。 5. 配置业务流程服务 在Java代码中配置业务流程服务。 ``` @Configuration public class FlowableConfiguration { @Autowired private DataSource dataSource; @Bean public StandaloneProcessEngineConfiguration processEngineConfiguration() { StandaloneProcessEngineConfiguration configuration = new StandaloneProcessEngineConfiguration(); configuration.setDataSource(dataSource); configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE); configuration.setAsyncExecutorActivate(true); configuration.setHistory(ProcessEngineConfiguration.HISTORY_AUDIT); return configuration; } @Bean public ProcessEngine processEngine() { return processEngineConfiguration().buildProcessEngine(); } @Bean public RepositoryService repositoryService() { return processEngine().getRepositoryService(); } @Bean public RuntimeService runtimeService() { return processEngine().getRuntimeService(); } @Bean public TaskService taskService() { return processEngine().getTaskService(); } @Bean public HistoryService historyService() { return processEngine().getHistoryService(); } } ``` 6. 创建业务流程控制器 创建一个控制器类,用于处理业务流程的相关操作。 ``` @RestController @RequestMapping("/processes") public class ProcessController { @Autowired private RuntimeService runtimeService; @Autowired private TaskService taskService; @PostMapping("/start") public void startProcessInstance() { runtimeService.startProcessInstanceByKey("myProcess"); } @GetMapping("/tasks/{assignee}") public List<Task> getTasks(@PathVariable("assignee") String assignee) { return taskService.createTaskQuery().taskAssignee(assignee).list(); } @PostMapping("/complete/{taskId}") public void completeTask(@PathVariable("taskId") String taskId) { taskService.complete(taskId); } } ``` 7. 启动应用程序 最后,我们可以启动应用程序,在浏览器中访问 http://localhost:8080/flowable-rest/runtime/process-instances 可以查看当前正在运行的业务流程实例。 通过上述步骤,我们可以实现SpringBoot整合Flowable的功能,并快速开发出支持业务流程的应用程序。 ### 回答3: Spring Boot是现今非常流行的Java开发框架,而Flowable则是一个非常强大的开源工作流引擎。将二者进行整合可以使工作流的实现更加简单高效,能够帮助开发人员快速构建出完整的业务系统。 以下是Spring Boot整合Flowable的具体步骤: 1. 加入Flowable包依赖 在项目的pom.xml文件中加入以下依赖代码即可引入Flowable: ``` <dependency> <groupId>org.flowable</groupId> <artifactId>flowable-spring-boot-starter</artifactId> <version>${flowable.version}</version> </dependency> ``` 其中,${flowable.version}需要根据所使用版本进行修改。 2. Flowable配置文件 在src/main/resources目录下新建flowable.cfg.xml文件。该文件中定义了Flowable框架的数据库配置信息。 示例代码: ``` <?xml version="1.0" encoding="UTF-8"?> <flowable xmlns="http://flowable.org/schema/flowable"> <datasource> <url>jdbc:mysql://localhost:3306/db_flowable?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai</url> <driver>com.mysql.cj.jdbc.Driver</driver> <username>root</username> <password>123456</password> <maxActive>20</maxActive> <maxIdle>2</maxIdle> <maxWait>10000</maxWait> </datasource> <job-executor activate="true" /> <process-engine> <name>default</name> <database-schema-update>true</database-schema-update> <history-level>full</history-level> <configuration-resource>flowable.properties</configuration-resource> </process-engine> </flowable> ``` 其中,此处示例使用的是MySQL数据库,如果要使用其他类型的数据库需要进行对应修改。 3. Flowable属性文件 在src/main/resources目录下新建flowable.properties文件。该文件中定义了Flowable框架的各种配置信息,如邮件服务器、任务分配策略等。 示例代码: ``` # 邮件服务器配置 mail.server.host=smtp.163.com mail.server.port=465 mail.server.username=your@mail.com mail.server.password=xxx # 任务分配策略 activiti.bpmn.userTask.assignmentStrategy=org.flowable.spring.boot.app.task.SimpleTaskAssignmentStrategy ``` 其中,示例代码中的邮件服务器为163邮箱服务器,如果使用其他邮箱需要进行对应修改。任务分配策略也可根据具体需求进行修改。 4. 编写工作流程定义文件 在src/main/resources/processes目录下新建flowable配置文件,使用BPMN2.0的XML格式描述组织的流程图。 示例代码: ``` <?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn" targetNamespace="http://www.activiti.org/bpmn" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd http://activiti.org/bpmn http://activiti.org/bpmn"> <process id="myProcess" name="My process"> <startEvent id="start" activiti:formKey="key_start"></startEvent> <sequenceFlow id="flow1" sourceRef="start" targetRef="task1"></sequenceFlow> <userTask id="task1" name="任务1" activiti:assignee="userId1" activiti:formKey="key_task1"></userTask> <sequenceFlow id="flow2" sourceRef="task1" targetRef="end"></sequenceFlow> <endEvent id="end"></endEvent> </process> </definitions> ``` 其中,activiti:formKey为工作流程表单路径,activiti:assignee为任务的受让人。 5. 编写Java代码 - 启动方式 在启动类中加上@EnableFlowable注解即可启动Flowable引擎。 ``` @SpringBootApplication @EnableFlowable public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` - 工作流程定义 在Java类中使用以下代码即可进行工作流程的定义: ``` @RepositoryRestController @RequestMapping("/workflow-definition") public class WorkflowDefinitionController { @Autowired private RepositoryService repositoryService; @PostMapping("/deploy") public void deploy(@RequestParam("file") MultipartFile file) throws Exception { if (file.isEmpty()) { throw new IllegalArgumentException("文件不能为空"); } Deployment deployment = repositoryService.createDeployment() .addInputStream(file.getOriginalFilename(), file.getInputStream()) .deploy(); } } ``` 在示例代码中,@RepositoryRestController注解用于定义RESTful接口,@RequestMapping注解用于映射URI路径。 - 工作流程实例 使用以下代码即可开启一个工作流程实例: ``` @RestController @RequestMapping("/process") public class ProcessController { @Autowired private RuntimeService runtimeService; @PostMapping("/start") public void start(@RequestParam String processDefinitionKey) { runtimeService.startProcessInstanceByKey(processDefinitionKey); } } ``` 6. 运行工作流 启动Spring Boot程序,并访问RESTful接口所映射的URL,即可实现工作流的运行。 以上就是Spring Boot整合Flowable的教程,通过以上步骤,可以非常快速地搭建出一个高效的工作流系统,帮助开发人员实现更加快速、可靠的业务流程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值