Camunda(二):springboot 整合Camunda 使用工作流程(含完整代码)

5 篇文章 0 订阅
2 篇文章 1 订阅

前言:因为公司有个项目需求要使用到工作流引擎,考查了市面各种的工作流引擎,对比它们之间的优劣势,最后选择Camunda工作流引擎。此前自己对Camunda工作流引擎了解的并不多,所以就记录下自己学习Camunda工作流引擎到springboot项目中整合Camunda工作流引擎使用的过程。

在上一篇文章中已经介绍了Camunda Platform和Modeler创建工作流的玩法了。在本文就将Camunda 应用在生产项目的各种审核流程中,重点是springboot整合Camunda ,并使用Camunda 的各种API。因为camunda本来就是一个轻量级的框架,项目中就主要使用Camunda 的工作流的流程流转和审核,流程的创建和前端bpmn页面流程编辑器部分这里就不介绍使用了。因为在经历几个生产项目,无论是使用flowable或者Camunda 工作流框架,流程bpmn文件都是提前通过其他工具创建好,然后放在项目中加载部署的,项目主要是对应的流程的流转和审核。不多废话,下面就直接进入正题。

一、引入Camunda依赖

springboot引入Camunda要考虑版本兼容性的问题,我的springboot版本2.5.x,所以我引入Camunda的版本是7.16.x,

要看springboot对应Camunda的具体的版本:

https://docs.camunda.org/manual/7.19/user-guide/spring-boot-integration/version-compatibility/

在这里插入图片描述

<dependency>
    <groupId>org.camunda.bpm.springboot</groupId>
    <artifactId>camunda-bpm-spring-boot-starter</artifactId>
    <version>7.16.0</version>
</dependency>
二、在yml配置camunda

camunda的详细配置说明:

https://docs.camunda.org/manual/latest/user-guide/spring-boot-integration/configuration/#camunda-engine-properties

这里就说几个比较重要的配置

camunda.bpm.auto-deployment-enabled :流程是否应该自动部署,默认为true。

很重要camunda.bpm.deployment-resource-pattern:自动部署位置。一开始我学习我不理解为什么bpmn文件无论放在那里都能自动部署。

默认位置:

classpath*😗*/*.bpmn,

classpath*😗*/*.bpmn20.xml,

classpath*😗*/*.dmn,

classpath*😗*/*.dmn11.xml,

classpath*😗*/*.cmmn,

classpath*😗*/*.cmmn10.xml,

