1. 前言
上一篇博客【SpringBoot整合Flowable工作流-1(画流程定义) 】介绍用 Flowable-ui 画了一个简单的流程图。
这篇博客将介绍代码整合部分,主要内容有:【发布流程定义】、【开启流程任务】、【获取用户任务】、【用户审批任务】、【添加审批意见】、【获取流程图】、【获取我的待办任务】、【获取我发起的流程】、【我审批过的流程】...
2. 代码添加依赖
org.flowable
flowable-spring-boot-starter
6.4.2
3. 创建数据库
创建数据库可以使用通过 Flowable 提供的 sql 实现,也可以通过程序自动创建数据库实现
3.1 Flowable 提供的 sql
下载文件 Flowable 相关的资源,进入 https://flowable.com/open-source/downloads,然后点击 【Download Flowable v6.x.x】,下载下来是一个压缩包,解压后会看到如下目录结构
└─database # 数据库文件
└─create
└─all
└─flowable.mysql.all.create.sql
找到 $/database/create/database/create/flowable.mysql.all.create.sql 文件,导入mysql数据库即可
3.2 应用程序自动创建数据库(推荐)
需要在 jdbc 的 url 中添加一个参数值,nullCatalogMeansCurrent=true
如下:
jdbc:mysql://127.0.0.1:3306/flowable?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false&nullCatalogMeansCurrent=true
4. 代码部分
4.1 常用的几个Service类
/** 运行时Service(用于运行时流程实例、流程变量、流程节点) */
@Autowired
private RuntimeService runtimeService;
/** 资源存储Service(用于模型、流程定义) */
@Autowired
private RepositoryService repositoryService;
/** 流程引擎Service */
@Qualifier("processEngine")
@Autowired
private ProcessEngine processEngine;
/** 任务Service(用于运行时的用户任务、审批日志) */
@Autowired
private TaskService taskService;
@Autowired
protected ManagementService managementService;
/** 历史Service(用于历史记录,可以找到历史的流程实例、流程节点) */
@Autowired
protected HistoryService historyService;
4.2 流程定义相关代码
4.2.1 发布流程定义
上一篇博客【SpringBoot整合Flowable工作流-1(画流程定义) 】画好了流程,然后下载下来是一个 “请假流程1.bpmn20.xml” 的xml文件,下载就可以通过代码把这个流程发布到流程定义中了。
代码如下
@Override
public boolean importProcessDefinition(MultipartFile file) {
try {
Deployment deployment = repositoryService.createDeployment()
// .key()
// .name(name)
// .category(category)
// .tenantId()
// 通过压缩包的形式一次行多个发布
// .addZipInputStream()
// 通过InputStream的形式发布
.addInputStream(file.getOriginalFilename(), file.getInputStream())
// 通过存放在classpath目录下的文件进行发布
// .addClasspathResource("p1.bpmn20.xml")
// 通过xml字符串的形式
// .addString()
.deploy();
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).singleResult();
if (processDefinition == null) {
return false;
}
} catch (Exception e) {
throw new BusinessException("导入流程定义失败:" + e.getMessage());
}
return true;
}
基于 SpringBoot 发布流程定义,还有一种巧妙的形式,那就是在 resources 目录下建立一个文件夹 processes ,然后把对应的流程文件发到这个文件夹下即可,启动 SpringBoot 项目的时候,通过观察日志就会发现该流程就自动发布了。(不推荐)
workflow-server
└─src
└─main
├─java
└─resources
├─mapper
└─processes
└─请假流程1.bpmn20.xml
4.2.2 查询流程定义
// 创建 ProcessDefinitionQuery
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
// 根据流程定义ID
// processDefinitionQuery.processDefinitionId(requestDTO.getId());
// 根据流程定义Key
// processDefinitionQuery.processDefinitionKeyLike("%" + requestDTO.getKey().trim() + "%");
// 根据流程定义名称
// processDefinitionQuery.processDefinitionNameLike("%" + requestDTO.getName().trim() + "%");
//
// 获取总数
long count = processDefinitionQuery.count();
// 获取单个
ProcessDefinition processDefinition = processDefinitionQuery.singleResult();
// 获取列表
List processDefinitions = processDefinitionQuery.list();
// 获取分页
List processDefinitions = processDefinitionQuery.listPage(0, 10)
4.2.3 获取流程定义xml
public String getXmlResource(String id) {
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(id).singleResult();
InputStream inputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(),
processDefinition.getResourceName());
try {
return IOUtils.toString(inputStream, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new BusinessException("获取资源失败:" + e.getMessage());
} finally {
try {
IOUtils.close(inputStream, null);
} catch (IOException ignored) {
}
}
}
4.2.4 获取流程定义图片
public String getDiagramImageResource(String id) {
// 理论上我用这种形式也是行的,但是我获取出来会有乱码,我也比较奇怪,所以换了通过 bpmnModel 的方式
// ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(id).singleResult();
// InputStream inputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(),
// processDefinition.getDiagramResourceName());
// 获取bpmnModel对象
BpmnModel bpmnModel = repositoryService.getBpmnModel(id);
// 生成图片流
ProcessEngineConfiguration configuration = processEngine.getProcessEngineConfiguration();
ProcessDiagramGenerator diagramGenerator = configuration.getProcessDiagramGenerator();
InputStream inputStream = diagramGenerator.generateDiagram(bpmnModel, "png", Collections.emptyList(),
Collections.emptyList(), "宋体", "宋体", "宋体",
this.getClass().getClassLoader(), 1.0, true);
try {
return "data:image/png;base64," + Base64.encode(inputStream);
} catch (Exception e) {
throw new BusinessException("获取资源失败:" + e.getMessage());
} finally {
try {
IOUtils.close(inputStream, null);
} catch (IOException ignored) {
}
}
}
4.2.5 删除流程定义
public void deleteByIds(List ids) {
List processDefinitions = repositoryService.createProcessDefinitionQuery().processDefinitionIds(new HashSet<>(ids)).list();
// repositoryService.deleteDeployment(String deploymentId, boolean cascade)
// 删除给定的部署和级联删除流程实例、历史流程实例和作业。
processDefinitions.forEach(v -> repositoryService.deleteDeployment(v.getDeploymentId(), true));
}
4.3 流程实例相关代码
4.3.1 添加流程实例审批意见
起到类似于记录流程的操作记录的作用,我这里是自己封装了一层,我封装了自己的业务用户ID、用户名、执行类型、意见内容...
@Data
@ApiModel("流程实例-审批意见请求参数")
public class ProcessInstanceCommentRequestDTO implements Serializable {
@ApiModelProperty(value = "流程定义Key")
private String processInstanceId;
@ApiModelProperty(value = "任务ID(缺省)")
private String taskId;
@ApiModelProperty(value = "类型 CommentEntity: event/comment")
private String type;
@ApiModelProperty(value = "用户ID")
private String userId;
@ApiModelProperty(value = "用户昵称")
private String nickname;
@ApiModelProperty(value = "执行类型")
private String executeType;
@ApiModelProperty(value = "执行类型(参考ExecuteTypeEnum)SUBMIT-提交;YES-同意;NO-拒绝;STOP-流程终止;DELETE-流程删除")
private String executeTypeValue;
@ApiModelProperty(value = "内容")
private String content;
@ApiModelProperty(value = "额外携带的内容")
private String ext;
}
添加流程实例审批意见
// 添加流程实例审批记录
public void addProcessInstanceComment(ProcessInstanceCommentRequestDTO requestDTO) {
CommentWrapper wrapper = new CommentWrapper();
wrapper.setUserId(requestDTO.getUserId());
wrapper.setNickname(requestDTO.getNickname());
wrapper.setExecuteType(requestDTO.getExecuteType());
wrapper.setExecuteTypeValue(requestDTO.getExecuteTypeValue());
wrapper.setContent(requestDTO.getContent());
wrapper.setExt(requestDTO.getExt());
String message = JSON.toJSONString(wrapper);
// 使用 taskService 添加一条审批意见
taskService.addComment(requestDTO.getTaskId(), requestDTO.getProcessInstanceId(), requestDTO.getType(), message);
}
4.3.2 启动流程实例
@Data
@ApiModel("流程实例-启动请求参数")
public class ProcessInstanceStartRequestDTO implements Serializable {
@ApiModelProperty(value = "流程定义Key")
@NotEmpty(message = "流程定义Key 不可以为空")
private String processDefinitionKey;
@ApiModelProperty(value = "流程实例名称")
@NotEmpty(message = "流程实例名称 不可以为空")
private String name;
@ApiModelProperty(value = "项目ID")
@NotEmpty(message = "项目ID 不可以为空")
private String communityId;
@ApiModelProperty(value = "全局变量")
private Map variables;
}
启动流程实例
@Transactional(rollbackFor = Exception.class)
public ProcessInstanceStartResponseDTO startProcessInstance(ProcessInstanceStartRequestDTO requestDTO) {
ValidatorUtils.validate(requestDTO);
//
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
processDefinitionQuery.processDefinitionKey(requestDTO.getProcessDefinitionKey());
ProcessDefinition processDefinition = processDefinitionQuery.latestVersion().singleResult();
AssertUtils.notEmpty(processDefinition, "找不到流程定义");
// 启动流程
ProcessInstanceBuilder builder = runtimeService.createProcessInstanceBuilder();
builder.processDefinitionKey(requestDTO.getProcessDefinitionKey());
builder.name(requestDTO.getName());
// variables("name", "value")
// 可以添加流程过程的变量,比如这里我添加了我不少业务变量进来,方面流程流转的时候处理业务
builder.variables(requestDTO.getVariables());
builder.variable(VAR_COMMUNITY_ID, VAR_COMMUNITY_ID_EQ + requestDTO.getCommunityId());
builder.variable(VAR_PROCESS_INSTANCE_NAME, VAR_PROCESS_INSTANCE_NAME_EQ + requestDTO.getName());
builder.variable(VAR_CREATE_USER_ID, VAR_CREATE_USER_ID_EQ + SecurityUser.getUserId());
builder.variable(VAR_CREATE_USER_NICKNAME, VAR_CREATE_USER_NICKNAME_EQ + SecurityUser.get().getName());
builder.variable(VAR_PROCESS_DEFINITION_NAME, VAR_PROCESS_DEFINITION_NAME_EQ + processDefinition.getName());
builder.transientVariables(requestDTO.getTransientVariables());
// builder.tenantId("101");
ProcessInstance processInstance = builder.start();
// 添加审批意见
ProcessInstanceCommentRequestDTO commentRequestDTO = new ProcessInstanceCommentRequestDTO();
commentRequestDTO.setProcessInstanceId(processInstance.getProcessInstanceId());
commentRequestDTO.setTaskId(null);
commentRequestDTO.setUserId(SecurityUser.getUserId());
commentRequestDTO.setNickname(SecurityUser.get().getName());
commentRequestDTO.setExecuteType(ExecuteTypeEnum.SUBMIT.name());
commentRequestDTO.setExecuteTypeValue(ExecuteTypeEnum.SUBMIT.getValue());
commentRequestDTO.setContent(requestDTO.getName() + " 提交流程");
commentRequestDTO.setExt("");
this.addProcessInstanceComment(commentRequestDTO);
// 构建 ResponseDTO
ProcessInstanceStartResponseDTO responseDTO = new ProcessInstanceStartResponseDTO();
responseDTO.setProcessInstanceId(processInstance.getProcessInstanceId());
responseDTO.setProcessDefinitionId(processInstance.getProcessDefinitionId());
responseDTO.setProcessDefinitionKey(processInstance.getProcessDefinitionKey());
responseDTO.setProcessDefinitionName(processInstance.getProcessDefinitionName());
responseDTO.setName(processInstance.getName());
responseDTO.setBusinessKey(processInstance.getBusinessKey());
responseDTO.setDescription(processInstance.getDescription());
//
return responseDTO;
}
4.3.3 获取流程进度图片
public String getProcessImage(String processInstanceId) {
// 1.获取当前的流程实例
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
String processDefinitionId;
List activeActivityIds = new ArrayList<>();
List highLightedFlows = new ArrayList<>();
// 2.获取所有的历史轨迹线对象
List historicActivityInstances = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId).activityType(BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW).list();
historicActivityInstances.forEach(historicActivityInstance -> highLightedFlows.add(historicActivityInstance.getActivityId()));
// 3. 获取流程定义id和高亮的节点id
if (processInstance != null) {
// 3.1 正在运行的流程实例
processDefinitionId = processInstance.getProcessDefinitionId();
activeActivityIds = runtimeService.getActiveActivityIds(processInstanceId);
} else {
// 3.2 已经结束的流程实例
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
.processInstanceId(processInstanceId).singleResult();
processDefinitionId = historicProcessInstance.getProcessDefinitionId();
// 3.3 获取结束节点列表
List historicEnds = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId).activityType(BpmnXMLConstants.ELEMENT_EVENT_END).list();
List finalActiveActivityIds = activeActivityIds;
historicEnds.forEach(historicActivityInstance -> finalActiveActivityIds.add(historicActivityInstance.getActivityId()));
}
// 4. 获取bpmnModel对象
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
// 5. 生成图片流
ProcessEngineConfiguration configuration = processEngine.getProcessEngineConfiguration();
ProcessDiagramGenerator diagramGenerator = configuration.getProcessDiagramGenerator();
InputStream inputStream = diagramGenerator.generateDiagram(bpmnModel, "png", activeActivityIds,
highLightedFlows, "宋体", "宋体", "宋体",
this.getClass().getClassLoader(), 1.0, true);
// 6. 转化成Base64网络传输
return "data:image/png;base64," + Base64.encode(inputStream);
}
4.3.4 获取流程审批意见
@Override
public List findProcessInstanceCommentList(String processInstanceId) {
List processInstanceComments = taskService.getProcessInstanceComments(processInstanceId);
List list = processInstanceComments.stream()
.map(this::convertComment)
.filter(Objects::nonNull).collect(Collectors.toList());
return list;
}
private ProcessInstanceCommentResponseDTO convertComment(Comment v) {
String fullMessage = v.getFullMessage();
if (StringUtils.startsWith(fullMessage, "{")) {
CommentWrapper wrapper = JSON.parseObject(fullMessage, CommentWrapper.class);
ProcessInstanceCommentResponseDTO responseDTO = new ProcessInstanceCommentResponseDTO();
responseDTO.setProcessInstanceId(v.getProcessInstanceId());
responseDTO.setType(v.getType());
responseDTO.setTaskId(v.getTaskId());
responseDTO.setTime(v.getTime());
responseDTO.setUserId(wrapper.getUserId());
responseDTO.setNickname(wrapper.getNickname());
responseDTO.setExecuteType(wrapper.getExecuteType());
responseDTO.setExecuteTypeValue(wrapper.getExecuteTypeValue());
responseDTO.setContent(wrapper.getContent());
responseDTO.setExt(wrapper.getExt());
return responseDTO;
}
return null;
}
4.3.5 流程实例执行下一步
@Data
@ApiModel("流程实例-执行下一步请求参数")
public class ProcessInstanceExecuteNextStepRequestDTO implements Serializable {
@ApiModelProperty(value = "流程实例ID")
@NotEmpty(message = "流程实例ID 不可以为空")
private String processInstanceId;
@ApiModelProperty(value = "任务ID")
private String taskId;
@ApiModelProperty(value = "ExecuteTypeEnum 执行类型")
@NotEmpty(message = "执行类型 不可以为空")
private String executeType;
@ApiModelProperty(value = "审批意见")
@NotEmpty(message = "审批意见 不可以为空")
private String commentContent;
@ApiModelProperty(value = "变量参数")
private HashMap variables;
}
@Transactional(rollbackFor = Exception.class)
public void executeNextStep(ProcessInstanceExecuteNextStepRequestDTO requestDTO) {
ValidatorUtils.validate(requestDTO);
//
if (ExecuteTypeEnum.of(requestDTO.getExecuteType()).isNone()) {
throw new BusinessException("未知执行状态");
}
TaskQuery taskQuery = taskService.createTaskQuery();
taskQuery.taskId(requestDTO.getTaskId());
Task task = taskQuery.singleResult();
AssertUtils.notEmpty(task, "找不到任务");
//
// 添加审批意见
ProcessInstanceCommentRequestDTO commentRequestDTO = new ProcessInstanceCommentRequestDTO();
commentRequestDTO.setProcessInstanceId(task.getProcessInstanceId());
commentRequestDTO.setTaskId(task.getId());
// commentRequestDTO.setType("event");
commentRequestDTO.setUserId(SecurityUser.getUserId());
commentRequestDTO.setNickname(SecurityUser.get().getName());
commentRequestDTO.setExecuteType(requestDTO.getExecuteType());
commentRequestDTO.setExecuteTypeValue(ExecuteTypeEnum.of(requestDTO.getExecuteType()).getValue());
commentRequestDTO.setContent(task.getName() + ":" + requestDTO.getCommentContent());
commentRequestDTO.setExt("");
//
this.addProcessInstanceComment(commentRequestDTO);
// 处理流程审批
HashMap variables = requestDTO.getVariables();
if (variables == null) {
variables = new HashMap<>(8);
}
// 这里会put一个执行变量executeType,也就是流程定义xml中的那个变量名称,这个变量决定了流程再走向
variables.put(WorkflowConstants.EXECUTE_TYPE, requestDTO.getExecuteType());
// 添加执行人
variables.put("_execute_user_id=" + SecurityUser.getUserId(), "_execute_user_id=" + SecurityUser.getUserId());
taskService.complete(task.getId(), variables);
}
4.3.6 终止流程实例
@Data
@ApiModel("流程实例-分页请求参数")
public class ProcessInstanceStopRequestDTO implements Serializable {
@ApiModelProperty(value = "流程实例ID")
@NotEmpty(message = "流程实例ID 不可以为空")
private String processInstanceId;
@ApiModelProperty(value = "审批意见")
@NotEmpty(message = "审批意见 不可以为空")
private String commentContent;
}
public void stopProcessInstance(ProcessInstanceStopRequestDTO requestDTO) {
ValidatorUtils.validate(requestDTO);
// 修改流转执行状态
runtimeService.setVariable(requestDTO.getProcessInstanceId(), WorkflowConstants.EXECUTE_TYPE, ExecuteTypeEnum.STOP.name());
//
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId(requestDTO.getProcessInstanceId()).singleResult();
// 添加一条审批记录
ProcessInstanceCommentRequestDTO commentRequestDTO = new ProcessInstanceCommentRequestDTO();
commentRequestDTO.setProcessInstanceId(processInstance.getProcessInstanceId());
commentRequestDTO.setTaskId(null);
commentRequestDTO.setUserId(SecurityUser.getUserId());
commentRequestDTO.setNickname(SecurityUser.get().getName());
commentRequestDTO.setExecuteType(ExecuteTypeEnum.STOP.name());
commentRequestDTO.setExecuteTypeValue(ExecuteTypeEnum.STOP.getValue());
commentRequestDTO.setContent(StringUtils.defaultString(requestDTO.getCommentContent(), "终止流程"));
commentRequestDTO.setExt("");
this.addProcessInstanceComment(commentRequestDTO);
/// 执行终止
List executions = runtimeService.createExecutionQuery().parentId(requestDTO.getProcessInstanceId()).list();
List executionIds = executions.stream().map(v -> v.getId()).collect(Collectors.toList());
// 获取流程结束点
BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
Process process = bpmnModel.getMainProcess();
List endNodes = process.findFlowElementsOfType(EndEvent.class);
String endId = endNodes.get(endNodes.size() - 1).getId();
// 执行跳转
runtimeService.createChangeActivityStateBuilder()
.moveExecutionsToSingleActivityId(executionIds, endId)
.changeState();
}
4.3.7 批量获取流程实例变量列表
这个方法是自定义实现的,因为 Flowable 没有对应的根据流程实例ID列表获取批量的流程变量
/**
* 实例映射 Flowable 的 act_hi_varinst 表
*/
@Data
public class HistoryVariable implements Serializable {
public static final HistoryVariable EMPTY = new HistoryVariable();
private String id;
private String rev;
private String processInstanceId;
private String executionId;
private String taskId;
private String name;
private String varType;
private String scopeId;
private String subScopeId;
private String scopeType;
private String bytearrayId;
private Double doubleValue;
private Long longValue;
private String text;
private String text2;
private Date createTime;
private Date lastUpdatedTime;
/*
act_hi_varinst 字段列表:
ID_
REV_
PROC_INST_ID_
EXECUTION_ID_
TASK_ID_
NAME_
VAR_TYPE_
SCOPE_ID_
SUB_SCOPE_ID_
SCOPE_TYPE_
BYTEARRAY_ID_
DOUBLE_
LONG_
TEXT_
TEXT2_
CREATE_TIME_
LAST_UPDATED_TIME_
*/
}
Service
@Override
public List findHistoryVariableList(Collection processInstanceIds) {
if (CollectionUtils.isEmpty(processInstanceIds)) {
return Collections.emptyList();
}
QueryWrapper ew = new QueryWrapper<>();
ew.in("t.PROC_INST_ID_", processInstanceIds);
return this.baseMapper.findHistoryVariableList(ew);
}
Dao
List findHistoryVariableList(@Param("ew") QueryWrapper ew);
xml
4.3.8 获取流程实例分页
获取流程实例分页,因为这里涉及到
数据权限过滤
、以及待办
、已办
、历史记录
、我发起
等等,逻辑还是挺复杂的,因此简单通过Flowable的API可能不是一个很好的选择了,因此这里自定义实现,通过查找Flowable相关的数据库表找出符合记录
1.如果流程实例还在进行中数据是保存在
act_ru_*
这几张表中,如果流程实例结束了数据是保存在act_hi_*
这几张表中,因此查询的时候需要根据不用场景查询不用的表;
2.流程定义图中定义的分配的用户组,保存在act_ru_identitylink
表中;
流程实例-分页请求参数
@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel("流程实例-分页请求参数")
public class ProcessInstancePageRequestDTO extends PageParamsEntity {
@ApiModelProperty(value = "项目ID")
private String communityId;
@ApiModelProperty(value = "查找范围:MY_TODO-我的待办;MY_DONE-我的已办;MY_SCOPE-我的范围;MY_CREATE-我的创建;")
private String searchScope;
@ApiModelProperty(value = "任务名称")
private String processInstanceName;
}
流程定义-分页响应结果
@Data
@ApiModel("流程定义-分页响应结果")
public class ProcessInstancePageResponseDTO implements Serializable {
@ApiModelProperty(value = "项目ID")
private String communityId;
@ApiModelProperty(value = "项目名称")
private String communityName;
@ApiModelProperty(value = "流程实例ID")
private String processInstanceId;
@ApiModelProperty(value = "流程实例名称")
private String processInstanceName;
@ApiModelProperty(value = "流程定义ID")
private String processDefinitionId;
@ApiModelProperty(value = "流程定义名称")
private String processDefinitionName;
@ApiModelProperty(value = "任务ID")
private String taskId;
@ApiModelProperty(value = "任务名称")
private String taskName;
@ApiModelProperty(value = "开始时间")
private Date startTime;
@ApiModelProperty(value = "结束时间")
private Date endTime;
@ApiModelProperty(value = "持续时间")
private String duration;
@ApiModelProperty(value = "创建人ID")
private String createId;
@ApiModelProperty(value = "创建人名称")
private String createName;
}
Service
public PageDTO findPage(ProcessInstancePageRequestDTO requestDTO) {
// 在这里实现数据过滤
String filterSql = StringUtils.defaultString(processFilterSQL("TEXT_", requestDTO.getCommunityId(), true), "");
filterSql = filterSql.replace("('", "('" + WorkflowConstants.VAR_COMMUNITY_ID_EQ);
filterSql = filterSql.replace(", '", ", '" + WorkflowConstants.VAR_COMMUNITY_ID_EQ);
// TEXT_ IN ('_community_id=1545645315843546', '_community_id=15456453158436521')
// System.out.println("filterSQL = " + filterSQL);
//
PageDTO page = this.buildPage(requestDTO);
if ("MY_TODO".equals(requestDTO.getSearchScope())) {
// 我的待办
QueryWrapper ew = buildEmptyQueryWrapper();
ew.like(StringUtils.isNotEmpty(requestDTO.getProcessInstanceName()), "t4.NAME_", requestDTO.getProcessInstanceName());
ew.eq("1", 1);
ew.apply(CoreUtil.isNotEmpty(filterSql), "t3." + filterSql);
ew.orderByDesc("t.CREATE_TIME_");
ew.groupBy("t.PROC_INST_ID_");
//
if (!AuthHelper.isRoleSuperAdmin(SecurityUser.current().getRoleCodeSet())) {
// 不是超级管理员,需要过滤
ew.and(and -> and.in("t2.GROUP_ID_", SecurityUser.current().getRoleCodeSet()).or(or -> {
or.eq("t2.USER_ID_", SecurityUser.getUserId());
}));
}
page = this.baseMapper.findMyTodo(page, ew);
} else if ("MY_DONE".equals(requestDTO.getSearchScope())) {
// 我的已办
QueryWrapper ew = buildEmptyQueryWrapper();
ew.like(StringUtils.isNotEmpty(requestDTO.getProcessInstanceName()), "t.NAME_", requestDTO.getProcessInstanceName());
ew.eq("t2.TEXT_", "_execute_user_id=" + SecurityUser.getUserId());
ew.apply(filterSql.length() > 0, "t3." + filterSql);
ew.orderByDesc("t.START_TIME_");
ew.groupBy("t.ID_");
//
page = this.baseMapper.findMyDonePage(page, ew);
} else if ("MY_SCOPE".equals(requestDTO.getSearchScope())) {
// 我的范围
QueryWrapper ew = buildEmptyQueryWrapper();
ew.like(StringUtils.isNotEmpty(requestDTO.getProcessInstanceName()), "t.NAME_", requestDTO.getProcessInstanceName());
ew.eq("1", 1);
ew.apply(filterSql.length() > 0, "t4." + filterSql);
ew.orderByDesc("t.START_TIME_");
ew.groupBy("t.ID_");
//
if (!AuthHelper.isRoleSuperAdmin(SecurityUser.current().getRoleCodeSet())) {
// 不是超级管理员,需要过滤
ew.and(and -> and.in("t3.GROUP_ID_", SecurityUser.current().getRoleCodeSet()).or(or -> {
or.eq("t3.USER_ID_", SecurityUser.getUserId());
}));
}
page = this.baseMapper.findMyScopePage(page, ew);
} else if ("MY_CREATE".equals(requestDTO.getSearchScope())) {
// 我发起的
QueryWrapper ew = buildEmptyQueryWrapper();
ew.like(StringUtils.isNotEmpty(requestDTO.getProcessInstanceName()), "t.NAME_", requestDTO.getProcessInstanceName());
ew.eq("t2.TEXT_", "_create_user_id=" + SecurityUser.getUserId());
ew.apply(filterSql.length() > 0, "t3." + filterSql);
ew.orderByDesc("t.START_TIME_");
ew.groupBy("t.ID_");
//
page = this.baseMapper.findMyDonePage(page, ew);
}
//
if (CollectionUtils.isNotEmpty(page.getRecords())) {
// 填充其他属性
List processInstanceIds = page.getRecords().stream().map(v -> v.getProcessInstanceId()).distinct().collect(Collectors.toList());
List variableList = this.findHistoryVariableList(processInstanceIds);
Map variableMap = variableList.stream()
.collect(Collectors.toMap(v -> v.getProcessInstanceId() + "_" + v.getName(), v -> v));
page.getRecords().forEach(v -> {
String prefix = v.getProcessInstanceId() + "_";
//
HistoryVariable variable = variableMap.getOrDefault(prefix + VAR_COMMUNITY_ID, HistoryVariable.EMPTY);
String text = Optional.ofNullable(variable.getText()).map(t -> t.replace(VAR_COMMUNITY_ID_EQ, "")).orElse(null);
v.setCommunityId(text);
//
// variable = variableMap.getOrDefault(prefix + VAR_PROCESS_INSTANCE_NAME, HistoryVariable.EMPTY);
// text = Optional.ofNullable(variable.getText()).map(t -> t.replace(VAR_PROCESS_INSTANCE_NAME_EQ, "")).orElse(null);
// v.setProcessInstanceName(text);
//
variable = variableMap.getOrDefault(prefix + VAR_CREATE_USER_ID, HistoryVariable.EMPTY);
text = Optional.ofNullable(variable.getText()).map(t -> t.replace(VAR_CREATE_USER_ID_EQ, "")).orElse(null);
v.setCreateId(text);
//
variable = variableMap.getOrDefault(prefix + VAR_CREATE_USER_NICKNAME, HistoryVariable.EMPTY);
text = Optional.ofNullable(variable.getText()).map(t -> t.replace(VAR_CREATE_USER_NICKNAME_EQ, "")).orElse(null);
v.setCreateName(text);
//
variable = variableMap.getOrDefault(prefix + VAR_PROCESS_DEFINITION_NAME, HistoryVariable.EMPTY);
text = Optional.ofNullable(variable.getText()).map(t -> t.replace(VAR_PROCESS_DEFINITION_NAME_EQ, "")).orElse(null);
v.setProcessDefinitionName(text);
});
sysOrganizationRemote.fillOrganization(page.getRecords(), v -> v.getCommunityId(), (v, c) -> v.setCommunityName(c.getName()));
}
return page;
}
Dao
/**
* 获取我的待办任务
*
* @author houyu [email protected]
* @param page 分页
* @param ew 参数包装器
* @return PageDTO
*/
PageDTO findMyTodo(@Param("page") PageDTO page, @Param("ew") QueryWrapper ew);
/**
* 获取我的范围内的任务
*
* @author houyu [email protected]
* @param page 分页
* @param ew 参数包装器
* @return PageDTO
*/
PageDTO findMyScopePage(@Param("page") PageDTO page, @Param("ew") QueryWrapper ew);
/**
* 获取我的已办(我的发起 / 我审批的)
*
* @author houyu [email protected]
* @param page 分页
* @param ew 参数包装器
* @return PageDTO
*/
PageDTO findMyDonePage(@Param("page") PageDTO page, @Param("ew") QueryWrapper ew);
Xml
5. Linux部署流程图文字乱码
简单描述一下我遇到的情况,我当时是在Windows上开发的,设置流程图的字体为宋体,没有出现乱码的情况,但是我部署到Linux服务器上查看流程图的时候文字出现了乱码,然后我大概能猜到是因为缺少字体的问题(因为之前有了解过activiti流程图乱码是缺少字体的问题),所以我这次也是按照相同套路给Linux添加宋体字体就解决了。
5.1 复制Windows上的字体
进入目录:C:\Windows\Fonts 复制 “宋体 常规”到桌面上备用
5.2 Linux找出 java 位置
执行命令
whereis java
我的是在 /var/lib/jdk/jdk1.8.0_211/bin/java
5.3 复制字体文件到 jre/lib/fonts
找出了java的位置,jre 的位置在 java 的前几级目录下
java:
/var/lib/jdk/jdk1.8.0_211/bin/java
jre 字体目录(复制到这里):
/var/lib/jdk/jdk1.8.0_211/jre/lib/fonts
5.4 复制字体文件到系统字体目录中(/usr/share/fonts)
这个目录可能不存在,如果不存在则自己创建出来
/usr/share/fonts
5.5 重启系统
reboot
重启系统之后,启动应用程序,即不会出现乱码的情况了,祝你好运~
上一篇博客:SpringBoot整合Flowable工作流-1(画流程定义)
基于 flowable-spring-boot-starter 整合的代码基本完成,但是感觉还是少了一点东西,流程一步一步执行下去了,什么时候执行完?现在到什么环节了?貌似我们都不太清楚,执行完了业务要怎么操作,这就要介绍一下 flowable 全局事件监听器了,下一篇博客将介绍 flowable 全局事件监听器,结合监听器实现业务的通知业务。
- 公众号:IT加载中(it_loading)
- CSDN:https://blog.csdn.net/JinglongSource
- 博客:https://ihouyu.cn/
- 邮箱:[email protected]