Day02:流程中心 - 管理员操作
今日学习目标:
- 掌握前端vue工程的编译、启动和部署
- 掌握模型、流程图、模型定义的含义和相互关系
- 掌握模型的基本操作:增、删、改、查
- 掌握流程图的操作:保存、部署、展示
- 掌握流程定义的操作:查询、删除、下载资源等
- 掌握流程定义的激活、挂起操作
需求分析
- 在流程审批系统中,管理员需要做的事情包括以下两类:
- 设计流程图
- 保存流程图、部署(发布)流程图
设计流程图有两种方式:
- 一种是使用第一天讲解的方式,用actiBPMN设计一个流程图,把流程图上传到服务器上,然后进行保存、发布、使用。
- 第二种方式是直接在系统中设计流程图,这种方式避免了上传流程图的过程,是主流的开发方式。
本项目采用的就是第二种方式,即在线流程设计。这个方式需要一个在线流程设计器,这是一种前端解决方案,有很多前端组件可以供我们选择使用。
注意:上图中大部分操作只需要在前端进行。
- 我们需要开发的是如何将前端框架生成的文件进行保存、部署、查询等操作。本质上是一些对象的增删改查。
- 模型管理
流程定义管理
2. 在线设计器
2.1. bpmn2.0规范
为什么一个mysql的数据库脚本,可以在不同公司的mysql数据库上执行?
答案是规范,也就是说这些mysql数据库,都遵循了相同的规范和标准,所以数据库实例是可以共用的。相同的例子还有:
- 一个word文档,可以在不同的机器上打开,只要这些机器都安装了office程序
- 一个pdf文件,可以在不同机器上打开,但是需要安装pdf阅读器
- 一个java程序,可以在不同人的idea里打开
activiti的流程图,满足了bpmn2.0规范
我们将第一天设计的bpmn文件,保存成以下是一个符合bpmn2.0规范的xml文件,这个文件可以被其他bpmn设计器打开、解析。