classpath*😗*/*.cmmn11.xml

camunda.bpm.database.schema-update: 如果应应用自动架构更新,请使用 [true、false、create、create-drop、drop-create] 之一,默认为true。

camunda.bpm.database.type: 底层数据库的类型。可能的值:h2、mysql、mariadb、oracle、postgres、mssql、db2。

camunda.bpm.admin-user.id: 用户名

camunda.bpm.admin-user.password: 初始化密码

camunda.bpm.admin-user.firstName: 附加(可选)用户属性 ,默认为“id”的值

camunda.bpm.admin-user.lastName: 附加(可选)用户属性 ,默认为“id”的值

camunda.bpm.filter.create:“显示全部”过滤器的名称。如果设置,则会在启动时创建一个显示所有任务的新过滤器。

下面是在实际项目中的配置

# camunda配置
camunda:
  bpm:
    admin-user:
      id: camunda
      password: camunda
      first-name: admin
    filter:
      create: All tasks
    database:
      type: mysql
      schema-update: true
    auto-deployment-enabled: true
    deployment-resource-pattern: classpath:/processes/*.bpmn
三、初始化camunda数据库,执行建表脚本(很重要

这里需要手动建好camunda相关的表,不提前建好的话,到导致项目中的camunda的相关的bean没办法自动注入到spring容器中,会无法正常启动项目。camunda的相关脚本语句,去官网找到对应版本(此例中Camunda版本为7.16.0)的sql脚本文件:

https://camunda.com/download/

解压后,找到./configuration/sql目录下即可找到sql文件,engine和identity都执行。项目中使用的是mysql数据,所以执行mysql的脚本。

在这里插入图片描述

四、camunda数据库表的说明(扩展)

PS: 这一步跟项目无关,但是能加深对camunda的理解,而且对项目中出现问题的排查能提供很好的帮助。

Camunda bpm流程引擎的数据库由多个表组成,表名都以ACT开头,第二部分是说明表用途的两字符标识。而Camunda7.16版本共49张表。

ACT_RE_* : 'RE’表示流程资源存储,这个前缀的表包含了流程定义和流程静态资源(图片,规则等)
(最重要)ACT_RU_* : 'RU’表示流程运行时。 这些运行时的表,包含流程实例,任务,变量,Job等运行中的数据。 Camunda只在流程实例执行过程中保存这些数据,在流程结束时就会删除这些记录, 这样运行时表的数据量最小,可以最快运行
ACT_ID_* : 'ID’表示组织用户信息,比如用户,组等,
ACT_HI_* : 'HI’表示流程历史记录。 这些表包含历史数据,比如历史流程实例,变量,任务等
ACT_GE_* : ‘GE’表示流程通用数据

要记住一个很重要的一个点:流程运行时的数据是存在ACT_RU相关的表上,当流程结束后,该流程相关的数据就会被物理删除掉,能减少很多数据量,提高流程的性能。而想要看相关流程的过程记录,则需要到ACT_HI相关的表上去查找

流程引擎的最核心表是流程定义、流程执行、流程任务、流程变量和事件订阅表。它们之间的关系见下面的UML模型。

在这里插入图片描述

下面是项目中排查问题用的比较多,比较重要的几张表的说明

act_id_user(用户表)
字段名称字段类型可否为空描述
ID_varchar(64)主键
REV_int(11)NULL版本
FIRST_varchar(255)NULL
LAST_varchar(255)NULL
EMAIL_varchar(255)NULL邮件
PWD_varchar(255)NULL密码
SALT_varchar(255)NULL盐值
LOCK_EXP_TIME_datetimeNULL锁定过期时间
ATTEMPTS_int(11)NULL尝试次数
PICTURE_ID_varchar(64)NULL图片ID
act_ge_bytearray(二进制数据表)
字段名称字段类型可否为空描述
ID_varchar(64)主键
REV_int(11)NULL版本
NAME_varchar(255)NULL名称
DEPLOYMENT_ID_varchar(64)NULL部署ID
BYTES_longblobNULL字节内容
GENERATED_tinyint(4)NULL是否系统生成(0用户创建,null系统生成)
TENANT_ID_varchar(64)NULL租户ID
TYPE_int(11)NULL类型
CREATE_TIME_datetimeNULL创建时间
ROOT_PROC_INST_ID_varchar(64)NULL流程实例根ID
REMOVAL_TIME_datetimeNULL删除时间
act_re_procdef(流程定义表)

流程定义表,包含所有已部署的流程定义,诸如版本详细信息、资源名称或挂起状态等信息。

字段名称字段类型可否为空描述
ID_varchar(64)主键
REV_int(11)NULL版本
CATEGORY_varchar(255)NULL流程定义的Namespace分类
NAME_varchar(255)NULL流程定义名称
KEY_varchar(255)流程定义KEY
VERSION_int(11)流程定义版本号
DEPLOYMENT_ID_varchar(64)NULL部署ID
RESOURCE_NAME_varchar(4000)NULL资源名称
DGRM_RESOURCE_NAME_varchar(4000)NULLDGRM资源名称
HAS_START_FORM_KEY_tinyint(4)NULL是否有启动表单
SUSPENSION_STATE_int(11)NULL流程挂起
TENANT_ID_varchar(64)NULL租户ID
VERSION_TAG_varchar(64)NULL版本标签
HISTORY_TTL_int(11)NULL
STARTABLE_tinyint(1)是否是可启动流程
act_ru_execution(流程运行时表)—最重要

BPMN流程运行时记录表。该表时整个流程引擎的核心表,它包括流程定义、父级执行、当前活动和有关执行状态的不同元数据等信息。

字段名称字段类型可否为空描述
ID_varchar(64)主键
REV_int(11)NULL版本
ROOT_PROC_INST_ID_varchar(64)NULL流程实例根ID
PROC_INST_ID_varchar(64)NULL流程实例ID
BUSINESS_KEY_varchar(255)NULL业务KEY
PARENT_ID_varchar(64)NULL流程父实例ID
PROC_DEF_ID_varchar(64)NULL流程定义ID
SUPER_EXEC_varchar(64)NULL父流程实例对应的执行
SUPER_CASE_EXEC_varchar(64)NULL父案例实例对应的执行
CASE_INST_ID_varchar(64)NULL案例实例ID
ACT_ID_varchar(255)NULL节点ID
ACT_INST_ID_varchar(64)NULL节点实例ID
IS_ACTIVE_tinyint(4)NULL是否激活
IS_CONCURRENT_tinyint(4)NULL是否并行
IS_SCOPE_tinyint(4)NULL是否多实例范围
IS_EVENT_SCOPE_tinyint(4)NULL是否事件多实例范围
SUSPENSION_STATE_int(11)NULL挂起状态
CACHED_ENT_STATE_int(11)NULL缓存状态
SEQUENCE_COUNTER_bigint(20)NULL序列计数器
TENANT_ID_varchar(64)NULL租户ID
act_ru_identitylink(流程运行时表)

运行时流程人员表,主要存储当前节点参与者的信息

字段名称字段类型可否为空描述
ID_varchar(64)主键
REV_int(11)NULL版本
GROUP_ID_varchar(255)NULL用户组ID
TYPE_varchar(255)NULL类型
USER_ID_varchar(255)NULL用户ID
TASK_ID_varchar(64)NULL任务ID
PROC_DEF_ID_varchar(64)NULL流程定义ID
TENANT_ID_varchar(64)NULL租户ID
act_ru_task( 流程运行时任务表)

流程运行时任务表,包含所有正在运行的流程实例的所有打开的任务,包括诸如相应的流程实例、执行以及元数据(如创建时间、办理人或到期时间)等信息。

字段名称字段类型可否为空描述
ID_varchar(64)主键
REV_int(11)NULL版本
EXECUTION_ID_varchar(64)NULL流程执行ID
PROC_INST_ID_varchar(64)NULL流程实例ID
PROC_DEF_ID_varchar(64)NULL流程定义ID
CASE_EXECUTION_ID_varchar(64)NULL案例执行ID
CASE_INST_ID_varchar(64)NULL案例实例ID
CASE_DEF_ID_varchar(64)NULL案例定义ID
NAME_varchar(255)NULL名称
PARENT_TASK_ID_varchar(64)NULL父任务ID
DESCRIPTION_varchar(4000)NULL描述
TASK_DEF_KEY_varchar(255)NULL任务定义KEY
OWNER_varchar(255)NULL委托人
ASSIGNEE_varchar(255)NULL办理人
DELEGATION_varchar(64)NULL委托状态
PRIORITY_int(11)NULL优先级
CREATE_TIME_datetimeNULL创建时间
DUE_DATE_datetimeNULL截止时间
FOLLOW_UP_DATE_datetimeNULL跟踪时间
SUSPENSION_STATE_int(11)NULL挂起状态
TENANT_ID_varchar(64)NULL租户ID
act_hi_comment(历史流程审批意见表)

历史流程审批意见表,存放历史流程的审批意见。

字段名称字段类型可否为空描述
ID_varchar(64)主键
TYPE_varchar(255)NULL类型(event事件、comment意见)
TIME_datetime时间
USER_ID_varchar(255)NULL处理人
TASK_ID_varchar(64)NULL任务ID
ROOT_PROC_INST_ID_varchar(64)NULL流程实例跟ID
PROC_INST_ID_varchar(64)NULL流程实例ID
ACTION_varchar(255)NULL行为类型
MESSAGE_varchar(4000)NULL基本内容
FULL_MSG_longblobNULL全部内容
TENANT_ID_varchar(64)NULL租户ID
REMOVAL_TIME_datetimeNULL移除时间
act_hi_detail(历史的流程运行详情表)

历史的流程运行变量详情记录表。流程中产生的变量详细,包括控制流程流转的变量,业务表单中填写的流程需要用到的变量等。

字段名称字段类型可否为空描述
ID_varchar(64)主键
TYPE_varchar(255)类型
PROC_DEF_KEY_varchar(255)NULL流程定义KEY
PROC_DEF_ID_varchar(64)NULL流程定义ID
ROOT_PROC_INST_ID_varchar(64)NULL流程实例根ID
PROC_INST_ID_varchar(64)NULL流程实例ID
EXECUTION_ID_varchar(64)NULL流程执行ID
CASE_DEF_KEY_varchar(255)NULL案例定义KEY
CASE_DEF_ID_varchar(64)NULL案例定义ID
CASE_INST_ID_varchar(64)NULL案例实例ID
CASE_EXECUTION_ID_varchar(64)NULL案例执行ID
TASK_ID_varchar(64)NULL任务ID
ACT_INST_ID_varchar(64)NULL节点实例ID
VAR_INST_ID_varchar(64)NULL流程变量记录ID
NAME_varchar(255)名称
VAR_TYPE_varchar(255)NULL变量类型
REV_int(11)NULL版本
TIME_datetime时间戳
BYTEARRAY_ID_varchar(64)NULL二进制数据对应ID
DOUBLE_doubleNULLdouble类型值
LONG_bigint(20)NULLlong类型值
TEXT_varchar(4000)NULL文本类型值
TEXT2_varchar(4000)NULL文本类型值2
SEQUENCE_COUNTER_bigint(20)NULL序列计数器
TENANT_ID_varchar(64)NULL租户ID
OPERATION_ID_varchar(64)NULL
REMOVAL_TIME_datetimeNULL移除时间

五、编写camunda的工具类。

其实完成前面3步,可以说springboot已经整合camunda成功了,但是一个项目中引入一个框架主要是为了使用,camunda官方提供了很多API,参考官方文档:https://docs.camunda.org/manual/7.18/reference/rest/

但是在camunda不同的流程的审核所 使用的API是大多数是相同的,所以在项目中封装一个工具类提供使用。

/**
 * camunda 流程工具类
 */
