1. activiti5使用command命令清除流程定义缓存
package com.yl.command;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.deploy.DeploymentCache;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.apache.commons.lang3.StringUtils;
import java.util.Objects;
/**
* 清除缓存
*
* @author liuxb
* @date 2022/12/11 12:36
*/
@Slf4j
public class ClearProcDefCacheCmd implements Command<Object> {
/**
* procDefId 流程定义id
*/
private String procDefId;
public ClearProcDefCacheCmd(String procDefId) {
this.procDefId = procDefId;
}
@Override
public Object execute(CommandContext commandContext) {
try {
//清除缓存
DeploymentCache<ProcessDefinitionEntity> processDefinitionCache = commandContext.getProcessEngineConfiguration().getProcessDefinitionCache();
if (StringUtils.isNoneBlank(procDefId)) {
ProcessDefinitionEntity processDefinitionEntity = processDefinitionCache.get(procDefId);
if (Objects.nonNull(processDefinitionEntity)) {
processDefinitionCache.remove(procDefId);
log.info("-------------清除deployId:{}, procDefId:{}, 流程定义缓存--------------", processDefinitionEntity.getDeploymentId(), procDefId);
}
} else {
processDefinitionCache.clear();
log.info("-------------清除全部流程定义缓存--------------");
}
} catch (Exception e) {
log.error("删除流程定义缓存异常", e);
}
return null;
}
}
执行command命令
@Autowired
private ManagementService managementService;
/**
* 清除流程定义缓存
*
* @param procDefId 流程定义id
*/
public void executeClearProcDefCacheCmd(String procDefId) {
managementService.executeCommand(new ClearProcDefCacheCmd(procDefId));
}
注意需要读取activiti的表act_ge_bytearray
2. activiti5使用command命令更新流程定义并清除流程定义缓存
UpdateByteArrayCmd
package com.yl.command;
import com.yl.exception.FlowException;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ByteArrayEntity;
/**
* 修改流程定义表act_ge_bytearray,并清除缓存
*
* @author liuxb
* @date 2022/12/11 12:36
*/
@Slf4j
public class UpdateByteArrayCmd implements Command<Object> {
/**
* act_ge_bytearray表实体类
*/
private ByteArrayEntity byteArrayEntity;
/**
* procDefId 流程定义id
*/
private String procDefId;
public UpdateByteArrayCmd(ByteArrayEntity byteArrayEntity, String procDefId) {
this.byteArrayEntity = byteArrayEntity;
this.procDefId = procDefId;
}
@Override
public Object execute(CommandContext commandContext) {
try {
//org.activiti.engine.ActivitiOptimisticLockingException: ByteArrayEntity[id=2, name=null, size=4479] was updated by another transaction concurrently
//更新act_ge_bytearray表,使用了乐观锁,必须加上版本号
commandContext.getDbSqlSession().update(byteArrayEntity);
//清除缓存
commandContext.getProcessEngineConfiguration().getProcessDefinitionCache().remove(procDefId);
log.info("-------------更新流程定义并删除缓存deployId:{}, ,procDefId:{}--------------", byteArrayEntity.getDeploymentId(), procDefId);
} catch (Exception e) {
throw new FlowException("更新流程定义文件异常", e);
}
return null;
}
}
CommandUtil
package com.yl.util;
import com.yl.command.ClearProcDefCacheCmd;
import com.yl.command.UpdateByteArrayCmd;
import org.activiti.engine.ManagementService;
import org.activiti.engine.impl.persistence.entity.ByteArrayEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* 执行command服务
*
* @author liuxb
* @date 2022/12/11 17:53
*/
@Service
public class CommandUtil {
@Autowired
private ManagementService managementService;
/**
* 修改流程定义并清除缓存
*
* @param byteArrayEntity
* @param procDefId 流程定义id
*/
public void executeUpdateByteArrayCmd(ByteArrayEntity byteArrayEntity, String procDefId) {
managementService.executeCommand(new UpdateByteArrayCmd(byteArrayEntity, procDefId));
}
/**
* 清除流程定义缓存
*
* @param procDefId 流程定义id
*/
public void executeClearProcDefCacheCmd(String procDefId) {
managementService.executeCommand(new ClearProcDefCacheCmd(procDefId));
}
}
GeByteArrayService
package com.yl.service;
import com.yl.entity.GeByteArrayEntity;
import com.yl.exception.FlowException;
import com.yl.mapper.GeByteArrayMapper;
import com.yl.util.CommandUtil;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.impl.persistence.entity.ByteArrayEntity;
import org.activiti.engine.repository.ProcessDefinition;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
/**
* 对应 act_ge_bytearray表的实体类
*
* @author liuxubo
* @date 2022/11/20 17:14
*/
@Slf4j
@Service
public class GeByteArrayService {
@Autowired
private GeByteArrayMapper geByteArrayMapper;
@Autowired
private RepositoryService repositoryService;
@Autowired
private CommandUtil commandUtil;
/**
* 修改流程定义并清除缓存
*
* @param multipartFile 修改后的流程定义文件
* @param procDefId 要修改的流程定义id
* @return
*/
public int update(MultipartFile multipartFile, String procDefId) {
if (multipartFile == null || multipartFile.isEmpty()) {
throw new FlowException("上传流程定义文件不能为空");
}
if (StringUtils.isBlank(procDefId)) {
throw new FlowException("流程定义id不能为空");
}
GeByteArrayEntity geByteArrayEntity = getGeByteArrayEntity(procDefId);
try {
byte[] bytes = multipartFile.getBytes();
ByteArrayEntity byteArrayEntity = new ByteArrayEntity(bytes);
byteArrayEntity.setId(geByteArrayEntity.getId());
//版本号不能为空,有乐观锁
byteArrayEntity.setRevision(geByteArrayEntity.getVer());
byteArrayEntity.setName(geByteArrayEntity.getName());
byteArrayEntity.setDeploymentId(geByteArrayEntity.getDeploymentId());
commandUtil.executeUpdateByteArrayCmd(byteArrayEntity, procDefId);
} catch (Exception e) {
throw new FlowException("更新流程定义异常", e);
}
return Objects.nonNull(geByteArrayEntity) ? 1 : 0;
}
/**
* 清除流程定义缓存
*
* @param procDefId 要修改的流程定义id
* @return
*/
public boolean clearCache(String procDefId) {
// String id = "";
// if(StringUtils.isNoneBlank(procDefId)){
// GeByteArrayEntity geByteArrayEntity = getGeByteArrayEntity(procDefId);
// id = geByteArrayEntity.getId();
// }
commandUtil.executeClearProcDefCacheCmd(procDefId);
return true;
}
/**
* 根据流程定义id查询流程定义的二进制数据
*
* @param procDefId 要修改的流程定义id
* @return
*/
private GeByteArrayEntity getGeByteArrayEntity(String procDefId) {
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().
processDefinitionId(procDefId)
.singleResult();
if (Objects.isNull(processDefinition)) {
throw new FlowException("流程定义文件查询不存在");
}
String deploymentId = processDefinition.getDeploymentId();
String bpmnName = "";
List<String> resourceNames = repositoryService.getDeploymentResourceNames(deploymentId);
for (String resourceName : resourceNames) {
if (resourceName.endsWith(".bpmn") || resourceName.endsWith(".xml")) {
bpmnName = resourceName;
break;
}
}
GeByteArrayEntity geByteArrayEntity = geByteArrayMapper.findByDeploymentId(deploymentId, bpmnName);
log.info("id:{}, ver:{}, name:{}, deploymentId:{}", geByteArrayEntity.getId(), geByteArrayEntity.getVer(), geByteArrayEntity.getName(), geByteArrayEntity.getDeploymentId());
return geByteArrayEntity;
}
}
GeByteArrayEntity
package com.yl.entity;
import lombok.Data;
/**
* 对应 act_ge_bytearray表的实体类
*
* @author liuxubo
* @date 2022/11/20 17:14
*/
@Data
public class GeByteArrayEntity {
/**
* 主键id
*/
private String id;
/**
* 版本
*/
private Integer ver;
/**
* 部署文件名
*/
private String name;
/**
* 部署文件的二进制数据
*/
private byte[] bytes;
/**
* 部署id
*/
private String deploymentId;
/**
* 该资源是否是activiti引擎自动生成(0表示用户生成,1表示由activiti引擎生成)
*/
private boolean generated = false;
}
GeByteArrayMapper
package com.yl.mapper;
import com.yl.entity.GeByteArrayEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 对应 act_ge_bytearray表的实体类
*
* @author liuxubo
* @date 2022/11/20 17:14
*/
@Mapper
public interface GeByteArrayMapper {
List<GeByteArrayEntity> findList(GeByteArrayEntity geByteArrayEntity);
GeByteArrayEntity findByDeploymentId(@Param("deploymentId") String deploymentId, @Param("name") String name);
int add(GeByteArrayEntity geByteArrayEntity);
int deleteByDeploymentId(@Param("deploymentId") String deploymentId, @Param("name") String name);
int update(GeByteArrayEntity geByteArrayEntity);
}
GeByteArrayMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace='com.yl.mapper.GeByteArrayMapper'>
<resultMap id='applyDataResultMap' type='com.yl.entity.GeByteArrayEntity'>
<id column='ID_' property='id' jdbcType='VARCHAR' />
<result column='REV_' property='ver' jdbcType='INTEGER' />
<result column='NAME_' property='name' jdbcType='VARCHAR' />
<result column='BYTES_' property='bytes' jdbcType='BLOB' />
<result column='DEPLOYMENT_ID_' property='deploymentId' jdbcType='VARCHAR' />
<result column='GENERATED_' property='generated' jdbcType='BOOLEAN' />
</resultMap>
<sql id='applyDataColumns'>
ID_,REV_,NAME_,BYTES_,DEPLOYMENT_ID_,GENERATED_
</sql>
<select id='findList' resultMap='applyDataResultMap'>
SELECT
<include refid='applyDataColumns'/>
FROM act_ge_bytearray
<where>
<if test='id != null and id != "" '> and ID_=#{id}</if>
<if test='REV_ != null '> and REV_=#{rev}</if>
<if test='name != null and name != "" '> and NAME_=#{name}</if>
<if test='deploymentId != null and deploymentId != "" '> and DEPLOYMENT_ID_=#{deploymentId}</if>
</where>
</select>
<select id='findByDeploymentId' resultMap='applyDataResultMap'>
SELECT
<include refid='applyDataColumns'/>
FROM act_ge_bytearray
WHERE DEPLOYMENT_ID_=#{deploymentId} and NAME_=#{name}
</select>
<insert id='add'>
INSERT INTO act_ge_bytearray(
ID_,REV_,NAME_,BYTES_,DEPLOYMENT_ID_,GENERATED_
)
VALUES (
#{id},1, #{name},#{bytes},#{deploymentId},0
)
</insert>
<delete id='deleteByDeploymentId'>
DELETE FROM act_ge_bytearray WHERE DEPLOYMENT_ID_=#{deploymentId} and NAME_=#{name}
</delete>
<!-- 只修改流程部署文件内容 -->
<update id='update'>
UPDATE act_ge_bytearray
<set>
<if test='bytes != null '>BYTES_=#{bytes}</if>
</set>
WHERE DEPLOYMENT_ID_=#{deploymentId} and NAME_=#{name}
</update>
</mapper>
GeByteArrayController
package com.yl.controller;
import com.yl.common.annotation.RequestSingleBody;
import com.yl.common.base.RetModel;
import com.yl.common.base.RetResult;
import com.yl.common.base.vo.FlagVo;
import com.yl.common.base.vo.NumberVo;
import com.yl.common.base.vo.ViewObject;
import com.yl.service.GeByteArrayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
/**
* 流程定义
*
* @author liuxb
* @date 2022/11/20 18:07
*/
@Validated
@RestController
@RequestMapping("/activiti5/geByteArray")
public class GeByteArrayController {
@Autowired
private GeByteArrayService geByteArrayService;
/**
* 修改流程定义
*
* @param file 修改后的流程定义文件
* @param procDefId 要修改的流程定义id
* @return
*/
@PostMapping("/update")
public RetResult<NumberVo> update(MultipartFile file, String procDefId) {
return RetModel.ok().setData(ViewObject.number(geByteArrayService.update(file, procDefId)));
}
/**
* 清除流程定义缓存
*
* @param procDefId 要修改的流程定义id
* @return
*/
@PostMapping("/clearCache")
public RetResult<FlagVo> clearCache(@RequestSingleBody String procDefId) {
return RetModel.ok().setData(ViewObject.flag(geByteArrayService.clearCache(procDefId)));
}
}
3. 总结
//更新act_ge_bytearray表,使用了乐观锁,必须加上版本号,否则报错 org.activiti.engine.ActivitiOptimisticLockingException
commandContext.getDbSqlSession().update(byteArrayEntity);
//如果是activit6,只需修改ClearProcDefCacheCmd内
DeploymentCache<ProcessDefinitionCacheEntry> processDefinitionCache = commandContext.getProcessEngineConfiguration().getProcessDefinitionCache();
注意:修改完流程定义后,如果不清除缓存,会不生效,或者不清除缓存,重启项目也可以