工作流的23张表是如何存取的?每一步操作逻辑是什么样子的?我们来学习一下。
一、管理流程定义
1设计流程定义文档
1.1流程图
我们之前已经看过,常见流程图如下如所示:
包含了开始节点/结束节点/任务/流向线
1.2bpmn文件
BPMN 2.0根节点是definitions节点。 这个元素中,可以定义多个流程定义(不过我们建议每个文件只包含一个流程定义, 可以简化开发过程中的维护难度)。 一个空的流程定义看起来像下面这样。注意,definitions元素 最少也要包含xmlns 和 targetNamespace的声明。 targetNamespace可以是任意值,它用来对流程实例进行分类。
说明:流程定义文档有两部分组成:
1)bpmn文件
流程规则文件。在部署后,每次系统启动时都会被解析,把内容封装成流程定义放入项目缓存中。Activiti框架结合这个xml文件自动管理流程,流程的执行就是按照bpmn文件定义的规则执行的,bpmn文件是给计算机执行用的。
2)展示流程图的图片
在系统里需要展示流程的进展图片,图片是给用户看的。
2部署流程定义(classpath路径加载文件)
/**部署流程定义*/
@Test
public void deploymentProcessDefinition(){
//与流程定义和部署对象相关的Service
RepositoryService repositoryService=processEngine.getRepositoryService();
DeploymentBuilder deploymentBuilder=repositoryService.createDeployment();//创建一个部署对象
deploymentBuilder.name("helloWorld入门程序");//添加部署的名称
deploymentBuilder.addClasspathResource("diagrams/MyProcess.bpmn");//从classpath的资源加载,一次只能加载一个文件
deploymentBuilder.addClasspathResource("diagrams/MyProcess.png");//从classpath的资源加载,一次只能加载一个文件
Deployment deployment=deploymentBuilder.deploy();//完成部署
//打印我们的流程信息
System.out.println("部署Id:"+deployment.getId());
System.out.println("部署名称Name:"+deployment.getName());
}
说明:
1)先获取流程引擎对象:在创建时会自动加载classpath下的activiti.cfg.xml
//获取流程引擎对象
//getDefaultProcessEngine方法内部会自动读取名为activiti.cfg.xml文件的配置信息
ProcessEngine processEngine=ProcessEngines.getDefaultProcessEngine();
2)首先获得默认的流程引擎,通过流程引擎获取了一个RepositoryService对象(仓库对象)
3)由仓库的服务对象产生一个部署对象配置对象,用来封装部署操作的相关配置。
4)这是一个链式编程,在部署配置对象中设置显示名,上传流程定义规则文件
5)向数据库表中存放流程定义的规则信息。
6)这一步在数据库中将操作三张表:
a)act_re_deployment(部署对象表)
存放流程定义的显示名和部署时间,每部署一次增加一条记录
注:如果部署相同Key的流程,那么Version将会升级,也就是版本升级:
图7.2.jpg
启动该Key的流程时,默认启动最新版本(Version)的流程。
b)act_re_procdef(流程定义表)
存放流程定义的属性信息,部署每个新的流程定义都会在这张表中增加一条记录。
注意:当流程定义的key相同的情况下,使用的是版本升级。
c)act_ge_bytearray(资源文件表)
存储流程定义相关的部署信息。即流程定义文档的存放地。每部署一次就会增加两条记录,
一条是关于bpmn规则文件的,一条是图片的(如果部署时只指定了bpmn一个文件,activiti
会在部署时解析bpmn文件内容自动生成流程图)。两个文件不是很大,都是以二进制形式存储在数据库中。
注意,部署流程定义的时候,可以把bpmn文件和png文件压缩成ZIP格式的压缩文件
进行上传:
处理代码有所改变:
/**部署流程定义(Zip)*/
@Test
public void deploymentProcessDefinitionZip(){
//获得上传文件的输入流程
InputStream in=this.getClass().getClassLoader().getResourceAsStream("diagrams/MyProcess.zip");
ZipInputStream zipInputStream=new ZipInputStream(in);
//获取仓库服务,从类路径下完成部署
RepositoryService repositoryService=processEngine.getRepositoryService();
DeploymentBuilder deploymentBuilder=repositoryService.createDeployment();//创建一个部署对象
deploymentBuilder.name("helloWorld入门程序");//添加部署的名称
deploymentBuilder.addZipInputStream(zipInputStream);
Deployment deployment=deploymentBuilder.deploy();//完成部署
//打印我们的流程信息
System.out.println("部署Id:"+deployment.getId());
System.out.println("部署名称Name:"+deployment.getName());
}
3.查看流程定义
查询流程定义的信息
/**查看流程定义
* id:(key):(version):(随机值)
* name:对应流程文件process节点的name属性
* key:对应流程文件process节点的id属性
* version:发布时自动生成的。如果是第一次发布的流程,version默认从1开始;
* 如果当前流程引擎中已存在相同的流程,则找到当前key对应的最高版本号,在最高版本号上加1*/
@Test
public void queryProcessDefinition() throws Exception{
//获取仓库服务对象,使用版本的升级排列,查询列表
List<ProcessDefinition> pdList=processEngine.getRepositoryService()
.createProcessDefinitionQuery()
//添加查询条件
//.processDefinitionId(processDefinitionId)
//.processDefinitionKey(processDefinitionKey)
//.processDefinitionName(processDefinitionName)
//排序(可以按照id/key/name/version/Cagetory排序)
.orderByProcessDefinitionVersion().asc()
//.count()
//.listPage(firstResult, maxResults)
//.singleResult()
.list();//总的结果集数量
//便利集合,查看内容
for (ProcessDefinition pd:pdList) {
System.out.println("id:"+pd.getId());
System.out.println("name:"+pd.getName());
System.out.println("key:"+pd.getKey());
System.out.println("version:"+pd.getVersion());
System.out.println("resourceName:"+pd.getDiagramResourceName());
System.out.println("###########################################");
}
}
结果:
我们再次部署一次HelloWorld流程(用刚刚的Zip):
那么查询流程定义的信息的运行结果为:
可以看到流程定义的key值相同的情况下,版本是从1开始逐次升级的
流程定义的Id是【key:版本:生成ID】
说明:
1)流程定义和部署对象相关的Service都是RepositoryService。
2)创建流程定义查询对象,可以在ProcessDefinitionQuery上设置查询的相关参数
3)调用ProcessDefinitionQuery对象的list方法,执行查询,获得符合条件的流程定义列表
4)由运行结果可以看出:
Key和Name的值为:bpmn文件process节点的id和name的属性值
5)key属性被用来区别不同的流程定义。
6)带有特定key的流程定义第一次部署时,version为1。之后每次部署都会在当前最高版本号上加1
7)Id的值的生成规则为:{processDefinitionKey}:{processDefinitionVersion}:{generated-id}, 这里的generated-id是一个自动生成的唯一的数字
8)重复部署一次,deploymentId的值以一定的形式变化
规则act_ge_property表生成
4.删除流程定义
删除部署到activiti中的流程定义。
/**删除流程*/
@Test
public void deleteDeployment(){
//删除发布信息
String deploymentId="1";
//获取仓库服务对象
RepositoryService repositoryService=processEngine.getRepositoryService();
//普通删除,如果当前规则下有正在执行的流程,则抛异常
//repositoryService.deleteDeployment(deploymentId);
//级联删除,会删除和当前规则相关的所有信息,正在执行的信息,也包括历史信息
repositoryService.deleteDeployment(deploymentId, true);
}
说明:
1)因为删除的是流程定义,而流程定义的部署是属于仓库服务的,所以应该先得到RepositoryService
2)如果该流程定义下没有正在运行的流程,则可以用普通删除。如果是有关联的信息,用级联删除。项目开发中使用级联删除的情况比较多,删除操作一般只开放给超级管理员使用。
5.获取流程定义文档的资源(查看流程图附件)
查询出流程定义文档。主要查的是图片,用于显示流程用。
/**查看流程附件(查看流程图片)*/
@Test
public void viewImage() throws Exception{
//从仓库中找需要展示的文件
String deploymentId="1";
List<String> names=processEngine.getRepositoryService()
.getDeploymentResourceNames(deploymentId);
String imageName=null;
for(String name:names){
System.out.println("name:"+name);
if(name.indexOf(".png")>0){
imageName=name;
break;
}
}
System.out.println("imageName:"+imageName);
if(imageName!=null){
File f=new File("e:/"+imageName);
//通过部署ID和文件名称得到文件的输入流
InputStream in = processEngine.getRepositoryService()
.getResourceAsStream(deploymentId, imageName);
FileUtils.copyInputStreamToFile(in, f);
}
}
运行结果:
说明:
1)deploymentId为流程部署ID
2)resourceName为act_ge_bytearray表中NAME_列的值
图7.9.jpg
3)使用repositoryService的getDeploymentResourceNames方法可以获取指定部署下得所有文件的名称
图7.10.jpg
4)使用repositoryService的getResourceAsStream方法传入部署ID和资源图片名称可以获取部署下指定名称文件的输入流
5)最后的有关IO流的操作,使用FileUtils工具的copyInputStreamToFile方法完成流程流程到文件的拷贝,将资源文件以流的形式输出到指定文件夹下。
如果我们的流程需要修改应该怎么操作呢?请看下一篇