@Component
@Slf4j
public class FlowUtil {
    private static final FlowUtil util = new FlowUtil();

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private HistoryService historyService;

    @PostConstruct
    public void initialize() {
        util.repositoryService = repositoryService;
        util.runtimeService = runtimeService;
        util.taskService = taskService;
        util.historyService = historyService;
    }
    /**
     * 部署流程,参数本地bpmn的路径
     * @param filePath  bpmn路径
     * @param name  流程名称
     */
    public static void deployment(String filePath,String name){
        log.info("开始部署本地审批流程:{},文件地址:{}",name,filePath);
        util.repositoryService.createDeployment()
                .name(name)
                .addClasspathResource(filePath)
                .deploy();

        log.info("完成部署本地审批流程:{},文件地址:{}",name,filePath);
    }

    /**
     * 启动流程
     * @param key 流程标识,需唯一,如果存在相同key则会启动版本号最新的流程
     * @param businessKey  业务id
     * @param map 流程变量(包含节点审批人及业务判断变量等)
     */
    public static void startProcess(String key, Object businessKey, Map<String,Object> map){
        log.info("开始启动审批流程:{},业务源:{},流程变量: {}",key,businessKey.toString(), JSONUtil.toJsonStr(JSONUtil.parse(map)));
        ProcessInstance processInstance = util.runtimeService.startProcessInstanceByKey(key, businessKey.toString(), map);
        log.info("完成启动审批流程:{},业务源:{},流程实例ID:{}",key,businessKey.toString(), processInstance.getId());
    }

