精华内容
下载资源
问答
  • Activiti7

    2020-04-01 16:39:25
    一.Activiti7体系架构 通过加载activiti.cfg.xml文件得到ProcessEngineConfiguration对象,通过ProcessEngineConfiguration对象可以得到ProcessEngine对象 得到该对象后,可以通过流程引擎对象ProcessEngine来得到...

    一.Activiti7体系架构

    通过加载activiti.cfg.xml文件得到ProcessEngineConfiguration对象,通过ProcessEngineConfiguration对象可以得到ProcessEngine对象

    得到该对象后,可以通过流程引擎对象ProcessEngine来得到各种Service,每一种Service接口有每个用途

    RepositoryService activiti 的资源管理类

    RuntimeService activiti 的流程运行管理类

    TaskService activiti 的任务管理类

    HistoryService activiti 的历史管理类

    ManagerService activiti 的引擎管理类

    二.Activiti使用步骤:

    1.流程定义

    使用Activiti Designer工具创建流程图

    新建一个BPMNFile流程图,可更改该流程图的ID和每个任务环节的执行人,流程图就是一个xml文件,每一个流程需要生成一张流程图保存,首先将.bpmn文件改为.xml文件

    然后右键该xml文件Diagrams—>show BPMN 2.0 Designer就能生成一张流程图,将流程图导出保存到项目对应目录即可,然后将xml改回bpmn即可

    2.流程部署

    需要将流程部署到Activiti当中,代表当前有该流程
    /**

    • 流程部署
    • act_ge_bytearray 流程定义的资源信息,包含bpmn和png流程文件信息
    • act_re_deployment 流程部署信息,包含流程名称,ID,Key等
    • act_re_procdef 流程定义信息
      */
    @Test
    public void deployment(){
    //获取ProcessEngine对象   默认配置文件名称:activiti.cfg.xml  并且configuration的Bean实例ID为processEngineConfiguration
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    //获取RepositoryService对象进行流程部署
    RepositoryService repositoryService = processEngine.getRepositoryService();
    //进行部署,将对应的流程定义文件生成到数据库当中,作为记录进行保存
    Deployment deployment = repositoryService.createDeployment()
    .addClasspathResource("bpmnfile/holiday.bpmn")     //加载流程文件
    .addClasspathResource("bpmnfile/holiday.png")
    .name("请假流程")       //设置流程名称
    .key("holidayKey")
    .deploy();              //部署
    
    //输出部署信息
    System.out.println("流程名称:"+deployment.getName());
    System.out.println("流程ID:"+deployment.getId());
    System.out.println("流程Key:"+deployment.getKey());
    }
    

    3.创建流程实例

    流程定义相当于类
    流程实例相当于类的实例(对象)

    /**
    * 启动流程实例
    * `act_hi_actinst`  已开始和执行完毕的活动信息
    * `act_hi_identitylink`    历史参与者信息
    * `act_hi_procinst`        流程实例信息
    * `act_hi_taskinst`        历史任务实例
    *  act_ru_execution        任务执行信息
    *  act_ru_identitylink     当前任务参与者
    * `act_ru_task`            任务信息
    *
    */
    @Test
    public void startInstance(){
    //获取ProcessEngine对象   默认配置文件名称:activiti.cfg.xml  并且configuration的Bean实例ID为processEngineConfiguration
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    //获取到RuntimeService对象
    RuntimeService runtimeService = processEngine.getRuntimeService();
    //创建流程实例
    ProcessInstance holiday = runtimeService.startProcessInstanceByKey("holiday");
    //输出实例信息
    System.out.println("流程部署ID:"+holiday.getDeploymentId());
    System.out.println("流程实例ID:"+holiday.getId());
    System.out.println("活动ID:"+holiday.getActivityId());
    }
    

    4.用户查询代办任务

    /**
    * 查看代办任务
    */
    @Test
    public void getTask(){
    //获取ProcessEngine对象   默认配置文件名称:activiti.cfg.xml  并且configuration的Bean实例ID为processEngineConfiguration
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    //获取一个TaskService对象
    TaskService taskService = processEngine.getTaskService();
    //查询代办业务 createTaskQuery查询任务   taskCandidateOrAssigned查询任务执行者   processDefinitionKey:查询流程
    /**
    * taskCandidateOrAssigned匹配规则:1.Assigned   2.配置bpmn文件中定义的值
    * taskAssignee匹配规则:1.Assigned
    */
    /*List<Task> list = taskService.createTaskQuery().taskCandidateOrAssigned("lisi").processDefinitionKey("holiday").list();*/
    List<Task> list = taskService.createTaskQuery().taskAssignee("zhangsan").processDefinitionKey("holiday").list();
    //分页:List<Task> list = taskService.createTaskQuery().taskAssignee("zhangsan").processDefinitionKey("holiday").listPage(i,j);
    for (Task task:list) {
    System.out.println("任务名称:"+task.getName());
    System.out.println("任务执行人:"+task.getAssignee());
    System.out.println("任务ID:"+task.getId());
    System.out.println("流程实例ID:"+task.getProcessInstanceId());
    }
    }
    

    5.用户进行任务处理

    /**
    * 任务处理:当所有任务处理完毕,对应当前流程实例信息删除,但是可以在历史中查看到该信息
    */	
    @Test
    public void completeTask(){
    //获取ProcessEngine对象   默认配置文件名称:activiti.cfg.xml  并且configuration的Bean实例ID为processEngineConfiguration
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    //获取一个TaskService对象
    TaskService taskService = processEngine.getTaskService();
    //任务处理
    taskService.complete("10002");
    }
    

    6.流程结束

    7.当业务流程结束后通过历史可以查看到已经走完的流程

    /**
    * 查看历史任务
    */
    @Test
    public void getHistory() {
    //获取ProcessEngine对象   默认配置文件名称:activiti.cfg.xml  并且configuration的Bean实例ID为processEngineConfiguration
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    //获取HistoryService接口
    HistoryService historyService = processEngine.getHistoryService();
    //获取历史任务
    HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
    //获取指定流程实例的任务
    historicActivityInstanceQuery.processInstanceId("2501");
    //获取任务列表
    List<HistoricActivityInstance> list = historicActivityInstanceQuery.list();
    for (HistoricActivityInstance ai : list) {
    System.out.println("任务节点ID:"+ai.getActivityId());
    System.out.println("任务节点名称:"+ai.getActivityName());
    System.out.println("流程实例ID信息:"+ai.getProcessDefinitionId());
    System.out.println("流程实例ID信息:"+ai.getProcessInstanceId());
    System.out.println("==============================");
    }
    }
    
    展开全文
  • activiti7

    2019-08-12 23:54:25
    activiti7详情介绍: 必须看的:下面的链接excel中记载了详情介绍。 https://download.csdn.net/my

    activiti7详情介绍:
    必须看的:下面的链接excel中记载了详情介绍。
    https://download.csdn.net/download/weixin_42603009/11530206

    展开全文
  • Activiti7系列课程7-activiti7设计器

    万次阅读 2019-06-17 10:39:38
    摘要:本文重点讲解一下Activiti7可以使用的流程设计器。目前Activiti最新版本是7.1.0.M1。 Activiti7可以使用的设计器 要想非常方便的使用Activiti7框架,则必须要安装流程设计器插件,关于Activiti7流程设计器相关...

    摘要:本文重点讲解一下Activiti7可以使用的流程设计器。目前Activiti最新版本是7.1.0.M1。

    Activiti7可以使用的设计器

    要想非常方便的使用Activiti7框架,则必须要安装流程设计器插件,关于Activiti7流程设计器相关插件说明如下:

    1. activiti6 官方提供有Web设计器(Modeler设计器)。这个不需要进行安装,直接部署运行activiti-modeler模块即可使用。
    2. 官方提供有Eclipse开发工具流程插件。
    3. 官方提供有IntelliJ IDEA开发工具相关的流程插件

    由于Activiti7新团队将开发重心放到了云Bpmn上,所以对于上述的几个流程设计器都不在进行维护。对于Eclipse开发工具的流程插件止步不前,几乎停滞更新和维护。这样就导致了开发人员使用Eclipse或者IntelliJ IDEA开发工具的流程插件有如下几个风险:

    • Activiti7.x版本中的新增特性、新功能无法使用。
    • 使用Activiti流程插件绘制的流程不一定完全可以在Activiti7框架中运行。
    • Activiti流程插件(该插件对准的是5.x版本)。
    • 使用IntelliJ IDEA开发工具的读者可以安装Activiti流程插件(actibpm)进行开发。但是无法享受Activiti7.x版本带来的的新功能。

    Activiti7推荐使用的设计器

    Activiti7开发团队已经完全抛弃了IntelliJ IDEA/Eclipse中的流程插件以及Modeler设计器。开始使用了bpmn.io提供的bpmn-js设计器。如下图所示:
    在这里插入图片描述

    新建流程

    在这里插入图片描述
    点击Create new process输入流程的名称,点击create即可完成流程的创建。

    目前设计器支持的元素说明

    bpmn-js设计器是市面上比较成熟和符合BPMN标准的一款建模工具,由于Activiti7重构比较大,所以目前仅支持如下几个元素

    1. 空结束事件、空启动事件
    2. 用户任务、服务任务、调用活动(callActivity)
    3. 排他网关和并行网关

    目前元素支持设置的属性

    1. 目前所有的元素均不支持定义执行监听器和任务监听器。Activiti7改为事件触发机制,只要项目运行环境中存在具体子类,就去直接使用。
    2. Activiti7支持抽象任务的概念。
    3. 服务任务直接设置响应的实现类即可,这样实例运行的时候直接从Spring容器中获取该类,并触发。
    4. 用户任务支持的属性如下图所示。
      5分享牛
      服务任务可以定义的属性如下
      在这里插入图片描述

    建议

    目前建议使用activiti7提供的bpmn-js设计器,不建议使用其他的设计器。因为Cloud提供的一系列API目前仅支持上述的几个元素,其他元素暂时不支持。

    展开全文
  • Activiti7工作流+SpringBoot

    万次阅读 多人点赞 2018-12-10 14:13:39
    一、Activiti介绍: Activiti是基于Apache许可的开源BPM平台,创始人Tom Baeyens原是JBPM架构师,可以理解为与JBPM出自同一祖师爷。它提供了Eclipse插件,开发可以通过插件直接绘制业务流程图。基于Spring,ibatis等...

    一. Activiti相关概念

    1. Activiti介绍

        Activiti是基于Apache许可的开源BPM平台,创始人Tom Baeyens原是JBPM架构师,可以理解为与JBPM出自同一祖师爷。它提供了Eclipse插件,开发可以通过插件直接绘制业务流程图。基于Spring,ibatis等框架,并在此之上构建了非常清晰的开发框架。是由Alfresco软件发布的业务流程管理(BPM)框架,它是覆盖了业务流程管理、工作流、服务协作等领域的一个开源的、灵活的、易扩展的可执行流程语言框架。 本文基于Activiti7的Activiti Core,基于Spring Boot做简单学习总结。(Activiti最新版本向微服务这边靠齐了,并分Activiti Core与Activiti Cloud两块,Activiti Cloud还没研究)

    2. 核心类

    2.1 ProcessEngine

        流程引擎的抽象,可以通过此类获取需要的所有服务。

    2.2 服务(Service)类

        通过ProcessEngine获取,Activiti将不同生命周期的服务封装在不同Service中,包括定义、部署、运行。通过服务类可获取相关生命周期中的服务信息。

    2.2.1 TaskService

        流程运行过程中,每个任务节点的相关操作接口,如complete,delete,delegate等。

    2.2.2 RepositoryService

        流程定义和部署相关的存储服务。

    2.2.3 RuntimeService

        流程运行时相关的服务,如根据流程好启动流程实例startProcessInstanceByKey。

    2.2.3 HistoryService

        历史记录相关服务接口。

    2.3 CommandContextIntercepter或CommandExecutor

        Activiti使用命令模式作为基础开发模式,如Service中调用的各个方法都对应相应的命令对象。Service将请求委托给命令对象,命令对象来命令接受者,接受者接收后执行并返回结果。而CommandContextIntercepter的作用是拦截所有命令,并在命令前后执行一些公共方法。

    2.4 核心业务对象

        org.activiti.engine.impl.persistence.entity包下的类,包括Task,ProcessInstance,Execution等。会根据不同职责实现相应接口的方法(如需要持久化则继承PersistentObject接口),与传统的实体类不同。

    3. 上下文组件(Context)

        用来保存生命周期比较长,全局性的信息,类似Application,主要包括如下三类。

    3.1 CommandContext

        命令上下文,保存每个命令必要的资源,如持久化需要的session。

    3.2 ProcessEngineConfigurationImpl

        流程引擎相关配置信息,整个引擎全局的配置信息,如数据源DataSource等。该对象为单例,在流程引擎创建的时候初始化。

    3.3 ExecutionContext

        持有ExecutionEntity对象。

    4. 持久化组件

        Activiti使用ibatis作OR映射,并在此基础上增加设计了自己的持久化框架。在流程引擎创建时初始化。顶层接口Session、SessionFactory。Session有两个实现类:DbSqlSession,负责sql表达式的执行。AbstractManager负责对象的持久化操作。SessionFactory有两个实现类:DbSqlSessionFactory负责DbSqlSession相关操作,GenericManagerFactory负责AbstractManager相关操作。

    5. Event-Listener组件

        Activiti允许客户代码介入流程执行,提供了事件监听组件。监听的事件类型可以分为TaskListener、JavaDelegate、Expression、ExecutionListener。ProcessEngineConfigurationImpl持有DelegateInterceptor的某个实例,方便调用handleInvocation。

    6. Cache组件

        DbSqlSession中有cache的实现,Activiti基于List和Map来做缓存。如查询时先查缓存,没有则直接查询并放入缓存。

    7. 异步执行组件

        Activiti可以执行任务,JobExecutor为启核心类,JobExecutor包含三个主要属性:JobAcquisitionThread,BlockingQueue,ThreadPoolExecutor。方法ProcessEngines在引擎启动时调用JobExecutor.start,JobAcquisitionThread 线程即开始工作,其run方法不断循环执行AcquiredJobs中的job,执行一次后线程等待一定时间直到超时或者JobExecutor.jobWasAdded方法,因为有新任务而被调用。

    8. PVM:Process Virtal Machine

        流程虚拟机API暴露了流程虚拟机的POJO核心,流程虚拟机API描述了一个工作流流程必备的组件,这些组件包括:
        PvmProcessDefinition:流程的定义,形象点说就是用户画的那个图。静态含义。
        PvmProcessInstance:流程实例,用户发起的某个PvmProcessDefinition的一个实例,动态含义。
        PvmActivity:流程中的一个节点
        PvmTransition:衔接各个节点之间的路径,形象点说就是图中各个节点之间的连接线。
        PvmEvent:流程执行过程中触发的事件

    二. Eclipse插件安装:

        我的Eclipse版本如下:
    在这里插入图片描述
        下载离线安装包(在线安装始终失败,应该出于网络限制),地址:http://www.activiti.org/designer/archived/activiti-designer-5.18.0.zip
        离线安装包安装安装依然提示相关包找不到,于是下载另外三个依赖包(org.eclipse.emf.transaction_1.4.0.v20100331-1738.jar、org.eclipse.emf.validation_1.7.0.201306111341.jar、org.eclipse.emf.workspace_1.5.1.v20120328-0001.jar,在Maven仓库可以找到),放到Eclipse的plugin目录下,继续安装,如下:
    在这里插入图片描述
        确定后勾选相关选项,完成安装,重启Eclipse,New->Other
    在这里插入图片描述
        出现以上标志,则安装完成。

    三. 项目搭建

    1. 新建Spring Boot工程

        (我的Eclipse已经安装Spring Boot插件)
    我的Eclipse已经安装Spring Boot插件
        然后Next->Next…->Finish即可,然后改application.properties为application.yml(个人习惯)
    在这里插入图片描述

    2. 引入Activiti相关依赖

        在pom属性中定义版本号,并添加Activiti相关依赖:

    <activiti-dependencies.version>7.0.56</activiti-dependencies.version>
    
    <dependencyManagement>
      <dependencies>
        <dependency>
          <groupId>org.activiti.dependencies</groupId>
          <artifactId>activiti-dependencies</artifactId>
          <version>${activiti-dependencies.version}</version>
          <scope>import</scope>
          <type>pom</type>
        </dependency>
      </dependencies>
    </dependencyManagement>
    
    <dependency>
          <groupId>org.activiti</groupId>
          <artifactId>activiti-spring-boot-starter</artifactId>
    </dependency>
    

        由于Activiti默认使用H2数据库,所以需添加H2数据库支持(这里使用此SpringBoot版本默认1.4.197):

    <dependency>
          <groupId>com.h2database</groupId>
          <artifactId>h2</artifactId>
    </dependency>
    

        出现错误:Missing artifact org.activiti:activiti-spring-boot-starter:jar:7.0.56

    在这里插入图片描述
        添加私服仓库地址:

    <repositories>
    	    <repository>
    	      <id>alfresco</id>
    	      <name>Activiti Releases</name>
    	      <url>https://artifacts.alfresco.com/nexus/content/repositories/activiti-releases/</url>
    	      <releases>
    	        <enabled>true</enabled>
    	      </releases>
    	    </repository>
    </repositories>
    

    在这里插入图片描述
        错误消失。

    3. 创建流程图

        在此版本Activiti+SpringBoot,默认加载/processes/目录下流程,于是在resources下新建processes目录,并在目录下new->Other,如下:
    在这里插入图片描述
        使用Activiti图编辑工具打开,创建如下流程(创建过程在此不介绍,就是右侧工具栏的运用):
    在这里插入图片描述

    4. 启动工程

        看日志:
    在这里插入图片描述
        从日志中可以看出,流程引擎已经默认创建,并可以看到使用的默认数据源是H2的数据源,我们创建的流程也已经部署。

    5. 修改配置

        在正常使用中,一般系统会有自己的数据库,而不会采用默认内存的H2数据库,这里以MySQL为例。修改application.yml。

    5.1 添加MySQL依赖

    <!--使用mysql数据库,导入mysql驱动-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
    </dependency>
    

    5.2 修改数据库

    spring:
      ##数据库连接信息
      datasource:
        # 数据源配置
        url: jdbc:mysql://127.0.0.1:3306/activity?useUnicode=true&characterEncoding=utf-8&useSSL=false
        username: root
        password: root
        driver-class-name: com.mysql.jdbc.Driver
        # SQLException: XAER_INVAL: Invalid arguments (or unsupported command)问题
        xa:
          properties:
            pinGlobalTxToPhysicalConnection: true
            useServerPrepStmts: true
    

    5.3 Activiti相关配置

      # 参考配置https://www.cnblogs.com/liaojie970/p/8857710.html
      activiti:
        # 自动建表
        database-schema: ACTIVITI
        database-schema-update: true
        history-level: full
        db-history-used: true
    

        注意:
        database-schema-update表示启动时检查数据库表,不存在则创建
        history-level表示哪种情况下使用历史表,这里配置为full表示全部记录历史,方便绘制流程图
        db-history-used为true表示使用历史表,如果不配置,则工程启动后可以检查数据库,只建立了17张表,历史表没有建立,则流程图及运行节点无法展示(暂未找到可行方式)

    5.4 附上application.yml完整配置:

    # 服务配置
    server:
      display-name: actdemo
      port: 8085
      
    # Spring相关配置
    spring:
      ##数据库连接信息
      datasource:
        # 数据源配置
        url: jdbc:mysql://127.0.0.1:3306/activity?useUnicode=true&characterEncoding=utf-8&useSSL=false
        username: root
        password: 888
        driver-class-name: com.mysql.jdbc.Driver
        
        # SQLException: XAER_INVAL: Invalid arguments (or unsupported command)问题
        xa:
          properties:
            pinGlobalTxToPhysicalConnection: true
            useServerPrepStmts: true
    
      thymeleaf:
        mode: HTML
        encoding: utf-8
        # 禁用缓存
        cache: false
      application:
        # 注册应用名
        name: actdemo
      mvc:
        # 静态资源路径
        static-path-pattern: /static/**
      # 参考配置https://www.cnblogs.com/liaojie970/p/8857710.html
      activiti:
        # 自动建表
        database-schema: ACTIVITI
        database-schema-update: true
        history-level: full
        db-history-used: true
    

    5.5 启动工程

        观察日志,流程引擎已成功加载,并已使用MySQL数据库,如下:
    在这里插入图片描述
        再看数据库,已经创建25张表(老版本的Activiti创建表有手动执行SQL和通过调用流程引擎创建两种方式,该版本与SpringBoot整合后,启动默认创建需要的表):
    在这里插入图片描述
        注意:
        原SpringBoot工程使用版本2.1.1.RELEASE,启动始终失败,各种错误,后改为2.0.4.RELEASE版本,则启动正常。

    6. 编写实例

        本例子使用Thymeleaf做前端页面展示(SpringBoot推荐使用),并创建控制器Controller调用工作流接口与前端交互。

    6.1 引入Thymeleaf依赖,(前端使用Thymeleaf的配置已经在application.yml中)

    <!-- Thymeleaf依赖 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    

    6.2 创建Controller控制器

        创建启动流程方法,主要代码如下

    /**
    	 * <p>启动请假流程</p>
    	 * @return String 流程实例ID
    	 * @author FRH
    	 * @time 2018年12月10日上午11:03:36
    	 * @version 1.0
    	 */
    	@RequestMapping(value="/start")
    	@ResponseBody
    	public String start() {
    		// xml中定义的ID
    		String instanceKey = "leaveProcess";
    		logger.info("开启请假流程...");
    		
    		// 设置流程参数,开启流程
    		Map<String,Object> map = new HashMap<String,Object>();
            map.put("jobNumber","A1001");
            map.put("busData","bus data");
    		ProcessInstance instance = runtimeService.startProcessInstanceByKey(instanceKey, map);//使用流程定义的key启动流程实例,key对应helloworld.bpmn文件中id的属性值,使用key值启动,默认是按照最新版本的流程定义启动
    		
    		logger.info("启动流程实例成功:{}", instance);
    		logger.info("流程实例ID:{}", instance.getId());
    		logger.info("流程定义ID:{}", instance.getProcessDefinitionId());
    		
    		
    		//验证是否启动成功
    	    //通过查询正在运行的流程实例来判断
    	    ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery();
    	    //根据流程实例ID来查询
    	    List<ProcessInstance> runningList = processInstanceQuery.processInstanceId(instance.getProcessInstanceId()).list();
    	    logger.info("根据流程ID查询条数:{}", runningList.size());
    		
    	    // 返回流程ID
    		return instance.getId();
    	}
    

    6.3 流程跟踪与流程图展示

        Activiti流程图展示,使用流程图生成器,本例生成的流程图在页面使用如下方式展示即可:

    <embed src="/demo/showImg?instanceId=5070fd58-f859-11e8-a359-484d7ec5762d" style="display:block;width:1000px;height:450px" />
    

        引入相关工具包,版本使用默认版本7.0.65

    <!-- Activiti生成流程图 -->
    <dependency>
      <groupId>org.activiti</groupId>
      <artifactId>activiti-image-generator</artifactId>
    </dependency>
    

        调用输出流程图

    /**
    	 * <p>查看当前流程图</p>
    	 * @param instanceId 流程实例
    	 * @param response void 响应
    	 * @author FRH
    	 * @time 2018年12月10日上午11:14:12
    	 * @version 1.0
    	 */
    	@ResponseBody
    	@RequestMapping(value="/showImg")
    	public void showImg(String instanceId, HttpServletResponse response) {
    		/*
    		 * 参数校验
    		 */
    		logger.info("查看完整流程图!流程实例ID:{}", instanceId);
    		if(StringUtils.isBlank(instanceId)) return;
    		
    		
    		/*
    		 *  获取流程实例
    		 */
    		HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(instanceId).singleResult();
    		if(processInstance == null) {
    			logger.error("流程实例ID:{}没查询到流程实例!", instanceId);
    			return;
    		}
    		
    		// 根据流程对象获取流程对象模型
    		BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
    		
    		
    		/*
    		 *  查看已执行的节点集合
    		 *  获取流程历史中已执行节点,并按照节点在流程中执行先后顺序排序
    		 */
    		// 构造历史流程查询
    		HistoricActivityInstanceQuery historyInstanceQuery = historyService.createHistoricActivityInstanceQuery().processInstanceId(instanceId);
    		// 查询历史节点
    		List<HistoricActivityInstance> historicActivityInstanceList = historyInstanceQuery.orderByHistoricActivityInstanceStartTime().asc().list();
    		if(historicActivityInstanceList == null || historicActivityInstanceList.size() == 0) {
    			logger.info("流程实例ID:{}没有历史节点信息!", instanceId);
    			outputImg(response, bpmnModel, null, null);
    			return;
    		}
    		// 已执行的节点ID集合(将historicActivityInstanceList中元素的activityId字段取出封装到executedActivityIdList)
    		List<String> executedActivityIdList = historicActivityInstanceList.stream().map(item -> item.getActivityId()).collect(Collectors.toList());
    		
    		/*
    		 *  获取流程走过的线
    		 */
    		// 获取流程定义
    		ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition(processInstance.getProcessDefinitionId());
    		List<String> flowIds = ActivitiUtils.getHighLightedFlows(bpmnModel, processDefinition, historicActivityInstanceList);
    		
    		
    		/*
    		 * 输出图像,并设置高亮
    		 */
    		outputImg(response, bpmnModel, flowIds, executedActivityIdList);
    	}
    
    	/**
    	 * <p>输出图像</p>
    	 * @param response 响应实体
    	 * @param bpmnModel 图像对象
    	 * @param flowIds 已执行的线集合
    	 * @param executedActivityIdList void 已执行的节点ID集合
    	 * @author FRH
    	 * @time 2018年12月10日上午11:23:01
    	 * @version 1.0
    	 */
    	private void outputImg(HttpServletResponse response, BpmnModel bpmnModel, List<String> flowIds, List<String> executedActivityIdList) {
    		InputStream imageStream = null;
    		try {
    			imageStream = processDiagramGenerator.generateDiagram(bpmnModel, executedActivityIdList, flowIds, "宋体", "微软雅黑", "黑体", true, "png");
    			// 输出资源内容到相应对象
    			byte[] b = new byte[1024];
    			int len;
    			while ((len = imageStream.read(b, 0, 1024)) != -1) {
    				response.getOutputStream().write(b, 0, len);
    			}
    			response.getOutputStream().flush();
    		}catch(Exception e) {
    			logger.error("流程图输出异常!", e);
    		} finally { // 流关闭
    			StreamUtils.closeInputStream(imageStream);
    		}
    	}
    

        流程图工具类ActivitiUtils

    package com.mypro.activiti.utils;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import org.activiti.bpmn.model.BpmnModel;
    import org.activiti.bpmn.model.FlowNode;
    import org.activiti.bpmn.model.SequenceFlow;
    import org.activiti.engine.history.HistoricActivityInstance;
    import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
    
    /**
     * <p>Activiti工作流工具类</p>
     * @author FRH
     * @time 2018年12月10日上午11:26:02
     * @version 1.0
     */
    public class ActivitiUtils {
    	
    
    	/**
    	 * <p>获取流程走过的线</p>
    	 * @param bpmnModel 流程对象模型
    	 * @param processDefinitionEntity 流程定义对象
    	 * @param historicActivityInstances 历史流程已经执行的节点,并已经按执行的先后顺序排序
    	 * @return List<String> 流程走过的线
    	 * @author FRH
    	 * @time 2018年12月10日上午11:26:19
    	 * @version 1.0
    	 */
    	public static List<String> getHighLightedFlows(BpmnModel bpmnModel, ProcessDefinitionEntity processDefinitionEntity, List<HistoricActivityInstance> historicActivityInstances) {
    		// 用以保存高亮的线flowId
    		List<String> highFlows = new ArrayList<String>();
    		if(historicActivityInstances == null || historicActivityInstances.size() == 0) return highFlows;
    
    		// 遍历历史节点
    		for (int i = 0; i < historicActivityInstances.size() - 1; i++) {
    			// 取出已执行的节点
    			HistoricActivityInstance activityImpl_ = historicActivityInstances.get(i);
    
    			// 用以保存后续开始时间相同的节点
    			List<FlowNode> sameStartTimeNodes = new ArrayList<FlowNode>();
    
    			// 获取下一个节点(用于连线)
    			FlowNode sameActivityImpl = getNextFlowNode(bpmnModel, historicActivityInstances, i, activityImpl_);
    //			FlowNode sameActivityImpl = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstances.get(i + 1).getActivityId());
    			
    			// 将后面第一个节点放在时间相同节点的集合里
    			if(sameActivityImpl != null) sameStartTimeNodes.add(sameActivityImpl);
    			
    			// 循环后面节点,看是否有与此后继节点开始时间相同的节点,有则添加到后继节点集合
    			for (int j = i + 1; j < historicActivityInstances.size() - 1; j++) {
    				HistoricActivityInstance activityImpl1 = historicActivityInstances.get(j);// 后续第一个节点
    				HistoricActivityInstance activityImpl2 = historicActivityInstances.get(j + 1);// 后续第二个节点
    				if (activityImpl1.getStartTime().getTime() != activityImpl2.getStartTime().getTime()) break;
    				
    				// 如果第一个节点和第二个节点开始时间相同保存
    				FlowNode sameActivityImpl2 = (FlowNode) bpmnModel.getMainProcess().getFlowElement(activityImpl2.getActivityId());
    				sameStartTimeNodes.add(sameActivityImpl2);
    			}
    			
    			// 得到节点定义的详细信息
    			FlowNode activityImpl = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstances.get(i).getActivityId());
    			// 取出节点的所有出去的线,对所有的线进行遍历
    			List<SequenceFlow> pvmTransitions = activityImpl.getOutgoingFlows();
    			for (SequenceFlow pvmTransition : pvmTransitions) {
    				// 获取节点
    				FlowNode pvmActivityImpl = (FlowNode) bpmnModel.getMainProcess().getFlowElement(pvmTransition.getTargetRef());
    				
    				// 不是后继节点
    				if(!sameStartTimeNodes.contains(pvmActivityImpl)) continue;
    				
    				// 如果取出的线的目标节点存在时间相同的节点里,保存该线的id,进行高亮显示
    				highFlows.add(pvmTransition.getId());
    			}
    		}
    		
    		//返回高亮的线
    		return highFlows;
    	}
    
    
    
    	/**
    	 * <p>获取下一个节点信息</p>
    	 * @param bpmnModel 流程模型
    	 * @param historicActivityInstances 历史节点
    	 * @param i 当前已经遍历到的历史节点索引(找下一个节点从此节点后)
    	 * @param activityImpl_ 当前遍历到的历史节点实例
    	 * @return FlowNode 下一个节点信息
    	 * @author FRH
    	 * @time 2018年12月10日上午11:26:55
    	 * @version 1.0
    	 */
    	private static FlowNode getNextFlowNode(BpmnModel bpmnModel, List<HistoricActivityInstance> historicActivityInstances, int i, HistoricActivityInstance activityImpl_) {
    		// 保存后一个节点
    		FlowNode sameActivityImpl = null;
    		
    		// 如果当前节点不是用户任务节点,则取排序的下一个节点为后续节点
    		if(!"userTask".equals(activityImpl_.getActivityType())) {
    			// 是最后一个节点,没有下一个节点
    			if(i == historicActivityInstances.size()) return sameActivityImpl;
    			// 不是最后一个节点,取下一个节点为后继节点
    			sameActivityImpl = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstances.get(i + 1).getActivityId());// 找到紧跟在后面的一个节点
    			// 返回
    			return sameActivityImpl;
    		}
    		
    		// 遍历后续节点,获取当前节点后续节点
    		for (int k = i + 1; k <= historicActivityInstances.size() - 1; k++) {
    			// 后续节点
    			HistoricActivityInstance activityImp2_ = historicActivityInstances.get(k);
    			// 都是userTask,且主节点与后续节点的开始时间相同,说明不是真实的后继节点
    			if("userTask".equals(activityImp2_.getActivityType()) && activityImpl_.getStartTime().getTime() == activityImp2_.getStartTime().getTime()) continue;
    			// 找到紧跟在后面的一个节点
    			sameActivityImpl = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstances.get(k).getActivityId());
    			break;
    		}
    		return sameActivityImpl;
    	}
    }
    
    

    6.4 附上DemoController完整代码

    package com.mypro.activiti.controller;
    
    import java.io.InputStream;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.stream.Collectors;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.activiti.bpmn.model.BpmnModel;
    import org.activiti.engine.HistoryService;
    import org.activiti.engine.RepositoryService;
    import org.activiti.engine.RuntimeService;
    import org.activiti.engine.TaskService;
    import org.activiti.engine.history.HistoricActivityInstance;
    import org.activiti.engine.history.HistoricActivityInstanceQuery;
    import org.activiti.engine.history.HistoricProcessInstance;
    import org.activiti.engine.impl.RepositoryServiceImpl;
    import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
    import org.activiti.engine.runtime.ProcessInstance;
    import org.activiti.engine.runtime.ProcessInstanceQuery;
    import org.activiti.engine.task.Task;
    import org.activiti.image.ProcessDiagramGenerator;
    import org.apache.commons.lang3.StringUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import com.mypro.activiti.utils.ActivitiUtils;
    import com.mypro.activiti.utils.StreamUtils;
    
    /**
     * <p>Activiti控制器</p>
     * @author FRH
     * @time 2018年12月10日上午9:30:18
     * @version 1.0
     */
    @Controller
    @RequestMapping("/demo")
    public class DemoController {
    
    private static final Logger logger = LoggerFactory.getLogger(DemoController.class);
    	
    	/** 流程定义和部署相关的存储服务 */
    	@Autowired
    	private RepositoryService repositoryService;
    	
    	/** 流程运行时相关的服务 */
    	@Autowired
    	private RuntimeService runtimeService;
    	
    	/** 节点任务相关操作接口 */
    	@Autowired
    	private TaskService taskService;
    	
    	/** 流程图生成器 */
    	@Autowired
    	private ProcessDiagramGenerator processDiagramGenerator;
    
    	/** 历史记录相关服务接口 */
    	@Autowired
    	private HistoryService historyService;
    
    	
    	
    	/**
    	 * <p>跳转到测试主页面</p>
    	 * @return String 测试主页面
    	 * @author FRH
    	 * @time 2018年12月10日上午11:12:28
    	 * @version 1.0
    	 */
    	@RequestMapping(value="/toIndex.html")
    	public String toTestPage() {
    		return "/index";
    	}
    	
    	
    	
    	/**
    	 * <p>跳转到上级审核页面</p>
    	 * @return String 上级审核页面
    	 * @author FRH
    	 * @time 2018年12月5日下午2:31:42
    	 * @version 1.0
    	 */
    	@RequestMapping(value="/toLeave")
    	public String employeeLeave() {
    		return "/employeeLeave";
    	}
    	
    	
    	
    	/**
    	 * <p>启动请假流程(流程key即xml中定义的ID为leaveProcess)</p>
    	 * @return String 启动的流程ID
    	 * @author FRH
    	 * @time 2018年12月10日上午11:12:50
    	 * @version 1.0
    	 */
    	@RequestMapping(value="/start")
    	@ResponseBody
    	public String start() {
    		/*
    		 *  xml中定义的ID
    		 */
    		String instanceKey = "leaveProcess";
    		logger.info("开启请假流程...");
    		
    		
    		/*
    		 *  设置流程参数,开启流程
    		 */
    		Map<String,Object> map = new HashMap<String,Object>();
            map.put("jobNumber","A1001");
            map.put("busData","bus data");
    		ProcessInstance instance = runtimeService.startProcessInstanceByKey(instanceKey, map);//使用流程定义的key启动流程实例,key对应helloworld.bpmn文件中id的属性值,使用key值启动,默认是按照最新版本的流程定义启动
    		
    		logger.info("启动流程实例成功:{}", instance);
    		logger.info("流程实例ID:{}", instance.getId());
    		logger.info("流程定义ID:{}", instance.getProcessDefinitionId());
    		
    		
    		/*
    		 * 验证是否启动成功
    		 */
    	    //通过查询正在运行的流程实例来判断
    	    ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery();
    	    //根据流程实例ID来查询
    	    List<ProcessInstance> runningList = processInstanceQuery.processInstanceId(instance.getProcessInstanceId()).list();
    	    logger.info("根据流程ID查询条数:{}", runningList.size());
    		
    	    
    	    /*
    	     *  返回流程ID
    	     */
    		return instance.getId();
    	}
    	
    	
    	
    	/**
    	 * <p>查看当前流程图</p>
    	 * @param instanceId 流程实例
    	 * @param response void 响应
    	 * @author FRH
    	 * @time 2018年12月10日上午11:14:12
    	 * @version 1.0
    	 */
    	@ResponseBody
    	@RequestMapping(value="/showImg")
    	public void showImg(String instanceId, HttpServletResponse response) {
    		/*
    		 * 参数校验
    		 */
    		logger.info("查看完整流程图!流程实例ID:{}", instanceId);
    		if(StringUtils.isBlank(instanceId)) return;
    		
    		
    		/*
    		 *  获取流程实例
    		 */
    		HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(instanceId).singleResult();
    		if(processInstance == null) {
    			logger.error("流程实例ID:{}没查询到流程实例!", instanceId);
    			return;
    		}
    		
    		// 根据流程对象获取流程对象模型
    		BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
    		
    		
    		/*
    		 *  查看已执行的节点集合
    		 *  获取流程历史中已执行节点,并按照节点在流程中执行先后顺序排序
    		 */
    		// 构造历史流程查询
    		HistoricActivityInstanceQuery historyInstanceQuery = historyService.createHistoricActivityInstanceQuery().processInstanceId(instanceId);
    		// 查询历史节点
    		List<HistoricActivityInstance> historicActivityInstanceList = historyInstanceQuery.orderByHistoricActivityInstanceStartTime().asc().list();
    		if(historicActivityInstanceList == null || historicActivityInstanceList.size() == 0) {
    			logger.info("流程实例ID:{}没有历史节点信息!", instanceId);
    			outputImg(response, bpmnModel, null, null);
    			return;
    		}
    		// 已执行的节点ID集合(将historicActivityInstanceList中元素的activityId字段取出封装到executedActivityIdList)
    		List<String> executedActivityIdList = historicActivityInstanceList.stream().map(item -> item.getActivityId()).collect(Collectors.toList());
    		
    		/*
    		 *  获取流程走过的线
    		 */
    		// 获取流程定义
    		ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition(processInstance.getProcessDefinitionId());
    		List<String> flowIds = ActivitiUtils.getHighLightedFlows(bpmnModel, processDefinition, historicActivityInstanceList);
    		
    		
    		/*
    		 * 输出图像,并设置高亮
    		 */
    		outputImg(response, bpmnModel, flowIds, executedActivityIdList);
    	}
    	
    
    
    	/**
    	 * <p>员工提交申请</p>
    	 * @param request 请求
    	 * @return String 申请受理结果
    	 * @author FRH
    	 * @time 2018年12月10日上午11:15:09
    	 * @version 1.0
    	 */
    	@RequestMapping(value="/employeeApply")
    	@ResponseBody
    	public String employeeApply(HttpServletRequest request){
    		/*
    		 * 获取请求参数
    		 */
    		String taskId = request.getParameter("taskId"); // 任务ID
    		String jobNumber = request.getParameter("jobNumber"); // 工号
    		String leaveDays = request.getParameter("leaveDays"); // 请假天数
    		String leaveReason = request.getParameter("leaveReason"); // 请假原因
    		
    		
    		/*
    		 *  查询任务
    		 */
    		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
    		if(task == null) {
    			logger.info("任务ID:{}查询到任务为空!", taskId);
    			return "fail";
    		}
    
    		
    		/*
    		 * 参数传递并提交申请
    		 */
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("days", leaveDays);
            map.put("date", new Date());
            map.put("reason", leaveReason);
            map.put("jobNumber", jobNumber);
            taskService.complete(task.getId(), map);
            logger.info("执行【员工申请】环节,流程推动到【上级审核】环节");
            
            /*
             * 返回成功
             */
    		return "success";
    	}
    	
    	
    	/**
    	 * <p>跳转到上级审核页面</p>
    	 * @return String 页面
    	 * @author FRH
    	 * @time 2018年12月5日下午2:31:42
    	 * @version 1.0
    	 */
    	@RequestMapping(value="/viewTask")
    	public String toHigherAudit(String taskId, HttpServletRequest request) {
    		/*
    		 * 获取参数
    		 */
    		logger.info("跳转到任务详情页面,任务ID:{}", taskId);
    		if(StringUtils.isBlank(taskId)) return "/higherAudit";
    		
    		
    		/*
    		 *  查看任务详细信息
    		 */
    		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
    		if(task == null) {
    			logger.info("任务ID:{}不存在!", taskId);
    			return "/higherAudit";
    		}
    		
    		
    		/*
    		 * 完成任务
    		 */
    		Map<String, Object> paramMap = taskService.getVariables(taskId);
    		request.setAttribute("task", task);
    		request.setAttribute("paramMap", paramMap);
    		return "higherAudit";
    	}
    	
    	
    	
    	/**
    	 * <p>跳转到部门经理审核页面</p>
    	 * @param taskId 任务ID
    	 * @param request 请求
    	 * @return String 响应页面
    	 * @author FRH
    	 * @time 2018年12月6日上午9:54:34
    	 * @version 1.0
    	 */
    	@RequestMapping(value="/viewTaskManager")
    	public String viewTaskManager(String taskId, HttpServletRequest request) {
    		/*
    		 * 获取参数
    		 */
    		logger.info("跳转到任务详情页面,任务ID:{}", taskId);
    		if(StringUtils.isBlank(taskId)) return "/manageAudit";
    		
    		
    		/*
    		 *  查看任务详细信息
    		 */
    		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
    		if(task == null) {
    			logger.info("任务ID:{}不存在!", taskId);
    			return "/manageAudit";
    		}
    		
    		
    		/*
    		 * 完成任务
    		 */
    		Map<String, Object> paramMap = taskService.getVariables(taskId);
    		request.setAttribute("task", task);
    		request.setAttribute("paramMap", paramMap);
    		return "manageAudit";
    	}
    	
    	
    
    	/**
    	 * <p>上级审核</p>
    	 * @param request 请求
    	 * @return String 受理结果
    	 * @author FRH
    	 * @time 2018年12月10日上午11:19:44
    	 * @version 1.0
    	 */
    	@ResponseBody
    	@RequestMapping(value="/higherLevelAudit")
    	public String higherLevelAudit(HttpServletRequest request) {
    		/*
    		 * 获取请求参数
    		 */
    		String taskId = request.getParameter("taskId");
    		String higherLevelOpinion = request.getParameter("sug");
    		String auditStr = request.getParameter("audit");
    		logger.info("上级审核任务ID:{}", taskId);
    		if(StringUtils.isBlank(taskId)) return "fail";
    
    		
    		/*
    		 * 查找任务
    		 */
    		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
    		if(task == null) {
    			logger.info("审核任务ID:{}查询到任务为空!", taskId);
    			return "fail";
    		}
    		
    		
    		/*
    		 * 设置局部变量参数,完成任务
    		 */
    		Map<String, Object> map = new HashMap<String, Object>();
    		map.put("audit", "1".equals(auditStr) ? false : true);
    		map.put("higherLevelOpinion", higherLevelOpinion);
    		taskService.complete(taskId, map);
    		return "success";
    	}
    	
    	
    	
    	/**
    	 * <p>部门经理审核</p>
    	 * @param request 请求
    	 * @return String 受理结果
    	 * @author FRH
    	 * @time 2018年12月10日上午11:20:44
    	 * @version 1.0
    	 */
    	@ResponseBody
    	@RequestMapping(value="/divisionManagerAudit")
    	public String divisionManagerAudit(HttpServletRequest request) {
    		/*
    		 * 获取请求参数
    		 */
    		String taskId = request.getParameter("taskId");
    		String opinion = request.getParameter("sug");
    		String auditStr = request.getParameter("audit");
    		logger.info("上级审核任务ID:{}", taskId);
    		if(StringUtils.isBlank(taskId)) return "fail";
    
    		
    		/*
    		 * 查找任务
    		 */
    		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
    		if(task == null) {
    			logger.info("审核任务ID:{}查询到任务为空!", taskId);
    			return "fail";
    		}
    		
    		
    		/*
    		 * 设置局部变量参数,完成任务
    		 */
    		Map<String, Object> map = new HashMap<String, Object>();
    		map.put("audit", "1".equals(auditStr) ? false : true);
    		map.put("managerOpinion", opinion);
    		taskService.complete(taskId, map);
    		return "success";
    	}
    	
    	
    	/**
    	 * <p>查看任务</p>
    	 * @param request 请求
    	 * @return String  任务展示页面
    	 * @author FRH
    	 * @time 2018年12月10日上午11:21:33
    	 * @version 1.0
    	 */
    	@RequestMapping(value="/toShowTask")
    	public String toShowTask(HttpServletRequest request) {
    		/*
    		 * 获取请求参数
    		 */
    		List<Task> taskList = taskService.createTaskQuery().list();
    		if(taskList == null || taskList.size() == 0) {
    			logger.info("查询任务列表为空!");
    			return "/task";
    		}
    		
    		
    		/*
    		 * 查询所有任务,并封装
    		 */
    		List<Map<String, String>> resultList = new ArrayList<Map<String, String>>();
    		for(Task task : taskList) {
    			Map<String, String> map = new HashMap<String, String>();
    			map.put("taskId", task.getId());
    			map.put("name", task.getName());
    			map.put("createTime", task.getCreateTime().toString());
    			map.put("assignee", task.getAssignee());
    			map.put("instanceId", task.getProcessInstanceId());
    			map.put("executionId", task.getExecutionId());
    			map.put("definitionId", task.getProcessDefinitionId());
    			resultList.add(map);
    		}
    		
    		
    		/*
    		 * 返回结果
    		 */
    		logger.info("返回集合:{}", resultList.toString());
    		request.setAttribute("resultList", resultList);
    		return "/task";
    	}
    	
    
    
    	/**
    	 * <p>输出图像</p>
    	 * @param response 响应实体
    	 * @param bpmnModel 图像对象
    	 * @param flowIds 已执行的线集合
    	 * @param executedActivityIdList void 已执行的节点ID集合
    	 * @author FRH
    	 * @time 2018年12月10日上午11:23:01
    	 * @version 1.0
    	 */
    	private void outputImg(HttpServletResponse response, BpmnModel bpmnModel, List<String> flowIds, List<String> executedActivityIdList) {
    		InputStream imageStream = null;
    		try {
    			imageStream = processDiagramGenerator.generateDiagram(bpmnModel, executedActivityIdList, flowIds, "宋体", "微软雅黑", "黑体", true, "png");
    			// 输出资源内容到相应对象
    			byte[] b = new byte[1024];
    			int len;
    			while ((len = imageStream.read(b, 0, 1024)) != -1) {
    				response.getOutputStream().write(b, 0, len);
    			}
    			response.getOutputStream().flush();
    		}catch(Exception e) {
    			logger.error("流程图输出异常!", e);
    		} finally { // 流关闭
    			StreamUtils.closeInputStream(imageStream);
    		}
    	}
    	
    
    
    	/**
    	 * <p>判断流程是否完成</p>
    	 * @param processInstanceId 流程实例ID
    	 * @return boolean 已完成-true,未完成-false
    	 * @author FRH
    	 * @time 2018年12月10日上午11:23:26
    	 * @version 1.0
    	 */
    	public boolean isFinished(String processInstanceId) {
            return historyService.createHistoricProcessInstanceQuery().finished().processInstanceId(processInstanceId).count() > 0;
        }
    	
    }
    
    

    7. 效果

    在这里插入图片描述
        看出Activiti默认使用Spring的security,添加配置,关闭安全认证,如下:

    # 关闭activiti登录验证
    security:
      basic:
        enabled: false
    

        重启后继续访问,可正常进入首页(如还是无法进入首页,请添加@EnableAutoConfiguration(exclude = {org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class}),或者从pom.xml中移除Security包):
    在这里插入图片描述
        点击我要请假后,得到流程实例ID,再查看流程图,如下:

    在这里插入图片描述

        附上首页/index.html代码,其它页面相比比较简单:

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
    <head>
    	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    	<meta name="viewport" content="width=device-width, initial-scale=1">
    	<title>首页</title>
    	<script th:src="@{/static/jquery.min.js}"></script>
    	<script type="text/javascript">
    		$(function(){
    			// 点击菜单
    			$(".show-page").bind("click", function(){
    				$(".main-body").html("");
    				$(".result-div").html("");
    				var url = $(this).attr("url");
    				
    				$.ajax({
    					async : false,
    					cache : false,
    					type : 'POST',
    					url : url,
    					dataType : "html",
    					error : function() {
    						alert('请求失败');
    					},
    					success : function(data) {
    						$(".result-div").html(data);
    					}
    				});
    			});
    			
    			// 点击我要请假,开启流程
    			$(".show-instance").bind("click", function(){
    				$(".main-body").html("");
    				$(".result-div").html("");
    				var url = $(this).attr("url");
    				
    				$.ajax({
    					async : false,
    					cache : false,
    					type : 'POST',
    					url : url,
    					dataType : "html",
    					error : function() {
    						alert('请求失败');
    					},
    					success : function(data) {
    						$("input[name='instanceId']").val(data);
    					}
    				});
    			});
    			
    			// 绑定查看流程图
    			$(".show-img").bind("click", function(){
    				var instanceId = $("input[name='instanceId']").val();
    				if(instanceId == "") {
    					alert("暂无流程!");
    					return;
    				}
    				var imgHtml = '<embed src="/demo/showImg?instanceId=' + instanceId + '" style="display:block;width:1000px;height:450px" />';
    				$(".result-div").html(imgHtml);
    			});
    			
    			// 查看任务
    			$(".show-task").bind("click", function(){
    				$.ajax({
    					async : false,
    					cache : false,
    					type : 'POST',
    					url : "/demo/toShowTask",
    					data : {"aaabbbccc":"aa"},
    					dataType : "html",
    					error : function() {
    						alert('请求失败');
    					},
    					success : function(data) {
    						$(".result-div").html(data);
    					}
    				});
    			});
    			
    		});
    		
    		/**
    		 * 员工提交申请
    		 */
    		function toLeave() {
    			$.ajax({
    				async : false,
    				cache : false,
    				type : 'POST',
    				url : "/demo/employeeApply",
    				dataType: "text",
    				data: $(".employee-leave").serialize(),
    				error : function() {
    					alert('请求失败');
    				},
    				success : function(data) {
    					alert(data);
    				}
    			});
    		}
    		
    		/**
    		 * 上级审核
    		 */
    		function higherAudit() {
    			$.ajax({
    				async : false,
    				cache : false,
    				type : 'POST',
    				url : "/demo/higherLevelAudit",
    				dataType: "text",
    				data: $(".higher-audit").serialize(),
    				error : function() {
    					alert('请求失败');
    				},
    				success : function(data) {
    					alert(data);
    				}
    			});
    		}
    		
    		/**
    		 * 部门经理审核
    		 */
    		function managerAudit() {
    			$.ajax({
    				async : false,
    				cache : false,
    				type : 'POST',
    				url : "/demo/divisionManagerAudit",
    				dataType: "text",
    				data: $(".manager-audit").serialize(),
    				error : function() {
    					alert('请求失败');
    				},
    				success : function(data) {
    					alert(data);
    				}
    			});
    		}
    		
    		/**
    		 * 上级审核
    		 */
    		function viewTask(taskId, name) {
    			var url = "/demo/viewTask";
    			if(name != "上级审核") {
    				url = "/demo/viewTaskManager";
    			}
    			
    			
    			$.ajax({
    				async : false,
    				cache : false,
    				type : 'POST',
    				url : url,
    				data : {"taskId" : taskId},
    				dataType : "html",
    				error : function() {
    					alert('请求失败');
    				},
    				success : function(data) {
    					$(".result-div").html(data);
    				}
    			});
    		}
    	</script>
    </head>
    <body>
    	<!-- 菜单栏 -->
    	<div class="main-menu">
    		<button class="show-instance" url="/demo/start">我要请假</button>
    		<button class="show-page" url="/demo/toLeave">开始填单</button>
    		<button class="show-img">查看流程图</button>
    		<button class="show-task">查看任务</button>
    	</div>
    	<br/>
    		流程实例ID:<input type="text" name="instanceId"/>
    	<br/>
    	<!-- 操作栏 -->
    	<div class="main-body">
    		
    	</div>	
    	<br/>
    	<!-- 结果栏 -->
    	<div class="result-div">
    		<embed src="/demo/showImg?instanceId=5070fd58-f859-11e8-a359-484d7ec5762d" style="display:block;width:1000px;height:450px" />
    		<br>
    		<!-- <img src="/static/leave-process.png"/> -->
    	</div>
    </body>
    </html>
    
    展开全文
  • activiti7.rar

    2021-02-23 12:43:04
    最新工作流引擎Activiti7基础与进阶源码,包含activiti7基础、activiti7-spring、activiti7-springboot、activiti7-springboot-demo
  • activiti7
  • springboot整合activiti7
  • Activiti7正式版- Activiti Cloud SR1

    万次阅读 2019-03-10 15:15:33
    2019年3月18版本,Activiti7正式版Activiti Cloud SR1正式发布。 我很高兴地宣布第一个服务版本的Activiti Cloud 和Activiti Core artefacts。在从我们的第一次GA迭代中获得大量社区反馈之后,我们现在发布了7.0.0...
  • Activiti7.zip

    2020-08-08 19:13:30
    Activiti7 最新教程,背景介绍,详细步骤操作, 实例,压缩包一共三个文件,基础部分、进阶部分、Activiti7新特性
  • activiti7开发指南

    2019-08-02 14:01:36
    activiti7开发指南
  • 4、执行user.sql创建用户表并修复Activiti7官方Bug 注意:先运行一次项目,Activiti会自动初始化数据库需要的表,然后再执行下面的sql 使用Navicat等工具执行项目根目录下user.sql 5、运行项目 测试账号:...
  • activiti7简介与helloworld,旨在学习activiti7的工作流程和原理
  • Activiti7工作流引擎

    2020-11-01 11:45:51
    Activiti7工作流引擎, 包扩了 讲义 与 源码, 是Activiti7入门的好资料.
  • Activiti7创建数据库表

    2020-05-27 13:00:55
    Activiti7数据库表的建立,其中包含了17张以上的数据表,这些数据表原本是可以通过Activiti7自行创建,但是Activiti7还不持直接通过MySQL8.0的数据库来创建表,所以通过这个文件手动创建
  • 第2章 什么是Activiti7 2.1 Activiti 介绍 Alfresco 软件在 2010 年 5 月 17 日宣布 Activiti 业务流程管理(BPM)开源项目的正式启动,其首席架构师由业务流程管理 BPM 的专家 Tom Baeyens 担任,Tom Baeyens 就是...
  • activiti7与spring、springBoot整合
  • Activiti7工作流引擎环境搭建在IEDA中添加actiBPM插件file -->>Settings -->> Plugins -->> actiBPM添加Activiti所需的jar包activiti-engine-7.0.0.beta1.jaractiviti 依赖的 jar 包:mybatis、alf...
  • Activiti7的学习教程

    2019-08-18 16:40:38
    2019年最新的Activiti7的学习教程,包含视频和代码等等,可以更系统的进行activiti7工作流引擎的学习
  • Activiti7是一个工作流引擎何为工作流?工作的一个流程,事务发展的一个业务过程。如请假流程:员工申请----部门主管审批----总经理审批----归档录入在计算机的帮助下,能够实现实现流程的自动化控制,就称为工作流...
  • Activiti7最新工作引擎资料
  • activiti7搭建

    2021-03-09 12:36:57
    activiti7搭建(spring cloud2.X + activiti7 +mysql) maven依赖 <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-...
  • 1|1简介最近基于最新的Activiti7配置了SpringBoot2。简单上手使用了一番。发现市面上解决Activiti7的教程很少,采坑也比较多,在Activiti6配置数据源和Activiti7有所区别,基于Activiti6在Activiti7里是无法正常使用...
  • activiti7笔记

    2020-05-03 13:18:30
    学习路径:E:\黑马JAVA2019\01-Activiti7工作流引擎
  • Activiti7 笔记

    2021-02-11 11:28:30
    第一章 Activiti7 功能简介 一、概念 通过以下两点完成目标 1.人工审批某任务 2.预定义规则自动执行行某任务 二、工作流系统 1.业务系统 2.纯工作流系统(不关心相关业务、和业务系统区分降低耦合性) 三、适用业务 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,725
精华内容 690
关键字:

activiti7