2.2. bpmn-js框架
在线流程设计器是一个前端的框架,可以方便的集成到我们的项目的前端工程中。
bpmn-js是一个BPMN2.0的工具包和web建模器
JavaScript编写,轻松嵌入到任何web应用。
既可以是web查看器也可以是web建模器。
官网:https://bpmn.io/toolkit/bpmn-js/
源码:https://github.com/bpmn-io/bpmn-js
案例:https://bpmn.io/toolkit/bpmn-js/examples/
演示:https://demo.bpmn.io/
2.3. 前端工程
2.3.1 工程介绍
流程中心的前端工程使用的是vue框架,集成了bpmn-js框架。
目录结构:
服务端口:
前端工程有两种启动方式,本地源代码启动和服务器端部署启动。本地源码启动需要在本机安装nodejs,并执行编译命令。服务器端启动则可以直接将编译后的程序部署到nginx服务器中。
为简便起见,推荐使用服务器端启动。
2.3.2 本地启动
- 编译
npm install
启动
npm run serve
访问
2.3.3 服务器启动
通过以下方式部署生产环境
- 生成
npm run build
前端工程中的dist目录中的文件拷贝到Nginx的工程目录、改名
修改nginx.conf文件
location /api {
proxy_pass http://127.0.0.1:8090/;
}
启动Nginx、页面访问
3. 模型管理
3.1 工程改造
前端工程师开发的前端项目,需要后端工程提供服务,我们在第一天项目基础上进行改造。改造完成后,进行前文需求分析章节里提到的功能接口的开发。
3.1.1. 更新pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.itheima</groupId>
<artifactId>itcast-workflow</artifactId>
<version>0.0.1</version>
<name>${project.artifactId}</name>
<description>itcast-workflow</description>
<packaging>jar</packaging>
<properties>
<java.version>1.8</java.version>
<activiti.version>7.1.0.M6</activiti.version>
<knife4j.version>3.0.2</knife4j.version>
<spring-cloud.version>2020.0.3</spring-cloud.version>
<spring-plugin.version>2.0.0.RELEASE</spring-plugin.version>
<jwt.version>0.9.1</jwt.version>
<druid.version>1.2.6</druid.version>
<mybatis-plus.version>3.4.2</mybatis-plus.version>
<mybatis.version>3.5.6</mybatis.version>
<fastjson.version>1.2.62</fastjson.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<!-- Activiti -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-image-generator</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
<exclusions>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!-- druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
<version>5.0.7</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-metadata</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-core</artifactId>
<version>${spring-plugin.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-metadata</artifactId>
<version>${spring-plugin.version}</version>
</dependency>
<!-- md5 工具类 -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jwt.version}</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<repositories>
<repository>
<id>itheima</id>
<name>itheima</name>
<url>http://repo.itheima.net/repository/maven-public/</url>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.1.2. 更新yml文件
server:
port: 8090
spring:
application:
name: 流程审批中心
datasource: # JDBC配置
druid:
url: jdbc:mysql://localhost:3306/itcast_workflow?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: root
password: root
# 连接池配置(通常来说只需要修改initial-size,min-idle,mac-active)
initial-size: 1
max-active: 20
min-idle: 1
# 获取连接等待的超时时间
max-wait: 60000
#打开PSCache,并且指定每个连接上PSCache的大小
pool-prepared-statements: true
max-pool-prepared-statement-per-connection-size: 20
validation-query: SELECT 'x'
test-on-borrow: false
test-on-retur: false
test-while-idle: true
# 配置间隔多久进行一次检查,检查需要关闭的空闲连接,单位毫秒
time-between-eviction-runs-millis: 60000
# 配置一个连接在连接池中最小的生存时间,单位毫秒
min-evictable-idle-time-millis: 300000
# 配置多个英文逗号分割
filters: stat
activiti:
db-history-used: true #使用历史表,如果不配置,则工程启动后可以检查数据库,只建立了17张表,历史表没有建立
history-level: full #记录全部历史操作
database-schema-update: true #自动建表
# flase: 默认值。activiti在启动时,会对比数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常。
# true: activiti会对数据库中所有表进行更新操作。如果表不存在,则自动创建。
# create_drop: 在activiti启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)。
# drop-create: 在activiti启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎
check-process-definitions: false # 自动部署验证设置:true-开启(默认)、false-关闭 在resource目录下添加processes文件夹,并且文件夹不能为空
# main:
# allow-bean-definition-overriding: true #当遇到同样名字的时候,是否允许覆盖注册
database-schema: atc #置建表策略,如果没有表,自动创建表 修改这个地方为大写
#关闭springAutoDeployment自动部署流程定义
deployment-mode: never-fail
main:
allow-bean-definition-overriding: true
swagger:
enabled: true
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
auto-mapping-behavior: full
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: ID_WORKER
3.1.3. 清空数据库
删除数据库中所有的表
3.1.4. 导入公共类
common包和config包是一些基础公共的类,导入到项目里。
- Result类:这个类是用于封装给前端的返回一个统一的对象,这个对象便于前端统一解析和处理
- SpringContextHolder:spring上下文的工具类,包含获取bean、设置bean、判断bean等方法
- WorkflowException:统一封装运行时异常
- ConfigurationSupport:webmvc的配置类,实现Swagger的配置类和一些方法的实现
- ExceptionConfiguration:
- MybatisPlusConfig:mybatisplus的分页插件
3.2. 模型管理
3.2.1 需求分析
模型管理是针对模型对象的一些操作,这些将是我们开发的接口:
- 保存模型对象的基本信息
- 保存模型对象的流程图
- 查询模型对象的列表
- 删除模型对象
- 部署模型对象
- 查询部署后生成的流程定义
- 挂起模型对象
- 启用挂起的模型对象
因为我们使用的是Activiti框架,此框架提供了一系列实体对象,如模型类:org.activiti.engine.repository.Model。
在本项目中对于一个Activiti对象的增删改查操作,开发过程是:
DTO:模型传输对象**(如:ModelDTO),dto的字段是根据产品原型得到的。
- 前端到后端的数据传输对象
- 分页查询返回的结果
导入DTO对象:
3.2.2. 新增
ModelerController:
package com.itheima.activiti.controller.modeler;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.activiti.common.Result;
import com.itheima.activiti.dto.modeler.ModelDTO;
import com.itheima.activiti.service.modeler.ModelerService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@Slf4j
@RestController
@RequestMapping("/modeler")
@Api(tags = "模型管理")
public class ModelerController {
@Autowired
ModelerService modelerService;
/**
* 保存流程模型
* @param modelDTO
* @return
*/
@PostMapping
@ApiOperation(value = "新增模型")
public Result save(@RequestBody ModelDTO modelDTO){
//调用服务的方法
modelerService.save(modelDTO);
return Result.success();
}
}
ModelerService:
package com.itheima.activiti.service.modeler;
import com.itheima.activiti.dto.modeler.ModelDTO;
public interface ModelerService {
/**
* 保存模型
*/
String save(ModelDTO modelDTO);
}
ModelerServiceImpl:
package com.itheima.activiti.service.modeler.impl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.itheima.activiti.dto.modeler.ModelDTO;
import com.itheima.activiti.service.modeler.ModelerService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ModelQuery;
import org.activiti.engine.repository.ProcessDefinition;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class ModelerServiceImpl implements ModelerService {
@Autowired
RepositoryService repositoryService;
@Autowired
ObjectMapper objectMapper;
@Override
public String save(ModelDTO modelDTO) {
//创建activiti模型对象
Model model = repositoryService.newModel();
//设置模型的基本属性
model.setKey(modelDTO.getKey());
model.setName(modelDTO.getName());
//设置模型的mateInfo
ObjectNode objectNode = objectMapper.createObjectNode();
objectNode.put("name", modelDTO.getName());
objectNode.put("description", modelDTO.getDescription());
objectNode.put("reversion", model.getVersion());
model.setMetaInfo(objectNode.toString());
//保存模型
repositoryService.saveModel(model);
return model.getId();
}
}
### 3.2.3. 列表