    /**
     * 销毁流程
     * @param key 流程标识,需唯一,如果存在相同key则会启动版本号最新的流程
     * @param businessKey  业务id
     * @param reason 销毁原因
     * @param reason 审批人
     */
    public static void destroyProcess(String key, String businessKey, String reason,String assignee){
        //查询待办任务
        List<Task> tasks = FlowUtil.getTaskByCandidateUserAndBusinessKey(key, businessKey, assignee);
        if(CollUtil.isEmpty(tasks)){
            log.info("{}完成审批任务失败:{}--{}",assignee,key,businessKey);
            throw new ResultException("暂未到您审批");
        }
        FlowUtil.claimTask(tasks.get(0).getId(),assignee);
        List<Task> taskList = FlowUtil.getTasksByBusinessKey(key, businessKey);
        if(CollUtil.isEmpty(taskList)) return;
        log.info("开始销毁审批流程:{},业务源:{},流程实例ID:{}:",key,businessKey, taskList.get(0).getProcessInstanceId());
        util.runtimeService.deleteProcessInstance(taskList.get(0).getProcessInstanceId(), reason);
        log.info("完成销毁审批流程:{},业务源:{},流程实例ID:{}",key,businessKey, taskList.get(0).getProcessInstanceId());
    }

    /**
     * 领取任务
     * @param taskId  任务id
     * @param candidateUser  候选用户名
     */
    public static void claimTask(String taskId,String candidateUser){
        Task task = util.taskService.createTaskQuery()
                .taskId(taskId)
                .taskCandidateUser(candidateUser)
                .singleResult();
        if(Objects.isNull(task)){
            log.info("{}领取审批任务失败:{}",candidateUser,taskId);
            throw new ResultException("任务领取失败");
        }
        util.taskService.claim(taskId,candidateUser);
    }

