mirror of
https://gitee.com/dromara/RuoYi-Vue-Plus.git
synced 2026-09-20 10:13:28 +08:00
remove 移除原生ui接口,增加新ui接口
This commit is contained in:
parent
ebbd85275c
commit
d7a738648e
File diff suppressed because one or more lines are too long
@ -53,6 +53,19 @@
|
|||||||
<version>6.8.0</version>
|
<version>6.8.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- svg转png图片工具-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.xmlgraphics</groupId>
|
||||||
|
<artifactId>batik-all</artifactId>
|
||||||
|
<version>1.10</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>xalan</groupId>
|
||||||
|
<artifactId>xalan</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!--系统模块-->
|
<!--系统模块-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.dromara</groupId>
|
<groupId>org.dromara</groupId>
|
||||||
|
|||||||
@ -1,36 +1,26 @@
|
|||||||
package org.dromara.workflow.controller;
|
package org.dromara.workflow.controller;
|
||||||
|
|
||||||
import cn.hutool.core.convert.Convert;
|
|
||||||
import cn.hutool.core.io.resource.ResourceUtil;
|
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import jakarta.validation.constraints.NotEmpty;
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.dromara.common.core.domain.R;
|
import org.dromara.common.core.domain.R;
|
||||||
import org.dromara.common.core.domain.model.LoginUser;
|
|
||||||
import org.dromara.common.core.validate.AddGroup;
|
import org.dromara.common.core.validate.AddGroup;
|
||||||
|
import org.dromara.common.core.validate.EditGroup;
|
||||||
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
import org.dromara.common.idempotent.annotation.RepeatSubmit;
|
||||||
import org.dromara.common.json.utils.JsonUtils;
|
|
||||||
import org.dromara.common.log.annotation.Log;
|
import org.dromara.common.log.annotation.Log;
|
||||||
import org.dromara.common.log.enums.BusinessType;
|
import org.dromara.common.log.enums.BusinessType;
|
||||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
import org.dromara.common.satoken.utils.LoginHelper;
|
|
||||||
import org.dromara.common.web.core.BaseController;
|
import org.dromara.common.web.core.BaseController;
|
||||||
import org.dromara.workflow.domain.bo.ModelBo;
|
import org.dromara.workflow.domain.bo.ModelBo;
|
||||||
import org.dromara.workflow.domain.vo.AccountVo;
|
import org.dromara.workflow.domain.vo.ModelVo;
|
||||||
import org.dromara.workflow.domain.vo.ResultListDataRepresentation;
|
|
||||||
import org.dromara.workflow.service.IActModelService;
|
import org.dromara.workflow.service.IActModelService;
|
||||||
import org.flowable.engine.RepositoryService;
|
import org.flowable.engine.RepositoryService;
|
||||||
import org.flowable.engine.repository.Model;
|
import org.flowable.engine.repository.Model;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.MultiValueMap;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,20 +49,6 @@ public class ActModelController extends BaseController {
|
|||||||
return actModelService.page(modelBo);
|
return actModelService.page(modelBo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 设计器登录信息
|
|
||||||
*/
|
|
||||||
@GetMapping("/rest/account")
|
|
||||||
public String getAccount() {
|
|
||||||
AccountVo accountVo = new AccountVo();
|
|
||||||
LoginUser loginUser = LoginHelper.getLoginUser();
|
|
||||||
accountVo.setId(Convert.toStr(loginUser.getUserId()));
|
|
||||||
accountVo.setFirstName("");
|
|
||||||
accountVo.setLastName(loginUser.getUsername());
|
|
||||||
accountVo.setFullName(loginUser.getUsername());
|
|
||||||
return JsonUtils.toJsonString(accountVo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增模型
|
* 新增模型
|
||||||
*
|
*
|
||||||
@ -80,7 +56,7 @@ public class ActModelController extends BaseController {
|
|||||||
*/
|
*/
|
||||||
@Log(title = "模型管理", businessType = BusinessType.INSERT)
|
@Log(title = "模型管理", businessType = BusinessType.INSERT)
|
||||||
@RepeatSubmit()
|
@RepeatSubmit()
|
||||||
@PostMapping("/rest/models")
|
@PostMapping("/save")
|
||||||
public R<Void> saveNewModel(@Validated(AddGroup.class) @RequestBody ModelBo modelBo) {
|
public R<Void> saveNewModel(@Validated(AddGroup.class) @RequestBody ModelBo modelBo) {
|
||||||
return toAjax(actModelService.saveNewModel(modelBo));
|
return toAjax(actModelService.saveNewModel(modelBo));
|
||||||
}
|
}
|
||||||
@ -88,25 +64,35 @@ public class ActModelController extends BaseController {
|
|||||||
/**
|
/**
|
||||||
* 查询模型
|
* 查询模型
|
||||||
*
|
*
|
||||||
* @param modelId 模型id
|
* @param id 模型id
|
||||||
*/
|
*/
|
||||||
@GetMapping("/rest/models/{modelId}/editor/json")
|
@GetMapping("/getInfo/{id}")
|
||||||
public ObjectNode getModelInfo(@NotBlank(message = "模型id不能为空") @PathVariable String modelId) {
|
public R<ModelVo> getInfo(@NotBlank(message = "模型id不能为空") @PathVariable String id) {
|
||||||
return actModelService.getModelInfo(modelId);
|
return R.ok(actModelService.getInfo(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编辑模型
|
* 修改模型信息
|
||||||
*
|
*
|
||||||
* @param modelId 模型id
|
* @param modelBo 模型数据
|
||||||
* @param values 模型数据
|
|
||||||
*/
|
*/
|
||||||
@Log(title = "模型管理", businessType = BusinessType.UPDATE)
|
@Log(title = "模型管理", businessType = BusinessType.UPDATE)
|
||||||
@RepeatSubmit()
|
@RepeatSubmit()
|
||||||
@PostMapping(value = "/rest/models/{modelId}/editor/json")
|
@PostMapping(value = "/update")
|
||||||
public R<Void> editModel(@PathVariable String modelId, @RequestParam MultiValueMap<String, String> values) {
|
public R<Void> update(@RequestBody ModelBo modelBo) {
|
||||||
return toAjax(actModelService.editModel(modelId, values));
|
return toAjax(actModelService.update(modelBo));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑XMl模型
|
||||||
|
*
|
||||||
|
* @param modelBo 模型数据
|
||||||
|
*/
|
||||||
|
@Log(title = "模型管理", businessType = BusinessType.UPDATE)
|
||||||
|
@RepeatSubmit()
|
||||||
|
@PostMapping(value = "/editModelXml")
|
||||||
|
public R<Void> editModel(@Validated(EditGroup.class) @RequestBody ModelBo modelBo) {
|
||||||
|
return toAjax(actModelService.editModelXml(modelBo));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -146,36 +132,4 @@ public class ActModelController extends BaseController {
|
|||||||
HttpServletResponse response) {
|
HttpServletResponse response) {
|
||||||
actModelService.exportZip(modelId, response);
|
actModelService.exportZip(modelId, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询用户
|
|
||||||
*
|
|
||||||
* @param filter 参数
|
|
||||||
*/
|
|
||||||
@GetMapping(value = "/rest/editor-users")
|
|
||||||
public ResultListDataRepresentation editorUsers(@RequestParam(value = "filter", required = false) String filter) {
|
|
||||||
return actModelService.getUsers(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询用户组
|
|
||||||
*
|
|
||||||
* @param filter 参数
|
|
||||||
*/
|
|
||||||
@GetMapping(value = "/rest/editor-groups")
|
|
||||||
public ResultListDataRepresentation editorGroups(@RequestParam(required = false, value = "filter") String filter) {
|
|
||||||
return actModelService.getGroups(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析翻译模型设计器内容
|
|
||||||
*/
|
|
||||||
@GetMapping(value = "/rest/stencil-sets/editor")
|
|
||||||
public String getStencilset() {
|
|
||||||
try (InputStream inputStream = ResourceUtil.getStream("static/stencilset.json")) {
|
|
||||||
return IOUtils.toString(inputStream, StandardCharsets.UTF_8);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new SecurityException("Error while loading stencil set", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import jakarta.validation.constraints.Pattern;
|
|||||||
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.common.core.validate.EditGroup;
|
||||||
import org.dromara.workflow.common.PageEntity;
|
import org.dromara.workflow.common.PageEntity;
|
||||||
import org.dromara.workflow.common.constant.FlowConstant;
|
import org.dromara.workflow.common.constant.FlowConstant;
|
||||||
|
|
||||||
@ -23,6 +24,12 @@ public class ModelBo extends PageEntity implements Serializable {
|
|||||||
@Serial
|
@Serial
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模型id
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "模型ID不能为空", groups = {EditGroup.class})
|
||||||
|
private String id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 模型名称
|
* 模型名称
|
||||||
*/
|
*/
|
||||||
@ -42,6 +49,18 @@ public class ModelBo extends PageEntity implements Serializable {
|
|||||||
@NotBlank(message = "模型分类不能为空", groups = {AddGroup.class})
|
@NotBlank(message = "模型分类不能为空", groups = {AddGroup.class})
|
||||||
private String categoryCode;
|
private String categoryCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模型XML
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "模型XML不能为空", groups = {AddGroup.class})
|
||||||
|
private String xml;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模型SVG图片
|
||||||
|
*/
|
||||||
|
@NotBlank(message = "模型SVG不能为空", groups = {EditGroup.class})
|
||||||
|
private String svg;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 备注
|
* 备注
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,21 +0,0 @@
|
|||||||
package org.dromara.workflow.domain.vo;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 参考官方提供的响应数据
|
|
||||||
*
|
|
||||||
* @author may
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class AccountVo {
|
|
||||||
private String id;
|
|
||||||
private String firstName;
|
|
||||||
private String lastName;
|
|
||||||
private String email;
|
|
||||||
private String fullName;
|
|
||||||
private List<String> groups;
|
|
||||||
private List<String> privileges;
|
|
||||||
}
|
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
package org.dromara.workflow.domain.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模型视图对象
|
||||||
|
*
|
||||||
|
* @author may
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ModelVo implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模型id
|
||||||
|
*/
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模型名称
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模型标识key
|
||||||
|
*/
|
||||||
|
private String key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模型分类
|
||||||
|
*/
|
||||||
|
private String categoryCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模型XML
|
||||||
|
*/
|
||||||
|
private String xml;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
private String description;
|
||||||
|
}
|
||||||
@ -1,39 +0,0 @@
|
|||||||
/* 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 org.dromara.workflow.domain.vo;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Tijs Rademakers
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class ResultListDataRepresentation {
|
|
||||||
|
|
||||||
protected Integer size;
|
|
||||||
protected Long total;
|
|
||||||
protected Integer start;
|
|
||||||
protected List<?> data;
|
|
||||||
|
|
||||||
public ResultListDataRepresentation(List<?> data) {
|
|
||||||
this.data = data;
|
|
||||||
if (data != null) {
|
|
||||||
size = data.size();
|
|
||||||
total = (long) data.size();
|
|
||||||
start = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,30 +0,0 @@
|
|||||||
/* 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 org.dromara.workflow.domain.vo;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Joram Barrez
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class UserRepresentation {
|
|
||||||
|
|
||||||
protected String id;
|
|
||||||
protected String firstName;
|
|
||||||
protected String lastName;
|
|
||||||
protected String email;
|
|
||||||
protected String fullName;
|
|
||||||
protected String tenantId;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,12 +1,11 @@
|
|||||||
package org.dromara.workflow.service;
|
package org.dromara.workflow.service;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
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.dromara.workflow.domain.vo.ResultListDataRepresentation;
|
import org.dromara.workflow.domain.vo.ModelVo;
|
||||||
import org.flowable.engine.repository.Model;
|
import org.flowable.engine.repository.Model;
|
||||||
import org.springframework.util.MultiValueMap;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 模型管理 服务层
|
* 模型管理 服务层
|
||||||
@ -36,16 +35,23 @@ public interface IActModelService {
|
|||||||
* @param modelId 模型id
|
* @param modelId 模型id
|
||||||
* @return 模型数据
|
* @return 模型数据
|
||||||
*/
|
*/
|
||||||
ObjectNode getModelInfo(String modelId);
|
ModelVo getInfo(String modelId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编辑模型
|
* 修改模型信息
|
||||||
*
|
*
|
||||||
* @param modelId 模型id
|
* @param modelBo 模型数据
|
||||||
* @param values 模型数据
|
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
boolean editModel(String modelId, MultiValueMap<String, String> values);
|
boolean update(ModelBo modelBo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑模型XML
|
||||||
|
*
|
||||||
|
* @param modelBo 模型数据
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
boolean editModelXml(ModelBo modelBo);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 模型部署
|
* 模型部署
|
||||||
@ -62,20 +68,4 @@ public interface IActModelService {
|
|||||||
* @param response 相应
|
* @param response 相应
|
||||||
*/
|
*/
|
||||||
void exportZip(String modelId, HttpServletResponse response);
|
void exportZip(String modelId, HttpServletResponse response);
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询用户
|
|
||||||
*
|
|
||||||
* @param filter 参数
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
ResultListDataRepresentation getUsers(String filter);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询用户组
|
|
||||||
*
|
|
||||||
* @param filter 参数
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
ResultListDataRepresentation getGroups(String filter);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,34 +7,24 @@ 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.core.util.ZipUtil;
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
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.io.IOUtils;
|
||||||
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;
|
||||||
import org.dromara.common.core.utils.StreamUtils;
|
|
||||||
import org.dromara.common.json.utils.JsonUtils;
|
|
||||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
import org.dromara.common.tenant.helper.TenantHelper;
|
import org.dromara.common.tenant.helper.TenantHelper;
|
||||||
import org.dromara.system.domain.SysRole;
|
|
||||||
import org.dromara.system.domain.SysUser;
|
|
||||||
import org.dromara.system.mapper.SysRoleMapper;
|
import org.dromara.system.mapper.SysRoleMapper;
|
||||||
import org.dromara.system.mapper.SysUserMapper;
|
import org.dromara.system.mapper.SysUserMapper;
|
||||||
import org.dromara.workflow.common.constant.FlowConstant;
|
import org.dromara.workflow.common.constant.FlowConstant;
|
||||||
import org.dromara.workflow.domain.bo.ModelBo;
|
import org.dromara.workflow.domain.bo.ModelBo;
|
||||||
import org.dromara.workflow.domain.vo.GroupRepresentation;
|
import org.dromara.workflow.domain.vo.ModelVo;
|
||||||
import org.dromara.workflow.domain.vo.ResultListDataRepresentation;
|
|
||||||
import org.dromara.workflow.domain.vo.UserRepresentation;
|
|
||||||
import org.dromara.workflow.service.IActModelService;
|
import org.dromara.workflow.service.IActModelService;
|
||||||
import org.dromara.workflow.utils.WorkflowUtils;
|
import org.dromara.workflow.utils.ModelUtils;
|
||||||
import org.flowable.bpmn.model.BpmnModel;
|
import org.flowable.bpmn.model.BpmnModel;
|
||||||
import org.flowable.editor.constants.ModelDataJsonConstants;
|
|
||||||
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.Deployment;
|
||||||
import org.flowable.engine.repository.Model;
|
import org.flowable.engine.repository.Model;
|
||||||
@ -43,21 +33,18 @@ import org.flowable.engine.repository.ProcessDefinition;
|
|||||||
import org.flowable.validation.ValidationError;
|
import org.flowable.validation.ValidationError;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.MultiValueMap;
|
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipOutputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
import static org.dromara.workflow.common.constant.FlowConstant.NAMESPACE;
|
|
||||||
import static org.flowable.editor.constants.ModelDataJsonConstants.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 模型管理 服务层实现
|
* 模型管理 服务层实现
|
||||||
*
|
*
|
||||||
@ -95,16 +82,6 @@ public class ActModelServiceImpl implements IActModelService {
|
|||||||
query.orderByCreateTime().desc();
|
query.orderByCreateTime().desc();
|
||||||
// 分页查询
|
// 分页查询
|
||||||
List<Model> modelList = query.listPage(modelBo.getPageNum(), modelBo.getPageSize());
|
List<Model> modelList = query.listPage(modelBo.getPageNum(), modelBo.getPageSize());
|
||||||
if (CollUtil.isNotEmpty(modelList)) {
|
|
||||||
modelList.parallelStream().forEach(e -> {
|
|
||||||
boolean isNull = JSONUtil.isNull(JSONUtil.parseObj(e.getMetaInfo()).get(ModelDataJsonConstants.MODEL_DESCRIPTION));
|
|
||||||
if (!isNull) {
|
|
||||||
e.setMetaInfo((String) JSONUtil.parseObj(e.getMetaInfo()).get(ModelDataJsonConstants.MODEL_DESCRIPTION));
|
|
||||||
} else {
|
|
||||||
e.setMetaInfo(StrUtil.EMPTY);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// 总记录数
|
// 总记录数
|
||||||
long total = query.count();
|
long total = query.count();
|
||||||
return new TableDataInfo<>(modelList, total);
|
return new TableDataInfo<>(modelList, total);
|
||||||
@ -124,38 +101,22 @@ public class ActModelServiceImpl implements IActModelService {
|
|||||||
String key = modelBo.getKey();
|
String key = modelBo.getKey();
|
||||||
String name = modelBo.getName();
|
String name = modelBo.getName();
|
||||||
String description = modelBo.getDescription();
|
String description = modelBo.getDescription();
|
||||||
|
String categoryCode = modelBo.getCategoryCode();
|
||||||
|
String xml = modelBo.getXml();
|
||||||
Model checkModel = repositoryService.createModelQuery().modelKey(key).modelTenantId(TenantHelper.getTenantId()).singleResult();
|
Model checkModel = repositoryService.createModelQuery().modelKey(key).modelTenantId(TenantHelper.getTenantId()).singleResult();
|
||||||
if (ObjectUtil.isNotNull(checkModel)) {
|
if (ObjectUtil.isNotNull(checkModel)) {
|
||||||
throw new ServiceException("模型key已存在!");
|
throw new ServiceException("模型key已存在!");
|
||||||
}
|
}
|
||||||
// 1. 初始空的模型
|
//初始空的模型
|
||||||
Model model = repositoryService.newModel();
|
Model model = repositoryService.newModel();
|
||||||
model.setKey(key);
|
model.setKey(key);
|
||||||
model.setName(name);
|
model.setName(name);
|
||||||
model.setCategory(modelBo.getCategoryCode());
|
|
||||||
model.setVersion(version);
|
model.setVersion(version);
|
||||||
model.setTenantId(TenantHelper.getTenantId());
|
model.setCategory(categoryCode);
|
||||||
ObjectMapper objectMapper = JsonUtils.getObjectMapper();
|
model.setMetaInfo(description);
|
||||||
// 封装模型json对象
|
//保存初始化的模型基本信息数据
|
||||||
ObjectNode objectNode = JsonUtils.getObjectMapper().createObjectNode();
|
|
||||||
objectNode.put(MODEL_NAME, name);
|
|
||||||
objectNode.put(MODEL_REVISION, version);
|
|
||||||
objectNode.put(MODEL_DESCRIPTION, description);
|
|
||||||
model.setMetaInfo(objectNode.toString());
|
|
||||||
// 保存初始化的模型基本信息数据
|
|
||||||
repositoryService.saveModel(model);
|
repositoryService.saveModel(model);
|
||||||
// 封装模型对象基础数据json串
|
repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(xml));
|
||||||
ObjectNode editorNode = objectMapper.createObjectNode();
|
|
||||||
ObjectNode stencilSetNode = objectMapper.createObjectNode();
|
|
||||||
stencilSetNode.put("namespace", NAMESPACE);
|
|
||||||
editorNode.replace("stencilset", stencilSetNode);
|
|
||||||
// 标识key
|
|
||||||
ObjectNode propertiesNode = objectMapper.createObjectNode();
|
|
||||||
propertiesNode.put("process_id", key);
|
|
||||||
propertiesNode.put("name", name);
|
|
||||||
propertiesNode.put("description", description);
|
|
||||||
editorNode.replace("properties", propertiesNode);
|
|
||||||
repositoryService.addModelEditorSource(model.getId(), editorNode.toString().getBytes(StandardCharsets.UTF_8));
|
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -166,93 +127,97 @@ public class ActModelServiceImpl implements IActModelService {
|
|||||||
/**
|
/**
|
||||||
* 查询模型
|
* 查询模型
|
||||||
*
|
*
|
||||||
* @param modelId 模型id
|
* @param id 模型id
|
||||||
* @return 模型数据
|
* @return 模型数据
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ObjectNode getModelInfo(String modelId) {
|
public ModelVo getInfo(String id) {
|
||||||
ObjectNode modelNode = null;
|
ModelVo modelVo = new ModelVo();
|
||||||
Model model = repositoryService.createModelQuery().modelId(modelId).modelTenantId(TenantHelper.getTenantId()).singleResult();
|
Model model = repositoryService.getModel(id);
|
||||||
ObjectMapper objectMapper = JsonUtils.getObjectMapper();
|
|
||||||
if (model != null) {
|
if (model != null) {
|
||||||
try {
|
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());
|
|
||||||
modelNode.put("key", model.getKey());
|
|
||||||
Integer version = model.getVersion();
|
|
||||||
if (version > 0) {
|
|
||||||
byte[] modelEditorSource = repositoryService.getModelEditorSource(model.getId());
|
byte[] modelEditorSource = repositoryService.getModelEditorSource(model.getId());
|
||||||
BpmnModel bpmnModel = WorkflowUtils.xmlToBpmnModel(modelEditorSource);
|
modelVo.setXml(StrUtil.utf8Str(modelEditorSource));
|
||||||
BpmnJsonConverter bpmnJsonConverter = new BpmnJsonConverter();
|
modelVo.setId(model.getId());
|
||||||
ObjectNode jsonNodes = bpmnJsonConverter.convertToJson(bpmnModel);
|
modelVo.setKey(model.getKey());
|
||||||
modelNode.set("model", jsonNodes);
|
modelVo.setName(model.getName());
|
||||||
} else {
|
modelVo.setCategoryCode(model.getCategory());
|
||||||
ObjectNode editorJsonNode = (ObjectNode) objectMapper.readTree(
|
modelVo.setDescription(model.getMetaInfo());
|
||||||
new String(repositoryService.getModelEditorSource(model.getId()), StandardCharsets.UTF_8));
|
return modelVo;
|
||||||
modelNode.set("model", editorJsonNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
throw new ServiceException(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return modelNode;
|
return modelVo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 编辑模型
|
* 修改模型信息
|
||||||
*
|
*
|
||||||
* @param modelId 模型id
|
* @param modelBo 模型数据
|
||||||
* @param values 模型数据
|
* @return 结果
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean update(ModelBo modelBo) {
|
||||||
|
try {
|
||||||
|
Model model = repositoryService.getModel(modelBo.getId());
|
||||||
|
List<Model> list = repositoryService.createModelQuery().modelTenantId(TenantHelper.getTenantId()).modelKey(modelBo.getKey()).list();
|
||||||
|
list.stream().filter(e -> !e.getId().equals(model.getId())).findFirst().ifPresent(e -> {
|
||||||
|
throw new ServiceException("模型KEY已存在!");
|
||||||
|
});
|
||||||
|
model.setKey(modelBo.getKey());
|
||||||
|
model.setName(modelBo.getName());
|
||||||
|
model.setCategory(modelBo.getCategoryCode());
|
||||||
|
model.setMetaInfo(modelBo.getDescription());
|
||||||
|
repositoryService.saveModel(model);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ServiceException(e.getMessage());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑模型XML
|
||||||
|
*
|
||||||
|
* @param modelBo 模型数据
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public boolean editModel(String modelId, MultiValueMap<String, String> values) {
|
public boolean editModelXml(ModelBo modelBo) {
|
||||||
try {
|
try {
|
||||||
Model model = repositoryService.createModelQuery().modelId(modelId).modelTenantId(TenantHelper.getTenantId()).singleResult();
|
String xml = modelBo.getXml();
|
||||||
ObjectMapper objectMapper = JsonUtils.getObjectMapper();
|
String svg = modelBo.getSvg();
|
||||||
ObjectNode modelJson = (ObjectNode) objectMapper.readTree(model.getMetaInfo());
|
String modelId = modelBo.getId();
|
||||||
|
String key = modelBo.getKey();
|
||||||
modelJson.put(MODEL_NAME, values.getFirst("name"));
|
String name = modelBo.getName();
|
||||||
modelJson.put(MODEL_DESCRIPTION, values.getFirst("description"));
|
BpmnModel bpmnModel = ModelUtils.xmlToBpmnModel(xml);
|
||||||
modelJson.put(MODEL_REVISION, model.getVersion() + 1);
|
ModelUtils.checkBpmnModel(bpmnModel);
|
||||||
model.setMetaInfo(modelJson.toString());
|
Model model = repositoryService.getModel(modelId);
|
||||||
model.setName(values.getFirst("name"));
|
List<Model> list = repositoryService.createModelQuery().modelTenantId(TenantHelper.getTenantId()).modelKey(key).list();
|
||||||
// 每次保存把版本更新+1
|
list.stream().filter(e -> !e.getId().equals(model.getId())).findFirst().ifPresent(e -> {
|
||||||
model.setVersion(model.getVersion() + 1);
|
throw new ServiceException("模型KEY已存在!");
|
||||||
// 获取唯一标识key
|
});
|
||||||
String key = values.getFirst("key");
|
|
||||||
// 校验key命名规范
|
// 校验key命名规范
|
||||||
if (!Validator.isMatchRegex(FlowConstant.MODEL_KEY_PATTERN, key)) {
|
if (!Validator.isMatchRegex(FlowConstant.MODEL_KEY_PATTERN, key)) {
|
||||||
throw new ServiceException("模型标识key只能字符或者下划线开头!");
|
throw new ServiceException("模型标识KEY只能字符或者下划线开头!");
|
||||||
}
|
}
|
||||||
List<Model> list = repositoryService.createModelQuery().modelKey(key).modelTenantId(TenantHelper.getTenantId()).list();
|
|
||||||
list.stream().filter(e -> !e.getId().equals(model.getId())).findFirst().ifPresent(e -> {
|
|
||||||
throw new ServiceException("模型标识key已存在!");
|
|
||||||
});
|
|
||||||
model.setKey(key);
|
model.setKey(key);
|
||||||
|
model.setName(name);
|
||||||
|
model.setVersion(model.getVersion() + 1);
|
||||||
repositoryService.saveModel(model);
|
repositoryService.saveModel(model);
|
||||||
JsonNode jsonNode = objectMapper.readTree(values.getFirst("json_xml"));
|
repositoryService.addModelEditorSource(model.getId(), StrUtil.utf8Bytes(xml));
|
||||||
// 校验流程标识
|
// 转换图片
|
||||||
String processId = jsonNode.get("properties").get("process_id").textValue();
|
InputStream svgStream = new ByteArrayInputStream(StrUtil.utf8Bytes(svg));
|
||||||
if (StringUtils.isBlank(processId)) {
|
TranscoderInput input = new TranscoderInput(svgStream);
|
||||||
throw new ServiceException("流程标识不能为空!");
|
|
||||||
}
|
|
||||||
if (!Validator.isMatchRegex(FlowConstant.MODEL_KEY_PATTERN, processId)) {
|
|
||||||
throw new ServiceException("流程标识只能字符或者下划线开头!");
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] xmlBytes = WorkflowUtils.bpmnJsonToXmlBytes(Objects.requireNonNull(JsonUtils.toJsonString(jsonNode)).getBytes(StandardCharsets.UTF_8));
|
PNGTranscoder transcoder = new PNGTranscoder();
|
||||||
if (ArrayUtil.isEmpty(xmlBytes)) {
|
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
||||||
throw new ServiceException("模型不能为空!");
|
TranscoderOutput output = new TranscoderOutput(outStream);
|
||||||
}
|
|
||||||
repositoryService.addModelEditorSource(model.getId(), xmlBytes);
|
transcoder.transcode(input, output);
|
||||||
|
final byte[] result = outStream.toByteArray();
|
||||||
|
repositoryService.addModelEditorSourceExtra(model.getId(), result);
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -276,14 +241,14 @@ public class ActModelServiceImpl implements IActModelService {
|
|||||||
throw new ServiceException("模型数据为空,请先设计流程定义模型,再进行部署!");
|
throw new ServiceException("模型数据为空,请先设计流程定义模型,再进行部署!");
|
||||||
}
|
}
|
||||||
if (JSONUtil.isTypeJSON(IOUtils.toString(xmlBytes, StandardCharsets.UTF_8.toString()))) {
|
if (JSONUtil.isTypeJSON(IOUtils.toString(xmlBytes, StandardCharsets.UTF_8.toString()))) {
|
||||||
byte[] bytes = WorkflowUtils.bpmnJsonToXmlBytes(xmlBytes);
|
byte[] bytes = ModelUtils.bpmnJsonToXmlBytes(xmlBytes);
|
||||||
if (ArrayUtil.isEmpty(bytes)) {
|
if (ArrayUtil.isEmpty(bytes)) {
|
||||||
throw new ServiceException("模型不能为空,请至少设计一条主线流程!");
|
throw new ServiceException("模型不能为空,请至少设计一条主线流程!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BpmnModel bpmnModel = WorkflowUtils.xmlToBpmnModel(xmlBytes);
|
BpmnModel bpmnModel = ModelUtils.xmlToBpmnModel(xmlBytes);
|
||||||
// 校验模型
|
// 校验模型
|
||||||
WorkflowUtils.checkBpmnModel(bpmnModel);
|
ModelUtils.checkBpmnModel(bpmnModel);
|
||||||
List<ValidationError> validationErrors = repositoryService.validateProcess(bpmnModel);
|
List<ValidationError> validationErrors = repositoryService.validateProcess(bpmnModel);
|
||||||
if (CollUtil.isNotEmpty(validationErrors)) {
|
if (CollUtil.isNotEmpty(validationErrors)) {
|
||||||
String errorMsg = validationErrors.stream().map(ValidationError::getProblem).distinct().collect(Collectors.joining(","));
|
String errorMsg = validationErrors.stream().map(ValidationError::getProblem).distinct().collect(Collectors.joining(","));
|
||||||
@ -337,7 +302,7 @@ public class ActModelServiceImpl implements IActModelService {
|
|||||||
Model model = repositoryService.getModel(modelId);
|
Model model = repositoryService.getModel(modelId);
|
||||||
byte[] xmlBytes = repositoryService.getModelEditorSource(modelId);
|
byte[] xmlBytes = repositoryService.getModelEditorSource(modelId);
|
||||||
if (ObjectUtil.isNotNull(model)) {
|
if (ObjectUtil.isNotNull(model)) {
|
||||||
if (JSONUtil.isTypeJSON(IOUtils.toString(xmlBytes, StandardCharsets.UTF_8.toString())) && ArrayUtil.isEmpty(WorkflowUtils.bpmnJsonToXmlBytes(xmlBytes))) {
|
if (JSONUtil.isTypeJSON(IOUtils.toString(xmlBytes, StandardCharsets.UTF_8.toString())) && ArrayUtil.isEmpty(ModelUtils.bpmnJsonToXmlBytes(xmlBytes))) {
|
||||||
zipName = "模型不能为空,请至少设计一条主线流程!";
|
zipName = "模型不能为空,请至少设计一条主线流程!";
|
||||||
zos.putNextEntry(new ZipEntry(zipName + ".txt"));
|
zos.putNextEntry(new ZipEntry(zipName + ".txt"));
|
||||||
zos.write(zipName.getBytes(StandardCharsets.UTF_8));
|
zos.write(zipName.getBytes(StandardCharsets.UTF_8));
|
||||||
@ -371,49 +336,4 @@ public class ActModelServiceImpl implements IActModelService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询用户
|
|
||||||
*
|
|
||||||
* @param filter 参数
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public ResultListDataRepresentation getUsers(String filter) {
|
|
||||||
|
|
||||||
LambdaQueryWrapper<SysUser> wrapper = Wrappers.lambdaQuery();
|
|
||||||
wrapper.like(StringUtils.isNotBlank(filter), SysUser::getNickName, filter);
|
|
||||||
List<SysUser> sysUsers = sysUserMapper.selectList(wrapper);
|
|
||||||
List<UserRepresentation> userRepresentations = new ArrayList<>();
|
|
||||||
for (SysUser sysUser : sysUsers) {
|
|
||||||
UserRepresentation userRepresentation = new UserRepresentation();
|
|
||||||
userRepresentation.setFullName(sysUser.getNickName());
|
|
||||||
userRepresentation.setLastName(sysUser.getNickName());
|
|
||||||
userRepresentation.setTenantId(sysUser.getTenantId());
|
|
||||||
userRepresentation.setEmail(sysUser.getEmail());
|
|
||||||
userRepresentation.setId(sysUser.getUserId().toString());
|
|
||||||
userRepresentations.add(userRepresentation);
|
|
||||||
}
|
|
||||||
return new ResultListDataRepresentation(userRepresentations);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询用户组
|
|
||||||
*
|
|
||||||
* @param filter 参数
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public ResultListDataRepresentation getGroups(String filter) {
|
|
||||||
|
|
||||||
LambdaQueryWrapper<SysRole> wrapper = Wrappers.lambdaQuery();
|
|
||||||
wrapper.like(StringUtils.isNotBlank(filter), SysRole::getRoleName, filter);
|
|
||||||
List<SysRole> sysRoles = sysRoleMapper.selectList(wrapper);
|
|
||||||
List<GroupRepresentation> result = StreamUtils.toList(sysRoles, sysRole -> {
|
|
||||||
GroupRepresentation groupRepresentation = new GroupRepresentation();
|
|
||||||
groupRepresentation.setId(sysRole.getRoleId().toString());
|
|
||||||
groupRepresentation.setName(sysRole.getRoleName());
|
|
||||||
groupRepresentation.setType(sysRole.getRoleKey());
|
|
||||||
return groupRepresentation;
|
|
||||||
});
|
|
||||||
return new ResultListDataRepresentation(result);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,194 @@
|
|||||||
|
package org.dromara.workflow.utils;
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
|
import cn.hutool.core.io.IoUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.dromara.common.core.utils.StreamUtils;
|
||||||
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
|
import org.dromara.common.json.utils.JsonUtils;
|
||||||
|
import org.dromara.workflow.domain.vo.MultiInstanceVo;
|
||||||
|
import org.flowable.bpmn.converter.BpmnXMLConverter;
|
||||||
|
import org.flowable.bpmn.model.*;
|
||||||
|
import org.flowable.bpmn.model.Process;
|
||||||
|
import org.flowable.editor.language.json.converter.BpmnJsonConverter;
|
||||||
|
import org.flowable.engine.impl.util.ProcessDefinitionUtil;
|
||||||
|
|
||||||
|
import javax.xml.stream.XMLInputFactory;
|
||||||
|
import javax.xml.stream.XMLStreamException;
|
||||||
|
import javax.xml.stream.XMLStreamReader;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.rmi.ServerException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模型工具
|
||||||
|
*
|
||||||
|
* @author may
|
||||||
|
*/
|
||||||
|
public class ModelUtils {
|
||||||
|
public ModelUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BpmnModel xmlToBpmnModel(String xml) throws IOException {
|
||||||
|
if (xml == null) {
|
||||||
|
throw new ServerException("xml不能为空");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
InputStream inputStream = new ByteArrayInputStream(StrUtil.utf8Bytes(xml));
|
||||||
|
XMLInputFactory factory = XMLInputFactory.newInstance();
|
||||||
|
XMLStreamReader reader = factory.createXMLStreamReader(inputStream);
|
||||||
|
return new BpmnXMLConverter().convertToBpmnModel(reader);
|
||||||
|
} catch (XMLStreamException e) {
|
||||||
|
throw new ServerException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bpmnModel转为xml
|
||||||
|
*
|
||||||
|
* @param jsonBytes json
|
||||||
|
*/
|
||||||
|
public static byte[] bpmnJsonToXmlBytes(byte[] jsonBytes) throws IOException {
|
||||||
|
if (jsonBytes == null) {
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
// 1. json字节码转成 BpmnModel 对象
|
||||||
|
ObjectMapper objectMapper = JsonUtils.getObjectMapper();
|
||||||
|
JsonNode jsonNode = objectMapper.readTree(jsonBytes);
|
||||||
|
BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(jsonNode);
|
||||||
|
|
||||||
|
if (bpmnModel.getProcesses().isEmpty()) {
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
// 2.将bpmnModel转为xml
|
||||||
|
return new BpmnXMLConverter().convertToXML(bpmnModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xml转为bpmnModel
|
||||||
|
*
|
||||||
|
* @param xmlBytes xml
|
||||||
|
*/
|
||||||
|
public static BpmnModel xmlToBpmnModel(byte[] xmlBytes) throws XMLStreamException {
|
||||||
|
ByteArrayInputStream byteArrayInputStream = IoUtil.toStream(xmlBytes);
|
||||||
|
XMLInputFactory xif = XMLInputFactory.newInstance();
|
||||||
|
XMLStreamReader xtr = xif.createXMLStreamReader(byteArrayInputStream);
|
||||||
|
return new BpmnXMLConverter().convertToBpmnModel(xtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验模型
|
||||||
|
*
|
||||||
|
* @param bpmnModel bpmn模型
|
||||||
|
*/
|
||||||
|
public static void checkBpmnModel(BpmnModel bpmnModel) throws ServerException {
|
||||||
|
Collection<FlowElement> flowElements = bpmnModel.getMainProcess().getFlowElements();
|
||||||
|
|
||||||
|
checkBpmnNode(flowElements, false);
|
||||||
|
|
||||||
|
List<SubProcess> subProcessList = flowElements.stream().filter(SubProcess.class::isInstance).map(SubProcess.class::cast).collect(Collectors.toList());
|
||||||
|
if (!CollUtil.isEmpty(subProcessList)) {
|
||||||
|
for (SubProcess subProcess : subProcessList) {
|
||||||
|
Collection<FlowElement> subProcessFlowElements = subProcess.getFlowElements();
|
||||||
|
checkBpmnNode(subProcessFlowElements, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<MultiInstanceVo> multiInstanceVoList = new ArrayList<>();
|
||||||
|
for (FlowElement flowElement : flowElements) {
|
||||||
|
if (flowElement instanceof UserTask && ObjectUtil.isNotEmpty(((UserTask) flowElement).getLoopCharacteristics()) && StringUtils.isNotBlank(((UserTask) flowElement).getLoopCharacteristics().getInputDataItem())) {
|
||||||
|
MultiInstanceVo multiInstanceVo = new MultiInstanceVo();
|
||||||
|
multiInstanceVo.setAssigneeList(((UserTask) flowElement).getLoopCharacteristics().getInputDataItem());
|
||||||
|
multiInstanceVoList.add(multiInstanceVo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CollectionUtil.isNotEmpty(multiInstanceVoList) && multiInstanceVoList.size() > 1) {
|
||||||
|
Map<String, List<MultiInstanceVo>> assigneeListGroup = StreamUtils.groupByKey(multiInstanceVoList, MultiInstanceVo::getAssigneeList);
|
||||||
|
for (Map.Entry<String, List<MultiInstanceVo>> entry : assigneeListGroup.entrySet()) {
|
||||||
|
List<MultiInstanceVo> value = entry.getValue();
|
||||||
|
if (CollectionUtil.isNotEmpty(value) && value.size() > 1) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
throw new ServerException("会签人员集合【" + key + "】重复,请重新设置集合KEY");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验bpmn节点是否合法
|
||||||
|
*
|
||||||
|
* @param flowElements 节点集合
|
||||||
|
* @param subtask 是否子流程
|
||||||
|
*/
|
||||||
|
private static void checkBpmnNode(Collection<FlowElement> flowElements, boolean subtask) throws ServerException {
|
||||||
|
|
||||||
|
if (CollUtil.isEmpty(flowElements)) {
|
||||||
|
throw new ServerException(subtask ? "子流程必须存在节点" : "必须存在节点!");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<StartEvent> startEventList = flowElements.stream().filter(StartEvent.class::isInstance).map(StartEvent.class::cast).collect(Collectors.toList());
|
||||||
|
if (CollUtil.isEmpty(startEventList)) {
|
||||||
|
throw new ServerException(subtask ? "子流程必须存在开始节点" : "必须存在开始节点!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startEventList.size() > 1) {
|
||||||
|
throw new ServerException(subtask ? "子流程只能存在一个开始节点" : "只能存在一个开始节点!");
|
||||||
|
}
|
||||||
|
|
||||||
|
StartEvent startEvent = startEventList.get(0);
|
||||||
|
List<SequenceFlow> outgoingFlows = startEvent.getOutgoingFlows();
|
||||||
|
if (CollUtil.isEmpty(outgoingFlows)) {
|
||||||
|
throw new ServerException(subtask ? "子流程流程节点为空,请至少设计一条主线流程!" : "流程节点为空,请至少设计一条主线流程!");
|
||||||
|
}
|
||||||
|
|
||||||
|
FlowElement targetFlowElement = outgoingFlows.get(0).getTargetFlowElement();
|
||||||
|
if (!(targetFlowElement instanceof UserTask) && !subtask) {
|
||||||
|
throw new ServerException("开始节点后第一个节点必须是用户任务!");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<EndEvent> endEventList = flowElements.stream().filter(EndEvent.class::isInstance).map(EndEvent.class::cast).collect(Collectors.toList());
|
||||||
|
if (CollUtil.isEmpty(endEventList)) {
|
||||||
|
throw new ServerException(subtask ? "子流程必须存在结束节点!" : "必须存在结束节点!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程全部节点
|
||||||
|
*
|
||||||
|
* @param processDefinitionId 流程定义id
|
||||||
|
*/
|
||||||
|
public static List<FlowElement> getFlowElements(String processDefinitionId) {
|
||||||
|
BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(processDefinitionId);
|
||||||
|
List<FlowElement> list = new ArrayList<>();
|
||||||
|
List<Process> processes = bpmnModel.getProcesses();
|
||||||
|
Collection<FlowElement> flowElements = processes.get(0).getFlowElements();
|
||||||
|
buildFlowElements(flowElements, list);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归获取所有节点
|
||||||
|
*
|
||||||
|
* @param flowElements 节点信息
|
||||||
|
* @param list 集合
|
||||||
|
*/
|
||||||
|
private static void buildFlowElements(Collection<FlowElement> flowElements, List<FlowElement> list) {
|
||||||
|
for (FlowElement flowElement : flowElements) {
|
||||||
|
list.add(flowElement);
|
||||||
|
if (flowElement instanceof SubProcess) {
|
||||||
|
Collection<FlowElement> subFlowElements = ((SubProcess) flowElement).getFlowElements();
|
||||||
|
buildFlowElements(subFlowElements, list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -66,117 +66,6 @@ public class WorkflowUtils {
|
|||||||
private static final IWorkflowUserService I_WORKFLOW_USER_SERVICE = SpringUtils.getBean(WorkflowUserServiceImpl.class);
|
private static final IWorkflowUserService I_WORKFLOW_USER_SERVICE = SpringUtils.getBean(WorkflowUserServiceImpl.class);
|
||||||
private static final IActHiProcinstService I_ACT_HI_PROCINST_SERVICE = SpringUtils.getBean(IActHiProcinstService.class);
|
private static final IActHiProcinstService I_ACT_HI_PROCINST_SERVICE = SpringUtils.getBean(IActHiProcinstService.class);
|
||||||
|
|
||||||
/**
|
|
||||||
* bpmnModel转为xml
|
|
||||||
*
|
|
||||||
* @param jsonBytes json
|
|
||||||
*/
|
|
||||||
public static byte[] bpmnJsonToXmlBytes(byte[] jsonBytes) throws IOException {
|
|
||||||
if (jsonBytes == null) {
|
|
||||||
return new byte[0];
|
|
||||||
}
|
|
||||||
// 1. json字节码转成 BpmnModel 对象
|
|
||||||
ObjectMapper objectMapper = JsonUtils.getObjectMapper();
|
|
||||||
JsonNode jsonNode = objectMapper.readTree(jsonBytes);
|
|
||||||
BpmnModel bpmnModel = new BpmnJsonConverter().convertToBpmnModel(jsonNode);
|
|
||||||
|
|
||||||
if (bpmnModel.getProcesses().isEmpty()) {
|
|
||||||
return new byte[0];
|
|
||||||
}
|
|
||||||
//解决设计器选择设置流程发起人设置变量有问题
|
|
||||||
Collection<FlowElement> flowElements = bpmnModel.getMainProcess().getFlowElements();
|
|
||||||
repairInitiatorVariable(flowElements);
|
|
||||||
// 2.将bpmnModel转为xml
|
|
||||||
return new BpmnXMLConverter().convertToXML(bpmnModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修复发起人节点变量错误问题
|
|
||||||
*
|
|
||||||
* @param flowElements 节点
|
|
||||||
*/
|
|
||||||
private static void repairInitiatorVariable(Collection<FlowElement> flowElements) {
|
|
||||||
for (FlowElement flowElement : flowElements) {
|
|
||||||
if (flowElement instanceof SubProcess) {
|
|
||||||
Collection<FlowElement> subFlowElements = ((SubProcess) flowElement).getFlowElements();
|
|
||||||
repairInitiatorVariable(subFlowElements);
|
|
||||||
} else {
|
|
||||||
if (flowElement instanceof UserTask && INITIATOR_SET.equals(((UserTask) flowElement).getAssignee())) {
|
|
||||||
((UserTask) flowElement).setAssignee(INITIATOR_SET_UPDATE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* xml转为bpmnModel
|
|
||||||
*
|
|
||||||
* @param xmlBytes xml
|
|
||||||
*/
|
|
||||||
public static BpmnModel xmlToBpmnModel(byte[] xmlBytes) throws XMLStreamException {
|
|
||||||
ByteArrayInputStream byteArrayInputStream = IoUtil.toStream(xmlBytes);
|
|
||||||
XMLInputFactory xif = XMLInputFactory.newInstance();
|
|
||||||
XMLStreamReader xtr = xif.createXMLStreamReader(byteArrayInputStream);
|
|
||||||
return new BpmnXMLConverter().convertToBpmnModel(xtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 校验模型
|
|
||||||
*
|
|
||||||
* @param bpmnModel bpmn模型
|
|
||||||
*/
|
|
||||||
public static void checkBpmnModel(BpmnModel bpmnModel) throws ServerException {
|
|
||||||
Collection<FlowElement> flowElements = bpmnModel.getMainProcess().getFlowElements();
|
|
||||||
|
|
||||||
checkBpmnNode(flowElements, false);
|
|
||||||
|
|
||||||
List<SubProcess> subProcessList = flowElements.stream().filter(SubProcess.class::isInstance).map(SubProcess.class::cast).collect(Collectors.toList());
|
|
||||||
if (!CollUtil.isEmpty(subProcessList)) {
|
|
||||||
for (SubProcess subProcess : subProcessList) {
|
|
||||||
Collection<FlowElement> subProcessFlowElements = subProcess.getFlowElements();
|
|
||||||
checkBpmnNode(subProcessFlowElements, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 校验bpmn节点是否合法
|
|
||||||
*
|
|
||||||
* @param flowElements 节点集合
|
|
||||||
* @param subtask 是否子流程
|
|
||||||
*/
|
|
||||||
private static void checkBpmnNode(Collection<FlowElement> flowElements, boolean subtask) throws ServerException {
|
|
||||||
|
|
||||||
if (CollUtil.isEmpty(flowElements)) {
|
|
||||||
throw new ServerException(subtask ? "子流程必须存在节点" : "必须存在节点!");
|
|
||||||
}
|
|
||||||
|
|
||||||
List<StartEvent> startEventList = flowElements.stream().filter(StartEvent.class::isInstance).map(StartEvent.class::cast).collect(Collectors.toList());
|
|
||||||
if (CollUtil.isEmpty(startEventList)) {
|
|
||||||
throw new ServerException(subtask ? "子流程必须存在开始节点" : "必须存在开始节点!");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (startEventList.size() > 1) {
|
|
||||||
throw new ServerException(subtask ? "子流程只能存在一个开始节点" : "只能存在一个开始节点!");
|
|
||||||
}
|
|
||||||
|
|
||||||
StartEvent startEvent = startEventList.get(0);
|
|
||||||
List<SequenceFlow> outgoingFlows = startEvent.getOutgoingFlows();
|
|
||||||
if (CollUtil.isEmpty(outgoingFlows)) {
|
|
||||||
throw new ServerException(subtask ? "子流程流程节点为空,请至少设计一条主线流程!" : "流程节点为空,请至少设计一条主线流程!");
|
|
||||||
}
|
|
||||||
|
|
||||||
FlowElement targetFlowElement = outgoingFlows.get(0).getTargetFlowElement();
|
|
||||||
if (!(targetFlowElement instanceof UserTask) && !subtask) {
|
|
||||||
throw new ServerException("开始节点后第一个节点必须是用户任务!");
|
|
||||||
}
|
|
||||||
|
|
||||||
List<EndEvent> endEventList = flowElements.stream().filter(EndEvent.class::isInstance).map(EndEvent.class::cast).collect(Collectors.toList());
|
|
||||||
if (CollUtil.isEmpty(endEventList)) {
|
|
||||||
throw new ServerException(subtask ? "子流程必须存在结束节点!" : "必须存在结束节点!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建一个新任务
|
* 创建一个新任务
|
||||||
*
|
*
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user