从零开始:如何用Activiti 7.x搭建你的第一个BPM流程(附避坑指南)

springboot2.x集成activiti6.0在线流程设计器 我在网上找了很多资料都没有找到关于activiti6.0的在线流程设计器,大多数都是基于5.x的。因为6.0的源码包中没有在线设计器的资源包,因此本文使用的是activiti 5.22.0中web资源包来做的,只是依赖不一样ui一样,下面就能开始来实现一下吧。 第一步:在activiti官网下载5.22.0的源码包:https://www.activiti.org/get-started 第二步:... 阅读详情

从零构建:基于Activiti 7.x的企业级流程自动化实战指南

你是否曾为繁琐的报销审批流程而等待数日?是否经历过因流程节点不清导致的任务卡顿?在数字化转型浪潮中,企业运营效率的核心往往不在于某个炫酷的功能,而在于那些支撑日常业务流转的“隐形骨架”——业务流程。对于Java开发者而言,掌握一套成熟、稳定的流程引擎技术,就如同为业务系统装上了智能导航,能够将复杂的规则逻辑转化为清晰、自动化的执行路径。

今天,我们将深入探索业界广泛使用的开源流程引擎Activiti的最新版本——7.x系列。与网络上泛泛而谈的概念介绍不同,本文将以一名一线架构师的视角,带你从环境搭建、流程设计、表单绑定,到高级特性与生产环境避坑,完成一次完整的、可落地的实战之旅。无论你是希望为现有系统引入工作流能力,还是正在评估技术选型,这篇文章都将提供一套经过验证的实践方案。

1. 环境准备与项目初始化

在开始编写第一行流程代码之前,一个稳定、兼容的开发环境是成功的基石。Activiti 7.x 与 Spring Boot 2.x+ 进行了深度整合,这极大地简化了传统工作流引擎繁重的配置工作。然而,版本间的细微差异往往是新手遇到的第一个“暗礁”。

首先,我们通过Spring Initializr或手动创建一个标准的Spring Boot项目。核心依赖除了Spring Boot Starter Web、JPA等常规组件外,关键在于引入Activiti Spring Boot Starter。这里有一个常见的版本匹配陷阱需要注意:Activiti 7.1.x 通常与 Spring Boot 2.3.x ~ 2.7.x 兼容性最佳。盲目使用最新版本可能导致意料之外的冲突。

Maven核心依赖配置示例:

<properties>
    <activiti.version>7.1.0.M6</activiti.version>
    <spring-boot.version>2.7.18</spring-boot.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-spring-boot-starter</artifactId>
        <version>${activiti.version}</version>
    </dependency>
    <!-- 使用H2数据库作为快速开始的嵌入式数据库 -->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
    <!-- 生产环境推荐使用MySQL或PostgreSQL -->
    <!-- <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency> -->
</dependencies>

注意:Activiti 7.x 默认使用了新的 activiti-spring-boot-starter,它内部整合了流程引擎、Spring Security(用于任务分配和权限)等。如果你的项目已有自己的安全框架,需要仔细处理配置,避免冲突。

数据库是流程引擎的“记忆中枢”。Activiti 在启动时会自动检查数据库表结构,若不存在则根据依赖的数据库方言(如MySQL, PostgreSQL, H2)自动创建约25张核心表。这些表主要分为五大类:

表前缀全称存储内容说明
ACT_RE_Repository流程定义、模型等静态部署资源。
ACT_RU_Runtime运行时数据,如流程实例、执行流、任务、变量。流程结束时这部分数据会被清除。
ACT_HI_History历史数据,包括已完成的流程实例、任务、变量详情,用于审计与分析。
ACT_ID_Identity身份信息,如用户、用户组及其关系。
ACT_GE_General通用数据,如存储流程定义图片、部署文件等二进制资源。

完成依赖配置后,一个最简单的 application.yml 配置文件可能如下所示:

spring:
  datasource:
    url: jdbc:h2:mem:activitidb;DB_CLOSE_DELAY=-1
    driver-class-name: org.h2.Driver
    username: sa
    password:
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true

# Activiti 配置
activiti:
  database-schema-update: true # 自动更新数据库表结构
  db-history-used: true # 使用历史数据
  history-level: audit # 历史记录级别:none, activity, audit, full
  check-process-definitions: false # 启动时不强制检查流程定义文件
  async-executor-activate: false # 开发环境可关闭异步执行器以简化调试