    /**
     * 完成任务
     * @param taskId  任务id
     * @param assignee  用户名
     */
    public static void completeTask(String taskId,String assignee){
        Task task = util.taskService.createTaskQuery()
                .taskId(taskId)
                .taskAssignee(assignee)
                .singleResult();
        if(Objects.isNull(task)){
            log.info("{}完成审批任务失败:{}",assignee,taskId);
            throw new ResultException("任务完成失败");
        }
        util.taskService.complete(taskId);
    }

    /**
     * 领取并完成任务
     * @param taskId  任务id
     * @param assignee  用户名
     */
    public static void claimAndCompleteTask(String taskId,String assignee){
        Task task = util.taskService.createTaskQuery()
                .taskId(taskId)
                .singleResult();
        if(Objects.isNull(task)){
            log.info("{}审批任务不存在:{}",assignee,taskId);
            throw new ResultException("审批任务不存在");
        }
        if(StrUtil.isNotBlank(task.getAssignee())){
            if(!task.getAssignee().equalsIgnoreCase(assignee)){
                log.info("{}完成审批任务失败:{}",assignee,taskId);
                throw new ResultException("暂未到您审批");
            }
            util.taskService.complete(taskId);
            return;
        }
        Task unClaimTask = util.taskService.createTaskQuery()
                .taskId(taskId)
                .taskCandidateUser(assignee)
                .singleResult();
        if(Objects.isNull(unClaimTask)){
            log.info("{}完成审批任务失败:{}",assignee,taskId);
            throw new ResultException("暂未到您审批");
        }
        util.taskService.claim(taskId,assignee);
        util.taskService.complete(taskId);
    }

    /**
     * 查询待办任务,参数:候选用户、业务id
     * @param candidateUser 候选用户
     * @param key 流程标识,需唯一,如果存在相同key则会启动版本号最新的流程
     * @param businessKey  业务id
     * @return
     */
    public static List<Task> getTaskByCandidateUserAndBusinessKey(String key,String businessKey,String candidateUser){
        return util.taskService.createTaskQuery()
                .processInstanceBusinessKey(businessKey)
                .processDefinitionKey(key)
                .taskCandidateUser(candidateUser)
                .list();

    }

