fix: 完善 bpm 模型流程

This commit is contained in:
yunlong.li 2021-11-18 10:55:43 +08:00
parent 480b17507f
commit 00f59fdc75
11 changed files with 195 additions and 12 deletions

View File

@ -1,15 +1,20 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.FileResp;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.TodoTaskRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.model.ModelCreateVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.model.ModelPageReqVo;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.model.ModelRespVo;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.model.ModelUpdateVO;
import cn.iocoder.yudao.adminserver.modules.bpm.service.workflow.BpmModelService;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.*;
@ -36,18 +41,41 @@ public class ModelController {
private final BpmModelService bpmModelService;
@GetMapping ("/page")
@ApiOperation(value = "分页数据")
public PageResult<Model> pageList(ModelPageReqVo modelPageReqVo) {
return bpmModelService.pageList(modelPageReqVo);
}
@PostMapping("/create")
@ApiOperation(value = "新建模型")
public CommonResult<String> newModel(@RequestBody ModelCreateVO modelCreateVO) {
return bpmModelService.newModel(modelCreateVO);
}
@PostMapping("/update")
@ApiOperation(value = "修改模型属性")
public CommonResult<String> updateModel(@RequestBody ModelUpdateVO modelUpdateVO) {
return bpmModelService.updateModel(modelUpdateVO);
}
@PostMapping("/deploy/{modelId}")
public CommonResult<String> updateModel(@PathVariable String modelId) {
@PostMapping("/delete")
@ApiOperation(value = "删除模型")
public CommonResult<String> deleteModel(@RequestParam String modelId) {
return bpmModelService.deleteModel(modelId);
}
@PostMapping("/deploy")
@ApiOperation(value = "部署模型")
public CommonResult<String> deploy(@RequestParam String modelId) {
return bpmModelService.deploy(modelId);
}
@GetMapping("/exportBpmnXml")
@ApiOperation(value = "导出模型")
public void export(@RequestParam String deploymentId, HttpServletResponse response) throws IOException {
FileResp fileResp = bpmModelService.exportBpmnXml(deploymentId);
ServletUtils.writeAttachment(response, fileResp.getFileName(), fileResp.getFileByte());
}
}

View File

@ -60,13 +60,12 @@ public class TaskController {
return success(bpmTaskService.getHistorySteps(processInstanceId));
}
// TODO @Li: 项目里暂时不使用 path 路径参数监控等麻烦
/**
* 返回高亮的流转图SVG
* @param processInstanceId
* @param processInstanceId 流程Id
*/
@GetMapping("/process/highlight-img/{id}")
public void getHighlightImg(@PathVariable("id") String processInstanceId, HttpServletResponse response) throws IOException {
@GetMapping("/process/highlight-img")
public void getHighlightImg(@RequestParam String processInstanceId, HttpServletResponse response) throws IOException {
FileResp fileResp = bpmTaskService.getHighlightImg(processInstanceId);
ServletUtils.writeAttachment(response, fileResp.getFileName(), fileResp.getFileByte());
}

View File

@ -0,0 +1,20 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.model;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
/**
* @author yunlong.li
*/
@ApiModel("模型分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class ModelPageReqVo extends PageParam {
@ApiModelProperty("模型名字")
private String name;
}

View File

@ -0,0 +1,16 @@
package cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.model;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
/**
* @author yunlong.li
*/
@ApiModel("模型出口内容 Request VO")
@Data
@ToString(callSuper = true)
public class ModelRespVo {
}

View File

@ -0,0 +1,20 @@
package cn.iocoder.yudao.adminserver.modules.bpm.convert.workflow;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.TodoTaskRespVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.model.ModelRespVo;
import org.activiti.api.task.model.Task;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
* @author yunlongn
*/
@Mapper
public interface ModelConvert {
ModelConvert INSTANCE = Mappers.getMapper(ModelConvert.class);
ModelRespVo convert(Model model);
}

View File

@ -28,5 +28,6 @@ public interface BpmErrorCodeConstants {
ErrorCode BPMN_MODEL_EDITOR_SOURCE_NOT_EXISTS = new ErrorCode(1004001001, "模型数据为空,请先成功设计流程并保存");
ErrorCode BPMN_MODEL_ERROR = new ErrorCode(1004001002, "工作流模型异常");
ErrorCode BPMN_MODEL_PROCESS_NOT_EXISTS = new ErrorCode(1004001003, "流程数据为空");
ErrorCode BPMN_PROCESS_DEFINITION_NOT_EXISTS = new ErrorCode(1004001004, "流程定义不存在");
}

View File

@ -1,8 +1,15 @@
package cn.iocoder.yudao.adminserver.modules.bpm.service.workflow;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.FileResp;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.model.ModelCreateVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.model.ModelPageReqVo;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.model.ModelRespVo;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.model.ModelUpdateVO;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.activiti.engine.repository.Model;
import javax.servlet.http.HttpServletResponse;
/**
* 工作流模型接口
@ -10,16 +17,45 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
*/
public interface BpmModelService {
/**
* 模型数据分页返回
* @param modelPageReqVo 分页入参
* @return 分页model
*/
PageResult<Model> pageList(ModelPageReqVo modelPageReqVo);
/**
* 新增一个模型
* @param modelCreateVO 模型对象
* @return 返回成功
*/
CommonResult<String> newModel(ModelCreateVO modelCreateVO);
/**
* 修改模型属性填充bpmn数据
* @param modelUpdateVO 模型对象
* @return 返回成功
*/
CommonResult<String> updateModel(ModelUpdateVO modelUpdateVO);
/**
* 部署模型 使模型成为一个 process
* @param modelId 模型Id
* @return 返回成功
*/
CommonResult<String> deploy(String modelId);
/**
* 导出模型
* @param modelId 模型Id
* @return {@link FileResp} 返回文件
*/
FileResp exportBpmnXml(String modelId);
/**
* 删除模型
* @param modelId 模型Id
* @return 返回成功
*/
CommonResult<String> deleteModel(String modelId);
}

View File

@ -51,6 +51,7 @@ public interface BpmTaskService {
/**
* 返回高亮的流转进程
* @param processInstanceId 实例Id
* @return {@link FileResp} 返回文件
*/
FileResp getHighlightImg(String processInstanceId);
}

View File

@ -1,28 +1,42 @@
package cn.iocoder.yudao.adminserver.modules.bpm.service.workflow.impl;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.FileResp;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.model.ModelCreateVO;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.model.ModelPageReqVo;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.model.ModelRespVo;
import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.model.ModelUpdateVO;
import cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants;
import cn.iocoder.yudao.adminserver.modules.bpm.service.workflow.BpmModelService;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.activiti.api.runtime.shared.query.Pageable;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ModelQuery;
import org.activiti.engine.repository.ProcessDefinition;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import javax.servlet.http.HttpServletResponse;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional;
/**
@ -36,6 +50,19 @@ public class BpmModelServiceImpl implements BpmModelService {
private final RepositoryService repositoryService;
@Override
public PageResult<Model> pageList(ModelPageReqVo modelPageReqVo) {
ModelQuery modelQuery = repositoryService.createModelQuery();
String likeName = modelPageReqVo.getName();
if (StrUtil.isNotBlank(likeName)){
modelQuery.modelNameLike("%"+likeName+"%");
}
List<Model> models = modelQuery.orderByCreateTime().desc()
.listPage((modelPageReqVo.getPageNo() - 1) * modelPageReqVo.getPageSize(), modelPageReqVo.getPageSize());
return new PageResult<>(models, modelQuery.count());
}
@Override
public CommonResult<String> newModel(ModelCreateVO modelCreateVO) {
try {
@ -119,4 +146,28 @@ public class BpmModelServiceImpl implements BpmModelService {
throw ServiceExceptionUtil.exception(BpmErrorCodeConstants.BPMN_MODEL_ERROR);
}
}
@Override
public FileResp exportBpmnXml(String deploymentId) {
// 查询流程定义
ProcessDefinition pd = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();
if (ObjectUtils.isEmpty(pd)) {
throw ServiceExceptionUtil.exception(BpmErrorCodeConstants.BPMN_PROCESS_DEFINITION_NOT_EXISTS);
}
String resourceName = Optional.ofNullable(pd.getDiagramResourceName()).orElse(pd.getResourceName());
InputStream inputStream = repositoryService.getResourceAsStream(deploymentId,
resourceName);
FileResp fileResp = new FileResp();
fileResp.setFileName(String.format("%s.bpmn", Optional.ofNullable(pd.getName()).orElse("流程图")));
fileResp.setFileByte(IoUtil.readBytes(inputStream));
return fileResp;
}
@Override
public CommonResult<String> deleteModel(String modelId) {
repositoryService.deleteModel(modelId);
return CommonResult.success("删除成功");
}
}

View File

@ -31,6 +31,7 @@ import org.activiti.image.ProcessDiagramGenerator;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import javax.annotation.Resource;
import java.io.IOException;
@ -174,6 +175,18 @@ public class BpmTaskServiceImpl implements BpmTaskService {
if (hpi == null) {
throw exception(PROCESS_INSTANCE_NOT_EXISTS);
}
// 如果有结束时间 返回model的流程图
if (!ObjectUtils.isEmpty(hpi.getEndTime())) {
ProcessDefinition pd = repositoryService.createProcessDefinitionQuery().processDefinitionId(hpi.getProcessDefinitionId()).singleResult();
String resourceName = Optional.ofNullable(pd.getDiagramResourceName()).orElse(pd.getResourceName());
BpmnModel bpmnModel = repositoryService.getBpmnModel(pd.getId());
InputStream inputStream = processDiagramGenerator.generateDiagram(bpmnModel, new ArrayList<>(1), new ArrayList<>(1),
"宋体", "宋体", "宋体");
FileResp fileResp = new FileResp();
fileResp.setFileName( resourceName + ".svg");
fileResp.setFileByte(IoUtil.readBytes(inputStream));
return fileResp;
}
// 没有结束时间说明流程在执行过程中
// TODO @Li一些 runtimeService 的查询貌似比较通用是不是抽一些小方法出来
ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
@ -195,13 +208,11 @@ public class BpmTaskServiceImpl implements BpmTaskService {
try (InputStream inputStream = processDiagramGenerator.generateDiagram(bpmnModel, highLightedActivities, highLightedFlowIds,
"宋体", "宋体", "宋体")){
FileResp fileResp = new FileResp();
String picName = hpi.getProcessDefinitionName() + ".svg"; // TODO @Li一次性的变量可以直接 set 的时候直接拼接
fileResp.setFileName(picName);
fileResp.setFileName( hpi.getProcessDefinitionName() + ".svg");
fileResp.setFileByte(IoUtil.readBytes(inputStream));
return fileResp;
} catch (IOException e) {
// TODO @Lilog.error("[getHighlightImg][流程({}) 生成图表失败]", processInstanceId, e)
log.error(ExceptionUtils.getStackTrace(e));
log.error("[getHighlightImg][流程({}) 生成图表失败]", processInstanceId, e);
throw exception(HIGHLIGHT_IMG_ERROR);
}
}

View File

@ -85,7 +85,7 @@ export function processHistorySteps(id) {
export function getHighlightImg(id) {
return request({
url: '/workflow/task/process/highlight-img/'+id,
url: '/workflow/task/process/highlight-img?processInstanceId='+id,
method: 'get'
})
}