mirror of
http://git.pig4cloud.com/pig/pigx.git
synced 2026-11-08 20:49:00 +08:00
feat(pigx-flow-biz): 优化流程创建逻辑
- 在创建流程时增加对空节点用户列表的检查,避免空指针异常 - 当 nodeUserList 为空时直接返回成功结果,跳过后续处理步骤
This commit is contained in:
1 parent
1b27c695d8
commit
ecdbfaca68
1 file changed
+233
-224
+233
-224
@@ -60,261 +60,270 @@ import java.util.Objects;
|
||||
@RequiredArgsConstructor
|
||||
public class ProcessServiceImpl extends ServiceImpl<ProcessMapper, Process> implements IProcessService {
|
||||
|
||||
private final IProcessStarterService processStarterService;
|
||||
private final IProcessStarterService processStarterService;
|
||||
|
||||
private final RepositoryService repositoryService;
|
||||
private final RepositoryService repositoryService;
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private final Sequence flowSequence;
|
||||
private final Sequence flowSequence;
|
||||
|
||||
private final FlowStatusEventPublisher flowStatusEventPublisher;
|
||||
private final FlowStatusEventPublisher flowStatusEventPublisher;
|
||||
|
||||
/**
|
||||
* 获取流程详细信息
|
||||
* <p>
|
||||
* 根据流程ID获取完整的流程配置信息,包括: - 流程基本信息 - 表单配置(自动生成序列号字段的值) - 需要发起人选择执行人的节点列表 - 表单权限配置
|
||||
* </p>
|
||||
* @param flowId 流程定义ID
|
||||
* @return 包含流程详细信息的响应对象
|
||||
*/
|
||||
@Override
|
||||
public R<ProcessVO> getDetail(String flowId) {
|
||||
// 获取流程详情
|
||||
ProcessVO processVO = this.getProcessVO(flowId);
|
||||
return R.ok(processVO);
|
||||
}
|
||||
/**
|
||||
* 获取流程详细信息
|
||||
* <p>
|
||||
* 根据流程ID获取完整的流程配置信息,包括: - 流程基本信息 - 表单配置(自动生成序列号字段的值) - 需要发起人选择执行人的节点列表 - 表单权限配置
|
||||
* </p>
|
||||
*
|
||||
* @param flowId 流程定义ID
|
||||
* @return 包含流程详细信息的响应对象
|
||||
*/
|
||||
@Override
|
||||
public R<ProcessVO> getDetail(String flowId) {
|
||||
// 获取流程详情
|
||||
ProcessVO processVO = this.getProcessVO(flowId);
|
||||
return R.ok(processVO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程视图对象
|
||||
* <p>
|
||||
* 内部方法,用于构建流程的视图对象。主要处理: - 解析流程节点结构 - 查找需要发起人选择的节点 - 处理序列号类型的表单字段,自动生成下一个序号 -
|
||||
* 提取起始节点的表单权限配置
|
||||
* </p>
|
||||
* @param flowId 流程定义ID
|
||||
* @return 流程视图对象,包含所有展示所需的信息
|
||||
*/
|
||||
@SneakyThrows
|
||||
private ProcessVO getProcessVO(String flowId) {
|
||||
/**
|
||||
* 获取流程视图对象
|
||||
* <p>
|
||||
* 内部方法,用于构建流程的视图对象。主要处理: - 解析流程节点结构 - 查找需要发起人选择的节点 - 处理序列号类型的表单字段,自动生成下一个序号 -
|
||||
* 提取起始节点的表单权限配置
|
||||
* </p>
|
||||
*
|
||||
* @param flowId 流程定义ID
|
||||
* @return 流程视图对象,包含所有展示所需的信息
|
||||
*/
|
||||
@SneakyThrows
|
||||
private ProcessVO getProcessVO(String flowId) {
|
||||
|
||||
Process oaForms = getByFlowId(flowId);
|
||||
String process = oaForms.getProcess();
|
||||
String formItems = oaForms.getFormItems();
|
||||
Node startNode = objectMapper.readValue(process, new TypeReference<>() {
|
||||
});
|
||||
Process oaForms = getByFlowId(flowId);
|
||||
String process = oaForms.getProcess();
|
||||
String formItems = oaForms.getFormItems();
|
||||
Node startNode = objectMapper.readValue(process, new TypeReference<>() {
|
||||
});
|
||||
|
||||
List<String> selectUserNodeId = NodeUtil.selectUserNodeId(startNode);
|
||||
List<String> selectUserNodeId = NodeUtil.selectUserNodeId(startNode);
|
||||
|
||||
ProcessVO processVO = BeanUtil.copyProperties(oaForms, ProcessVO.class);
|
||||
processVO.setSelectUserNodeId(selectUserNodeId);
|
||||
ProcessVO processVO = BeanUtil.copyProperties(oaForms, ProcessVO.class);
|
||||
processVO.setSelectUserNodeId(selectUserNodeId);
|
||||
|
||||
JSONArray formItemJsonArray = JSONUtil.parseArray(formItems);
|
||||
// 特殊字段复制
|
||||
for (Object object : formItemJsonArray) {
|
||||
if (object instanceof JSONObject) {
|
||||
JSONObject formVO = (JSONObject) object;
|
||||
JSONObject props = formVO.getJSONObject(FormItemVO.Fields.props);
|
||||
if (Objects.nonNull(props)
|
||||
&& FormTypeEnum.SEQUENCE.getType().equals(props.getStr(FormItemVO.Fields.type))) {
|
||||
String nextNo = flowSequence.nextNo();
|
||||
props.set(FormItemVO.Props.Fields.value, nextNo);
|
||||
formVO.set(FormItemVO.Props.Fields.value, nextNo);
|
||||
}
|
||||
}
|
||||
}
|
||||
JSONArray formItemJsonArray = JSONUtil.parseArray(formItems);
|
||||
// 特殊字段复制
|
||||
for (Object object : formItemJsonArray) {
|
||||
if (object instanceof JSONObject) {
|
||||
JSONObject formVO = (JSONObject) object;
|
||||
JSONObject props = formVO.getJSONObject(FormItemVO.Fields.props);
|
||||
if (Objects.nonNull(props)
|
||||
&& FormTypeEnum.SEQUENCE.getType().equals(props.getStr(FormItemVO.Fields.type))) {
|
||||
String nextNo = flowSequence.nextNo();
|
||||
props.set(FormItemVO.Props.Fields.value, nextNo);
|
||||
formVO.set(FormItemVO.Props.Fields.value, nextNo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processVO.setFormItems(formItemJsonArray.toStringPretty());
|
||||
processVO.setFormPerms(startNode.getFormPerms());
|
||||
return processVO;
|
||||
}
|
||||
processVO.setFormItems(formItemJsonArray.toStringPretty());
|
||||
processVO.setFormPerms(startNode.getFormPerms());
|
||||
return processVO;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据流程ID查询流程定义
|
||||
* <p>
|
||||
* 通过流程的唯一标识符查询流程定义实体。 注意:一个流程可能有多个版本,此方法返回当前有效版本。
|
||||
* </p>
|
||||
* @param flowId 流程定义ID
|
||||
* @return 流程定义实体,如果不存在返回null
|
||||
*/
|
||||
@Override
|
||||
public Process getByFlowId(String flowId) {
|
||||
return this.lambdaQuery().eq(Process::getFlowId, flowId).one();
|
||||
}
|
||||
/**
|
||||
* 根据流程ID查询流程定义
|
||||
* <p>
|
||||
* 通过流程的唯一标识符查询流程定义实体。 注意:一个流程可能有多个版本,此方法返回当前有效版本。
|
||||
* </p>
|
||||
*
|
||||
* @param flowId 流程定义ID
|
||||
* @return 流程定义实体,如果不存在返回null
|
||||
*/
|
||||
@Override
|
||||
public Process getByFlowId(String flowId) {
|
||||
return this.lambdaQuery().eq(Process::getFlowId, flowId).one();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据流程ID更新流程定义
|
||||
* <p>
|
||||
* 更新流程的配置信息,包括表单、节点、权限等。 更新不会影响已经运行的流程实例。
|
||||
* </p>
|
||||
* @param process 包含更新信息的流程实体
|
||||
*/
|
||||
@Override
|
||||
public void updateByFlowId(Process process) {
|
||||
this.lambdaUpdate().eq(Process::getFlowId, process.getFlowId()).update(process);
|
||||
}
|
||||
/**
|
||||
* 根据流程ID更新流程定义
|
||||
* <p>
|
||||
* 更新流程的配置信息,包括表单、节点、权限等。 更新不会影响已经运行的流程实例。
|
||||
* </p>
|
||||
*
|
||||
* @param process 包含更新信息的流程实体
|
||||
*/
|
||||
@Override
|
||||
public void updateByFlowId(Process process) {
|
||||
this.lambdaUpdate().eq(Process::getFlowId, process.getFlowId()).update(process);
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏流程定义
|
||||
* <p>
|
||||
* 将流程标记为隐藏状态,隐藏的流程: - 不在流程列表中显示 - 不能创建新的流程实例 - 已有的流程实例可以继续执行
|
||||
* </p>
|
||||
* @param flowId 要隐藏的流程ID
|
||||
*/
|
||||
@Override
|
||||
public void hide(String flowId) {
|
||||
this.lambdaUpdate()
|
||||
.set(Process::getHidden, YesNoEnum.YES.getCode())
|
||||
.eq(Process::getFlowId, flowId)
|
||||
.update(new Process());
|
||||
}
|
||||
/**
|
||||
* 隐藏流程定义
|
||||
* <p>
|
||||
* 将流程标记为隐藏状态,隐藏的流程: - 不在流程列表中显示 - 不能创建新的流程实例 - 已有的流程实例可以继续执行
|
||||
* </p>
|
||||
*
|
||||
* @param flowId 要隐藏的流程ID
|
||||
*/
|
||||
@Override
|
||||
public void hide(String flowId) {
|
||||
this.lambdaUpdate()
|
||||
.set(Process::getHidden, YesNoEnum.YES.getCode())
|
||||
.eq(Process::getFlowId, flowId)
|
||||
.update(new Process());
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建新的流程定义
|
||||
* <p>
|
||||
* 创建流程的完整流程: 1. 调用流程引擎创建BPMN模型 2. 如果是更新操作,隐藏旧版本 3. 保存流程定义到数据库 4. 设置流程发起人权限 5.
|
||||
* 生成流程使用范围描述
|
||||
* </p>
|
||||
* @param process 流程定义实体,包含流程的所有配置信息
|
||||
* @return 创建结果,成功返回流程ID,失败返回错误信息
|
||||
*/
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public R create(Process process) {
|
||||
String flowId;
|
||||
if (StrUtil.isNotBlank(process.getFlowId())) {
|
||||
flowId = process.getFlowId();
|
||||
}
|
||||
else {
|
||||
flowId = "P" + DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)
|
||||
+ RandomUtil.randomString(5).toUpperCase();
|
||||
}
|
||||
/**
|
||||
* 创建新的流程定义
|
||||
* <p>
|
||||
* 创建流程的完整流程: 1. 调用流程引擎创建BPMN模型 2. 如果是更新操作,隐藏旧版本 3. 保存流程定义到数据库 4. 设置流程发起人权限 5.
|
||||
* 生成流程使用范围描述
|
||||
* </p>
|
||||
*
|
||||
* @param process 流程定义实体,包含流程的所有配置信息
|
||||
* @return 创建结果,成功返回流程ID,失败返回错误信息
|
||||
*/
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public R create(Process process) {
|
||||
String flowId;
|
||||
if (StrUtil.isNotBlank(process.getFlowId())) {
|
||||
flowId = process.getFlowId();
|
||||
} else {
|
||||
flowId = "P" + DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN)
|
||||
+ RandomUtil.randomString(5).toUpperCase();
|
||||
}
|
||||
|
||||
BpmnModel bpmnModel = ModelUtil.buildBpmnModel(objectMapper.readValue(process.getProcess(), Node.class),
|
||||
process.getName(), flowId);
|
||||
{
|
||||
byte[] bpmnBytess = new BpmnXMLConverter().convertToXML(bpmnModel);
|
||||
String filename = "/tmp/flowable-deployment/" + flowId + ".bpmn20.xml";
|
||||
log.debug("部署时的模型文件:{}", filename);
|
||||
FileUtil.writeBytes(bpmnBytess, filename);
|
||||
}
|
||||
BpmnModel bpmnModel = ModelUtil.buildBpmnModel(objectMapper.readValue(process.getProcess(), Node.class),
|
||||
process.getName(), flowId);
|
||||
{
|
||||
byte[] bpmnBytess = new BpmnXMLConverter().convertToXML(bpmnModel);
|
||||
String filename = "/tmp/flowable-deployment/" + flowId + ".bpmn20.xml";
|
||||
log.debug("部署时的模型文件:{}", filename);
|
||||
FileUtil.writeBytes(bpmnBytess, filename);
|
||||
}
|
||||
|
||||
Process oldProcess = this.getByFlowId(flowId);
|
||||
Process oldProcess = this.getByFlowId(flowId);
|
||||
|
||||
Deployment deployment = repositoryService.createDeployment()
|
||||
.addBpmnModel(StrUtil.format("{}.bpmn20.xml", "pig"), bpmnModel)
|
||||
.tenantId(TenantContextHolder.getTenantId().toString())
|
||||
.deploy();
|
||||
Deployment deployment = repositoryService.createDeployment()
|
||||
.addBpmnModel(StrUtil.format("{}.bpmn20.xml", "pig"), bpmnModel)
|
||||
.tenantId(TenantContextHolder.getTenantId().toString())
|
||||
.deploy();
|
||||
|
||||
NodeUser nodeUser = objectMapper.readValue(process.getAdminList(), new TypeReference<List<NodeUser>>() {
|
||||
}).get(0);
|
||||
NodeUser nodeUser = objectMapper.readValue(process.getAdminList(), new TypeReference<List<NodeUser>>() {
|
||||
}).get(0);
|
||||
|
||||
// 更新流程
|
||||
if (StrUtil.isNotBlank(process.getFlowId()) && Objects.nonNull(oldProcess)) {
|
||||
this.hide(process.getFlowId());
|
||||
// 修改所有的管理员
|
||||
this.lambdaUpdate()
|
||||
.set(Process::getAdminId, nodeUser.getId())
|
||||
.eq(Process::getUniqueId, oldProcess.getUniqueId())
|
||||
.update(new Process());
|
||||
// 更新流程
|
||||
if (StrUtil.isNotBlank(process.getFlowId()) && Objects.nonNull(oldProcess)) {
|
||||
this.hide(process.getFlowId());
|
||||
// 修改所有的管理员
|
||||
this.lambdaUpdate()
|
||||
.set(Process::getAdminId, nodeUser.getId())
|
||||
.eq(Process::getUniqueId, oldProcess.getUniqueId())
|
||||
.update(new Process());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Node startNode = objectMapper.readValue(process.getProcess(), Node.class);
|
||||
Node startNode = objectMapper.readValue(process.getProcess(), Node.class);
|
||||
|
||||
List<NodeUser> nodeUserList = startNode.getNodeUserList();
|
||||
List<NodeUser> nodeUserList = startNode.getNodeUserList();
|
||||
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
if (CollUtil.isNotEmpty(nodeUserList)) {
|
||||
int index = 0;
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
if (CollUtil.isNotEmpty(nodeUserList)) {
|
||||
int index = 0;
|
||||
|
||||
for (NodeUser user : nodeUserList) {
|
||||
if (index > 0) {
|
||||
stringBuilder.append(",");
|
||||
}
|
||||
stringBuilder.append(user.getName());
|
||||
index++;
|
||||
if (index > 5) {
|
||||
break;
|
||||
}
|
||||
for (NodeUser user : nodeUserList) {
|
||||
if (index > 0) {
|
||||
stringBuilder.append(",");
|
||||
}
|
||||
stringBuilder.append(user.getName());
|
||||
index++;
|
||||
if (index > 5) {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Process p = new Process();
|
||||
}
|
||||
}
|
||||
Process p = new Process();
|
||||
|
||||
if (Objects.nonNull(oldProcess)) {
|
||||
p = oldProcess;
|
||||
}
|
||||
if (Objects.nonNull(oldProcess)) {
|
||||
p = oldProcess;
|
||||
}
|
||||
|
||||
p.setFlowId(flowId);
|
||||
p.setName(process.getName());
|
||||
p.setLogo(process.getLogo());
|
||||
p.setSettings(process.getSettings());
|
||||
p.setGroupId(process.getGroupId());
|
||||
p.setFormConfig(process.getFormConfig());
|
||||
p.setFormItems(process.getFormItems());
|
||||
p.setProcess(process.getProcess());
|
||||
p.setRemark(process.getRemark());
|
||||
p.setSort(0);
|
||||
p.setHidden("0");
|
||||
p.setStop("0");
|
||||
p.setAdminId(nodeUser.getId());
|
||||
p.setUniqueId(deployment.getId());
|
||||
p.setAdminList(process.getAdminList());
|
||||
p.setRangeShow(stringBuilder.toString());
|
||||
this.saveOrUpdate(p);
|
||||
p.setFlowId(flowId);
|
||||
p.setName(process.getName());
|
||||
p.setLogo(process.getLogo());
|
||||
p.setSettings(process.getSettings());
|
||||
p.setGroupId(process.getGroupId());
|
||||
p.setFormConfig(process.getFormConfig());
|
||||
p.setFormItems(process.getFormItems());
|
||||
p.setProcess(process.getProcess());
|
||||
p.setRemark(process.getRemark());
|
||||
p.setSort(0);
|
||||
p.setHidden("0");
|
||||
p.setStop("0");
|
||||
p.setAdminId(nodeUser.getId());
|
||||
p.setUniqueId(deployment.getId());
|
||||
p.setAdminList(process.getAdminList());
|
||||
p.setRangeShow(stringBuilder.toString());
|
||||
this.saveOrUpdate(p);
|
||||
|
||||
// 删除原有发起范围
|
||||
processStarterService
|
||||
.remove(Wrappers.<ProcessStarter>lambdaQuery().eq(ProcessStarter::getProcessId, p.getId()));
|
||||
for (NodeUser nodeUserDto : nodeUserList) {
|
||||
ProcessStarter processStarter = new ProcessStarter();
|
||||
processStarter.setProcessId(p.getId());
|
||||
processStarter.setTypeId(nodeUserDto.getId());
|
||||
processStarter.setType(nodeUserDto.getType());
|
||||
processStarterService.save(processStarter);
|
||||
}
|
||||
// 删除原有发起范围
|
||||
processStarterService.remove(Wrappers.<ProcessStarter>lambdaQuery().eq(ProcessStarter::getProcessId, p.getId()));
|
||||
|
||||
return R.ok();
|
||||
}
|
||||
if (Objects.isNull(nodeUserList)) {
|
||||
return R.ok();
|
||||
}
|
||||
for (NodeUser nodeUserDto : nodeUserList) {
|
||||
ProcessStarter processStarter = new ProcessStarter();
|
||||
processStarter.setProcessId(p.getId());
|
||||
processStarter.setTypeId(nodeUserDto.getId());
|
||||
processStarter.setType(nodeUserDto.getType());
|
||||
processStarterService.save(processStarter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新流程状态或分组
|
||||
* <p>
|
||||
* 支持三种操作类型: - stop:停用流程(设置stop=1) - delete:删除流程(逻辑删除,设置hidden=1) - 其他:启用流程(设置stop=0)
|
||||
* 同时支持修改流程所属分组
|
||||
* </p>
|
||||
* @param flowId 流程定义ID
|
||||
* @param type 操作类型:stop(停用)、delete(删除)、其他(启用)
|
||||
* @param groupId 流程分组ID,可选参数
|
||||
* @return 操作结果
|
||||
*/
|
||||
@Override
|
||||
public R update(String flowId, String type, Long groupId) {
|
||||
Process process = new Process();
|
||||
process.setFlowId(flowId);
|
||||
process.setStop("stop".equals(type) ? "1" : "0");
|
||||
process.setHidden("delete".equals(type) ? "1" : "0");
|
||||
process.setGroupId(groupId);
|
||||
this.updateByFlowId(process);
|
||||
return R.ok();
|
||||
}
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证流程ID是否已注册流程状态事件处理
|
||||
* <p>
|
||||
* 通过 Redis Set 查询 flowId 是否已被任意微服务模块注册,
|
||||
* 支持跨服务校验。
|
||||
* </p>
|
||||
*
|
||||
* @param flowId 流程定义ID
|
||||
* @return 验证结果:true表示存在,false表示不存在
|
||||
*/
|
||||
@Override
|
||||
public R<Boolean> validateFlowId(String flowId) {
|
||||
if (StrUtil.isBlank(flowId)) {
|
||||
return R.ok(false);
|
||||
}
|
||||
return R.ok(flowStatusEventPublisher.isFlowIdRegistered(flowId));
|
||||
}
|
||||
/**
|
||||
* 更新流程状态或分组
|
||||
* <p>
|
||||
* 支持三种操作类型: - stop:停用流程(设置stop=1) - delete:删除流程(逻辑删除,设置hidden=1) - 其他:启用流程(设置stop=0)
|
||||
* 同时支持修改流程所属分组
|
||||
* </p>
|
||||
*
|
||||
* @param flowId 流程定义ID
|
||||
* @param type 操作类型:stop(停用)、delete(删除)、其他(启用)
|
||||
* @param groupId 流程分组ID,可选参数
|
||||
* @return 操作结果
|
||||
*/
|
||||
@Override
|
||||
public R update(String flowId, String type, Long groupId) {
|
||||
Process process = new Process();
|
||||
process.setFlowId(flowId);
|
||||
process.setStop("stop".equals(type) ? "1" : "0");
|
||||
process.setHidden("delete".equals(type) ? "1" : "0");
|
||||
process.setGroupId(groupId);
|
||||
this.updateByFlowId(process);
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证流程ID是否已注册流程状态事件处理
|
||||
* <p>
|
||||
* 通过 Redis Set 查询 flowId 是否已被任意微服务模块注册,
|
||||
* 支持跨服务校验。
|
||||
* </p>
|
||||
*
|
||||
* @param flowId 流程定义ID
|
||||
* @return 验证结果:true表示存在,false表示不存在
|
||||
*/
|
||||
@Override
|
||||
public R<Boolean> validateFlowId(String flowId) {
|
||||
if (StrUtil.isBlank(flowId)) {
|
||||
return R.ok(false);
|
||||
}
|
||||
return R.ok(flowStatusEventPublisher.isFlowIdRegistered(flowId));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user