什么是activiti
activiti是一个业务流程管理的框架,这是一个开源的,首先业务流程管理应用就是BPM(business process management),简单点将就是这玩意儿就是做审批用的,它可以创建审批,以及审批的应用。类似于钉钉这个软件中的OA审批创建一样,创建以后应用过程基本是一致的。
activiti配置
首先activiti是有25张表的,所以对于它的应用个人推荐还是作为一个单独的项目来开发,由这个项目提供服务即可。
首先创建项目配置pom依赖
<properties> <activiti.version>7.0.0.Beta1</activiti.version> </properties> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-engine</artifactId> <version>${activiti.version}</version> </dependency> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-spring</artifactId> <version>${activiti.version}</version> </dependency> <!-- bpmn 模型处理 --> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-bpmn-model</artifactId> <version>${activiti.version}</version> </dependency> <!-- bpmn 转换 --> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-bpmn-converter</artifactId> <version>${activiti.version}</version> </dependency> <!-- bpmn json数据转换 --> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-json-converter</artifactId> <version>${activiti.version}</version> </dependency> <!-- bpmn 布局 --> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-bpmn-layout</artifactId> <version>${activiti.version}</version> </dependency> <!-- activiti 云支持 --> <dependency> <groupId>org.activiti.cloud</groupId> <artifactId>activiti-cloud-services-api</artifactId> <version>${activiti.version}</version> </dependency> <!--数据库连接--> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>
配置文件
基本的配置xml方式
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/contex http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!-- 这里可以使用 链接池 dbcp--> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/activiti" /> <property name="username" value="root" /> <property name="password" value="root" /> <property name="maxActive" value="3" /> <property name="maxIdle" value="1" /> </bean> <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration"> <!-- 引用数据源 上面已经设置好了--> <property name="dataSource" ref="dataSource" /> <!-- activiti数据库表处理策略 --> <property name="databaseSchemaUpdate" value="true"/> </bean> </beans>
第二种方式通过java代码进行配置
import org.apache.commons.dbcp.BasicDataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * DruidDataSourceConfiguration *数据库配置类 * @author 15821 * @date 13:11 2021/12/11 */ @Configuration public class DataSourceConfiguration { @Bean("dataSource") public BasicDataSource getDruidDataSource( @Value("${spring.datasource.driver-class-name}") String driverClassName, // 数据库驱动程序 @Value("${spring.datasource.url}") String url, // 数据库连接地址 @Value("${spring.datasource.username}") String username, // 数据库的用户名 @Value("${spring.datasource.password}") String password, // 数据库的用户名 @Value("${spring.datasource.tomcat.min-idle}") int minIdle, // 最小维持连接数 @Value("${spring.datasource.tomcat.max-active}") int maxActive // 最大连接数 ) { BasicDataSource dataSource = new BasicDataSource(); // 实例化DataSource子类对象 dataSource.setDriverClassName(driverClassName); // 数据库驱动程序 dataSource.setUrl(url); // 数据库的连接地址 dataSource.setUsername(username); // 数据库用户名 dataSource.setPassword(password); // 数据库密码 dataSource.setMinIdle(minIdle); // 最小维持的连接数量 dataSource.setMaxActive(maxActive); // 最大的连接数量 return dataSource; } }
对应数据库的配置信息在yml文件种
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/activiti?nullCatalogMeansCurrent=true username: root password: 123456 tomcat: max-active: 3 min-idle: 1
activiti的引擎配置
import org.activiti.engine.HistoryService; import org.activiti.engine.RepositoryService; import org.activiti.engine.RuntimeService; import org.activiti.engine.TaskService; import org.activiti.spring.ProcessEngineFactoryBean; import org.activiti.spring.SpringProcessEngineConfiguration; import org.apache.commons.dbcp.BasicDataSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.transaction.PlatformTransactionManager; import java.io.IOException; /** * ActivitiConfiguration *activiti的引擎配置 * @author 15821 */ @Configuration public class ActivitiConfiguration { @Autowired @Qualifier("dataSource") private BasicDataSource DataSource; @Autowired private PlatformTransactionManager platformTransactionManager; /** * 注册 activiti的配置信息 */ @Bean("processEngineConfiguration") public SpringProcessEngineConfiguration getProcessEngineConfiguration(){ SpringProcessEngineConfiguration configuration = new SpringProcessEngineConfiguration(); configuration.setDataSource(DataSource); // 添加数据源 configuration.setTransactionManager(platformTransactionManager); // 添加事务 configuration.setDatabaseSchemaUpdate("true"); // 如果有表则不创建 configuration.setDbHistoryUsed(true); // 允许查看历史信息 configuration.buildProcessEngine(); //执行创建25张表,如果已经创建就不再创建了 // 自动部署 bpmn文件 Resource[] resources = null; try { resources= new PathMatchingResourcePatternResolver().getResources("classpath*:bpmn/*.bpmn20.xml"); } catch (IOException e) { e.printStackTrace(); } //这里在程序启动时就去扫描了resource包中的资源,然后进行了部署。不需要在单独部署流程。 configuration.setDeploymentResources(resources); return configuration; } /** * 注册 ProcessEngineFactoryBean */ @Bean public ProcessEngineFactoryBean processEngine(){ ProcessEngineFactoryBean factoryBean = new ProcessEngineFactoryBean(); factoryBean.setProcessEngineConfiguration(getProcessEngineConfiguration()); return factoryBean; } /** * 注册 RepositoryService */ @Bean public RepositoryService repositoryService() throws Exception{ return processEngine().getObject().getRepositoryService(); } /** * 注册 RuntimeService */ @Bean public RuntimeService runtimeService() throws Exception{ return processEngine().getObject().getRuntimeService(); } /** * 注册 TaskService */ @Bean public TaskService taskService() throws Exception{ return processEngine().getObject().getTaskService(); } /** * 注册 HistoryService */ @Bean public HistoryService historyService() throws Exception{ return processEngine().getObject().getHistoryService(); } }
这是两种配置方式,配置完成以后启动程序后activiti会自动创建数据表一共25张。关于这个25张表的功能这里就不赘述了,有需要的可以上网查一下都有说明。
至此我们的程序就启动成功了。
那么审批(流程)怎么创建呢?
可以通过在idea种安装插件创建流程
搜索:Activiti BPMN visualizer,我这里是已经安装好的。
这里使用这个可视化界面可以进行bpm文件的编辑,鼠标右击会出现菜单,根据菜单选择需要的结点。
结点中的信息配置如下:
这里设置的任务处理人这里是设置的变量,方便动态设置后面会讲到这个怎么使用
以上这些就是流程模板的创建了。
下面就是在代码中具体操作了。
首先我们要知道activiti有一个流程引擎,这个引擎可以为我们提供7种服务
RepositoryServer:操作流程定义的方法。
Runtime:操作流程实例的方法。
FormServer:操作流程表单的方法。
TaskServer:操作任务的方法,例如(任务的完成、挂起、激活、添加处理人、认领、删除等操作)
HistoryServer:查询历史流程实例、历史变量、历史任务的方法
IdentityServer:操作用户或者用户组的方法。
ManagementServer:查询数据库表中的数据、表的元数据以及命令等方法。
我这次使用只有这两个加粗标记的服务,其它服务暂时还没有涉及到
流程启动
这个使用的就是Runtime的服务,这是创建流程实例的moudleName,这个参数是你创建的流程种的 这个id值,后面这个variables是一个map<String,Object>,这个map的key放的就是刚才我们设置的任务处理人的这个变量名称"Sponsor"
Object就是具体的参数了。这是流程实例开启时,需要放入的参数。如果你流程不需要动态参数而是已经制定好的参数那么startProcessInstanceByKey()这个方法时可以不传入这个map参数。
ProcessInstance ins = runtimeService.startProcessInstanceByKey(moudleName, variables);
这个流程实例创建成功后返回的这个ProcessInstance 对象中有该实例的id,后续会用。
任务处理
既然这个流程实例创建以后那么对应的流程中设置任务结点也就会产生,每个任务结点都有对应的处理,只有结点执行完毕这个流程实例才会被删除。
每一个结点的执行处理都需要这个taskService。
这里通过使用processInstanceId()根据流程实例id获取当前实例的任务
Task task = taskService.createTaskQuery() .processInstanceId(processInstanceId) .singleResult();
获取到当前流程实例的任务以后我们可以根据任务的id对这个任务做一些处理,比如根据id完成当前任务,那么流程会继续向下执行,这个任务点就算结束了。
activiti问题分享
数据库创建问题
在项目初期进行部署的时候需要创建数据表,那么数据库创建好了,但是数据表是由activiti创建的。就是咱们配置的datasource这个配置了“nullCatalogMeansCurrent”
这个配置的作用
nullCatalogMeansCurrent = true: 返回指定库涉及表 nullCatalogMeansCurrent = false: 返回所有库涉及表
创建表的时候会先去数据库的information_schema.TABLES中查找字段为TABLE_NAME是否有activiti相关的表。如果有则不进行创建数据表了。所以如果有用于测试的数据库进行已经有了一些activiti的数据表的话,我们进行正式创建的时候在项目的数据库连接的配置里面要加上 nullCatalogMeansCurrent = true: 返回指定库涉及表 这个配置。防止出现数据表没有创建上但也没有提示创建失败这个情况。
activiti事件监听器没有对象的问题
我们业务中有一个功能,就是让流程中的审批人员动态设置,而这里我想到的是使用监听器来动态的配置每一个流程任务结点的负责人。在这里有一个问题就是在本篇博客的上面设置项目的时候我们使用的那6个服务都交由spring bean容器管理了,所以在自己设置的监听器这个类中使用这些服务对象的时候就也是使用注入的形式。但是并没有生效,而是提示null空指针的问题。后来网上查阅资料以及做实验发现。activiti的监听器调用并没有和spring bean 容器做共享。 而是自己实例化调用的我们的写的监听器。
自己编写监听器要实现activiti的TaskListener 这个接口。
public class TaskListenerForSetttingNextAssigneeImpl implements TaskListener { @Override public void notify(DelegateTask delegateTask) { //activiti中监听类不归Spring管,真正使用的时候实际上是使用 new 对象的方式去使用(在当前监听类上加@Service注解没用) //所以我们要自己写一个工具类去获取TaskService 的对象(ActivitiConfiguration 中已经将这个类对象放在了SpringIOC容器中) //我们要做的是手动拿出SpringIOC容器中TaskService的对象供我们使用 TaskService taskService= SpringUtil.getObject(TaskService.class); //获取当前执行到的任务节点信息 //通过taskService 中装入的变量信息(实际上装的是下一个审批人) String userId=taskService.getVariable(delegateTask.getId(),"nextUserId").toString(); //设置当前任务的执行人 delegateTask.setAssignee(userId); } }
这是监听器的配置。这个是任务结点监听器,还有其它两个监听器。这里没有使用就不做叙述了。而且本人还没有具体去学习,,,嘿嘿
后续这个项目如果继续开发了,博主会继续更新相关的使用方式以及碰到的问题解决方法。
以上内容如果有问题的地方还请指出。
/