启动你的Spring Boot应用,如果控制台没有报错,并且能在H2控制台(默认地址 http://localhost:8080/h2-console,JDBC URL填写 jdbc:h2:mem:activitidb)中看到一系列 ACT_ 开头的表,那么恭喜你,流程引擎的基础环境已经就绪。

2. 第一个流程:请假审批的设计与实现

理论铺垫完毕,现在让我们动手创建一个实实在在的流程。我们将以实现一个经典的“员工请假审批”流程为例,它包含了用户任务(User Task)、网关(Gateway)等核心元素。

第一步:使用BPMN 2.0设计流程 Activiti遵循BPMN 2.0(业务流程模型与标注)国际标准。你可以使用官方Eclipse插件、在线工具如bpmn.io,或者IntelliJ IDEA的Activiti BPMN插件来绘制流程图。这里我们直接编写BPMN 2.0 XML文件,这有助于理解其本质。

在 src/main/resources/processes/ 目录下创建 leave-request.bpmn20.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
             xmlns:activiti="http://activiti.org/bpmn"
             targetNamespace="http://www.activiti.org/processdef">
    <!-- 定义一个流程,id用于代码中引用,name用于显示 -->
    <process id="leaveProcess" name="员工请假流程" isExecutable="true">
        <!-- 开始事件 -->
        <startEvent id="startEvent" name="开始申请">
            <extensionElements>
                <!-- 定义启动时需要填写的表单字段 -->
                <activiti:formProperty id="applicant" name="申请人" type="string" required="true"/>
                <activiti:formProperty id="leaveType" name="请假类型" type="enum" required="true">
                    <activiti:value id="annual" name="年假"/>
                    <activiti:value id="sick" name="病假"/>
                    <activiti:value id="personal" name="事假"/>
                </activiti:formProperty>
                <activiti:formProperty id="days" name="请假天数" type="long" required="true"/>
                <activiti:formProperty id="reason" name="事由" type="string"/>
            </extensionElements>
        </startEvent>

        <!-- 第一个用户任务:员工提交申请 -->
        <userTask id="submitRequest" name="提交请假申请" activiti:assignee="${applicant}">
            <documentation>
                员工 ${applicant} 提交了 ${days} 天 ${leaveType} 申请,事由:${reason}。
            </documentation>
        </userTask>

        <!-- 顺序流:从开始事件指向提交任务 -->
        <sequenceFlow id="flow1" sourceRef="startEvent" targetRef="submitRequest"/>

        <!-- 第二个用户任务:部门经理审批 -->
        <userTask id="deptManagerApprove" name="部门经理审批" activiti:candidateGroups="dept_manager">
            <extensionElements>
                <!-- 审批动作和意见 -->
                <activiti:formProperty id="managerApproved" name="是否批准" type="enum" required="true">
                    <activiti:value id="true" name="批准"/>
                    <activiti:value id="false" name="拒绝"/>
                </activiti:formProperty>
                <activiti:formProperty id="managerComment" name="审批意见" type="string"/>
            </extensionElements>
        </userTask>
        <sequenceFlow id="flow2" sourceRef="submitRequest" targetRef="deptManagerApprove"/>

        <!-- 排他网关:根据经理审批结果决定流向 -->
        <exclusiveGateway id="decisionGateway" name="审批决定"/>
        <sequenceFlow id="flowToHR" sourceRef="deptManagerApprove" targetRef="decisionGateway"/>

        <!-- 条件顺序流:如果批准且天数>3天,需HR审批 -->
        <sequenceFlow id="flow3" sourceRef="decisionGateway" targetRef="hrApprove">
            <conditionExpression xsi:type="tFormalExpression">
                <![CDATA[${managerApproved == 'true' && days > 3}]]>
            </conditionExpression>
        </sequenceFlow>

        <!-- HR审批任务 -->
        <userTask id="hrApprove" name="人力资源部审批" activiti:candidateGroups="hr">
            <extensionElements>
                <activiti:formProperty id="hrApproved" name="HR审批结果" type="enum" required="true">
                    <activiti:value id="true" name="最终批准"/>
                    <activiti:value id="false" name="驳回"/>
                </activiti:formProperty>
            </extensionElements>
        </userTask>
        <sequenceFlow id="flow4" sourceRef="hrApprove" targetRef="gatewayAfterHR"/>

        <!-- 另一个网关,处理HR审批后的逻辑 -->
        <exclusiveGateway id="gatewayAfterHR" name="HR审批后决定"/>
        <sequenceFlow id="flow5" sourceRef="gatewayAfterHR" targetRef="sendApprovalNotification">
            <conditionExpression xsi:type="tFormalExpression">
                <![CDATA[${hrApproved == 'true'}]]>
            </conditionExpression>
        </sequenceFlow>

        <!-- 条件顺序流:如果经理直接拒绝,或HR驳回,流程结束 -->
        <sequenceFlow id="flowToReject" sourceRef="decisionGateway" targetRef="rejectEnd">
            <conditionExpression xsi:type="tFormalExpression">
                <![CDATA[${managerApproved == 'false'}]]>
            </conditionExpression>
        </sequenceFlow>
        <sequenceFlow id="flowToRejectByHR" sourceRef="gatewayAfterHR" targetRef="rejectEnd">
            <conditionExpression xsi:type="tFormalExpression">
                <![CDATA[${hrApproved == 'false'}]]>
            </conditionExpression>
        </sequenceFlow>

        <!-- 条件顺序流:如果批准且天数<=3天,直接进入通知环节 -->
        <sequenceFlow id="flowToNotify" sourceRef="decisionGateway" targetRef="sendApprovalNotification">
            <conditionExpression xsi:type="tFormalExpression">
                <![CDATA[${managerApproved == 'true' && days <= 3}]]>
            </conditionExpression>
        </sequenceFlow>

        <!-- 服务任务:模拟发送通知邮件或消息 -->
        <serviceTask id="sendApprovalNotification" name="发送批准通知" activiti:class="org.example.workflow.service.SendNotificationDelegate"/>
        <sequenceFlow id="flow6" sourceRef="sendApprovalNotification" targetRef="endEvent"/>

        <!-- 结束事件 -->
        <endEvent id="endEvent" name="请假流程结束"/>
        <endEvent id="rejectEnd" name="申请被拒绝"/>
    </process>
</definitions>

这个XML定义了一个相对完整的流程:员工发起申请 -> 部门经理审批 -> 根据结果和天数判断是否需HR审批 -> 最终通知或拒绝。其中使用了 activiti:assignee(指定处理人)和 activiti:candidateGroups(指定候选用户组)来分配任务。

第二步:部署流程定义 将BPMN文件放入 resources/processes/ 目录后,Activiti会在应用启动时自动部署。你也可以通过API动态部署:

@Service
public class ProcessDeploymentService {
    @Autowired
    private RepositoryService repositoryService;

    public Deployment deployProcess(String bpmnFileName) {
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource("processes/" + bpmnFileName)
                .name("请假流程部署")
                .deploy();
        System.out.println("流程部署成功,部署ID: " + deployment.getId());
        return deployment;
    }
}

第三步:启动流程实例并完成任务 流程定义部署后,只是一个“模板”。真正的流程运行始于一个“流程实例”。我们通过一个简单的REST控制器来模拟前端操作:

@RestController
@RequestMapping("/api/leave")
public class LeaveProcessController {

    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private IdentityService identityService;

    /**
     * 发起一个请假流程
     */
    @PostMapping("/start")
    public String startLeaveProcess(@RequestBody LeaveRequest request) {
        // 设置流程发起人(通常从安全上下文获取)
        identityService.setAuthenticatedUserId(request.getApplicant());

        // 设置流程变量
        Map<String, Object> variables = new HashMap<>();
        variables.put("applicant", request.getApplicant());
        variables.put("leaveType", request.getLeaveType());
        variables.put("days", request.getDays());
        variables.put("reason", request.getReason());

        // 使用流程定义的Key启动实例
        ProcessInstance instance = runtimeService.startProcessInstanceByKey("leaveProcess", variables);
        return "流程启动成功,实例ID: " + instance.getId();
    }

    /**
     * 查询某个用户的待办任务
     */
    @GetMapping("/tasks")
    public List<TaskRepresentation> getTasks(@RequestParam String userId) {
        // 查询分配给该用户的任务
        List<Task> tasks = taskService.createTaskQuery().taskAssignee(userId).list();
        // 查询该用户所在候选组的任务
        List<Task> candidateTasks = taskService.createTaskQuery().taskCandidateUser(userId).list();
        tasks.addAll(candidateTasks);

        return tasks.stream().map(task -> {
            TaskRepresentation tr = new TaskRepresentation();
            tr.setTaskId(task.getId());
            tr.setTaskName(task.getName());
            tr.setProcessInstanceId(task.getProcessInstanceId());
            // 可以进一步查询流程变量,显示更详细信息
            Map<String, Object> vars = taskService.getVariables(task.getId());
            tr.setVariables(vars);
            return tr;
        }).collect(Collectors.toList());
    }

    /**
     * 办理任务(如经理审批)
     */
    @PostMapping("/complete/{taskId}")
    public String completeTask(@PathVariable String taskId, 
                               @RequestParam String action, 
                               @RequestParam(required = false) String comment) {
        Map<String, Object> taskVariables = new HashMap<>();
        taskVariables.put("managerApproved", "approve".equals(action));
        taskVariables.put("managerComment", comment);

        // 完成任务,并传递变量驱动流程走向
        taskService.complete(taskId, taskVariables);
        return "任务处理完成";
    }
}

至此,一个具备核心流转功能的请假流程已经可以运行。你可以通过调用 /api/leave/start 发起流程,然后以经理身份登录,调用 /api/leave/tasks 查看待办,并处理任务。

3. 核心概念深化:任务分配、变量与监听器

掌握了基础流程搭建后,我们需要深入几个关键机制,它们决定了流程的灵活性与健壮性。

任务分配策略 Activiti提供了多种任务分配方式,适应不同业务场景:

  • 固定分配:在BPMN中直接指定 activiti:assignee="zhangsan"。简单但不灵活。
  • 表达式分配:使用UEL(Unified Expression Language)表达式,如 activiti:assignee="${applicant}",动态指定处理人为流程变量中的申请人。
  • 候选用户/组:使用 activiti:candidateUsers 或 activiti:candidateGroups。任务会出现在这些用户或组成员的待办列表中,需要先“认领”(claim)才能成为处理人。
  • 监听器分配:通过实现 TaskListener 接口,在任务创建时动态计算处理人。这是最灵活的方式,可以集成组织架构服务。
@Component
public class DynamicTaskAssignmentListener implements TaskListener {
    @Override
    public void notify(DelegateTask delegateTask) {
        String eventName = delegateTask.getEventName();
        if (EVENTNAME_CREATE.equals(eventName)) {
            // 根据复杂业务规则,从外部系统查询负责人
            String processDefinitionKey = delegateTask.getProcessDefinitionId();
            String department = (String) delegateTask.getVariable("department");
            String assignee = findAssigneeByRule(processDefinitionKey, department);
            delegateTask.setAssignee(assignee);
        }
    }
    private String findAssigneeByRule(String key, String dept) {
        // 模拟从数据库或规则引擎查询
        return "manager_of_" + dept;
    }
}

在BPMN中配置监听器:

<userTask id="someTask" name="动态分配任务">
    <extensionElements>
        <activiti:taskListener event="create" class="com.yourcompany.DynamicTaskAssignmentListener"/>
    </extensionElements>
</userTask>

流程变量(Variables)的作用域与生命周期 流程变量是流程运行时携带数据的载体。理解其作用域至关重要:

  • 全局变量:通过 runtimeService.setVariable(executionId, key, value) 设置,在整个流程实例内可见。
  • 本地变量:通过 runtimeService.setVariableLocal(taskId, key, value) 设置,仅在当前执行分支或任务内有效。
  • 瞬态变量:通过 runtimeService.setVariable(executionId, key, value) 设置,但标记为瞬态,不保存到历史表,适用于中间计算结果。

一个常见的坑是混淆变量作用域,导致在网关条件表达式中读取不到预期的变量。务必在设置和读取时明确作用域。

事件监听器(Event Listeners) 监听器允许你在流程执行的特定节点注入自定义逻辑,实现业务解耦。

  • 执行监听器(Execution Listener):监听流程实例或活动(如开始事件、结束事件、网关)的生命周期事件。
  • 任务监听器(Task Listener):监听用户任务的生命周期事件(创建、分配、完成、删除)。

例如,我们可以在流程结束时,自动调用一个服务来更新业务状态:

@Component
public class ProcessEndListener implements ExecutionListener {
    @Autowired
    private BusinessStatusService statusService;

    @Override
    public void notify(DelegateExecution execution) {
        String processInstanceId = execution.getProcessInstanceId();
        String businessKey = execution.getProcessBusinessKey(); // 通常关联业务ID
        String status = "COMPLETED"; // 可根据流程结果细化
        statusService.updateStatus(businessKey, status);
        // 可以在这里发送通知、记录审计日志等
    }
}

4. 高级特性与生产环境避坑指南

当流程从Demo走向生产环境,你会遇到更复杂的需求和挑战。本节聚焦于那些容易被忽略却至关重要的高级特性和实践。

异步执行器与事务管理 Activiti默认使用异步执行器处理作业(如定时器事件、异步延续)。这能提升吞吐量,但也引入了复杂性。

activiti:
  async-executor-activate: true # 生产环境建议开启
  async-executor-core-pool-size: 10
  async-executor-max-pool-size: 50
  async-executor-queue-capacity: 100

关键提醒:异步执行器在一个独立线程池中运行,与触发它的主事务是分离的。这意味着,如果在服务任务(Service Task)中抛出的异常被捕获并处理,主事务可能提交成功,但异步作业却因异常而失败重试,导致数据不一致。务必确保你的服务任务逻辑是幂等的,并妥善处理异常。

历史数据配置与性能优化 Activiti的历史记录非常详尽,但也会导致历史表(ACT_HI_*)快速增长。需要根据业务需求调整历史级别:

  • none:不保存任何历史。
  • activity:保存流程实例和活动实例信息。
  • audit(默认):在activity基础上,保存所有变量、表单属性。
  • full:最详细,额外保存所有流程变量的更新细节。

对于高并发、长生命周期的流程,建议将历史数据定期归档或清理。Activiti提供了 HistoryService 的API进行手动清理,也可以结合业务定制清理策略。

集成自定义表单 虽然Activiti支持内嵌表单定义,但企业级应用通常使用自研或第三方UI表单设计器。此时,流程引擎只负责流转和任务分配,表单渲染与数据收集由前端负责。集成关键在于:

  1. 表单定义分离:将表单的字段、校验规则、布局等信息存储在独立的表或JSON文件中,与流程定义关联。
  2. 数据绑定:任务办理时,前端根据任务ID获取对应的表单定义和初始数据(流程变量),提交时再将表单数据作为流程变量传回引擎。
@Service
public class FormIntegrationService {
    public FormDefinition getStartForm(String processDefinitionKey) {
        // 从你的表单库中查询该流程的启动表单定义
        return customFormRepository.findByProcessKey(processDefinitionKey);
    }

    public FormDefinition getTaskForm(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        String formKey = task.getFormKey(); // 可以在BPMN中为任务设置formKey
        if (formKey != null) {
            return customFormRepository.findByKey(formKey);
        }
        // 或者根据任务定义Key来查找
        return customFormRepository.findByTaskDefKey(task.getTaskDefinitionKey());
    }

    public void submitTaskForm(String taskId, Map<String, Object> formData) {
        // 数据校验...
        validateFormData(formData);
        // 将表单数据转换为流程变量
        Map<String, Object> variables = convertFormToVariables(formData);
        // 完成任务并提交变量
        taskService.complete(taskId, variables);
    }
}

常见“坑点”与解决方案

  1. 流程版本管理:当你重新部署一个同ID的流程定义时,Activiti会创建新版本。默认情况下,新发起的流程实例会使用最新版本,但正在运行的老版本实例不受影响。这可能导致同一流程存在多个版本实例同时运行。如果业务要求强制升级,需要编写迁移脚本或使用 runtimeService.updateProcessInstanceBusinessKey 等操作进行干预。

  2. 网关条件表达式:在排他网关(Exclusive Gateway)的条件表达式中,确保引用的流程变量已存在且类型正确。表达式语言默认是JUEL,对于复杂逻辑,建议将判断逻辑封装在Spring Bean中,通过 ${myBean.checkCondition(execution)} 调用。

  3. 用户与组的管理:Activiti自带的 IdentityService 功能简单,生产环境通常需要与公司现有的LDAP、AD或用户中心集成。你可以实现 UserEntityManager 和 GroupEntityManager 接口,替换默认的身份管理实现。

  4. 高并发下的乐观锁:Activiti的运行时数据更新使用乐观锁。在高并发场景下(如多人同时抢签一个任务),可能抛出 ActivitiOptimisticLockingException。处理方式通常是在业务层进行重试,或者调整业务设计,避免对同一任务资源的激烈竞争。

  5. 流程图的动态生成与预览:很多场景需要展示实时流程图,并高亮当前节点。这需要结合流程实例ID和BPMN XML,使用GraphicGenerator生成图片,并根据当前活动节点信息进行渲染。社区有一些开源工具库可以简化此工作。

从环境搭建到第一个流程运行,再到深入核心机制与生产实践,我们完成了一次完整的Activiti 7.x入门之旅。记住,流程引擎的引入不仅仅是技术选型,更是对业务逻辑的一次重新梳理和标准化。初期建议从简单的、核心的流程入手,逐步迭代,在实战中积累对引擎特性的理解。当你熟悉了这些模式后,会发现Activiti提供的远不止是任务流转,它是一套完整的、用于构建可观测、可管理、可优化的业务流程自动化的强大框架。

Activiti7集成SpringBoot2官方实例 Activiti7集成SpringBoot2官方实例系列文章地址: https://www.xugj520.cn/category/Activiti/ 阅读详情

相关推荐

springboot+activiti整合并简单开发审批流程以及流程打回发起人

如果想更好的理解activity.这里有权威指南.pdf 百度网盘:链接: https://pan.baidu.com/s/1G8eLj--R5BjVCWwDbuu4Yg 。密码请关注。情感宣泄馆。回复668899 1、maven 引入依赖。都说springboot2.x要配activiti7.x。我的springboot版本是2.1.7 <dependency> <groupId>org.activiti</groupId> <artifa

王威振的博客 1万+

Activiti7流程操作详解

流程定义是线下按照bpmn2.0标准去描述 业务流程,通常使用idea中的插件对业务流程进行建模。使用idea下的designer.bpmn和.png查询流程相关信息也是经常要用到的操作,通常包含对流程定义,流程部署,流程定义版本的查询。/*** 查询流程定义// 1.创建流程引擎 ProcessEngine processEngine = ProcessEngines . getDefaultProcessEngine();

qq_44749491的博客 1万+

Activiti7

Activiti

weixin_38380811的博客 2010

Activiti7系列课程7-activiti7设计器

摘要:本文重点讲解一下Activiti7可以使用的流程设计器。目前Activiti最新版本是7.1.0.M1。 Activiti7可以使用的设计器 要想非常方便的使用Activiti7框架,则必须要安装流程设计器插件,关于Activiti7流程设计器相关插件说明如下: activiti6 官方提供有Web设计器(Modeler设计器)。这个不需要进行安装,直接部署运行activiti-model...

分享牛 4万+

Flowable vs Activiti vs Camunda:三大开源BPM引擎选型指南(2025版)

本文深度对比了Flowable、Activiti和Camunda三大开源BPM引擎在2025年的核心差异。文章从历史渊源、架构性能、云原生适配、社区生态及实战集成等维度进行剖析,重点分析了Flowable在高性能、轻量级架构及微服务友好性方面的优势,为企业在不同场景下的技术选型提供实战指南。

r2s3t4的博客 522

最新工作流引擎之activiti6.x、activiti5.x实时流程图追踪与高亮显示两种方式实现

在activiti5.x的追踪流程节点查找,可以用ActivityImpl这个类来实现,但是在activiti6版本,pvm包整个类包都被删除,再也没有ActivityImpl这个类。本章节就是教大家如何用activiti6来生成2种方式实时流程图追踪 第一种方式: 1.1 生成流程图核心类 主要是利用ProcessDiagramGenerator这个接口实现类,去实现generateDia...

hanyouyou_12的博客 2310

Activiti 7 开发者指南

Activiti 7 开发者指南 项目介绍 Activiti 是一个轻量级、可嵌入的 Java 工作流和业务流程管理(BPM)引擎。Activiti 7 是该项目的最新版本,它提供了更强大的功能和更好的性能。Activiti 7 支持 BPMN 2.0 规范,并且可以轻松地与 Spring Boot 集成,使得开发者能够快速构建和部署业务流程应用。 项目快速启动 环境准备 Java 8 或更高版...

gitblog_00493的博客 947

2021全网最全Activiti7教程01(Activiti7详细介绍-欢迎收藏)

BPMN 是目前被各 BPM 厂商广泛接受的 BPM 标准。Activiti 就是使用 BPMN 2.0 进行流程建模、流程执行管理,它包括很多的建模符号,比如: Event 用一个圆圈表示,它是流程中运行过程中发生的事情。 活动用圆角矩形表示,一个流程由一个活动或多个活动组成 Bpmn图形其实是通过xml表示业务流程,上边的.bpmn文件使用文本编辑器打开: <?xml version="1.0" encoding="UTF-8"?> <bpmndi:BPM.

m0_61364397的博客 1169

Activiti 7 配置及相关流程一站式介绍(包含基础流程及网关应用)

本文介绍了activit7的配置和流程相关信息,基于bpm设计构建xml进行工作流生成。是刚接触工作流学习的入门文章,欢迎大家参考评论~

轨迹的博客 3618

Activiti全面工作流与BPM实践笔记

Activiti是一个轻量级、可扩展的开源工作流和业务流程管理(BPM)平台,专为Java编写。它遵循BPMN 2.0标准,旨在提供高性能的业务流程引擎,适用于企业级应用。Activiti能够轻松嵌入任何Java应用程序中,并且能够与Spring框架无缝集成,使得流程管理变得简单而高效。一旦Activiti Designer成功安装,便可以启动程序并探索其界面。界面布局分为几个主要部分:项目浏览器(Project Explorer):显示当前工作空间中的项目和文件,用于导航和管理文件资源。

weixin_42527589的博客 1064

全面探索Activiti-6.0:BPM与工作流引擎的奥秘

业务流程管理(BPM)是一套覆盖设计、执行、监控和优化业务流程的全面方法。BPM的目标是确保组织内的业务流程高效且富有弹性,能够快速适应不断变化的市场需求。通过BPM的实施,组织能够更好地理解其业务过程,并持续提升效率和质量。Activiti目前支持主流的数据库类型,包括但不限于MySQL、PostgreSQL、Oracle和Microsoft SQL Server。不同版本的Activiti对数据库的支持程度可能会有所不同,因此在安装时需要参考官方文档中对数据库兼容性的说明。

weixin_42587866的博客 1064

Flowable 7.x:高效流程管理的终极指南

Flowable 是一个基于 BPMN 2.0 标准的流程引擎,用于构建和管理业务流程。它支持 BPMN 2.0 的图形化建模,使得非技术人员也能参与流程设计。Flowable 7.x 是最新版本,要求 JDK 17 和 Spring Boot 3.x。流程设计器可以通过 Docker 部署 Flowable-UI 或使用在线工具。对于复杂的业务需求,可以基于 BPMN.js 自定义流程设计器。Spring Boot 整合 Flowable 需要导入相关依赖并配置数据库,支持流程的部署、启动、查询和审批。

weixin_62307424的博客 3052

SpyGlass CDC实战:如何用sgdc约束文件解决跨时钟域报错(附常见错误排查)

本文详细介绍了如何使用SpyGlass CDC工具链中的sgdc约束文件解决跨时钟域(CDC)报错问题。从基础约束文件架构到复杂场景调试,涵盖了时钟域定义、复位信号约束、Waiver策略等关键技巧,并附有常见错误排查方法,帮助工程师高效处理CDC验证挑战。

loss4bartender的博客 1149

Activiti5、Activiti6、Activiti7对比分析,哪个版本好

Activiti流程引擎版本对比:Activiti5/6已停止维护,不建议选用;Activiti7(ActivitiCloud)采用云原生架构,依赖K8s等组件,支持BPMN元素较少,适合分布式环境但实施复杂。中小型项目不建议使用Activiti7,需根据团队技术能力选择。

3993

删除win10电脑U盘使用记录

手工删除:和查看的方法类似,分三步,缺一不可,顺序也不能反! 第一步 设置环境变量,变量名为“devmgr_show_nonpresent_devices”,值为“1”。 第二步 打开设备管理器,勾上“查看”菜单中的“显示隐藏设备”。如果之前已经打开设备管理器,则要关了,重新打开。 第三步 清除“磁盘驱动器”、“存储卷”、“通用串行总线控制器”3个栏目下所有的灰色的图标,注意是所有!右键点击灰色图标,然后选择“卸载”。 成功 :结果USBSTOR 没有了 ...

qq_40544338的博客 2万+

利用 Openocd 和 FT2232H 实现 ARMv8(Coretex-A53)高效调试方案

本文详细介绍了如何利用开源工具OpenOCD与高性能USB转接芯片FT2232H,构建一套针对ARMv8架构(如Cortex-A53)的高效、低成本调试方案。内容涵盖从环境搭建、驱动配置、核心调试架构解析到实战问题排查的全过程,帮助开发者实现对多核处理器的透明、可控调试,是嵌入式Linux及底层开发的实用指南。

weixin_29163581的博客 280

Activiti7工作流(四)流程符合及流程设计器

BPMN 2.0是业务流程建模符号2.0的缩写;它由Business Process Management Initiative这个非营利协会创建并不断发展。作为一种标识,BPMN 2.0是使用一些符号来明确业务流程设计流程图的一整套符号规范,它能增进业务建模时的沟通效率。目前BPMN2.0是最新的版本,它用于在BPM上下文中进行布局和可视化的沟通。Activiti7遵循BPMN 2.0规范,其核心图形符号主要分为以下几类:活动是工作或任务的一个通用术语。一个活动可以是一个任务,还可以是一个当前流程的子处理

tigerhhzz的博客 1120

从公式到实践:用SPSS解锁香农多样性指数的生态洞察

本文详细介绍了如何利用SPSS软件计算和应用香农多样性指数进行生态研究。从基础公式解析到SPSS实战操作,再到生态决策支持,全面展示了该指数在物种丰富度和均匀度量化中的价值。文章特别强调了SPSS操作中的关键技巧和常见误区,为生态研究者提供了一套完整的分析解决方案。

weixin_30832143的博客 466

Activiti7基础

一、工作流介绍 1.1 概念 工作流(Workflow),就是通过计算机对业务流程自动化执行管理。它主要解决的是“使在多个参与者之间按照某种预定义的规则自动进行传递文档、信息或任务的过程,从而实现某个预期的业务目标,或者促使此目标的实现”。 1.2 工作流系统 一个软件系统中具有工作流的功能,我们把它称为工作流系统,一个系统中工作流的功能是什么?就是对系统的业务流程进行自动化管理,所以工作流是建立在业务流程的基础上,所以一个软件的系统核心根本上还是系统的业务流程,工作流只是协助进行业务流程管理。即使没有工作

weixin_50020236的博客 2654

手机耳机麦克风(ECM)电路设计实战:从差分走线到射频干扰滤波,一个电阻引发的灵敏度问题

本文深入探讨了手机耳机麦克风(ECM)电路设计中的关键问题,从差分走线到射频干扰滤波,特别关注了一个电阻引发的灵敏度问题。通过实际案例分析,详细解析了ECM麦克风工作原理、偏置电阻选型、差分信号传输设计以及射频干扰抑制策略,为工程师提供了实用的设计指南和优化建议。

weixin_42563415的博客 244

【人工智能】架构演进:基于本体论与 LLM Agent 的供应链备件决策闭环实践

本文探讨了如何将本体论(Ontology)与大语言模型(LLM)Agent结合,构建供应链备件管理的智能决策系统。针对LLM在垂直领域存在的幻觉和逻辑缺陷问题,提出通过本体论建立结构化知识框架,形成四层架构:知识建模、动态感知、深度分析和决策闭环。系统利用图数据库实例化领域本体,融合多源数据实现实时感知,结合图谱推理和时序预测进行确定性分析,最终通过工具调用完成决策执行。技术选型推荐Gemini 1.5 Pro、Neo4j和LangChain等工具,实现从自动化到智能化的升级。该架构为工业领域提供了可解释、

奶爸的编程之路,也就一周冷个三天 172

Activiti7 探索系列一核心库的使用

本文为翻译文章,如有不合理处请查看原文https://hub.alfresco.com/t5/alfresco-process-services/activiti-7-deep-dive-series-using-the-core-libraries/ba-p/288484 简介 Activiti 7是Alfresco经过实战考验的Activiti工作流引擎的演变,完全被采用在云环境中运行。 ...

timkey 4420

YOLO11改进 | 主干网络 | 添加Hyper-YOLO的MANet混合聚合网络

本文详细介绍了在YOLO11目标检测模型中替换C3k2模块为MANet的具体实现方法。文章首先讲解MANet模块的原理,然后分步骤指导如何在YOLO11中添加该模块,包括代码修改、文件配置和模型注册等关键环节。通过实验对比,改进后的YOLO11_MANet模型在保持8.8GFLOPs计算量的同时,参数数量达到3,820,272,网络层数增加到343层。文章还提供了完整的代码实现和网络结构图,并建议结合其他注意力机制或损失函数进一步提升检测效果。最后推荐了相关的深度学习专栏,包含更多YOLO系列改进方法。

kay_545 660

弃坑入门:Activiti 7.1.0-M13+SpringBoot 2.5.0 开发环境搭建

由于Activiti项目团队自身的一些问题,新版本迭代很快,但功能基本上还是基于原来的Activiti 5.x/6.x,加上项目质量管控多少问题,新版本的bug多修复慢。 国内很多activiti的用户还停留在5.x/6.x的阶段,故网上各种教材文章的内容也如此,对Activiti 7.x的资料有点无面,基本上都是就一两个点的记录。 本测试将以尽量最新的环境版本来搭建,记录下备查也供有需之人参考。 1.开发环境 MacOS :11.3.1 ,JAVA环境,windows/linux应该也无大差异 jdk

5433

软考中级-软件设计师 知识点整理(一篇就过了 建议收藏)

软考中级-软件设计师上午题知识点总结

片言可决讼,半纸能缚龙 17万+

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

Activiti7笔记(一)Activiti7是什么,入门流程操作的代码实现

Activiti7笔记(一)Activiti7是什么,入门流程操作的代码实现

一天不写代码难受的博客 1709

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

上一篇: 从芯片手册到EDA工具:图解set_output_delay与setup/hold time的数学关系
下一篇: 慧眼BS主图通达信公式实战解析:源码优化与无未来信号验证
随身带U盘
博客等级 码龄4年 30粉丝 1526原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值