**ModelerController**:
```java
/**
* 分页查询、搜索
*
*/
@GetMapping("/page")
@ApiOperation(value = "分页模型")
public Result<Page<ModelDTO>> page(ModelDTO modelDTO,
@RequestParam(required = false, defaultValue = "1") int page,
@RequestParam(required = false, defaultValue = "10") int pageSize){
log.info("page = {}, pageSize = {}", page, pageSize);
Page<ModelDTO> list = modelerService.page(modelDTO, page, pageSize);
return Result.success(list);
}
ModelService:
/**
* 分页查询页面设计的模型
* @param modelDTO
* @param page
* @param pageSize
* @return
*/
Page<ModelDTO> page(ModelDTO modelDTO, int page, int pageSize);
ModelerServiceImpl:
页面上的信息包含:模型的属性,和最新的流程定义的版本号。所以需要查询两类数据:模型 + 流程定义
@Override
public Page<ModelDTO> page(ModelDTO modelDTO, int page, int pageSize) {
//从前端传入对象中,获取key和name
String key = modelDTO.getKey();
String name = modelDTO.getName();
//创建模型的查询对象
ModelQuery modelQuery = repositoryService.createModelQuery()
.orderByModelName().desc();
//设置查询条件
if(StringUtils.isNotEmpty(key)){
modelQuery.modelKey(key);
}
if(StringUtils.isNotEmpty(name)){
modelQuery.modelName(name);
}
//返回查询数量
long total = modelQuery.count();
//返回查询结果
List<Model> list = modelQuery.listPage((page - 1) * pageSize, pageSize);
//定义分页对象
Page<ModelDTO> pageResult = new Page(page, pageSize, total);
//遍历查询结果,返回ModelDTO
List<ModelDTO> modelDTOList = list.stream().map(item -> {
ModelDTO dto = new ModelDTO();
BeanUtils.copyProperties(item, dto);
//设置流程定义的属性
//获取流程定义
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey(item.getKey())
.latestVersion().singleResult();
if(processDefinition == null){
dto.setVersion(null);
}
else{
dto.setVersion(processDefinition.getVersion()); //当前部署的流程的版本
dto.setProcessDefinitionId(processDefinition.getId());//流程定义的id
dto.setProcessDefinitionSuspended(processDefinition.isSuspended());//流程的状态
}
return dto;
}).collect(Collectors.toList());
pageResult.setRecords(modelDTOList);
return pageResult;
}
3.2.4. 删除
ModelerController:
/**
* 删除模型
*/
@DeleteMapping
@ApiOperation(value = "删除模型")
public Result delete(String id){
modelerService.delete(id);
return Result.success();
}
ModelerService:
/**
* 删除模型
* @param id 模型id
*/
void delete(String id);
ModelerServiceImpl:
@Override
public void delete(String id) {
repositoryService.deleteModel(id);
}
3.3. 流程图管理
- 模型包括基本信息和流程图,流程图相关操作有保存、查看、部署。流程图是符合bpmn2.0规范文件,本质上是一个xml文件。
- 使用前端组件bpmn.js来设计和展示流程图,在本项目中,对该组件进行了改造。
- 保存流程图在ModelerService中
3.3.1. 保存
ModelerController:
/**
* 保存模型的流程图
*/
@PostMapping("/xml")
@ApiOperation("保存流程图")
public Result<ModelDTO> saveXml(@RequestBody ModelDTO modelDTO){
log.info("ModelDTO: {}",modelDTO);
modelerService.saveXml(modelDTO);
return Result.success(modelDTO);
}
ModelerService:
/**
* 保存流程图
*/
void saveXml(ModelDTO modelDTO);
ModelerServiceImpl:
@Override
public void saveXml(ModelDTO modelDTO) {
//保存模型
if(StringUtils.isEmpty(modelDTO.getId())){
String id = this.save(modelDTO);
modelDTO.setId(id);
}
try {
//保存流程图
repositoryService.addModelEditorSource(modelDTO.getId(), modelDTO.getContent().getBytes("utf-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
3.3.2. 查看
ModelerService:
/**
* 根据模型的id获取流程图
*/
String getXmlById(String id);
ModelerServiceImpl:
@Override
public String getXmlById(String id) {
byte[] content = repositoryService.getModelEditorSource(id);
if(content == null){ //新建时
return "";
}
else{
return new String(content);
}
}
ModelerController:
/**
* 查询流程图的内容
* @param id
* @return
*/
@GetMapping("/xml/{id}")
@ApiOperation(value = "查询流程图")
public Result getXmlById(@PathVariable String id){
log.info("流程图id:{}", id);
String content = modelerService.getXmlById(id);
return Result.success(content);
}
3.3.3. 部署
- 将流程模型(流程图)发布、部署到Activiti服务中
- 部署模型后,生成一个版本的流程定义(ProcessDefinition,数据库表是:ACT_RE_MODEL)
流程部署的传输对象(已导入):
@Data
@ApiModel("部署流程")
public class DeployDTO {
@ApiModelProperty("模型主键")
private String modelId;
}
DeployService
package com.itheima.activiti.service.activiti;
public interface DeployService {
/**
* 部署模型
* @param id
* @return
*/
void deploy(String id);
}
DeployServiceImpl:
package com.itheima.activiti.service.activiti.impl;import com.itheima.activiti.service.activiti.DeployService;import org.activiti.engine.RepositoryService;import org.activiti.engine.repository.Model;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;@Servicepublic class DeployServiceImpl implements DeployService { @Autowired RepositoryService repositoryService; @Override public void deploy(String id) { //根据模型id,获取模型对象 Model model = repositoryService.getModel(id); //根据模型id,获取模型资源 byte[] content = repositoryService.getModelEditorSource(id); //部署模型 repositoryService.createDeployment() .key(model.getKey()) .name(model.getName()) .addString(model.getName() + ".bpmn20.xml", new String(content)) .deploy(); }}
DeployController:
package com.itheima.activiti.controller.activiti;
import com.itheima.activiti.common.Result;
import com.itheima.activiti.dto.activiti.DeployDTO;
import com.itheima.activiti.service.activiti.DeployService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
@RequestMapping("/deploy")
@Api(tags = "流程部署")
public class DeployController {
@Autowired
private DeployService deployService;
@PostMapping
@ApiOperation(value="部署", notes = "传入模型id")
public Result deploy(@RequestBody DeployDTO deployDTO){
deployService.deploy(deployDTO.getModelId());
return Result.success();
}
}
3.4. 流程定义管理
将流程图部署(发布)到activiti引擎后,将会生成流程定义对象(ProcessDefinition),对应的数据库表是:ACT_RE_PROCDEF
3.4.1. 查询
根据流程定义列表,创建dto对象(已导入):
package com.itheima.activiti.dto.activiti;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@ApiModel("流程定义")
public class ProcessDefinitionDTO {
@ApiModelProperty("流程定义Id")
private String id;
@ApiModelProperty("流程定义名称")
private String name;
@ApiModelProperty("流程定义的key")
private String key;
@ApiModelProperty("流程定义的版本")
private Integer version;
@ApiModelProperty("资源名称bpmn文件")
private String resourceName;
@ApiModelProperty("资源名称png文件")
private String diagramResourceName;
@ApiModelProperty("部署对象ID")
private String deploymentId;
@ApiModelProperty("部署时间")
private LocalDateTime deploymentTime;
@ApiModelProperty("挂起状态")
private Boolean suspended;
}
DeployController:
@GetMapping("/page")
@ApiOperation(value = "分页")
public Result<Page<ProcessDefinitionDTO>> page(ProcessDefinitionDTO processDefinitionDTO,
@RequestParam(required = false, defaultValue = "1") int page,
@RequestParam(required = false, defaultValue = "10") int pageSize) {
return Result.success(deployService.page(processDefinitionDTO, page, pageSize));
}
DeployService:
/**
* 分页/搜索流程定义
* @param processDefinitionDTO
* @param page
* @param pageSize
* @return
*/
Page<ProcessDefinitionDTO> page(ProcessDefinitionDTO processDefinitionDTO, int page, int pageSize);
DeployServiceImpl:
@Override
public Page<ProcessDefinitionDTO> page(ProcessDefinitionDTO pdDTO, int page, int pageSize) {
//创建流程定义的查询对象
ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery();
//设置查询条件:key、version
if(StringUtils.isNotBlank(pdDTO.getKey())){
query.processDefinitionKey(pdDTO.getKey());
}
if(null != pdDTO.getVersion()){
query.processDefinitionVersion(pdDTO.getVersion());
}
//分页查询流程定义
List<ProcessDefinition> list = query.listPage((page - 1) * pageSize, pageSize);
//返回分页的流程定义dto:复制对象属性、设置部署时间
List<ProcessDefinitionDTO> pdDtoList = null;
if(null != list && list.size() > 0){
//将流程定义转换成dto对象
pdDtoList = list.stream().map(item ->{
ProcessDefinitionDTO dto = new ProcessDefinitionDTO();
//复制对象属性
BeanUtils.copyProperties(item, dto);
//查询此流程定义的部署时间
Deployment deployment = repositoryService.createDeploymentQuery()
.deploymentId(item.getDeploymentId())
.singleResult();
//设置dto的部署时间
dto.setDeploymentTime(LocalDateTime.ofInstant(deployment.getDeploymentTime().toInstant(), ZoneId.systemDefault()));
return dto;
}).collect(Collectors.toList());
}
//查询总数
long total = query.count();
//分页返回dto
Page<ProcessDefinitionDTO> pageResult = new Page(page, pageSize, total);
pageResult.setRecords(pdDtoList);
return pageResult;
}
3.4.2. 删除
DeployController:
@DeleteMapping
@ApiOperation(value = "删除流程", notes = "流程id")
public Result delete(@RequestParam List<String> ids) {
deployService.removeByIds(ids);
return Result.success("删除成功");
}
DeployService:
/**
* 根据部署id,删除流程定义
* @param ids:部署id的列表
*/
void removeByIds(List<String> ids);
DeployServiceImpl:
@Override
public void removeByIds(List<String> ids) {
for (int i = 0; i < ids.size(); i++) {
repositoryService.deleteDeployment(ids.get(i));
}
}
3.4.3. 挂起
挂起时,无法从此流程定义创建流程实例,类似于暂停某个制度的执行。
DeployController:
@PutMapping("suspend/{id}")
@ApiOperation("挂起流程")
@ApiImplicitParam(name = "id", value = "流程ID", paramType = "query", dataType = "String")
public Result suspend(@PathVariable("id") String id) {
deployService.suspend(id);
return Result.success();
}
DeployService:
/**
* 挂起
* @param id
*/
void suspend(String id);
DeployServiceImpl:
@Override
public void suspend(String id) {
repositoryService.suspendProcessDefinitionById(id, true, null);
}
3.4.4. 激活
DeployController:
@PutMapping("active/{id}")
@ApiOperation("激活流程")
@ApiImplicitParam(name = "id", value = "流程ID", paramType = "query", dataType = "String")
public Result active(@PathVariable("id") String id) {
deployService.active(id);
return Result.success();
}
DeployService:
/**
* 激活
* @param id
*/
void active(String id);
**
/**
* 激活
* @param id
*/
void active(String id);
DeployServiceImpl:
@Override
public void active(String id) {
repositoryService.activateProcessDefinitionById(id, true, null);
}
3.5. 下载流程图
查看下载流程图功能比较复杂,代码供参考,不做开发要求。
核心实现类是ActivitiProcessDiagramCanvas.java和ActivitiProcessDiagramGenerator.java,需要提前导入代码文件夹中的diagram包。
3.5.1. 下载文件
DeployController:
@GetMapping(value = "resource")
@ApiOperation("获取资源文件")
@ApiImplicitParams({
@ApiImplicitParam(name = "deploymentId", value = "部署ID", paramType = "query", dataType="String"),
@ApiImplicitParam(name = "resourceName", value = "资源名称", paramType = "query", dataType="String")
})
public void resource(String deploymentId, String resourceName, @ApiIgnore HttpServletResponse response) throws Exception {
InputStream resourceAsStream = deployService.getResourceAsStream(deploymentId, resourceName);
IOUtils.copy(resourceAsStream, response.getOutputStream());
}
DeployService:
/**
* 获取流程资源,返回数据流
* @param deploymentId
* @param resourceName
* @return
*/
InputStream getResourceAsStream(String deploymentId, String resourceName);
DeployServiceImpl:
@Override
public InputStream getResourceAsStream(String deploymentId, String resourceName) {
InputStream resourceAsStream = repositoryService.getResourceAsStream(deploymentId, resourceName);
return resourceAsStream;
}
3.5.2. 下载图片
DeployController:
@GetMapping(value = "svg")
@ApiOperation("获取图片文件")
public void svg(String deploymentId,@ApiIgnore HttpServletResponse response) throws Exception {
InputStream resourceAsStream = deployService.svg(deploymentId);
response.setHeader("Content-Type", "image/svg+xml");
response.setHeader("Cache-Control", "no-store, no-cache");
IOUtils.copy(resourceAsStream, response.getOutputStream());
}
DeployService:
/**
* 获取流程图片
* @param deploymentId
* @return
*/
InputStream svg(String deploymentId);
DeployServiceImpl:
@Override
public InputStream svg(String deploymentId) {
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
ProcessDiagramGenerator diagramGenerator = new ActivitiProcessDiagramGenerator();
InputStream inputStream = diagramGenerator.generateDiagram(bpmnModel, new ArrayList<>());
return inputStream;
}
总结
- 基本概念
- 流程模型、流程定义
- 流程模型和流程定义的操作
- 开发流程
- 流程模型的基本操作
- 保存、分页查询、删除
- 流程图的操作
- 保存、查看、部署
- 流程定义的操作
- 查询、删除、挂起和激活