文章目录
本文建议你熟悉Activiti之后在阅读,是Activiti的应用篇。直接上应用代码,包含流程查询,读取资源,部署流程文件,转模型,启动流程实例,激活/挂起,删除等功能。Springboot搭建Activiti整合流程设计器 请查看这篇博客https://blog.csdn.net/yy756127197/article/details/101211510
后台服务基于Springboot2 + Mybatis-plus3 + Lombok + Swagger + Hutool工具类
1. ActReProcdefController控制类
import cn.hutool.json.JSONUtil;
import com.it.cloud.common.annotation.SysLog;
import com.it.cloud.common.base.Result;
import com.it.cloud.common.exceptions.YYException;
import com.it.cloud.common.utils.PageUtils;
import com.it.cloud.modules.activiti.service.IActReProcdefService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
/**
* <p>
* 流程定义控制类
* </p>
*
* @author 司马缸砸缸了
* @since 2019-07-24
*/
@Api(value = "流程定义控制器", tags = "流程定义")
@Slf4j
@RestController
@RequestMapping("/act/procdef")
public class ActReProcdefController {
@Autowired
private IActReProcdefService actReProcdefService;
@ApiOperation(value = "分页查询接口", notes = "条件,分页查询")
@GetMapping("/page")
public Result list(@RequestParam Map<String, Object> params) {
log.info("分页查询所有流程定义接口,参数:{}", JSONUtil.toJsonStr(params));
PageUtils page = actReProcdefService.queryPage(params);
System.out.println(JSONUtil.toJsonStr(page));
return Result.ok(page);
}
@ApiOperation(value = "读取资源", notes = "读取资源,通过ProcessDefinitionId")
@GetMapping("/read")
public void resourceRead(String id,
@RequestParam(required = false) String proInsId,
String type,
HttpServletResponse response) {
log.info("读取资源, processDefinitionId:{}, proInsId:{}, type:{}", id, proInsId, type);
InputStream resourceAsStream = actReProcdefService.readResource(id, proInsId, type);
byte[] b = new byte[1024];
int len = -1;
int lenEnd = 1024;
while (true) {
try {
if (!((len = resourceAsStream.read(b, 0, lenEnd)) != -1)) break;
response.getOutputStream().write(b, 0, len);
} catch (IOException e) {
throw new YYException("读取资源文件失败", e);
}
}
}
@ApiOperation(value = "部署流程文件", notes = "部署流程文件")
@SysLog("部署流程文件")
@PostMapping("/deploy")
@RequiresPermissions("act:reprocdef:deploy")
public Result deploy(MultipartFile file) {
Result result = Result.ok();
String exportDir = this.getClass().getResource("/").getPath();
String fileName = file.getOriginalFilename();
if (StringUtils.isBlank(fileName)) {
throw new YYException("请选择要部署的流程文件");
} else {
result = actReProcdefService.deploy(exportDir, file);
}
return result;
}
@ApiOperation(value = "转模型", notes = "转模型")
@SysLog("转模型")
@GetMapping("/convertToModel")
@RequiresPermissions("act:reprocdef:convertToModel")
public Result convertToModel(String id) {
log.info("转模型, processDefinitionId:{}", id);
try {
actReProcdefService.convertToModel(id);
} catch (Exception e) {
return Result.error(e.getMessage());
}
return Result.ok();
}
@ApiOperation(value = "启动流程实例", notes = "启动流程实例,通过processDefinitionId")
@SysLog("启动流程实例")
@GetMapping("/startProcessInstance")
@RequiresPermissions("act:reprocdef:start")
public Result startProcessInstanceById(String processDefinitionId) {
log.info("启动流程实例, processDefinitionId:{}", processDefinitionId);
actReProcdefService.startProcessInstanceById(processDefinitionId);
return Result.ok();
}
@ApiOperation(value = "激活/挂起", notes = "激活/挂起")
@SysLog("激活/挂起")
@PutMapping("/status")
@RequiresPermissions("act:reprocdef:update")
public Result update(String id, Integer state) {
log.info("激活/挂起流程定义, id:{}, state:{}", id, state);
Result result = actReProcdefService.updateState(id, state);
return result;
}
@ApiOperation(value = "删除流程定义", notes = "删除流程定义(部署)")
@SysLog("删除流程定义")
@PostMapping("/delete")
@RequiresPermissions("act:reprocdef:delete")
public Result delete(@RequestBody String[] deploymentIds) {
log.info("删除流程定义, 参数:{}", JSONUtil.toJsonStr(deploymentIds));
actReProcdefService.deleteBatch(deploymentIds);
return Result.ok();
}
}
2. ActReProcdefServiceImpl服务类
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Lists;
import com.it.cloud.common.base.Result;
import com.it.cloud.common.constants.ActivitiConstant;
import com.it.cloud.common.exceptions.YYException;
import com.it.cloud.common.utils.PageUtils;
import com.it.cloud.common.utils.Query;
import com.it.cloud.modules.activiti.entity.ActReProcdefEntity;
import com.it.cloud.modules.activiti.mapper.ActReProcdefMapper;
import com.it.cloud.modules.activiti.service.IActReProcdefService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.repository.*;
import org.activiti.engine.runtime.ProcessInstance;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.zip.ZipInputStream;
/**
* <p>
* 服务实现类
* </p>
*
* @author 司马缸砸缸了
* @since 2019-08-23
*/
@Slf4j
@Service
public class ActReProcdefServiceImpl extends ServiceImpl<ActReProcdefMapper, ActReProcdefEntity> implements IActReProcdefService {
@Autowired
private RuntimeService runtimeService;
@Autowired
private RepositoryService repositoryService;
@Override
public PageUtils queryPage(Map<String, Object> params) {
String key = (String) params.get("key");
String name = (String) params.get("name");
int curPage = Integer.parseInt((String) params.get("page"));
int limit = Integer.parseInt((String) params.get("limit"));
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery()
.latestVersion()
.orderByProcessDefinitionKey()
.asc();
if (StringUtils.isNotBlank(name)) {
processDefinitionQuery.processDefinitionNameLike("%" + name + "%");
}
if (StringUtils.isNotBlank(key)) {
processDefinitionQuery.processDefinitionKey(key);
}
List<ProcessDefinition> processDefinitionList = processDefinitionQuery.listPage((curPage - 1) * limit, limit);
/**
* 转换类型
*/
List<ActReProcdefEntity> list = processDefinitionList.stream()
.map(item -> convertObject(item))
.collect(Collectors.toList());
Page<ActReProcdefEntity> page = new Query<ActReProcdefEntity>(params).getPage();
page.setTotal(processDefinitionQuery.count());
page.setRecords(list);
return new PageUtils(page);
}
@Override
public InputStream readResource(String id, String proInsId, String type) {
if (StringUtils.isBlank(id)) {
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId(proInsId)
.singleResult();
id = processInstance.getProcessDefinitionId();
}
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionId(id)
.singleResult();
String resourceName = "";
if (ActivitiConstant.IMAGE.equals(type)) {
resourceName = processDefinition.getDiagramResourceName();
} else if (ActivitiConstant.XML.equals(type)) {
resourceName = processDefinition.getResourceName();
}
InputStream resourceAsStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), resourceName);
return resourceAsStream;
}
@Override
public Result deploy(String exportDir, MultipartFile file) {
String fileName = file.getOriginalFilename();
InputStream fileInputStream = null;
try {
fileInputStream = file.getInputStream();
} catch (IOException e) {
throw new YYException("上传文件部署失败", e);
}
Deployment deployment = null;
String extension = FilenameUtils.getExtension(fileName);
if (ActivitiConstant.ZIP.equals(extension) || ActivitiConstant.BAR.equals(extension)) {
ZipInputStream zip = new ZipInputStream(fileInputStream);
deployment = repositoryService.createDeployment().addZipInputStream(zip).deploy();
} else if (ActivitiConstant.PNG.equals(extension)) {
deployment = repositoryService.createDeployment().addInputStream(fileName, fileInputStream).deploy();
} else if (fileName.indexOf(ActivitiConstant.BPMN20) != -1) {
deployment = repositoryService.createDeployment().addInputStream(fileName, fileInputStream).deploy();
} else if (ActivitiConstant.BPMN.equals(extension)) {
deployment = repositoryService.createDeployment().addInputStream(fileName, fileInputStream).deploy();
} else {
return Result.error("不支持的文件类型:" + extension);
}
List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).list();
if (CollectionUtil.isEmpty(list)) {
return Result.error("部署失败,没有流程");
}
// 设置流程分类(可选)
for (ProcessDefinition processDefinition : list) {
repositoryService.setProcessDefinitionCategory(processDefinition.getId(), processDefinition.getCategory());
log.info("部署成功,流程ID:{}", processDefinition.getId());
}
return Result.ok();
}
@Override
public Model convertToModel(String id) {
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(id).singleResult();
InputStream bpmnStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getResourceName());
XMLInputFactory xif = XMLInputFactory.newInstance();
InputStreamReader in = null;
XMLStreamReader xtr = null;
try {
in = new InputStreamReader(bpmnStream, "UTF-8");
xtr = xif.createXMLStreamReader(in);
} catch (Exception e) {
throw new YYException("转模型失败", e);
}
BpmnModel bpmnModel = new BpmnXMLConverter().convertToBpmnModel(xtr);
BpmnJsonConverter converter = new BpmnJsonConverter();
ObjectNode modelNode = converter.convertToJson(bpmnModel);
// Model 实体
Model modelData = repositoryService.newModel();
modelData.setKey(processDefinition.getKey());
modelData.setName(processDefinition.getName());
modelData.setCategory(processDefinition.getCategory());
modelData.setDeploymentId(processDefinition.getDeploymentId());
modelData.setVersion(Integer.parseInt(String.valueOf(repositoryService.createModelQuery().modelKey(modelData.getKey()).count() + 1)));
// 元数据
ObjectNode modelObjectNode = new ObjectMapper().createObjectNode();
modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, processDefinition.getName());
modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, modelData.getVersion());
modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, processDefinition.getDescription());
modelData.setMetaInfo(modelObjectNode.toString());
repositoryService.saveModel(modelData);
try {
repositoryService.addModelEditorSource(modelData.getId(), modelNode.toString().getBytes("utf-8"));
} catch (UnsupportedEncodingException e) {
throw new YYException("转模型失败", e);
}
return modelData;
}
@Override
public void startProcessInstanceById(String processDefinitionId) {
runtimeService.startProcessInstanceById(processDefinitionId);
}
@Override
public Result updateState(String id, Integer state) {
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionId(id)
.singleResult();
if (state == ActivitiConstant.ONE) {
// 激活
if (!processDefinition.isSuspended()) {
return Result.error("流程状态不能激活");
}
repositoryService.activateProcessDefinitionById(id, true, DateUtil.date());
log.info("已激活ID为[" + id + "]的流程定义");
} else if (state == ActivitiConstant.TWO) {
// 挂起
if (processDefinition.isSuspended()) {
return Result.error("流程状态不能挂起");
}
repositoryService.suspendProcessDefinitionById(id, true, DateUtil.date());
log.info("已挂起ID为[" + id + "]的流程定义");
}
return Result.ok();
}
@Transactional(rollbackFor = Exception.class)
@Override
public void deleteBatch(String[] deploymentIds) {
// false 不带级联的删除
// 只能删除没有启动的流程,如果流程启动,就会抛出异常
//
// true 能级联的删除
// 能删除启动的流程,会删除和当前规则相关的所有信息,正在执行的信息,也包括历史信息
Arrays.stream(deploymentIds).forEach(deploymentId -> {
repositoryService.deleteDeployment(deploymentId, false);
});
}
/**
* 转换类型
*
* @param processDefinition
* @return
*/
private ActReProcdefEntity convertObject(ProcessDefinition processDefinition) {
ActReProcdefEntity entity = new ActReProcdefEntity();
String deploymentId = processDefinition.getDeploymentId();
Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();
entity.setId(processDefinition.getId());
entity.setKey(processDefinition.getKey());
entity.setName(processDefinition.getName());
entity.setDeployTime(deployment == null ? null : DateUtil.date(deployment.getDeploymentTime()).toTimestamp());
entity.setDeploymentId(processDefinition.getDeploymentId());
entity.setSuspensionState(processDefinition.isSuspended() ? ActivitiConstant.TWO : ActivitiConstant.ONE);
entity.setResourceName(processDefinition.getResourceName());
entity.setDgrmResourceName(processDefinition.getDiagramResourceName());
entity.setCategory(processDefinition.getCategory());
entity.setVersion(processDefinition.getVersion());
entity.setDescription(processDefinition.getDescription());
entity.setEngineVersion(processDefinition.getEngineVersion());
entity.setTenantId(processDefinition.getTenantId());
return entity;
}
}
3. 实体类
对应Activiti数据表ACT_RE_PROCDEF
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableField;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* <p>
*
* </p>
*
* @author 司马缸砸缸了
* @since 2019-08-23
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("ACT_RE_PROCDEF")
public class ActReProcdefEntity implements Serializable {
@ApiModelProperty(value = "流程ID,由《流程编号:流程版本号:自增长ID》组成")
@TableId(value = "ID_")
private String id;
@ApiModelProperty(value = "乐观锁版本号")
@TableField("REV_")
private Integer rev;
@ApiModelProperty(value = "流程命名空间(该编号就是流程文件targetNamespace的属性值)")
@TableField("CATEGORY_")
private String category;
@ApiModelProperty(value = "流程名称(该编号就是流程文件process元素的name属性值)")
@TableField("NAME_")
private String name;
@ApiModelProperty(value = "流程编号(该编号就是流程文件process元素的id属性值)")
@TableField("KEY_")
private String key;
@ApiModelProperty(value = "流程版本号(由程序控制,新增即为1,修改后依次加1来完成的)")
@TableField("VERSION_")
private Integer version;
@ApiModelProperty(value = "部署编号")
@TableField("DEPLOYMENT_ID_")
private String deploymentId;
@ApiModelProperty(value = "资源文件名称")
@TableField("RESOURCE_NAME_")
private String resourceName;
@ApiModelProperty(value = "图片资源文件名称")
@TableField("DGRM_RESOURCE_NAME_")
private String dgrmResourceName;
@ApiModelProperty(value = "描述信息")
@TableField("DESCRIPTION_")
private String description;
@ApiModelProperty(value = "是否从key启动,start节点是否存在formKey,0否 1是")
@TableField("HAS_START_FORM_KEY_")
private String hasStartFormKey;
@ApiModelProperty(value = "是否有图片预览")
@TableField("HAS_GRAPHICAL_NOTATION_")
private String hasGraphicalNotation;
@ApiModelProperty(value = "是否挂起,1激活 2挂起")
@TableField("SUSPENSION_STATE_")
private Integer suspensionState;
@ApiModelProperty(value = "所属系统")
@TableField("TENANT_ID_")
private String tenantId;
@ApiModelProperty(value = "工作流引擎版本")
@TableField("ENGINE_VERSION_")
private String engineVersion;
@ApiModelProperty(value = "部署时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField(exist = false)
private Timestamp deployTime;
}
源码地址
IT-CLOUD :IT服务管理平台,集成基础服务,中间件服务,监控告警服务等。\