添加模型部署,导出模型

This commit is contained in:
gssong 2023-06-04 18:03:40 +08:00
parent 1ce0e61aba
commit 3a5e34acc7
6 changed files with 165 additions and 23 deletions

View File

@ -0,0 +1,16 @@
package org.dromara.workflow.common.constant;
/**
* 工作流常量
*
* @author may
*/
public interface FlowConstant {
/**
* 命名空间
*/
String NAMESPACE = "http://b3mn.org/stencilset/bpmn2.0#";
}

View File

@ -1,6 +1,8 @@
package org.dromara.workflow.controller; package org.dromara.workflow.controller;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotEmpty;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.R; import org.dromara.common.core.domain.R;
@ -46,8 +48,7 @@ public class ActModelController extends BaseController {
} }
/** /**
* 参考官方提供的响应数据 * 设计器登录信息
* "{\"id\":\"admin\",\"firstName\":\"Test\",\"lastName\":\"Administrator\",\"email\":\"admin@flowable.org\",\"fullName\":\"Test Administrator\",\"groups\":[],\"privileges\":[\"access-idm\",\"access-rest-api\",\"access-task\",\"access-modeler\",\"access-admin\"]}";
*/ */
@GetMapping("/rest/account") @GetMapping("/rest/account")
public String getAccount() { public String getAccount() {
@ -65,6 +66,7 @@ public class ActModelController extends BaseController {
* @param modelBo 模型请求对象 * @param modelBo 模型请求对象
*/ */
@Log(title = "模型管理", businessType = BusinessType.INSERT) @Log(title = "模型管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/rest/models") @PostMapping("/rest/models")
public R<Void> saveNewModel(@Validated(AddGroup.class) @RequestBody ModelBo modelBo) { public R<Void> saveNewModel(@Validated(AddGroup.class) @RequestBody ModelBo modelBo) {
return toAjax(iActModelService.saveNewModel(modelBo)); return toAjax(iActModelService.saveNewModel(modelBo));
@ -88,6 +90,7 @@ public class ActModelController extends BaseController {
* @param values 模型数据 * @param values 模型数据
*/ */
@Log(title = "模型管理", businessType = BusinessType.UPDATE) @Log(title = "模型管理", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PostMapping(value = "/rest/models/{modelId}/editor/json") @PostMapping(value = "/rest/models/{modelId}/editor/json")
public R<Void> editModel(@PathVariable String modelId, @RequestParam MultiValueMap<String, String> values) { public R<Void> editModel(@PathVariable String modelId, @RequestParam MultiValueMap<String, String> values) {
return toAjax(iActModelService.editModel(modelId, values)); return toAjax(iActModelService.editModel(modelId, values));
@ -109,4 +112,28 @@ public class ActModelController extends BaseController {
return R.ok(); return R.ok();
} }
/**
* 模型部署
*
* @param id 模型id
*/
@Log(title = "模型管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/modelDeploy/{id}")
public R<Void> deploy(@NotBlank(message = "模型id不能为空") @PathVariable("id") String id) {
return toAjax(iActModelService.modelDeploy(id));
}
/**
* 导出模型zip压缩包
*
* @param modelId 模型id
* @param response 相应
*/
@GetMapping("/export/zip/{modelId}")
public void exportZip(@NotEmpty(message = "模型id不能为空") @PathVariable String modelId,
HttpServletResponse response) {
iActModelService.exportZip(modelId, response);
}
} }

View File

@ -4,6 +4,7 @@ import jakarta.validation.constraints.NotBlank;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import org.dromara.common.core.validate.AddGroup; import org.dromara.common.core.validate.AddGroup;
import org.dromara.workflow.common.PageEntity;
import java.io.Serial; import java.io.Serial;
import java.io.Serializable; import java.io.Serializable;

View File

@ -1,6 +1,7 @@
package org.dromara.workflow.service; package org.dromara.workflow.service;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import jakarta.servlet.http.HttpServletResponse;
import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.workflow.domain.bo.ModelBo; import org.dromara.workflow.domain.bo.ModelBo;
import org.flowable.engine.repository.Model; import org.flowable.engine.repository.Model;
@ -44,4 +45,20 @@ public interface IActModelService {
* @return 结果 * @return 结果
*/ */
boolean editModel(String modelId, MultiValueMap<String, String> values); boolean editModel(String modelId, MultiValueMap<String, String> values);
/**
* 模型部署
*
* @param id 模型id
* @return 结果
*/
boolean modelDeploy(String id);
/**
* 导出模型zip压缩包
*
* @param modelId 模型id
* @param response 相应
*/
void exportZip(String modelId, HttpServletResponse response);
} }

View File

@ -5,9 +5,11 @@ import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.exception.ServiceException;
@ -22,6 +24,7 @@ import org.flowable.bpmn.model.BpmnModel;
import org.flowable.editor.constants.ModelDataJsonConstants; import org.flowable.editor.constants.ModelDataJsonConstants;
import org.flowable.editor.language.json.converter.BpmnJsonConverter; import org.flowable.editor.language.json.converter.BpmnJsonConverter;
import org.flowable.engine.RepositoryService; import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.Model; import org.flowable.engine.repository.Model;
import org.flowable.engine.repository.ModelQuery; import org.flowable.engine.repository.ModelQuery;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -31,11 +34,15 @@ import org.springframework.util.MultiValueMap;
import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamReader;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors; import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import static org.dromara.workflow.common.constant.FlowConstant.NAMESPACE;
import static org.flowable.editor.constants.ModelDataJsonConstants.*; import static org.flowable.editor.constants.ModelDataJsonConstants.*;
/** /**
@ -118,11 +125,10 @@ public class ActModelServiceImpl implements IActModelService {
model.setMetaInfo(objectNode.toString()); model.setMetaInfo(objectNode.toString());
// 保存初始化的模型基本信息数据 // 保存初始化的模型基本信息数据
repositoryService.saveModel(model); repositoryService.saveModel(model);
String namespace = "http://b3mn.org/stencilset/bpmn2.0#";
// 封装模型对象基础数据json串 // 封装模型对象基础数据json串
ObjectNode editorNode = objectMapper.createObjectNode(); ObjectNode editorNode = objectMapper.createObjectNode();
ObjectNode stencilSetNode = objectMapper.createObjectNode(); ObjectNode stencilSetNode = objectMapper.createObjectNode();
stencilSetNode.put("namespace", namespace); stencilSetNode.put("namespace", NAMESPACE);
editorNode.replace("stencilset", stencilSetNode); editorNode.replace("stencilset", stencilSetNode);
// 标识key // 标识key
ObjectNode propertiesNode = objectMapper.createObjectNode(); ObjectNode propertiesNode = objectMapper.createObjectNode();
@ -206,10 +212,9 @@ public class ActModelServiceImpl implements IActModelService {
// 获取唯一标识key // 获取唯一标识key
String key = values.getFirst("key"); String key = values.getFirst("key");
List<Model> list = repositoryService.createModelQuery().modelKey(key).modelTenantId(LoginHelper.getTenantId()).list(); List<Model> list = repositoryService.createModelQuery().modelKey(key).modelTenantId(LoginHelper.getTenantId()).list();
List<Model> modelList = list.stream().filter(e -> !e.getId().equals(model.getId())).collect(Collectors.toList()); list.stream().filter(e -> !e.getId().equals(model.getId())).findFirst().ifPresent(e -> {
if (CollectionUtil.isNotEmpty(modelList)) {
throw new ServiceException("模型key已存在!"); throw new ServiceException("模型key已存在!");
} });
model.setKey(key); model.setKey(key);
repositoryService.saveModel(model); repositoryService.saveModel(model);
byte[] xmlBytes = WorkflowUtils.bpmnJsonToXmlBytes(Objects.requireNonNull(values.getFirst("json_xml")).getBytes(StandardCharsets.UTF_8)); byte[] xmlBytes = WorkflowUtils.bpmnJsonToXmlBytes(Objects.requireNonNull(values.getFirst("json_xml")).getBytes(StandardCharsets.UTF_8));
@ -217,24 +222,100 @@ public class ActModelServiceImpl implements IActModelService {
throw new ServiceException("模型不能为空!"); throw new ServiceException("模型不能为空!");
} }
repositoryService.addModelEditorSource(model.getId(), xmlBytes); repositoryService.addModelEditorSource(model.getId(), xmlBytes);
/*InputStream svgStream = new ByteArrayInputStream(values.getFirst("svg_xml").getBytes(StandardCharsets.UTF_8));
TranscoderInput input = new TranscoderInput(svgStream);
PNGTranscoder transcoder = new PNGTranscoder();
// Setup output
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
TranscoderOutput output = new TranscoderOutput(outStream);
// Do the transformation
transcoder.transcode(input, output);
final byte[] result = outStream.toByteArray();
repositoryService.addModelEditorSourceExtra(model.getId(), result);
outStream.close();*/
return true; return true;
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
throw new ServiceException(e.getMessage()); throw new ServiceException(e.getMessage());
} }
} }
/**
* 模型部署
*
* @param id 模型id
* @return 结果
*/
@Override
@Transactional(rollbackFor = Exception.class)
public boolean modelDeploy(String id) {
try {
//查询流程定义模型xml
byte[] xmlBytes = repositoryService.getModelEditorSource(id);
if (ArrayUtil.isEmpty(xmlBytes)) {
throw new ServiceException("模型数据为空,请先设计流程定义模型,再进行部署!");
}
// 查询模型的基本信息
Model model = repositoryService.getModel(id);
// xml资源的名称 对应act_ge_bytearray表中的name_字段
String processName = model.getName() + ".bpmn20.xml";
//调用部署相关的api方法进行部署流程定义
Deployment deployment = repositoryService.createDeployment()
// 部署名称
.name(model.getName())
// 部署标识key
.key(model.getKey())
// 部署流程分类
.category(model.getCategory())
// bpmn20.xml资源
.addBytes(processName, xmlBytes)
// 租户id
.tenantId(LoginHelper.getTenantId())
.deploy();
// 更新 部署id 到流程定义模型数据表中
model.setDeploymentId(deployment.getId());
repositoryService.saveModel(model);
return true;
} catch (Exception e) {
e.printStackTrace();
throw new ServiceException(e.getMessage());
}
}
/**
* 导出模型zip压缩包
*
* @param modelId 模型id
* @param response 相应
*/
@Override
public void exportZip(String modelId, HttpServletResponse response) {
ZipOutputStream zos = null;
try {
zos = ZipUtil.getZipOutputStream(response.getOutputStream(), StandardCharsets.UTF_8);
// 压缩包文件名
String zipName = "模型不存在";
//查询模型基本信息
Model model = repositoryService.getModel(modelId);
if (ObjectUtil.isNotNull(model)) {
// 查询流程定义模型的json字节码
byte[] xmlBytes = repositoryService.getModelEditorSource(modelId);
if (ArrayUtil.isEmpty(xmlBytes)) {
zipName = "模型数据为空,请先设计流程定义模型,再进行部署!";
} else {
String fileName = model.getName() + "-" + model.getKey();
// 压缩包文件名
zipName = fileName + ".zip";
// 将xml添加到压缩包中(指定xml文件名请假流程.bpmn20.xml
zos.putNextEntry(new ZipEntry(fileName + ".bpmn20.xml"));
zos.write(xmlBytes);
}
}
response.setHeader("Content-Disposition",
"attachment; filename=" + URLEncoder.encode(zipName, StandardCharsets.UTF_8) + ".zip");
// 刷出响应流
response.flushBuffer();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (zos != null) {
try {
zos.closeEntry();
zos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
} }