# camunda-database-demo **Repository Path**: lin-yongjin/camunda-database-demo ## Basic Information - **Project Name**: camunda-database-demo - **Description**: 模仿Camunda的方式操作数据库 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 1 - **Created**: 2023-06-01 - **Last Updated**: 2024-11-28 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 1、主要的类 * Entity:实体类对应数据库中的数据模型,并且必须实现DbEntity接口。 ```java package org.augustus.camunda.entity; import org.camunda.bpm.engine.impl.db.DbEntity; import java.util.HashMap; import java.util.List; /** * @author: linyongjin * @create: 2023-05-26 17:17:58 */ public class JoinEntity implements DbEntity { // ... } ``` * Query:查询类,构建查询条件与排序条件。 ```java // 定义接口 public interface JoinQuery extends Query { // 定义添加查询条件的方法 JoinQuery processDefinitionId(String processDefinitionId); // 定义添加排序的方法 JoinQuery orderById(); } ``` ```java public class JoinQueryImpl extends AbstractQuery implements JoinQuery { protected String processDefinitionId; public JoinQueryImpl(CommandExecutor commandExecutor) { super(commandExecutor); } // 重写AbstractQuery的计数的方法 @Override public long executeCount(CommandContext commandContext) { JoinManager joinManager = commandContext.getSession(JoinManager.class); return joinManager.count(this); } // 重写AbstractQuery的列表查询的方法 @Override public List executeList(CommandContext commandContext, Page page) { JoinManager joinManager = commandContext.getSession(JoinManager.class); return joinManager.list(this, page); } @Override public JoinQuery processDefinitionId(String processDefinitionId) { // 查询添加直接赋值即可, 在调用Mybaits时参数就是当前对象"this" this.processDefinitionId = processDefinitionId; return this; } @Override public JoinQuery orderById() { // 构建排序对象 return orderBy(new QueryPropertyImpl("ID_")); } } ``` * Command:命令类,调用Manager执行SQL语句。一般用于增删改操作。 ```java public class DeleteJoinCmd implements Command { private final String processDefinitionId; private final boolean cascade; public DeleteJoinCmd(String processDefinitionId, boolean cascade) { this.processDefinitionId = processDefinitionId; this.cascade = cascade; } @Override public Void execute(CommandContext commandContext) { JobManager jobManager = commandContext.getSession(JobManager.class); JoinEntity joinEntity = new JoinEntity(); joinEntity.setProcessDefinitionId(processDefinitionId); jobManager.delete(joinEntity); if (cascade) { ProcessInstanceManager instanceManager = commandContext.getSession(ProcessInstanceManager.class); ProcessInstanceEntity instance = new ProcessInstanceEntity(); instance.setId(processDefinitionId); instanceManager.delete(instance); } return null; } ``` ```java public class InsertJoinCmd implements Command, Serializable { private final String processDefinitionId; private final String deploymentId; private final String processTitle; private final String processKey; private final String processInstanceId; public InsertJoinCmd(String processDefinitionId, String deploymentId, String processTitle, String processKey, String processInstanceId) { this.processDefinitionId = processDefinitionId; this.deploymentId = deploymentId; this.processTitle = processTitle; this.processKey = processKey; this.processInstanceId = processInstanceId; } @Override public Void execute(CommandContext commandContext) { JoinManager joinManager = commandContext.getSession(JoinManager.class); JoinEntity join = new JoinEntity(); join.setId(processDefinitionId); join.setProcessKey(processKey); join.setProcessTitle(processTitle); join.setDeploymentId(deploymentId); joinManager.insert(join); if (processInstanceId != null) { ProcessInstanceManager processInstanceManager = commandContext.getSession(ProcessInstanceManager.class); ProcessInstanceEntity instance = new ProcessInstanceEntity(); instance.setProcessInstanceId(processInstanceId); instance.setState("ACTIVE"); instance.setProcessDefinitionId(processDefinitionId); processInstanceManager.insert(instance); } return null; } } ``` ```java public class UpdateJoinCmd implements Command { private final String processDefinitionId; private final String processTitle; public UpdateJoinCmd(String processDefinitionId, String processTitle) { this.processDefinitionId = processDefinitionId; this.processTitle = processTitle; } @Override public Void execute(CommandContext commandContext) { JoinManager joinManager = commandContext.getSession(JoinManager.class); joinManager.update(processDefinitionId, processTitle); return null; } } ``` * Manager:管理器,调用方法操作数据库。命名规范:${实体类}Manager.java。在Camunda中不同的实体类有对应的Manager,如:TaskManager、JonManager。这些Manager都是通过硬编码形式添加到ProcessEngineConfiguration对象中,我在代码中进行了扩展,类似Spring@ComponentScan的机制,在配置文件中配置包名,在解析ProcessEngineConfiguration这个配置类的时候就会将指定包下面的Manager添加进去。 ```java public class JoinManager extends AbstractManager { public JoinEntity findJoinById(String id) { DbEntityManager dbEntityManager = getDbEntityManager(); // selectById方法是Camunda提供的默认方法, 需要有名称是selectXxx的Statement。 return dbEntityManager.selectById(JoinEntity.class, id); } public void update(String id, String name) { Map parameters = new HashMap<>(2) {{ this.put("processDefinitionId", id); this.put("processTitle", name); }}; getDbEntityManager().update(JoinEntity.class, "updateDefinition", parameters); } public long count(JoinQueryImpl joinQuery) { return (long) getDbEntityManager().selectOne("countJoin", joinQuery); } public List list(JoinQueryImpl joinQuery, Page page) { return getDbEntityManager().selectList("selectJoin", joinQuery, page); } } ``` ```yaml camunda: bpm: session-scan-packages: - org.augustus.camunda.persistence - org.augustus.camunda.engine ``` ```java @Component public class AnsProcessEngineConfiguration extends SpringProcessEngineConfiguration { // 核心代码, 执行完父类的添加逻辑之后添加自定义的Manager // 修改了默认的Camunda配置代码, 原本的配置类是SpringProcessEngineConfiguration // 现在被替换为AnsProcessEngineConfiguration @Override protected void initSessionFactories() { super.initSessionFactories(); if (sessionFactories != null) { Set sessionClasses = getSessionClasses(); for (String sessionClass : sessionClasses) { try { Class clazz = ClassUtils.forName(sessionClass, ClassUtils.getDefaultClassLoader()); addSessionFactory(new GenericManagerFactory((Class) clazz)); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } } } ``` * Service:入口类,执行SQL操作的类。也不一定叫Service,但是根据Camunda默认的命名规则来定义。 ```java public class JoinServiceImpl extends ServiceImpl implements JoinService { @Override public JoinQuery createJoinQuery() { return new JoinQueryImpl(commandExecutor); } @Override public void insertJoin(String processDefinitionId, String deploymentId, String processTitle, String processKey, String processInstanceId) { commandExecutor.execute(new InsertJoinCmd(processDefinitionId, deploymentId, processTitle, processKey, processInstanceId)); } @Override public void deleteJoin(String processDefinitionId, boolean cascade) { commandExecutor.execute(new DeleteJoinCmd(processDefinitionId, cascade)); } @Override public void updateJoin(String processDefinitionId, String processTitle) { commandExecutor.execute(new UpdateJoinCmd(processDefinitionId, processTitle)); } @Override public JoinEntity selectById(String id) { return commandExecutor.execute(new SelectJoinCmd(id)); } } ``` * 启动类:在项目启动之后做的后续操作。 ```java @Component public class StartUpPostProcessor implements CommandLineRunner, ApplicationContextAware { private ApplicationContext applicationContext; private final ProcessEngineConfigurationImpl processEngineConfiguration; public void setApplicationContext(ApplicationContext applicationContext) { this.applicationContext = applicationContext; } public StartUpPostProcessor(ProcessEngineConfigurationImpl processEngineConfiguration) { this.processEngineConfiguration = processEngineConfiguration; } @Override public void run(String... args) throws Exception { setCommandExecutor(); } // Camunda中自带的Service在ProcessEngineConfiguration的init()方法中就已经完成了初始化, 设置了CommandExecutor // 自定义的Service也需要设置CommandExecutor对象 private void setCommandExecutor() { Map beansMap = applicationContext.getBeansOfType(ServiceImpl.class); beansMap.values().forEach(bean -> { bean.setCommandExecutor(processEngineConfiguration.getCommandExecutorTxRequired()); }); } } ``` * mappings:项目中存在两个mapping,一个是Camunda的mapping,一个是自己的mapping。mapping中指定了要读取的Mapper.xml。原本的做法是在项目启动之后读取自己的mapping将Statement添加到Mybatis的Configuration中。但是Camunda在构造SqlSessionFactory之后会解析一遍,这就导致了后面加入的Statement不会被解析,从而无法使用Mybatis中的Configuration变量。然后在后续的代码中无法获取到Parse对象,无法重新进行解析。只能在项目中添加一个路径,这个路径和Camunda中的mappings.xml文件的路径一致,然后将自己的mappings.xml与Camunda的mappings.xml内容进行合并。直接在引擎初始化的一起读取。 ```xml ``` # 2、说明 * 实体类:实体类必须命名为XxxEntity,Camunda源代码中拼接selectById的statement是使用固定的前缀"select" + "实体类的名称",使用substring去掉了尾部的Entity。如果命名不以Entity结尾则会导致statement错误。 ```java package org.augustus.camunda.entity; import org.camunda.bpm.engine.impl.db.DbEntity; import java.util.HashMap; import java.util.List; /** * @author: linyongjin * @create: 2023-05-26 17:17:58 */ public class JoinEntity implements DbEntity { // ... } ``` * 增删查命名:增insertXxx,删deleteXxx,查selectXxx。主键字段的占位符表达式直接写为#{id}即可,因为实体类继承了DbEntity该接口,重写了getId()方法。 ```java // 对应的实体类必须实现该接口 public interface DbEntity { // 这个ID作为实体类的主键属性 String getId(); void setId(String id); Object getPersistentState(); } ``` ```xml insert into act_re_procdef (id_, name_, deployment_id_, key_, version_) values (#{processDefinitionId}, #{processTitle}, #{deploymentId}, #{processKey}, 1) delete from act_re_procdef where id_ = #{id} ``` * 排序:Camunda在SQLSessionFactory中的Property中添加了全局的变量orderBy,在SQL语句中只需要在指定的位置使用${orderBy}并且include一个Mybatis的Sql片段就可以使用排序。具体代码与说明见下面代码片段。 ```xml ``` ```xml ``` ```java List joinEntities = joinService .createJoinQuery() // 在JoinQuery中定义排序的方法 .orderById() // 基类的方法 .asc() .list(); ``` ```java public class JoinQueryImpl extends AbstractQuery implements JoinQuery { // ... @Override public JoinQuery orderById() { // 要排序的字段 return orderBy(new QueryPropertyImpl("ID_")); } } ``` * 分页:Camunda在SQLSessionFactory中的Property中添加了全局的变量limitAfter,在SQL语句中只需要在指定的位置使用${limitAfter}。 ```xml ``` ```java // 第一个参数是开始数据的索引从0开始 // 第二个参数是查询的结果数量 List joinEntities = joinService.createJoinQuery() .listPage(firstResult: 1, maxResults: 1); System.out.println(joinEntities); ```