开源流程引擎Camunda BPM如何扩展数据库表
前言
在使用开源流程引擎(如:JBPM、Activiti、Flowable、Camunda等)的时候,经常会遇到这样的需求,我们需要按照业务需求增加一张数据库的表,而且这张表是跟工作流引擎有交互的(注意不是一张业务表),那么如何扩展一张数据库表并无缝地融入到流程引擎的机制中呢?下面以Camunda BPM为例,介绍如何扩展自定义数据库表。
模拟一个客户需求
假设某一客户的业务流程很多,有几百个,这些流程在camunda里是平层放的,没有按照业务归类,不便于管理和使用,客户希望把这些流程按照业务分类展示,就像一棵目录树,分A、B、C一层目录,A下面又分A1、A2、A3第二层目录,A1、A2、A3下面放的是具体的业务流程定义。
我们分析这个需求,需要扩展一张数据库表记录业务分类目录,同时需要在流程定义表里扩展一个字段,关联这个业务分类目录,这样才能实现流程定义按照业务分类展示。
扩展数据库表步骤
1. 建表
在camunda数据库里创建一张表,命名为act_re_proc_catalog(流程分类目录表)。

MySQL建表语句:
CREATE TABLE `act_re_proc_catalog` (
`ID_` varchar(64) COLLATE utf8_bin NOT NULL DEFAULT '' COMMENT '主键',
`CATALOG_CODE_` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '业务分类编码',
`CATALOG_NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT '业务分类名称',
`PARENT_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '父节点ID',
`CREATE_TIME_` datetime DEFAULT NULL COMMENT '插入或修改时间',
`TENANT_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`ID_`) USING BTREE,
KEY `ACT_IDX_PROC_CATALOG_TENANT_ID` (`TENANT_ID_`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin ROW_FORMAT=COMPACT;
2. 创建实体类
按照camunda的规则,创建实体类必须基于接口,所以先创建接口,接口命名为ProcessCatalog。


import java.util.Date;
public interface ProcessCatalog {
String getId();
String getCatalogCode() ;
String getCatalogName() ;
String getParentId() ;
Date getCreateTime() ;
String getTenantId();
}
接着创建实体类,实现上面的接口和DbEntity接口,实体类命名为ProcessCatalogEntity。
import org.camunda.bpm.engine.impl.db.DbEntity;
import org.camunda.bpm.engine.repository.ProcessCatalog;
import java.io.Serializable;
import java.util.Date;
/** * 流程目录实体类 */
public class ProcessCatalogEntity implements Serializable, ProcessCatalog, DbEntity {
private static final long serialVersionUID = 1L;
protected String id;
protected String catalogCode;
protected String catalogName;
protected String parentId;
protected Date createTime;
protected String tenantId;
public Object getPersistentState() {
// properties of this entity are immutable
// so always the same value is returned
// so never will an update be issued for a DeploymentEntity
return ProcessCatalogEntity.class;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCatalogCode() {
return catalogCode;
}
public void setCatalogCode(String catalogCode) {
this.catalogCode = catalogCode;
}
public String getCatalogName() {
return catalogName;
}
public void setCatalogName(String catalogName) {
this.catalogName = catalogName;
}
public String getParentId() {
return parentId;
}
public void setParentId(String parentId) {
this.parentId = parentId;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public String getTenantId() {
return tenantId;
}
public void setTenantId(String tenantId) {
this.tenantId = tenantId;
}
@Override
public String toString() {
return this.getClass().getSimpleName()
+ "[id=" + id
+ ", catalogCode=" + catalogCode
+ ", catalogName=" + catalogName
+ ", parentId=" + parentId
+ ", createTime=" + createTime
+ ", tenantId=" + tenantId
+ "]";
}
}
3. 创建mybatis mapper文件
mapper文件命名为ProcessCatalog.xml
insert into ${prefix}ACT_RE_PROC_CATALOG(ID_, CATALOG_CODE_, CATALOG_NAME_, PARENT_ID_, CREATE_TIME_, TENANT_ID_)
values(#{id, jdbcType=VARCHAR}, #{catalogCode, jdbcType=VARCHAR}, #{catalogName, jdbcType=VARCHAR}, #{parentId, jdbcType=VARCHAR}, #{createTime, jdbcType=TIMESTAMP}, #{tenantId, jdbcType=VARCHAR})
update ${prefix}ACT_RE_PROC_CATALOG
PROCDEF_ = #{procdef, jdbcType=VARCHAR},
CATALOG_CODE_ = #{catalogCode, jdbcType=VARCHAR},
CATALOG_NAME_ = #{catalogName, jdbcType=VARCHAR},
PARENT_ID_ = #{parentId, jdbcType=VARCHAR},
CREATE_TIME_ = #{createTime, jdbcType=TIMESTAMP},
TENANT_ID_ = #{tenantId, jdbcType=VARCHAR}
where ID_= #{id, jdbcType=VARCHAR}
delete from ${prefix}ACT_RE_PROC_CATALOG where ID_ = #{id}
select * from ${prefix}ACT_RE_PROC_CATALOG where ID_ = #{id}
${limitBefore}
select ${distinct} RES.*
${limitBetween}
${orderBy}
${limitAfter}
select count(distinct RES.ID_)
from ${prefix}ACT_RE_PROC_CATALOG RES
RES.ID_ = #{id}
and RES.CATALOG_CODE_ = #{catalogCode}
and RES.CATALOG_NAME_ = #{catalogName}
and RES.PARENT_ID_ = #{parentId}
and RES.CREATE_TIME_ < #{createTimeBefore}
and RES.CREATE_TIME_ > #{createTimeAfter}
and ( RES.TENANT_ID_ in
#{tenantId}
or RES.TENANT_ID_ is null
)
and RES.TENANT_ID_ is null
select *
from ${prefix}ACT_RE_PROC_CATALOG
where PARENT_ID_ = #{parameter.parentId}
and CATALOG_CODE_ = #{parameter.catalogCode}
and CATALOG_NAME_ = #{parameter.catalogName}
and TENANT_ID_ is null
and TENANT_ID_ = #{parameter.tenantId}
order by CATALOG_CODE_ asc
${limitBefore}
select ${distinct} RES.*
${limitBetween}
${orderBy}
${limitAfter}
select count(distinct RES.ID_)
4. 创建数据查询类
按照camunda的规则,创建查询类必须基于接口,所以先创建查询接口,接口命名为ProcessCatalogQuery.java。
import org.camunda.bpm.engine.impl.QueryPropertyImpl;
import org.camunda.bpm.engine.query.Query;
import org.camunda.bpm.engine.query.QueryProperty;
import java.util.Date;
/** * 流程分类查询接口 */
public interface ProcessCatalogQuery extends Query<ProcessCatalogQuery, ProcessCatalog>{
public static final QueryProperty CATALOG_CODE = new QueryPropertyImpl("CATALOG_CODE_");
public static final QueryProperty CREATE_TIME = new QueryPropertyImpl("CREATE_TIME_");
public static final QueryProperty TENANT_ID = new QueryPropertyImpl("TENANT_ID_");
ProcessCatalogQuery id(String id);
ProcessCatalogQuery catalogCode(String catalogCode) ;
ProcessCatalogQuery catalogName(String catalogName);
ProcessCatalogQuery parentId(String parentId) ;
ProcessCatalogQuery createTimeBefore(Date before);
ProcessCatalogQuery createTimeAfter(Date after) ;
ProcessCatalogQuery tenantIdIn(String... tenantIds) ;
ProcessCatalogQuery withoutTenantId() ;
ProcessCatalogQuery orderByCatalogCode();
ProcessCatalogQuery orderByCreateTime();
ProcessCatalogQuery orderByTenantId();
}
然后创建查询实现类,命名为ProcessCatalogQueryImpl.java
import org.camunda.bpm.engine.impl.interceptor.CommandContext;
import org.camunda.bpm.engine.impl.interceptor.CommandExecutor;
import org.camunda.bpm.engine.impl.util.CompareUtil;
import org.camunda.bpm.engine.repository.ProcessCatalog;
import org.camunda.bpm.engine.repository.ProcessCatalogQuery;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import static org.camunda.bpm.engine.impl.util.EnsureUtil.ensureNotNull;
/** * 流程表单配置查询实现 */
public class ProcessCatalogQueryImpl extends AbstractQuery<ProcessCatalogQuery, ProcessCatalog> implements ProcessCatalogQuery, Serializable {
private static final long serialVersionUID = 1L;
protected String id;
protected String catalogCode;
protected String catalogName;
protected String parentId;
protected Date createTime;
protected String tenantId;
protected Date createTimeBefore;
protected Date createTimeAfter;
protected boolean isTenantIdSet = false;
protected String[] tenantIds;
public ProcessCatalogQueryImpl() {
}
public ProcessCatalogQueryImpl(CommandExecutor commandExecutor) {
super(commandExecutor);
}
public ProcessCatalogQuery id(String id) {
ensureNotNull("Id ", id);
this.id = id;
return this;
}
public ProcessCatalogQuery catalogCode(String catalogCode) {
ensureNotNull("catalogCode", catalogCode);
this.catalogCode = catalogCode;
return this;
}
public ProcessCatalogQuery catalogName(String catalogName) {
ensureNotNull("catalogName", catalogName);
this.catalogName = catalogName;
return this;
}
public ProcessCatalogQuery parentId(String parentId) {
ensureNotNull("parentId", parentId);
this.parentId = parentId;
return this;
}
public ProcessCatalogQuery createTimeBefore(Date before) {
ensureNotNull("createTimeBefore", before);
this.createTimeBefore = before;
return this;
}
public ProcessCatalogQuery createTimeAfter(Date after) {
ensureNotNull("createTimeAfter", after);
this.createTimeAfter = after;
return this;
}
public ProcessCatalogQuery tenantIdIn(String... tenantIds) {
ensureNotNull("tenantIds", (Object[]) tenantIds);
this.tenantIds = tenantIds;
isTenantIdSet = true;
return this;
}
public ProcessCatalogQuery withoutTenantId() {
isTenantIdSet = true;
this.tenantIds = null;
return this;
}
protected boolean hasExcludingConditions() {
return super.hasExcludingConditions() || CompareUtil.areNotInAscendingOrder(createTimeAfter, createTimeBefore);
}
public ProcessCatalogQuery orderByCatalogCode() {
return orderBy(ProcessCatalogQuery.CATALOG_CODE);
}
public ProcessCatalogQuery orderByCreateTime() {
return orderBy(ProcessCatalogQuery.CREATE_TIME);
}
public ProcessCatalogQuery orderByTenantId() {
return orderBy(ProcessCatalogQuery.TENANT_ID);
}
@Override
public long executeCount(CommandContext commandContext) {
checkQueryOk();
return commandContext.getProcessCatalogManager().findProcessCatalogCountByQueryCriteria(this);
}
@Override
public List executeList(CommandContext commandContext, Page page) {
checkQueryOk();
return commandContext.getProcessCatalogManager().findProcessCatalogsByQueryCriteria(this, page);
}
public String getId() {
return id;
}
public String getCatalogCode() {
return catalogCode;
}
public String getCatalogName() {
return catalogName;
}
public String getParentId() {
return parentId;
}
public Date getCreateTimeBefore() {
return createTimeBefore;
}
public Date getCreateTimeAfter() {
return createTimeAfter;
}
}
5. 创建数据库操作类
数据库操作类类似于DAO类,camunda的规则为xxxManager,我们命名该类为ProcessCatalogManager.java
import org.camunda.bpm.engine.impl.Page;
import org.camunda.bpm.engine.impl.ProcessCatalogQueryImpl;
import org.camunda.bpm.engine.impl.db.ListQueryParameterObject;
import org.camunda.bpm.engine.impl.persistence.AbstractManager;
import org.camunda.bpm.engine.repository.ProcessCatalog;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** * 流程分类数据库操作类 */
public class ProcessCatalogManager extends AbstractManager {
public void insertProcessCatalog(ProcessCatalogEntity processCatalogEntity) {
getDbEntityManager().insert(processCatalogEntity);
getDbEntityManager().update(ProcessCatalogEntity.class,"updateProcessCatalog",processCatalogEntity);
}
public void updateProcessCatalog(ProcessCatalogEntity processCatalogEntity) {
getDbEntityManager().update(ProcessCatalogEntity.class,"updateProcessCatalog",processCatalogEntity);
}
public void deleteProcessCatalog(String id, final boolean cascade) {
if (cascade) {
}
getDbEntityManager().delete(ProcessCatalogEntity.class, "deleteProcessCatalog", id);
}
public List findProcessCatalogsByParentId(String parentId) {
Map<String, Object> parameters = new HashMap<String, Object>();
parameters.put("parentId", parentId);
ListQueryParameterObject parameterObject = new ListQueryParameterObject();
parameterObject.setParameter(parameters);
List list = getDbEntityManager().selectList("selectProcessCatalogsByProcdef", parameterObject);
return list;
}
public ProcessCatalogEntity findProcessCatalogById(String id) {
return getDbEntityManager().selectById(ProcessCatalogEntity.class, id);
}
public long findProcessCatalogCountByQueryCriteria(ProcessCatalogQueryImpl processCatalogQuery) {
configureQuery(processCatalogQuery);
return (Long) getDbEntityManager().selectOne("selectProcessCatalogCountByQueryCriteria", processCatalogQuery);
}
@SuppressWarnings("unchecked")
public List findProcessCatalogsByQueryCriteria(ProcessCatalogQueryImpl processCatalogQuery, Page page) {
configureQuery(processCatalogQuery);
return getDbEntityManager().selectList("selectProcessCatalogsByQueryCriteria", processCatalogQuery, page);
}
@Override
public void close() {
}
@Override
public void flush() {
}
protected void configureQuery(ProcessCatalogQueryImpl query) {
getAuthorizationManager().configureCatalogQuery(query);
getTenantManager().configureQuery(query);
}
}
6. 在mybatis中注册mapping
我们自定义的的mapping文件需要注册到全局的mappings.xml中,其实就是mybatis的机制,找到mappings.xml文件,增加如下一条记录。
<mapper resource="org/camunda/bpm/engine/impl/mapping/entity/ProcessCatalog.xml" />
7. 在上下文中注册数据库操作类
Camunda中大量应用了命令模式,有自己的一套事务管理机制,数据库操作类必须要在CommandContext.java中进行注册。
public ProcessCatalogManager getProcessCatalogManager() {
return getSession(ProcessCatalogManager.class);
}
8. 在全局配置中注册数据库操作类
在ProcessEngineConfigurationImpl.java类的initSessionFactories方法中注册数据库操作类ProcessCatalogManager。
addSessionFactory(new GenericManagerFactory(ProcessCatalogManager.class));
总结
通过以上的8个步骤,就可以在camunda中任意扩展数据库表了,同时我们也深入了解camunda原生数据操作机制。
开源流程引擎Camunda BPM如何扩展数据库表的更多相关文章
- 基于开源流程引擎开发BPM或OA有哪些难点
前言 如何基于开源流程引擎开发OA系统?开源流程引擎哪个好?把它整合到自己的产品里难不难,有没有啥风险?这是大家经常遇到的问题.笔者从2006年开始参与流程引擎开发,经历了三代流程引擎研发,支 ...
- 开源流程引擎camunda如何扩展
市场上基于Java语言的开源工作流引擎有:osworkflow.jbpm.activiti.flowable.camunda等,其中osworkflow.jbpm流程引擎已经过时,目前主流的开源 ...
- 开源流程引擎osworkflow、jbpm、activiti、flowable、camunda哪个好?
市场上比较有名的开源流程引擎有osworkflow.jbpm.activiti.flowable.camunda.其中:Jbpm4.Activiti.Flowable.camunda四个框架同宗同源, ...
- 基于camunda开源流程引擎如何实现会签及会签原理解析
一.背景 市场上比较有名的开源流程引擎有osworkflow.jbpm.activiti.flowable.camunda.由于jbpm.activiti.flowable这几个流程引擎出现的比较早, ...
- 开源流程引擎该如何选择flowable还是camunda
市场上比较有名的开源流程引擎有osworkflow.jbpm.activiti.flowable.camunda.现在国内用的最多的是activiti.flowable.camunda,下面主要从功能 ...
- Camunda开源流程引擎快速入门——Hello World
市场上比较有名的开源流程引擎有osworkflow.jbpm.activiti.flowable.camunda.由于jbpm.activiti.flowable这几个流程引擎出现的比较早,国内人用的 ...
- Fixflow引擎解析(一)(介绍) - Fixflow开源流程引擎介绍
Fixflow引擎解析(四)(模型) - 通过EMF扩展BPMN2.0元素 Fixflow引擎解析(三)(模型) - 创建EMF模型来读写XML文件 Fixflow引擎解析(二)(模型) - BPMN ...
- camunda开源流程引擎的数据库表结构介绍
Camunda bpm流程引擎的数据库由多个表组成,表名都以ACT开头,第二部分是说明表用途的两字符标识.本文以Camunda7.11版本为例,共47张表. ACT_RE_*: 'RE'表示流程资源存 ...
- 基于laravel的有偿开源流程引擎
系统主要文档已经编写完成,具体请前往查看[系统文档](https://www.kancloud.cn/lijianlin/jishullin_workflow_engine/1894424 " ...
随机推荐
- vue项目中返回之前页面数据不刷新的问题
利用vue做项目的时候会有让用户选择当前页面的某些数据,然后再跳到下一页,而下一页是根据上一页的数据来的,有时候选择了上一页的不同选项,下一页的数据可能还是之前的 这个就属于vue的数据获取问题 解决 ...
- animate.css使用
解决 使用jquery单纯添加类不能出现动画 使用jQuery向元素中添加类制作动画的时候,需要使用setTimeout实现,因为动画需要从一个状态到另外一个状态!时间设置为0
- Java报错:org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.sirifeng.babytun.dao.GoodsDAO.findById
前言 最近学vue学得差不多了,想来搭个项目实战一下,结果刚开始搭建SSM框架的时候就来到了我们最喜欢的debug环节 org.apache.ibatis.binding.BindingExcepti ...
- Struts2-day1总结
1.Struts2的基本执行流程(详见我的博客) 2.Struts2的分模块开发 如果有多个项目的Struts.xml写在一起,容易造成数据混乱,所以可以使用分模块的方法,在项目下新建*.xml配置文 ...
- 怎么快速找出帝国CMS数据库配置文件路径及迁移网站后修改技巧!
首先,我们要了解一下帝国CMS整个目录结构,只有了解清楚结构,我们才有可能快速找到自己想要的文件,比如:帝国CMS数据库配置文件路径! 帝国CMS目录结构介绍 / 系统根目录├d/ 附件和数据存放目录 ...
- 另类终端「GitHub 热点速览 v.22.15」
作者:HelloGitHub-小鱼干 除了编译器之外,终端也是我们日常打交道的软件之一.但,你用它看过股票吗?OpenBBTerminal 不仅能让你看股票,还能让你用科学的方法进行股票投资.说到投资 ...
- VMware下ubuntu 20.04扩容/磁盘
最近搞zabbix监控,发现搭建的监控server主机磁盘告警.提示/超过阈值80%. 有实在VMware软件下的虚拟机,首先我就是给虚机磁盘增加容量. 增加后发现没什么改变,看来还需要其他操作. 在 ...
- Mybatis结果集映射问题
之前的数据库图简单都是纯小写格式,这一次做项目为了显得正规一些,模拟实际的情况,采用了驼峰命名的规则,这时候就遇到了结果匹配的问题. 之前只要 <select id="select&q ...
- SSM整合_年轻人的第一个增删改查_查找
写在前面 SSM整合_年轻人的第一个增删改查_基础环境搭建 SSM整合_年轻人的第一个增删改查_查找 SSM整合_年轻人的第一个增删改查_新增 SSM整合_年轻人的第一个增删改查_修改 SSM整合_年 ...
- django orm 更新数据时间不自动更新问题
gmt_create自动添加auto_now_add:gmt_modify自动更新auto_now class CommonInfo(models.Model): """ ...