add 工作流编辑器 接口

This commit is contained in:
lijiarao
2023-10-08 09:28:39 +08:00
parent ceb19a753a
commit 3c8e097402
5 changed files with 457 additions and 0 deletions
@@ -2,6 +2,9 @@ package com.jero.modules.activiti.controller;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jero.common.api.vo.Result;
import com.jero.common.constant.enums.LanguageEnum;
import com.jero.common.util.MessageUtils;
@@ -12,13 +15,17 @@ import com.jero.modules.activiti.service.LawsProcessNodeService;
import com.jero.modules.activiti.service.ProcessService;
import com.jero.modules.activiti.vo.AddTaskVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
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.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
@@ -34,8 +41,12 @@ import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
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.util.*;
@@ -183,6 +194,17 @@ public class AController {
public Result<Object> complete(@RequestBody Map<String,Object> map) {
//todo 判断当前节点,执行不同的操作
String taskId = map.get("taskId").toString();
Task task=taskService.createTaskQuery() // 创建任务查询
.taskId(taskId) // 根据任务id查询
.singleResult();
String taskName = task.getName();
if ("填写基本信息,在线编辑,分发其他起草人".equals(taskName)){
// todo
}else if ("其他起草人线下填写,上传".equals(taskName)){
// todo
}
//Map<String, Object> vars = new HashMap<>();
//List<String> otherDrafterList = new ArrayList<>();
//otherDrafterList.add("zhangsan");
@@ -0,0 +1,259 @@
package com.jero.modules.activiti.controller;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jero.common.api.vo.Result;
import com.jero.modules.activiti.service.LawsProcessNodeOriginService;
import com.jero.modules.activiti.util.CreatedTools;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
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.repository.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author liJiaRao
* @date 2023-10-07 9:51
*/
@Slf4j
@RestController
@Api(tags = "工作流模板管理")
@RequestMapping("/activitiModel")
public class ActivitiModelerController {
@Autowired
private RepositoryService repositoryService;
@Autowired
private ObjectMapper objectMapper;
@Resource
private LawsProcessNodeOriginService processNodeOriginService;
//@Autowired
//private IFormVariableService iFormVariableService;
//@Autowired
//private ICategoryService iCategoryService;
@ApiOperation(value = "导入model文件")
@ApiImplicitParams({
@ApiImplicitParam(name = "name", value = "模型名称")
})
@PostMapping("/importModelFile")
public void importModelFile(@RequestPart(value = "file", required = false) MultipartFile file,
@RequestParam(value = "name", required = false) String name) throws Exception {
InputStream fileInputStream = file.getInputStream();
XMLInputFactory xif = XMLInputFactory.newInstance();
InputStreamReader in = new InputStreamReader(fileInputStream, "UTF-8");
XMLStreamReader xtr = xif.createXMLStreamReader(in);
// 转为bpmnModel
BpmnModel bpmnModel = new BpmnXMLConverter().convertToBpmnModel(xtr);
Model model = repositoryService.newModel();
String modelKey = "m_" + CreatedTools.getCreated();
ObjectNode modelNode = objectMapper.createObjectNode();
modelNode.put(ModelDataJsonConstants.MODEL_NAME, modelKey);
modelNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
model.setName(name);
model.setKey(modelKey);
model.setMetaInfo(modelNode.toString());
repositoryService.saveModel(model);
ObjectNode objectNode = new BpmnJsonConverter().convertToJson(bpmnModel);
repositoryService.addModelEditorSource(model.getId(), objectNode.toString().getBytes("utf-8"));
}
@ApiOperation(value = "新建模板")
@ApiImplicitParam(name = "category_id", value = "类型id")
@SuppressWarnings("deprecation")
@GetMapping("/create")
public void newModel(HttpServletRequest request, HttpServletResponse response, String category_id)
throws IOException {
// 初始化一个空模型
Model model = repositoryService.newModel();
// 设置一些默认信息
String name = "";
String description = "";
int revision = 1;
String key = "m_" + CreatedTools.getCreated();
// 设置子系统
//model.setTenantId("子系统1");
//model.setCategory(category_id);
ObjectNode modelNode = objectMapper.createObjectNode();
modelNode.put(ModelDataJsonConstants.MODEL_NAME, name);
modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
modelNode.put(ModelDataJsonConstants.MODEL_REVISION, revision);
model.setName(name);
model.setKey(key);
model.setMetaInfo(modelNode.toString());
repositoryService.saveModel(model);
String id = model.getId();
// 完善ModelEditorSource
ObjectNode editorNode = objectMapper.createObjectNode();
editorNode.put("id", "canvas");
editorNode.put("resourceId", "canvas");
ObjectNode stencilSetNode = objectMapper.createObjectNode();
stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
editorNode.put("stencilset", stencilSetNode);
repositoryService.addModelEditorSource(id, editorNode.toString().getBytes("utf-8"));
response.sendRedirect(request.getContextPath() + "/modeler.html?modelId=" + id);
}
@ApiOperation(value = "模板列表")
@ApiImplicitParams({ @ApiImplicitParam(name = "name", value = "名称"),
@ApiImplicitParam(name = "category_id", value = "类型id") })
@GetMapping("/modelList")
public Result<List<Model>> modelList(String name, String category_id) {
//String sql = "select distinct RES.* from ACT_RE_MODEL RES WHERE RES.TENANT_ID_ = '子系统1' and RES.NAME_<>'' and RES.CATEGORY_=#{category} order by RES.CREATE_TIME_ desc";
String sql = "select distinct RES.* from ACT_RE_MODEL RES WHERE RES.NAME_<>'' order by RES.CREATE_TIME_ desc";
NativeModelQuery nativeModelQuery = repositoryService.createNativeModelQuery();
//if (StringUtils.isNull(category_id)) {
// sql = sql.replace("and RES.CATEGORY_=#{category}", "");
//}else {
// nativeModelQuery.parameter("category", category_id);
//}
nativeModelQuery.sql(sql);
List<Model> list = nativeModelQuery.list();
return Result.OK(list);
}
@ApiOperation(value = "模板列表-分页")
@ApiImplicitParams({ @ApiImplicitParam(name = "name", value = "名称"),
@ApiImplicitParam(name = "current", value = "当前页"),
@ApiImplicitParam(name = "size", value = "每页条数") })
@GetMapping("/modelListPage")
public Result<Map<String, Object>> modelListPage(String name, int current, int size) {
if (StringUtils.isBlank(name)) {
name = "";
} else {
current = 1;
}
ModelQuery modelQuery = repositoryService.createModelQuery();
//if (StringUtils.isNotNull(category_id)) {
// modelQuery.modelCategory(category_id);
//}
//modelQuery.modelNameLike("%" + name + "%").modelTenantId("子系统1");
long total = modelQuery.count();
List<Model> list = modelQuery.orderByCreateTime().desc().listPage((current - 1) * size, size);
List<Map<String, Object>> resultList = new ArrayList<>();
Map<String, Object> map = new HashMap<>();
for(Model model:list){
Map<String, Object> resultMap = beanToMap(model);
//if(resultMap.get("category")!=null){
// Category category = iCategoryService.getById(resultMap.get("category").toString());
// resultMap.put("categoryName",category.getType());
//}
resultList.add(resultMap);
}
map.put("records", resultList);
map.put("current", current);
map.put("size", size);
map.put("total", total);
return Result.OK(map);
}
public static <T> Map<String, Object> beanToMap(T bean) {
Map<String, Object> map = new HashMap<>();
if (bean != null) {
BeanMap beanMap = BeanMap.create(bean);
for (Object key : beanMap.keySet()) {
map.put(key+"", beanMap.get(key));
}
}
return map;
}
@ApiOperation(value = "删除模板")
@ApiImplicitParam(name = "modelId", value = "模型id")
@GetMapping("/deleteModel")
public Result<String> deleteModel(String modelId) {
repositoryService.deleteModel(modelId);
return Result.OK("删除成功");
}
@ApiOperation(value = "修改流程所属分类")
@ApiImplicitParam(name = "modelId", value = "模型id")
@GetMapping("/updatModel")
public Result<String> updatModel(String modelId,String categoryId) {
Model modelData = repositoryService.getModel(modelId);
modelData.setCategory(categoryId);
repositoryService.saveModel(modelData);
return Result.OK("修改成功");
}
@ApiOperation(value = "部署")
@ApiImplicitParam(name = "modelId", value = "模型id")
@GetMapping("/deploy")
public Result<Map<String, String>> deploy(String modelId) throws Exception {
// 获取模型
Model modelData = repositoryService.getModel(modelId);
byte[] bytes = repositoryService.getModelEditorSource(modelData.getId());
if (bytes == null) {
return Result.OK("模型数据为空,请先设计流程并成功保存,再进行发布。");
}
// 生成/更新 模板变量表
//iFormVariableService.createAndUpdateFormVariable(bytes, modelId);
JsonNode modelNode = new ObjectMapper().readTree(bytes);
BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
model.setTargetNamespace(modelData.getCategory());
if (model.getProcesses().size() == 0) {
return Result.OK("数据模型不符要求,请至少设计一条主线流程。");
}
byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(model);
// 发布流程
String processName = modelData.getName() + ".bpmn20.xml";
Deployment deployment = repositoryService.createDeployment()
.name(modelData.getName())
.category(modelData.getCategory())
.addString(processName, new String(bpmnBytes, "UTF-8"))
.deploy();
modelData.setDeploymentId(deployment.getId());
repositoryService.saveModel(modelData);
//创建一个流程定义查询
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
processDefinitionQuery.deploymentId(deployment.getId());
ProcessDefinition processDefinition = processDefinitionQuery.singleResult();
String processDefinitionId = processDefinition.getId();
processNodeOriginService.saveNodeList(processDefinitionId);
// 4、输出部署信息
Map<String, String> map = new HashMap<>();
map.put("流程部署id", deployment.getId());
map.put("流程部署名称:", deployment.getName());
map.put("流程部署key", deployment.getKey());
map.put("流程定义Id", processDefinitionId);
return Result.OK(map);
}
}
@@ -0,0 +1,142 @@
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jero.modules.activiti.editor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
/**
* @author Tijs Rademakers
*/
@Slf4j
@Api("工作流编辑器")
@RestController
@RequestMapping(value = "/service")
public class ModelEditorController implements ModelDataJsonConstants {
@Autowired
private RepositoryService repositoryService;
@Autowired
private ObjectMapper objectMapper;
@ApiOperation(value = "获取模型json数据")
@ApiImplicitParam(name = "modelId", value = "模型id")
@SuppressWarnings("deprecation")
@GetMapping(value = "/model/{modelId}/json", produces = "application/json")
public ObjectNode getEditorJson(@PathVariable String modelId) {
ObjectNode modelNode = null;
Model model = repositoryService.getModel(modelId);
if (model != null) {
try {
if (StringUtils.isNotEmpty(model.getMetaInfo())) {
modelNode = (ObjectNode) objectMapper.readTree(model.getMetaInfo());
} else {
modelNode = objectMapper.createObjectNode();
modelNode.put(MODEL_NAME, model.getName());
}
modelNode.put(MODEL_ID, model.getId());
byte[] modelEditorSource = repositoryService.getModelEditorSource(model.getId());
String s = new String(modelEditorSource, "utf-8");
ObjectNode editorJsonNode = (ObjectNode) objectMapper
.readTree(s);
modelNode.put("model", editorJsonNode);
} catch (Exception e) {
log.error("Error creating model JSON", e);
throw new ActivitiException("Error creating model JSON", e);
}
}
return modelNode;
}
@ApiOperation(value = "模型保存")
@ApiImplicitParams({ @ApiImplicitParam(name = "modelId", value = "模型id"),
@ApiImplicitParam(name = "name", value = "名称"),
@ApiImplicitParam(name = "json_xml", value = "流程图xml"),
@ApiImplicitParam(name = "svg_xml", value = "流程配置xml"),
@ApiImplicitParam(name = "description", value = "描述") })
@PutMapping(value = "/model/{modelId}/save")
@ResponseStatus(value = HttpStatus.OK)
public void saveModel(@PathVariable String modelId, @RequestParam("name") String name,
@RequestParam("json_xml") String json_xml, @RequestParam("svg_xml") String svg_xml,
@RequestParam("description") String description) {
try {
Model model = repositoryService.getModel(modelId);
ObjectNode modelJson = (ObjectNode) objectMapper.readTree(model.getMetaInfo());
modelJson.put(MODEL_NAME, name);
modelJson.put(MODEL_DESCRIPTION, description);
model.setMetaInfo(modelJson.toString());
model.setName(name);
repositoryService.saveModel(model);
repositoryService.addModelEditorSource(model.getId(), json_xml.getBytes("utf-8"));
InputStream svgStream = new ByteArrayInputStream(svg_xml.getBytes("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();
} catch (Exception e) {
log.error("Error saving model", e);
throw new ActivitiException("Error saving model", e);
}
}
@ApiOperation(value = "获取模型stencilset的数据")
@GetMapping(value = "/editor/stencilset", produces = "application/json;charset=utf-8")
public @ResponseBody String getStencilset() {
InputStream stencilsetStream = this.getClass().getClassLoader().getResourceAsStream("stencilset.json");
try {
return IOUtils.toString(stencilsetStream, "utf-8");
} catch (Exception e) {
throw new ActivitiException("Error while loading stencil set", e);
}
}
}
@@ -0,0 +1,30 @@
package com.jero.modules.activiti.util;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class CreatedTools {
private final static DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
// 返回long型的创建时间
public static long getCreated() {
Date d = new Date();
long l = Long.parseLong(df.format(d));
return l;
}
public static long getCreated(int add) {
long t = System.currentTimeMillis() + add;
Timestamp time = new Timestamp(t);
long l = Long.parseLong(df.format(time));
return l;
}
public static long t() {
return 0l;
}
}