    /**
     * 查询待办任务,参数: 业务id
     * @param key 流程标识,需唯一,如果存在相同key则会启动版本号最新的流程
     * @param businessKey  业务id
     * @return
     */
    public static List<Task> getTasksByBusinessKey(String key, String businessKey){
        return util.taskService.createTaskQuery()
                .processDefinitionKey(key)
                .processInstanceBusinessKey(businessKey)
                .list();
    }

    /**
     * 查询待办任务,参数: 业务id
     * @param key 流程标识,需唯一,如果存在相同key则会启动版本号最新的流程
     * @param businessKey  业务id
     * @param assignee  用户名
     * @return
     */
    public static boolean claimAndCompleteTask(String key, String businessKey,String assignee){
        //查询待办任务
        List<Task> tasks = FlowUtil.getTaskByCandidateUserAndBusinessKey(key, businessKey, assignee);
        if(CollUtil.isEmpty(tasks)){
            log.info("{}完成审批任务失败:{}--{}",assignee,key,businessKey);
            throw new ResultException("暂未到您审批");
        }
        for (Task task : tasks) {
            FlowUtil.claimAndCompleteTask(task.getId(),assignee);
        }
        if(CollUtil.isEmpty(FlowUtil.getTasksByBusinessKey(key,businessKey))){
            return true;
        }else{
            return false;
        }
    }

    /**
     * 查询历史任务
     * @param key
     * @param businessKey
     * @return
     */
    public static List<HistoricTaskInstance> getHistoricTask(String processInstanceId,String key, String businessKey){
        return util.historyService.createHistoricTaskInstanceQuery()
                .processInstanceBusinessKey(businessKey)
                .processInstanceId(processInstanceId)
                .processDefinitionKey(key)
                .list();
    }

    /**
     * 查询历史实例
     * @param key
     * @param businessKey
     * @return
     */
    public static HistoricProcessInstance getLastProcessInstance(String key, String businessKey){
        return util.historyService.createHistoricProcessInstanceQuery()
                .processDefinitionKey(key)
                .processInstanceBusinessKey(businessKey)
                .orderByProcessInstanceStartTime()
                .desc().list().get(0);
    }

    /**
     * 查询任务
     * @param key
     * @param taskId
     * @return
     */
    public static List<HistoricIdentityLinkLog> getHistoricIdentityLinkLog(String key, String taskId){
        return util.historyService.createHistoricIdentityLinkLogQuery()
                .processDefinitionKey(key)
                .taskId(taskId)
                .list();
    }


    /**
     * 查询任务
     * @param taskId
     * @return
     */
    public static List<IdentityLink> getTaskIdentityLink(String taskId){
        return util.taskService.getIdentityLinksForTask(taskId);
    }
}
五、模拟生产项目中的功能-费用审核流程

下面是费用审核的流程图

在这里插入图片描述

5.1 创建费用审核流程(即创建bpmn文件)

创建流程可以使用Camunda Modeler,具体的使用方法在我上一篇文章中有写到,又不了解的可以移步到:

https://blog.csdn.net/qq798867485/article/details/131439688

下面是流程图的创建和每个节点的设置情况

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.2 把bpmn文件放到项目的processes目录

一定要放在这个目录下,因为之前的yml的配置指定了自动部署的目录,不然无法自动部署。除非你在yml配置中不制动自动部署的目录。

5.3 创建费用审核流程

FlowUtil.startProcess(BizFlowTypeEnum.EXPENSE_APPROVE.getKey(),expense.getId(),params);

