
1. Preface
Last blog【Springboot integrates flowable workflow-1 (drawing process definition)】This paper draws a simple flow chart with flowable UI.
This blog will introduce the code integration part, which mainly includes: [publish process definition], [open process task], [get user task], [user approval task], [add approval opinion], [get flow chart], [get my to-do task], [get my initiated process], [my approved process]
2. Add code dependency
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>6.4.2</version>
</dependency>
3. Create database
Creating a database can be realized by using SQL provided by flowable, or by automatically creating a database through a program
3.1 SQL provided by flowable
Download the resources related to the file flowable and enterhttps://flowable.com/open-source/downloadsClick [download flowable V6. X.x] to download a compressed package. After decompression, you will see the following directory structure
└ - database # database file
└─create
└─all
└─flowable.mysql.all.create.sql
Find $/ database / create / database / create / flowable mysql. all. create. SQL file and import it into MySQL database
3.2 automatic database creation by application (recommended)
You need to add a parameter value in the JDBC URL, nullcatalogmeanscurrent = true
As follows:
jdbc:mysql://127.0.0.1:3306/flowable?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false&nullCatalogMeansCurrent=true
4. Code part
4.1 several common service classes
/**Runtime service (used for runtime process instances, process variables, process nodes)*/
@Autowired
private RuntimeService runtimeService;
/**Resource storage service (for model and process definition)*/
@Autowired
private RepositoryService repositoryService;
/**Process engine service*/
@Qualifier("processEngine")
@Autowired
private ProcessEngine processEngine;
/**Task service (used for user tasks and approval logs at runtime)*/
@Autowired
private TaskService taskService;
@Autowired
protected ManagementService managementService;
/**History service (used for history recording, which can find historical process instances and process nodes)*/
@Autowired
protected HistoryService historyService;
4.2 process definition and related codes
4.2.1 release process definition
Last blog【Springboot integrates flowable workflow-1 (drawing process definition)】After drawing the process, download an XML file of “leave process 1. Bpmn20. XML”. After downloading, you can publish the process to the process definition through code.
The code is as follows
@Override
public boolean importProcessDefinition(MultipartFile file) {
try {
Deployment deployment = repositoryService.createDeployment()
// .key()
// .name(name)
// .category(category)
// .tenantId()
//Publish multiple rows at a time in the form of compressed packages
// .addZipInputStream()
//Publish as InputStream
.addInputStream(file.getOriginalFilename(), file.getInputStream())
//Publish through the file stored in the classpath directory
// .addClasspathResource("p1.bpmn20.xml")
//In the form of an XML string
// .addString()
.deploy();
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deployment.getId()).singleResult();
if (processDefinition == null) {
return false;
}
} catch (Exception e) {
Throw new businessexception ("import process definition failed:" + e.getmessage());
}
return true;
}
Based on the springboot publishing process definition, another ingenious form is to create a folder processes in the resources directory, and then send the corresponding process file to this folder. When starting the springboot project, it will be found by observing the log, and the process will be published automatically. (not recommended)
workflow-server
└─src
└─main
├─java
└─resources
├─mapper
└─processes
└ - leave process 1 bpmn20. xml
4.2.2 query process definition
//Create processdefinitionquery
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
//Define ID according to process
// processDefinitionQuery.processDefinitionId(requestDTO.getId());
//Define key according to process
// processDefinitionQuery.processDefinitionKeyLike("%" + requestDTO.getKey().trim() + "%");
//Define name according to process
// processDefinitionQuery.processDefinitionNameLike("%" + requestDTO.getName().trim() + "%");
//
//Get total
long count = processDefinitionQuery.count();
//Get single
ProcessDefinition processDefinition = processDefinitionQuery.singleResult();
//Get list
List<ProcessDefinition> processDefinitions = processDefinitionQuery.list();
//Get paging
List<ProcessDefinition> processDefinitions = processDefinitionQuery.listPage(0, 10)
4.2.3 get process definition 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 ("failed to get resources:" + e.getmessage());
} finally {
try {
IOUtils.close(inputStream, null);
} catch (IOException ignored) {
}
}
}
4.2.4 obtain process definition picture
public String getDiagramImageResource(String id) {
//Theoretically, I can use this form, but there will be garbled code when I get it. I'm also strange, so I changed the way through bpmnmodel
// ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(id).singleResult();
// InputStream inputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(),
// processDefinition.getDiagramResourceName());
//Get bpmnmodel object
BpmnModel bpmnModel = repositoryService.getBpmnModel(id);
//Generate picture stream
ProcessEngineConfiguration configuration = processEngine.getProcessEngineConfiguration();
ProcessDiagramGenerator diagramGenerator = configuration.getProcessDiagramGenerator();
InputStream inputStream = diagramGenerator.generateDiagram(bpmnModel, "png", Collections.emptyList(),
Collections. Emptylist(), "Tahoma", "Tahoma", "Tahoma",
this.getClass().getClassLoader(), 1.0, true);
try {
return "data:image/png;base64," + Base64.encode(inputStream);
} catch (Exception e) {
Throw new businessexception ("failed to get resources:" + e.getmessage());
} finally {
try {
IOUtils.close(inputStream, null);
} catch (IOException ignored) {
}
}
}
4.2.5 delete process definition
public void deleteByIds(List<String> ids) {
List<ProcessDefinition> processDefinitions = repositoryService.createProcessDefinitionQuery().processDefinitionIds(new HashSet<>(ids)).list();
// repositoryService.deleteDeployment(String deploymentId, boolean cascade)
//Delete the given deployment and cascade process instances, historical process instances, and jobs.
processDefinitions.forEach(v -> repositoryService.deleteDeployment(v.getDeploymentId(), true));
}
4.3 process instance related codes
4.3.1 add process instance approval comments
It plays a role similar to the operation record of the recording process. Here, I encapsulate one layer by myself. I encapsulate my business user ID, user name, execution type, opinion content
@Data
@Apimodel ("process instance - approval opinion request parameter")
public class ProcessInstanceCommentRequestDTO implements Serializable {
@Apimodelproperty (value = "process definition key")
private String processInstanceId;
@Apimodelproperty (value = "task ID (default)")
private String taskId;
@Apimodelproperty (value = "type commententity: event / comment")
private String type;
@Apimodelproperty (value = "user ID")
private String userId;
@Apimodelproperty (value = "user nickname")
private String nickname;
@Apimodelproperty (value = "execution type")
private String executeType;
@Apimodelproperty (value = "execution type (refer to executetype enum) - submit; yes - agree; no - reject; stop - process termination; delete - process deletion")
private String executeTypeValue;
@Apimodelproperty (value = "content")
private String content;
@Apimodelproperty (value = "additional content carried")
private String ext;
}
Add process instance approval comments
//Add process instance approval record
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);
//Add an approval comment using taskservice
taskService.addComment(requestDTO.getTaskId(), requestDTO.getProcessInstanceId(), requestDTO.getType(), message);
}
4.3.2 example of startup process
@Data
@Apimodel ("process instance - start request parameter")
public class ProcessInstanceStartRequestDTO implements Serializable {
@Apimodelproperty (value = "process definition key")
@Notempty (message = "process definition key cannot be empty")
private String processDefinitionKey;
@Apimodelproperty (value = "process instance name")
@Notempty (message = "process instance name cannot be empty")
private String name;
@Apimodelproperty (value = "item ID")
@Notempty (message = "item ID cannot be empty")
private String communityId;
@Apimodelproperty (value = "global variable")
private Map<String, Object> variables;
}
Start process instance
@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, "process definition not found");
//Start process
ProcessInstanceBuilder builder = runtimeService.createProcessInstanceBuilder();
builder.processDefinitionKey(requestDTO.getProcessDefinitionKey());
builder.name(requestDTO.getName());
// variables("name", "value")
//You can add process variables. For example, I added many business variables here to process business when the process flows
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();
//Add approval comments
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() + "submission process");
commentRequestDTO.setExt("");
this.addProcessInstanceComment(commentRequestDTO);
//Build 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 obtain process progress picture
public String getProcessImage(String processInstanceId) {
// 1. Get the current process instance
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
String processDefinitionId;
List<String> activeActivityIds = new ArrayList<>();
List<String> highLightedFlows = new ArrayList<>();
// 2. Gets all historical Trackline objects
List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId).activityType(BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW).list();
historicActivityInstances.forEach(historicActivityInstance -> highLightedFlows.add(historicActivityInstance.getActivityId()));
// 3. Get the process definition ID and the highlighted node ID
if (processInstance != null) {
//3.1 running process instances
processDefinitionId = processInstance.getProcessDefinitionId();
activeActivityIds = runtimeService.getActiveActivityIds(processInstanceId);
} else {
//3.2 completed process examples
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
.processInstanceId(processInstanceId).singleResult();
processDefinitionId = historicProcessInstance.getProcessDefinitionId();
//3.3 get end node list
List<HistoricActivityInstance> historicEnds = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId).activityType(BpmnXMLConstants.ELEMENT_EVENT_END).list();
List<String> finalActiveActivityIds = activeActivityIds;
historicEnds.forEach(historicActivityInstance -> finalActiveActivityIds.add(historicActivityInstance.getActivityId()));
}
// 4. Get bpmnmodel object
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
// 5. Generate picture stream
ProcessEngineConfiguration configuration = processEngine.getProcessEngineConfiguration();
ProcessDiagramGenerator diagramGenerator = configuration.getProcessDiagramGenerator();
InputStream inputStream = diagramGenerator.generateDiagram(bpmnModel, "png", activeActivityIds,
Highlightedflows, "Tahoma", "Tahoma", "Tahoma",
this.getClass().getClassLoader(), 1.0, true);
// 6. Convert to Base64 network transmission
return "data:image/png;base64," + Base64.encode(inputStream);
}
4.3.4 obtain process approval opinions
@Override
public List<ProcessInstanceCommentResponseDTO> findProcessInstanceCommentList(String processInstanceId) {
List<Comment> processInstanceComments = taskService.getProcessInstanceComments(processInstanceId);
List<ProcessInstanceCommentResponseDTO> 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 process instance execution next step
@Data
@Apimodel ("process instance - execute next request parameter")
public class ProcessInstanceExecuteNextStepRequestDTO implements Serializable {
@Apimodelproperty (value = "process instance ID")
@Notempty (message = "process instance ID cannot be empty")
private String processInstanceId;
@Apimodelproperty (value = "task ID")
private String taskId;
@Apimodelproperty (value = "executetype enum execution type")
@Notempty (message = "execution type cannot be empty")
private String executeType;
@Apimodelproperty (value = "approval comments")
@Notempty (message = "approval comments cannot be blank")
private String commentContent;
@Apimodelproperty (value = "variable parameter")
private HashMap<String, Object> variables;
}
@Transactional(rollbackFor = Exception.class)
public void executeNextStep(ProcessInstanceExecuteNextStepRequestDTO requestDTO) {
ValidatorUtils.validate(requestDTO);
//
if (ExecuteTypeEnum.of(requestDTO.getExecuteType()).isNone()) {
Throw new businessexception ("unknown execution status");
}
TaskQuery taskQuery = taskService.createTaskQuery();
taskQuery.taskId(requestDTO.getTaskId());
Task task = taskQuery.singleResult();
AssertUtils. Notempty (task, "task not found");
//
//Add approval comments
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);
//Process approval
HashMap<String, Object> variables = requestDTO.getVariables();
if (variables == null) {
variables = new HashMap<>(8);
}
//Here, an execution variable executetype will be put, that is, the variable name in the process definition XML, which determines the direction of the process
variables.put(WorkflowConstants.EXECUTE_TYPE, requestDTO.getExecuteType());
//Add executor
variables.put("_execute_user_id=" + SecurityUser.getUserId(), "_execute_user_id=" + SecurityUser.getUserId());
taskService.complete(task.getId(), variables);
}
4.3.6 termination process example
@Data
@Apimodel ("process instance - paging request parameter")
public class ProcessInstanceStopRequestDTO implements Serializable {
@Apimodelproperty (value = "process instance ID")
@Notempty (message = "process instance ID cannot be empty")
private String processInstanceId;
@Apimodelproperty (value = "approval comments")
@Notempty (message = "approval comments cannot be blank")
private String commentContent;
}
public void stopProcessInstance(ProcessInstanceStopRequestDTO requestDTO) {
ValidatorUtils.validate(requestDTO);
//Modify flow execution status
runtimeService.setVariable(requestDTO.getProcessInstanceId(), WorkflowConstants.EXECUTE_TYPE, ExecuteTypeEnum.STOP.name());
//
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId(requestDTO.getProcessInstanceId()).singleResult();
//Add an approval record
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(), "terminate process");
commentRequestDTO.setExt("");
this.addProcessInstanceComment(commentRequestDTO);
///Execution termination
List<Execution> executions = runtimeService.createExecutionQuery().parentId(requestDTO.getProcessInstanceId()).list();
List<String> executionIds = executions.stream().map(v -> v.getId()).collect(Collectors.toList());
//Get process end point
BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
Process process = bpmnModel.getMainProcess();
List<EndEvent> endNodes = process.findFlowElementsOfType(EndEvent.class);
String endId = endNodes.get(endNodes.size() - 1).getId();
//Perform jump
runtimeService.createChangeActivityStateBuilder()
.moveExecutionsToSingleActivityId(executionIds, endId)
.changeState();
}
4.3.7 batch obtain process instance variable list
This method is user-defined because flowable does not have a corresponding method to obtain batch process variables according to the process instance ID list
/**
*Act of instance mapping flowable_ hi_ Varinst table
*/
@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 field list:
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<HistoryVariable> findHistoryVariableList(Collection<String> processInstanceIds) {
if (CollectionUtils.isEmpty(processInstanceIds)) {
return Collections.emptyList();
}
QueryWrapper<HistoryVariable> ew = new QueryWrapper<>();
ew.in("t.PROC_INST_ID_", processInstanceIds);
return this.baseMapper.findHistoryVariableList(ew);
}
Dao
List<HistoryVariable> findHistoryVariableList(@Param("ew") QueryWrapper<HistoryVariable> ew);
xml
<select resultType="cn.leadersheep.xz.workflow.server.entity.flowable.HistoryVariable">
SELECT
t.ID_ AS id,
t.REV_ AS rev,
t.PROC_INST_ID_ AS process_instance_id,
t.EXECUTION_ID_ AS execution_id,
t.TASK_ID_ AS task_id,
t.NAME_ AS name,
t.VAR_TYPE_ AS var_type,
t.SCOPE_ID_ AS scope_id,
t.SUB_SCOPE_ID_ AS sub_scope_id,
t.SCOPE_TYPE_ AS scope_type,
t.BYTEARRAY_ID_ AS bytearray_id,
t.DOUBLE_ AS double_value,
t.LONG_ AS long_value,
t.TEXT_ AS text,
t.TEXT2_ AS text2,
t.CREATE_TIME_ AS create_time,
t.LAST_UPDATED_TIME_ AS last_update_time
FROM act_hi_varinst t
<where>
${ew.sqlSegment}
</where>
</select>
4.3.8 get process instance Pagination
Get process instance paging, because it involves
Data permission filtering
, andneed to be dealt with
、Already done
、Historical records
、I initiate
Wait, the logic is quite complex, so it may not be a good choice to simply use the flowable API. Therefore, the custom implementation here finds the matching records by looking up the relevant database tables of flowable
1. If the process instance is still in progress, the data is saved in the
act_ru_*
In these tables, if the process instance ends, the data is saved in theact_hi_*
In these tables, you need to query unused tables according to different scenarios;
2. The assigned user groups defined in the process definition diagram are saved in theact_ru_identitylink
In the table;
Process instance – paging request parameters
@Data
@EqualsAndHashCode(callSuper = true)
@Apimodel ("process instance - paging request parameter")
public class ProcessInstancePageRequestDTO extends PageParamsEntity {
@Apimodelproperty (value = "item ID")
private String communityId;
@Apimodelproperty (value = "search range: my_todo - my to do; my_done - my done; my_scope - my range; my_create - my create;")
private String searchScope;
@Apimodelproperty (value = "task name")
private String processInstanceName;
}
Process definition – paging response results
@Data
@Apimodel ("process definition - paging response result")
public class ProcessInstancePageResponseDTO implements Serializable {
@Apimodelproperty (value = "item ID")
private String communityId;
@Apimodelproperty (value = "project name")
private String communityName;
@Apimodelproperty (value = "process instance ID")
private String processInstanceId;
@Apimodelproperty (value = "process instance name")
private String processInstanceName;
@Apimodelproperty (value = "process definition ID")
private String processDefinitionId;
@Apimodelproperty (value = "process definition name")
private String processDefinitionName;
@Apimodelproperty (value = "task ID")
private String taskId;
@Apimodelproperty (value = "task name")
private String taskName;
@Apimodelproperty (value = "start time")
private Date startTime;
@Apimodelproperty (value = "end time")
private Date endTime;
@Apimodelproperty (value = "duration")
private String duration;
@Apimodelproperty (value = "creator ID")
private String createId;
@Apimodelproperty (value = "creator name")
private String createName;
}
Service
public PageDTO<ProcessInstancePageResponseDTO> findPage(ProcessInstancePageRequestDTO requestDTO) {
//Data filtering is implemented here
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<ProcessInstancePageResponseDTO> page = this.buildPage(requestDTO);
if ("MY_TODO".equals(requestDTO.getSearchScope())) {
//My to-do list
QueryWrapper<ProcessInstancePageResponseDTO> 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())) {
//You are not a super administrator and need to filter
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())) {
//My work has been done
QueryWrapper<ProcessInstancePageResponseDTO> 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())) {
//My scope
QueryWrapper<ProcessInstancePageResponseDTO> 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())) {
//You are not a super administrator and need to filter
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())) {
//I initiated it
QueryWrapper<ProcessInstancePageResponseDTO> 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())) {
//Populate other attributes
List<String> processInstanceIds = page.getRecords().stream().map(v -> v.getProcessInstanceId()).distinct().collect(Collectors.toList());
List<HistoryVariable> variableList = this.findHistoryVariableList(processInstanceIds);
Map<String, HistoryVariable> 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
/**
*Get my to-do tasks
*
* @author houyu [email protected] <br>
*@ param page paging
*@ param EW parameter wrapper
* @return PageDTO<ProcessInstancePageResponseDTO>
*/
PageDTO<ProcessInstancePageResponseDTO> findMyTodo(@Param("page") PageDTO<ProcessInstancePageResponseDTO> page, @Param("ew") QueryWrapper<ProcessInstancePageResponseDTO> ew);
/**
*Get tasks in my scope
*
* @author houyu [email protected] <br>
*@ param page paging
*@ param EW parameter wrapper
* @return PageDTO<ProcessInstancePageResponseDTO>
*/
PageDTO<ProcessInstancePageResponseDTO> findMyScopePage(@Param("page") PageDTO<ProcessInstancePageResponseDTO> page, @Param("ew") QueryWrapper<ProcessInstancePageResponseDTO> ew);
/**
*Get my done (initiated / approved by me)
*
* @author houyu [email protected] <br>
*@ param page paging
*@ param EW parameter wrapper
* @return PageDTO<ProcessInstancePageResponseDTO>
*/
PageDTO<ProcessInstancePageResponseDTO> findMyDonePage(@Param("page") PageDTO<ProcessInstancePageResponseDTO> page, @Param("ew") QueryWrapper<ProcessInstancePageResponseDTO> ew);
Xml
<select resultType="cn.leadersheep.xz.workflow.client.dto.flowable.response.ProcessInstancePageResponseDTO">
SELECT
t.ID_ AS task_id,
t.PROC_INST_ID_ AS process_instance_id,
t4.NAME_ AS process_instance_name,
t.NAME_ AS task_name,
t.PROC_DEF_ID_ as process_definition_id,
t.CREATE_TIME_ as start_time,
NULL as end_time
FROM act_ru_task t
LEFT JOIN act_ru_identitylink t2 ON t2.TASK_ID_ = t.ID_
LEFT JOIN act_ru_variable t3 ON t3.PROC_INST_ID_ = t.PROC_INST_ID_
LEFT JOIN act_hi_procinst t4 ON t4.PROC_INST_ID_ = t.PROC_INST_ID_
<where>
${ew.sqlSegment}
</where>
</select>
<select resultType="cn.leadersheep.xz.workflow.client.dto.flowable.response.ProcessInstancePageResponseDTO">
SELECT
t.PROC_INST_ID_ AS process_instance_id,
t.NAME_ AS process_instance_name,
t.PROC_DEF_ID_ as process_definition_id,
t.START_TIME_ as start_time,
t.END_TIME_ as end_time
FROM act_hi_procinst t
LEFT JOIN act_hi_taskinst t2 ON t2.PROC_INST_ID_ = t.ID_
LEFT JOIN act_hi_identitylink t3 ON t3.TASK_ID_ = t2.ID_
LEFT JOIN act_hi_varinst t4 ON t4.PROC_INST_ID_ = t.ID_
<where>
${ew.sqlSegment}
</where>
</select>
<select resultType="cn.leadersheep.xz.workflow.client.dto.flowable.response.ProcessInstancePageResponseDTO">
SELECT
t.PROC_INST_ID_ AS process_instance_id,
t.NAME_ AS process_instance_name,
t.PROC_DEF_ID_ as process_definition_id,
t.START_TIME_ as start_time,
t.END_TIME_ as end_time
FROM act_hi_procinst t
LEFT JOIN act_hi_varinst t2 ON t2.PROC_INST_ID_ = t.ID_
LEFT JOIN act_hi_varinst t3 ON t3.PROC_INST_ID_ = t.ID_
<where>
${ew.sqlSegment}
</where>
</select>
5. Linux deployment flow chart text garbled
Briefly describe the situation I encountered. I developed it on windows and set the font of the flowchart to Song typeface. There was no garbled code, but when I deployed to the Linux server to view the flowchart, the text was garbled, Then I can probably guess that it is due to the lack of fonts (because I have known that the chaotic code of activiti flowchart is the lack of fonts), so I will add Song Ti fonts to Linux according to the same routine this time.
5.1 copying fonts on Windows
Enter the directory: C: \ windows \ fonts copy “Arial general” to the desktop for standby

5.2 Linux Java location
Execute command
whereis java
My is in / var / lib / JDK / jdk1 8.0_ 211/bin/java
5.3 copy font file to JRE / lib / fonts
Find out the location of Java, and the location of JRE is in the first few directories of Java
java:
/var/lib/jdk/jdk1.8.0_211/bin/java
JRE font directory (copy here):
/var/lib/jdk/jdk1.8.0_211/jre/lib/fonts
5.4 copy the font file to the system font directory (/ usr / share / fonts)
This directory may not exist. If it does not exist, create it yourself
/usr/share/fonts
5.5 restart the system
reboot
After restarting the system, start the application, that is, there will be no garbled code. Good luck~
Last blog:Springboot integrates flowable workflow-1 (drawing process definition)
The code based on flowable spring boot starter integration is basically completed, but it still feels a little missing. The process is executed step by step. When will it be completed? What’s the point now? It seems that we don’t know how to operate after executing the business. We need to introduce the flowable global event listener. The next blog will introduce the flowable global event listener and realize the business notification business in combination with the listener.
- Official account: IT loading (it_loading)
- CSDN:https://blog.csdn.net/JinglongSource
- Blog:https://ihouyu.cn/
- Email:[email protected]