这个方法就是 创建费用审核流程

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submit(Expense expense) {
        dao.insert(expense);
        List<User> userList = userService.listAll(new UserQueryBo());
        Set<String> companyUsers = userList.stream().filter(x -> x.getUserRole() == 1)
                .map(item -> item.getId().toString()).collect(Collectors.toSet());
        Set<String> groupUsers = userList.stream().filter(x -> x.getUserRole() == 2)
                .map(item -> item.getId().toString()).collect(Collectors.toSet());
        Set<String> headUsers = userList.stream().filter(x -> x.getUserRole() == 3)
                .map(item -> item.getId().toString()).collect(Collectors.toSet());

        Map<String,Object> params = new HashMap<>();
        params.put("companyUsers", companyUsers);
        params.put("groupUsers",groupUsers);
        params.put("headUsers",headUsers);
        FlowUtil.startProcess(BizFlowTypeEnum.EXPENSE_APPROVE.getKey(),expense.getId(),params);

    }
5.4 审核费用审核流程

##查看这个审核节点是否为审核流程最后的一个节点

FlowUtil.claimAndCompleteTask(BizFlowTypeEnum.EXPENSE_APPROVE.getKey(),expense.getId().toString(),expenseQueryBo.getApprovalId().toString())

##驳回

FlowUtil.destroyProcess(BizFlowTypeEnum.EXPENSE_APPROVE.getKey(),expense.getId().toString(),“不想通过”,expenseQueryBo.getApprovalId().toString())

 @Override
    @Transactional(rollbackFor = Exception.class)
    public void approval(Expense expense, ExpenseQueryBo expenseQueryBo) {
        if(expenseQueryBo.getApprovalStatus() == 2){
            //通过
            if(FlowUtil.claimAndCompleteTask(BizFlowTypeEnum.EXPENSE_APPROVE.getKey(),expense.getId().toString(),expenseQueryBo.getApprovalId().toString())){
                expense.setApprovalStatus(2);
            }else {
                expense.setApprovalStatus(1);
            }
        }else {
            //驳回
            FlowUtil.destroyProcess(BizFlowTypeEnum.EXPENSE_APPROVE.getKey(),expense.getId().toString(),"不想通过",expenseQueryBo.getApprovalId().toString());
            expense.setApprovalStatus(3);
        }

        this.updateById(expense);
    }
六、总结(代码)

学习camunda最主要是理解流程的流转和相关表的结构。上面只是我简单模拟一个费用审核流程的样例,实际生产中的业务代码比这个要复杂,但是核心的camunda的工具类的使用是不变的,变的只是业务流程。

例子完整的代码:https://github.com/gorylee/learnDemo/tree/master/camundaDemo

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
Camunda DMN 可以很容易地集成Spring Boot 项目中。下面是一个简单的步骤: 1. 在 pom.xml 中添加以下依赖: ```xml <dependency> <groupId>org.camunda.bpm.springboot</groupId> <artifactId>camunda-bpm-spring-boot-starter</artifactId> <version>${camunda.spring.boot.version}</version> </dependency> ``` 2. 在 application.properties 或 application.yml 文件中添加以下配置: ```yaml camunda.bpm: database: schema-update: true process-engine: name: default job-execution: enabled: true dmn: enabled: true ``` 这里设置了数据库更新、默认流程引擎、任务执行和 DMN 支持等配置。 3. 在 Spring Boot 应用程序中创建 DMN 决策表,例如 resources 目录下的 my-decision.dmn 文件。 4. 在应用程序中通过以下代码进行 DMN 决策表的执行和结果输出: ```java import org.camunda.bpm.dmn.engine.DmnDecisionTableResult; import org.camunda.bpm.engine.DecisionService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class MyService { @Autowired private DecisionService decisionService; public void executeDecision() { DmnDecisionTableResult result = decisionService.evaluateDecisionTableByKey("my-decision").execute(); System.out.println(result.getSingleResult()); } } ``` 这里使用Camunda DMN 决策服务中的 evaluateDecisionTableByKey 方法执行决策表并获取结果。 以上是一个简单的 Camunda DMN 集成 Spring Boot 的示例,你可以根据自己的需求和实际情况进行配置和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值