工作流第七篇之流程存储

RepositoryService主要用于对Activiti中的流程存储的相关数据进行操作,这些操作包括对流程存储数据的管理、流程部署以及对流程的基本操作等。
流程文件部署
RepositoryService负责对流程文件的部署以及流程的定义进行管理,不管是JBPM还是Activiti等工作流引擎,都会产生流程文件,工作流引擎需要对这些文件进行管理,这些文件包括流程描述文件、流程图等。
在Activiti中,如果需要对这些资源文件进行操作(包括添加、删除、查询等),可以使用RepositoryService提供的API。这些文件数据被保存在ACT_GE_BYTEARRAY表中,对应的实体为ResourceEntityImpl。
设置用户图片同样会向ACT_GE_BYTEARRAY表中写入数据,但是当数据为用户图片时,对应的实体是ByteArrayEntityImpl。ResourceEntityImpl与ByteArrayEntityImpl区别如下。
➢ ByteArrayEntityImpl对应的数据有版本管理数据,而ResourceEntityImpl则没有。
➢ ResourceEntityImpl 会设置 ACT_GE_BYTEARRAY 表的 GENERATED_字段值,而ByteArrayEntityImpl在进行保存时,该值为null。

Deployment对象
Deployment对象是一个接口,一个Deployment实例表示一条ACT_RE_DEPLOYMENT表的数据,同样,Deployment也遵循Activiti的实体命名规则,子接口为DeploymentEntity,实现类为DeploymentEntityImpl。如果要对属性进行修改,需要调用DeploymentBuilder提供的方法,Deployment只提供了一系列getter方法。DeploymentEntityImpl中包含以下映射属性。
➢ id:主键,对应ACT_RE_DEPLOYMENT表的ID_列。
➢ name:部署名称,对应ACT_RE_DEPLOYMENT表的NAME_列。
➢ deploymentTime:部署时间,对应DEPLOY_TIME_列。
➢ category:部署的类别,对应CATEGORY_列。
➢ tenantId:在云时代,同一个软件有可能被多个租户所使用,因此 Activiti 在部署、流程定义等数据中都预留了tenantId字段。
➢ key:为部署设置键属性,保存在KEY_列。
DeploymentBuilder对象
对流程文件进行部署,需要使用DeploymentBuilder对象,获取该对象,可以调用RepositoryService的createDeployment方法,
DeploymentBuilder中包含了多个addXXX方法,可以用于为部署添加资源,这些方法有:
➢ addClasspathResource(String resource):添加classpath下的资源文件。
➢ addInputStream(String resourceName,InputStream):添加输入流资源。
➢ addString(String resourceName,String text):添加字符串资源。
➢ addZipInputStream(ZipInputStream inputStream):添加zip压缩包资源。
➢ addBpmnModel(String resourceName,BpmnModel bpmnModel):解析BPMN模型对象,并作为资源保存。
➢ addBytes(String resourceName,byte[] bytes):添加字节资源。
除此之外,还提供了修改部署信息的方法,例如key、name、category等。下面将讲述这些方法的使用。
添加输入流资源
在DeploymentEntityImpl类中,使用一个Map来维护资源,表示一次部署中会有多个资源,就是我们平常所说的一对多关系。调用DeploymentBuilder的addInputStream方法,实际上就是往DeploymentEntityImpl的Map里面添加元素,Map的key是资源名称,value是解析InputStream后获得的byte数组。
使用addInputStream方法添加部署流程图资源。

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.DeploymentBuilder;
/**
 * 调用DeploymentBuilder的AddInputStream方法
 * 
 * @author yangenxiong
 * 
 */
public class AddInputStream {

	public static void main(String[] args) throws Exception {
		// 创建流程引擎
		ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
		// 得到流程存储服务实例
		RepositoryService repositoryService = engine.getRepositoryService();
		// 第一个资源输入流
		InputStream is1 = new FileInputStream(new File(
				"resource/artifact/flow_inputstream1.png"));
		// 第二个资源输入流
		InputStream is2 = new FileInputStream(new File(
				"resource/artifact/flow_inputstream1.png"));
		// 创建DeploymentBuilder实例
		DeploymentBuilder builder = repositoryService.createDeployment();
		// 为DeploymentBuilder添加资源输入流
		builder.addInputStream("inputA", is1);
		builder.addInputStream("inputB", is2);
		// 执行部署方法
		builder.deploy();
	}

}

工作流第七篇之流程存储工作流第七篇之流程存储 添加classpath资源
与addInputStream方法类似,addClasspathResource方法也是往部署实体的Map里面添加元素,但不同的是,addClasspathResource方法会得到当前的ClassLoader对象。调用getResourceAsStream方法将指定的classpath下的资源文件转换为InputStream,再调用addInputStream方法。

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.DeploymentBuilder;

/**
 * 调用DeploymentBuilder的AddClasspathResource方法
 * @author yangenxiong
 *
 */
public class AddClasspathResource {

	public static void main(String[] args) {
		//创建流程引擎
		ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
		//得到流程存储服务对象
		RepositoryService repositoryService = engine.getRepositoryService();
		//创建DeploymentBuilder实例
		DeploymentBuilder builder = repositoryService.createDeployment();
		//添加classpath下的资源
		builder.addClasspathResource("artifact/classpath.png");
		//执行部署(写入到数据库中)
		builder.deploy();		
	}
}

使用addClasspathResource方法将一份图片文件保存到ACT_GE_BYTEARRAY表中。需要注意的是,使用addClasspathResource方法并不需要指定名称参数,Activiti会使用其传入的路径作为资源的名称。
工作流第七篇之流程存储


import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.DeploymentBuilder;

/**
 * 调用DeploymentBuilder的AddString方法
 * @author yangenxiong
 *
 */
public class AddString {

	public static void main(String[] args) {
		//创建流程引擎
		ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
		//得到流程存储服务对象
		RepositoryService repositoryService = engine.getRepositoryService();
		//创建DeploymentBuilder实例
		DeploymentBuilder builder = repositoryService.createDeployment();
		//添加String资源
		builder.addString("test", "this is string method");
		//执行部署(写入到数据库中)
		builder.deploy();
	}

}

添加压缩包资源
在实际应用中,可能需要将多个资源部署到流程引擎中,如果这些关联的资源被放在一个压缩包(zip包)中,则可以使用DeploymentBuilder提供的addZipInputStream方法直接部署压缩包,该方法会遍历压缩包内的全部文件,然后将这些文件转换为byte数组,写到资源表中。使用addZipInputStream方法添加资源。

import java.io.File;
import java.io.FileInputStream;
import java.util.zip.ZipInputStream;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.DeploymentBuilder;

/**
 * 调用DeploymentBuilder的AddZipInputStream方法
 * @author yangenxiong
 *
 */
public class AddZipInputStream {

	public static void main(String[] args) throws Exception {
		//创建流程引擎
		ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
		//得到流程存储服务对象
		RepositoryService repositoryService = engine.getRepositoryService();
		//创建DeploymentBuilder实例
		DeploymentBuilder builder = repositoryService.createDeployment();
		//获取zip文件的输入流
		FileInputStream fis = new FileInputStream(new File("resource/artifact/ZipInputStream.zip"));
		//读取zip文件,创建ZipInputStream对象
		ZipInputStream zi = new ZipInputStream(fis);
		//添加Zip压缩包资源
		builder.addZipInputStream(zi);
		//执行部署(写入到数据库中)
		builder.deploy();
	}

}

添加BPMN模型资源
DeploymentBuilder提供了一个addBpmnModel方法,可传入BPMN规范的模型(BpmnModel类)来进行部署

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.EndEvent;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.bpmn.model.StartEvent;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.DeploymentBuilder;

public class AddBpmnModel {

	public static void main(String[] args) {
		// 创建流程引擎
		ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
		// 得到流程存储服务对象
		RepositoryService repositoryService = engine.getRepositoryService();
		// 创建DeploymentBuilder实例
		DeploymentBuilder builder = repositoryService.createDeployment();
		builder.addBpmnModel("MyCodeProcess", createProcessModel())
				.name("MyCodeDeploy").deploy();
	}

	private static BpmnModel createProcessModel() {
		// 创建BPMN模型对象
		BpmnModel model = new BpmnModel();
		org.activiti.bpmn.model.Process process = new org.activiti.bpmn.model.Process();
		model.addProcess(process);
		process.setId("myProcess");
		process.setName("My Process");
		// 开始事件
		StartEvent startEvent = new StartEvent();
		startEvent.setId("startEvent");
		process.addFlowElement(startEvent);
		// 用户任务
		UserTask userTask = new UserTask();
		userTask.setName("User Task");
		userTask.setId("userTask");
		process.addFlowElement(userTask);
		// 结束事件
		EndEvent endEvent = new EndEvent();
		endEvent.setId("endEvent");
		process.addFlowElement(endEvent);
		// 添加流程顺序
		process.addFlowElement(new SequenceFlow("startEvent", "userTask"));
		process.addFlowElement(new SequenceFlow("userTask", "endEvent"));
		return model;
	}
}

修改部署信息
使用DeploymentBuilder的name、key、category、tenanId方法可以设置部署属性,保存后会将数据保存到ACT_RE_DEPLOYMENT表的对应字段中。

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.DeploymentBuilder;

/**
 * 使用DeploymentBuilder的name方法
 * @author yangenxiong
 *
 */
public class Name {

	public static void main(String[] args) {
		//创建流程引擎
		ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
		//得到流程存储服务对象
		RepositoryService repositoryService = engine.getRepositoryService();
		//创建DeploymentBuilder实例
		DeploymentBuilder builder = repositoryService.createDeployment();
		//设置各个属性
		builder.name("crazyit").tenantId("tenanId").key("myKey").category("myCategory");
		//执行部署(写入到数据库中)
		builder.deploy();
	}

}

过滤重复部署
进行了第一次部署后,资源没有发生变化而再次进行部署,同样会将部署数据写入数据库中,想避免这种情况,可以调用DeploymentBuilder的enableDuplicateFiltering方法,该方法仅将DeploymentBuilder的isDuplicateFilterEnabled属性设置为true。在执行deploy方法时,如果发现该值为true,则根据部署对象的名称去查找最后一条部署记录,如果发现最后一条部署记录与当前需要部署的记录一致,则不会重复部署。
搭建环境
创建activiti.cfg.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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/act" />
		<property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
		<property name="jdbcUsername" value="root" />
		<property name="jdbcPassword" value="root" />
		<property name="databaseSchemaUpdate" value="true"/>
	</bean>

</beans>

创建log4j.properties配置文件

# Set root category priority to INFO and its only appender to CONSOLE.
log4j.rootCategory=INFO, CONSOLE
#log4j.rootCategory=INFO, CONSOLE, LOGFILE

# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE

# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1} - %m%n
log4j.logger.org.apache=INFO
log4j.logger.org.htmlparser=INFO
log4j.logger.org.htmlparser=INFO
log4j.logger.com.angus=INFO

创建DuplicateFilter.txt

abc

创建DuplicateFilterB.txt

abc

测试

package org.crazyit.activiti;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;

/**
 * 
 * @author yangenxiong
 *
 */
public class DuplicateFilter {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		//创建流程引擎
		ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
		//得到流程存储服务实例
		RepositoryService repositoryService = engine.getRepositoryService();
		//创建第一个部署对象
		DeploymentBuilder builderA = repositoryService.createDeployment();
		builderA.addClasspathResource("artifact/DuplicateFilter.txt");
		builderA.name("DuplicateFilterA");
		builderA.deploy();		
		//由于资源一样,并且调用了enableDuplicateFiltering方法,因此不会再写入到数据库中
		DeploymentBuilder builderB = repositoryService.createDeployment();
		builderB.addClasspathResource("artifact/DuplicateFilter.txt");
		builderB.name("DuplicateFilterA");
		builderB.enableDuplicateFiltering();
		builderB.deploy();
		//由于资源发生变化,即使调用了enableDuplicateFiltering方法,也会写到数据库中
		DeploymentBuilder builderC = repositoryService.createDeployment();
		builderC.addClasspathResource("artifact/DuplicateFilterB.txt");
		builderC.name("DuplicateFilterA");
		builderC.enableDuplicateFiltering();
		builderC.deploy();
	}
}

取消部署时的验证
默认情况下,在部署时会对流程的XML文件进行验证,包括验证是否符合BPMN 2.0的规范、定义的流程是否可执行。如果XML文件不符合规范或者定义的流程不可执行,那么将会在部署时抛出异常。如果想跳过这两个验证,可以调用DeploymentBuilder的disableSchemaValidation与disableBpmnValidation方法。
创建bpmnError.bpmn.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
  <process id="vacationProcess" name="vacation" isExecutable="true">
    <startEvent id="startevent1" name="Start"></startEvent>
    <userTask id="usertask1" name="User Task"></userTask>
    <startEvent id="startevent2" name="Start"></startEvent>
    <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
    <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="startevent2"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_vacationProcess">
    <bpmndi:BPMNPlane bpmnElement="vacationProcess" id="BPMNPlane_vacationProcess">
      <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="50.0" y="122.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
        <omgdc:Bounds height="60.0" width="100.0" x="190.0" y="110.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="startevent2" id="BPMNShape_startevent2">
        <omgdc:Bounds height="35.0" width="35.0" x="370.0" y="122.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
        <omgdi:waypoint x="85.0" y="139.0"></omgdi:waypoint>
        <omgdi:waypoint x="158.0" y="139.0"></omgdi:waypoint>
        <omgdi:waypoint x="190.0" y="140.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
        <omgdi:waypoint x="290.0" y="140.0"></omgdi:waypoint>
        <omgdi:waypoint x="370.0" y="139.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

工作流第七篇之流程存储创建xmlError.bpmn.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn"
	xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
	xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema"
	expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
	<process id="vacationProcess" name="vacation">
		<userTask id="usertask1" name="User Task"></userTask>
		<endEvent id="endevent1" name="End"></endEvent>
		<sequenceFlow id="flow2" name="" sourceRef="usertask1"
			targetRef="endevent1"></sequenceFlow>
		<startEvent id="startevent1" name="Start"></startEvent>
		<sequenceFlow id="flow3" name="" sourceRef="startevent1"
			targetRef="usertask1"></sequenceFlow>
	</process>
	<abc></abc>
	<bpmndi:BPMNDiagram id="BPMNDiagram_vacationProcess">
		<bpmndi:BPMNPlane bpmnElement="vacationProcess"
			id="BPMNPlane_vacationProcess">
			<bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
				<omgdc:Bounds height="55" width="105" x="310" y="160"></omgdc:Bounds>
			</bpmndi:BPMNShape>
			<bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
				<omgdc:Bounds height="35" width="35" x="490" y="170"></omgdc:Bounds>
			</bpmndi:BPMNShape>
			<bpmndi:BPMNShape bpmnElement="startevent1"
				id="BPMNShape_startevent1">
				<omgdc:Bounds height="35" width="35" x="170" y="170"></omgdc:Bounds>
			</bpmndi:BPMNShape>
			<bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
				<omgdi:waypoint x="415" y="187"></omgdi:waypoint>
				<omgdi:waypoint x="490" y="187"></omgdi:waypoint>
			</bpmndi:BPMNEdge>
			<bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
				<omgdi:waypoint x="205" y="187"></omgdi:waypoint>
				<omgdi:waypoint x="310" y="187"></omgdi:waypoint>
			</bpmndi:BPMNEdge>
		</bpmndi:BPMNPlane>
	</bpmndi:BPMNDiagram>
</definitions>

工作流第七篇之流程存储
测试

package org.crazyit.activiti;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.DeploymentBuilder;

public class DisableValidation {

	public static void main(String[] args) {
		// 创建流程引擎
		ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
		// 得到流程存储服务实例
		RepositoryService repositoryService = engine.getRepositoryService();
		// 部署一份错误的xml文件,不会报错
		DeploymentBuilder builderA = repositoryService.createDeployment();
		builderA.addClasspathResource("bpmn/xmlError.bpmn")
				.disableSchemaValidation().deploy();
		// 部署一份不可执行bpmn文件,不会报错
		DeploymentBuilder builderB = repositoryService.createDeployment();
		builderB.addClasspathResource("bpmn/bpmnError.bpmn")
				.disableBpmnValidation().deploy();
	}

}

流程定义的管理
这里所说的流程定义管理是指由RepositoryService提供的一系列对流程定义的控制,包括中止流程定义、激活流程定义和设置流程权限等。
ProcessDefinition对象
ProcessDefinition对象是一个接口,一个ProcessDefinition实例表示一条流程定义数据,在Activiti中,它的实现类为ProcessDefinitionEntityImpl,对应的数据表为ACT_RE_PROCDEF。ProcessDefinition接口有以下方法。
➢ getCategory:返回流程定义的category属性,对应CATEGORY_字段的值。
➢ getDeploymentId:返回部署的 id,这个流程定义是由哪次部署产生的,对应字段为DEPLOYMENT_ID_。
➢ getDescription:返回流程定义的描述。
➢ getDiagramResourceName:如果流程定义有流程图的话,将返回流程图对应的资源名称。
➢ getEngineVersion:返回流程引擎版本,当前无须关心该方法。
➢ getId:返回流程定义主键。
➢ getKey:返回流程定义的名称,此名称唯一。
➢ getName:返回流程定义显示的名称。
➢ getResourceName:在部署时,会将流程定义的XML文件存到资源表中,该方法返回资源的名称。
➢ getTenantId:返回租户ID。
➢ getVersion:返回流程定义的版本号,对应VERSION_字段,注意并不是revision属性。
➢ hasGraphicalNotation:该流程定义文件是否有流程图的XML元素。
➢ hasStartFormKey:流程的开始事件中是否存在activiti:formKey的定义。
➢ isSuspended:是否为中断状态,SUSPENSION_STATE_字段值为1表示激活状态,值为2则表示中断状态。
流程部署
流程部署实际上就是将流程的描述文件写入数据库中,Activiti在获取资源文件后,会对其后缀进行解析,如果后缀名为“BPMN 20.xml”或者“bpmn”,则它们均会被看作流程描述文件,交由Activiti的Deployer(部署流程描述文件实现类为BpmnDeployer)进行部署。
创建processDeploy.bpmn.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn"
	xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
	xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema"
	expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
	<process id="vacationProcess" name="vacation">
		<userTask id="usertask1" name="User Task"></userTask>
		<endEvent id="endevent1" name="End"></endEvent>
		<sequenceFlow id="flow2" name="" sourceRef="usertask1"
			targetRef="endevent1"></sequenceFlow>
		<startEvent id="startevent1" name="Start"></startEvent>
		<sequenceFlow id="flow3" name="" sourceRef="startevent1"
			targetRef="usertask1"></sequenceFlow>
	</process>
	<bpmndi:BPMNDiagram id="BPMNDiagram_vacationProcess">
		<bpmndi:BPMNPlane bpmnElement="vacationProcess"
			id="BPMNPlane_vacationProcess">
			<bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
				<omgdc:Bounds height="55" width="105" x="310" y="160"></omgdc:Bounds>
			</bpmndi:BPMNShape>
			<bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
				<omgdc:Bounds height="35" width="35" x="490" y="170"></omgdc:Bounds>
			</bpmndi:BPMNShape>
			<bpmndi:BPMNShape bpmnElement="startevent1"
				id="BPMNShape_startevent1">
				<omgdc:Bounds height="35" width="35" x="170" y="170"></omgdc:Bounds>
			</bpmndi:BPMNShape>
			<bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
				<omgdi:waypoint x="415" y="187"></omgdi:waypoint>
				<omgdi:waypoint x="490" y="187"></omgdi:waypoint>
			</bpmndi:BPMNEdge>
			<bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
				<omgdi:waypoint x="205" y="187"></omgdi:waypoint>
				<omgdi:waypoint x="310" y="187"></omgdi:waypoint>
			</bpmndi:BPMNEdge>
		</bpmndi:BPMNPlane>
	</bpmndi:BPMNDiagram>
</definitions>

工作流第七篇之流程存储
流程部署测试

package org.crazyit.activiti;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;

/**
 * 部署流程文件
 * @author yangenxiong
 *
 */
public class ProcessDeploy {

	public static void main(String[] args) {
		//创建流程引擎
		ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
		//得到流程存储服务对象
		RepositoryService repositoryService = engine.getRepositoryService();
		//创建DeploymentBuilder实例
		DeploymentBuilder builder = repositoryService.createDeployment();
		builder.addClasspathResource("bpmn/processDeploy.bpmn").deploy();
	}
}

流程图部署测试代码

package org.crazyit.activiti;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;

/**
 * 部署流程图
 * 
 * @author yangenxiong
 *
 */
public class DeployDiagram {

	public static void main(String[] args) {
		// 创建流程引擎
		ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
		// 得到流程存储服务实例
		RepositoryService repositoryService = engine.getRepositoryService();		
		//部署流程描述文件与流程图
		Deployment dep = repositoryService.createDeployment()
				.addClasspathResource("bpmn/diagram.bpmn")
				.addClasspathResource("bpmn/diagram.png").deploy();
		//查询流程定义实体
		ProcessDefinition def = repositoryService.createProcessDefinitionQuery()
				.deploymentId(dep.getId()).singleResult();
		// 输出结果为 bpmn/diagram.vacationProcess.png
		System.out.println(def.getDiagramResourceName());
	}
}

流程图自动生成
如果在部署时我们不提供流程图,但在流程定义的XML文件中保存了BPMN流程图的元素,则Activiti会自动生成流程图,并保存到资源表中。如果不希望Activiti帮我们生成流程图,则可以在流程引擎配置文件中加入以下属性:
工作流第七篇之流程存储

package org.crazyit.activiti;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;

public class NoGenDiagram {

	public static void main(String[] args) {
		// 创建流程引擎
		ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
		// 得到流程存储服务实例
		RepositoryService repositoryService = engine.getRepositoryService();
		// 部署流程描述文件与流程图
		Deployment dep = repositoryService.createDeployment()
				.addClasspathResource("bpmn/noGenDiagram.bpmn").deploy();
		// 查询流程定义实体
		ProcessDefinition def = repositoryService
				.createProcessDefinitionQuery().deploymentId(dep.getId())
				.singleResult();
		// 输出结果为 bpmn/diagram.vacationProcess.png
		System.out.println("自动生成流程图:" + def.getDiagramResourceName());

		// 读取不生成流程图的配置文件
		ProcessEngineConfiguration config = ProcessEngineConfiguration
				.createProcessEngineConfigurationFromResource("noGenDiagram.cfg.xml");
		ProcessEngine noGenEngine = config.buildProcessEngine();
		RepositoryService noGenService = noGenEngine.getRepositoryService();
		Deployment noGenDep = noGenService.createDeployment()
				.addClasspathResource("bpmn/noGenDiagram.bpmn").deploy();
		ProcessDefinition noGenDef = noGenService
				.createProcessDefinitionQuery().deploymentId(noGenDep.getId())
				.singleResult();
		// 输出结果为null
		System.out.println("不生成流程图,查询资源为:" + noGenDef.getDiagramResourceName());
	}
}

中止与激活流程定义
RepositoryService中提供了多个中止与激活流程定义的方法,可以将流程定义的数据置为中止与激活状态。其中有多个suspendProcessDefinitionById、suspendProcessDefinitionByKey重载的中止方法,也有多个activateProcessDefinitionById、activateProcessDefinitionByKey重载的激活方法。以activateProcessDefinitionById方法为例,有两个重载方法。
➢ activateProcessDefinitionById(String processDefinitionId):根据流程定义的id激活流程定义。
➢ activateProcessDefinitionById(String processDefinitionId,boolean activateProcessInstances,Date activationDate):在某个时间激活流程定义,需要注意的是activateProcessInstances参数,如果为true,则该流程定义下的流程实例,也会被激活。
本身流程定义就没有所谓的中止与激活的概念(流程才有),这里所说的中止与激活,只是流程定义的数据状态设置为中止状态和激活状态。流程定义文件一旦被部署,那么对应的流程定义数据状态为激活,可以调用RepositoryService的中止流程定义的方法改变其状态。RepositoryService提供了两个中止流程定义的方法。
➢ suspendProcessDefinitionById(String processDefinitionId):根据流程ID中止流程定义。
➢ suspendProcessDefinitionByKey(String processDefinitionKey):根据流程定义文件中的process 节点的 id 属性中止流程定义,也可以看作根据 ACT_RE_PROCDEF 表中的KEY_字段值中止流程定义。
当流程定义被中止后,如果想激活流程定义,同样可以使用RepositoryService中提供的激活流程定义的方法,方法描述如下。
➢ activateProcessDefinitionById(String processDefinitionId):根据流程ID激活流程定义。
➢ activateProcessDefinitionByKey(String processDefinitionKey):根据流程的key激活流程定义,与中止流程定义的suspendProcessDefinitionByKey方法一致。
创建suspendProcessDef.bpmn.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn"
	xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
	xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema"
	expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
	<process id="vacationProcess" name="vacation">
		<startEvent id="startevent1" name="Start"></startEvent>
		<userTask id="usertask1" name="Write Vacation"></userTask>
		<endEvent id="endevent1" name="End"></endEvent>
		<sequenceFlow id="flow1" name="" sourceRef="startevent1"
			targetRef="usertask1"></sequenceFlow>
		<sequenceFlow id="flow2" name="" sourceRef="usertask1"
			targetRef="endevent1"></sequenceFlow>
	</process>
</definitions>

工作流第七篇之流程存储
创建activiti.cfg.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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/act" />
		<property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
		<property name="jdbcUsername" value="root" />
		<property name="jdbcPassword" value="root" />
		<property name="databaseSchemaUpdate" value="true"/>
	</bean>

</beans>

创建log4j.properties配置文件

# Set root category priority to INFO and its only appender to CONSOLE.
log4j.rootCategory=INFO, CONSOLE
#log4j.rootCategory=INFO, CONSOLE, LOGFILE

# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE

# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1} - %m%n
log4j.logger.org.apache=INFO
log4j.logger.org.htmlparser=INFO
log4j.logger.org.htmlparser=INFO
log4j.logger.com.angus=INFO

测试

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;

/**
 * 中断流程
 * @author yangenxiong
 *
 */
public class SuspendProcessDef {

	public static void main(String[] args) {
		// 创建流程引擎
		ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
		// 得到流程存储服务实例
		RepositoryService repositoryService = engine.getRepositoryService();
		// 部署流程描述文件
		Deployment dep = repositoryService.createDeployment()
				.addClasspathResource("bpmn/suspendProcessDef.bpmn")
				.deploy();
		//查询流程定义实体
		ProcessDefinition def = repositoryService.createProcessDefinitionQuery()
				.deploymentId(dep.getId()).singleResult();		
		// 调用suspendProcessDefinitionById中止流程定义 
		repositoryService.suspendProcessDefinitionById(def.getId());
		// 调用activateProcessDefinitionById激活流程定义 
		repositoryService.activateProcessDefinitionById(def.getId());
		// 调用suspendProcessDefinitionByKey中止流程定义 
		repositoryService.suspendProcessDefinitionByKey(def.getKey());
		// 调用activateProcessDefinitionByKey激活流程定义 
		repositoryService.activateProcessDefinitionByKey(def.getKey());
	}

}

流程定义缓存配置
为了减少数据的查询,提升流程引擎性能,Activiti本身对某些常用的数据做了缓存。例如在解析完流程定义的XML文件后,会将流程定义缓存到一个Map中,key为流程定义的id(数据库的ID_字段),value为封装好的缓存对象。默认情况下,不需要进行配置,流程引擎会进行缓存的工作。
创建default-cache.bpmn.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn"
	xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
	xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema"
	expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
	<process id="testCache" name="testCache">
		<userTask id="usertask1" name="User Task"></userTask>
		<endEvent id="endevent1" name="End"></endEvent>
		<sequenceFlow id="flow2" name="" sourceRef="usertask1"
			targetRef="endevent1"></sequenceFlow>
		<startEvent id="startevent1" name="Start"></startEvent>
		<sequenceFlow id="flow3" name="" sourceRef="startevent1"
			targetRef="usertask1"></sequenceFlow>
	</process>
	<bpmndi:BPMNDiagram id="BPMNDiagram_vacationProcess">
		<bpmndi:BPMNPlane bpmnElement="vacationProcess"
			id="BPMNPlane_vacationProcess">
			<bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
				<omgdc:Bounds height="55" width="105" x="310" y="160"></omgdc:Bounds>
			</bpmndi:BPMNShape>
			<bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
				<omgdc:Bounds height="35" width="35" x="490" y="170"></omgdc:Bounds>
			</bpmndi:BPMNShape>
			<bpmndi:BPMNShape bpmnElement="startevent1"
				id="BPMNShape_startevent1">
				<omgdc:Bounds height="35" width="35" x="170" y="170"></omgdc:Bounds>
			</bpmndi:BPMNShape>
			<bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
				<omgdi:waypoint x="415" y="187"></omgdi:waypoint>
				<omgdi:waypoint x="490" y="187"></omgdi:waypoint>
			</bpmndi:BPMNEdge>
			<bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
				<omgdi:waypoint x="205" y="187"></omgdi:waypoint>
				<omgdi:waypoint x="310" y="187"></omgdi:waypoint>
			</bpmndi:BPMNEdge>
		</bpmndi:BPMNPlane>
	</bpmndi:BPMNDiagram>
</definitions>

工作流第七篇之流程存储创建activiti.cfg.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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/act" />
		<property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
		<property name="jdbcUsername" value="root" />
		<property name="jdbcPassword" value="root" />
		<property name="databaseSchemaUpdate" value="true"/>
	</bean>

</beans>

创建日志log4j.properties

# Set root category priority to INFO and its only appender to CONSOLE.
log4j.rootCategory=INFO, CONSOLE
#log4j.rootCategory=INFO, CONSOLE, LOGFILE

# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE

# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1} - %m%n
log4j.logger.org.apache=INFO
log4j.logger.org.htmlparser=INFO
log4j.logger.org.htmlparser=INFO
log4j.logger.com.angus=INFO

创建my-cache.cfg.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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="processEngineConfiguration"
		class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/act" />
		<property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
		<property name="jdbcUsername" value="root" />
		<property name="jdbcPassword" value="root" />
		<property name="databaseSchemaUpdate" value="true" />
		<property name="processDefinitionCache">
			<ref bean="myCache" />
		</property>
	</bean>

	<bean id="myCache" class="org.crazyit.activiti.MyCacheBean"></bean>
</beans>

创建use-limit.cfg.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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/act" />
		<property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
		<property name="jdbcUsername" value="root" />
		<property name="jdbcPassword" value="root" />
		<property name="databaseSchemaUpdate" value="true"/>
		<property name="processDefinitionCacheLimit" value="2" />		
	</bean>

</beans>

测试类


import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;

/**
 * 测试默认情况下的缓存
 * 
 * @author yangenxiong
 *
 */
public class DefaultCache {

	public static void main(String[] args) {
		// 创建流程引擎
		ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
		ProcessEngineConfigurationImpl config = (ProcessEngineConfigurationImpl) engine
				.getProcessEngineConfiguration();
		// 得到流程存储服务实例
		RepositoryService repositoryService = engine.getRepositoryService();
		// 进行10次部署
		for (int i = 0; i < 10; i++) {
			repositoryService.createDeployment()
					.addClasspathResource("bpmn/default-cache.bpmn")
					.name("dep_" + i).key("key_" + i).deploy();
		}
		// 获取缓存
		DefaultDeploymentCache cache = (DefaultDeploymentCache) config
				.getProcessDefinitionCache();
		// 遍历缓存,输出Map中的key
		for (Iterator it = cache.cache.keySet().iterator(); it.hasNext();) {
			String key = (String) it.next();
			System.out.println(key);
		}
	}

}

先进行10次部署,然后读取缓存对象,获取Map属性并输出内容。需要注意以下细节:
➢ 为了测试获取了缓存的Map,代码清单7-15的包与DefaultDeploymentCache的包是一致的,换言之,Map是protected的。
➢ DefaultDeploymentCache、ProcessEngineConfigurationImpl等实现类不应出现在业务代码中,尽量使用它们的接口。
由于缓存没有限制,因此部署了10次,缓存(Map)中就有10个元素,如果想限制缓存数量,可以在流程引擎的配置文件中使用以下配置:
工作流第七篇之流程存储


import java.util.Iterator;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;

/**
 * 测试默认情况下的缓存
 * 
 * @author yangenxiong
 *
 */
public class UserLimitCache {

	public static void main(String[] args) {
		// 创建流程引擎
		ProcessEngineConfigurationImpl config =
				 (ProcessEngineConfigurationImpl) ProcessEngineConfiguration
				.createProcessEngineConfigurationFromResource("use-limit.cfg.xml");
		ProcessEngine engine = config.buildProcessEngine();
		// 得到流程存储服务实例
		RepositoryService repositoryService = engine.getRepositoryService();
		// 进行10次部署
		for (int i = 0; i < 10; i++) {
			repositoryService.createDeployment()
					.addClasspathResource("bpmn/default-cache.bpmn")
					.name("dep_" + i).key("key_" + i).deploy();
		}
		// 获取缓存
		DefaultDeploymentCache cache = (DefaultDeploymentCache) config
				.getProcessDefinitionCache();
		// 遍历缓存,输出Map中的key
		for (Iterator it = cache.cache.keySet().iterator(); it.hasNext();) {
			String key = (String) it.next();
			System.out.println(key);
		}
	}
}

自定义缓存
如果想自己实现缓存,可以新建一个Java类,实现DeploymentCache接口,该接口主要有增、删、改、查方法,用于操作缓存数据。
自定义缓存类

import java.util.HashMap;
import java.util.Map;

import org.activiti.engine.impl.persistence.deploy.DeploymentCache;

public class MyCacheBean<T> implements DeploymentCache<T> {
	
	public Map<String, T> cache;

	public MyCacheBean() {
		cache = new HashMap<String, T>();
	}
	public T get(String id) {
		return cache.get(id);
	}
	public boolean contains(String id) {
		return cache.containsKey(id);
	}
	public void add(String id, T object) {
		cache.put(id, object);
	}
	public void remove(String id) {
		cache.remove(id);
	}
	public void clear() {
		cache.clear();
	}
}

测试类

package org.crazyit.activiti;
import java.util.Iterator;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;

public class MyCacheTest {

	public static void main(String[] args) {
		// 创建流程引擎
		ProcessEngineConfigurationImpl config =
				 (ProcessEngineConfigurationImpl) ProcessEngineConfiguration
				.createProcessEngineConfigurationFromResource("my-cache.cfg.xml");
		ProcessEngine engine = config.buildProcessEngine();		
		// 得到流程存储服务实例
		RepositoryService repositoryService = engine.getRepositoryService();
		// 进行10次部署
		for (int i = 0; i < 10; i++) {
			repositoryService.createDeployment()
					.addClasspathResource("bpmn/default-cache.bpmn")
					.name("dep_" + i).key("key_" + i).deploy();
		}
		// 获取缓存
		MyCacheBean cache = (MyCacheBean) config
				.getProcessDefinitionCache();
		// 遍历缓存,输出Map中的key
		for (Iterator it = cache.cache.keySet().iterator(); it.hasNext();) {
			String key = (String) it.next();
			System.out.println(key);
		}
	}

}

流程定义权限
对于一个用户或者用户组是否能操作(查看)某个流程定义的数据,需要进行相应的流程定义权限设置。在Activiti中,并没有对流程定义的权限进行检查,而是提供一种反向的方法,让调用者去管理这些权限数据,然后提供相应的API让使用人决定哪种数据可以被查询。

设置流程定义的用户权限
在默认情况下,所有用户(用户组)均可以根据流程定义创建流程实例(启动流程),可以使用Activiti提供的API来设置启动流程的权限数据(设置启动流程的候选用户)。Activiti提供了设置流程权限数据的API,可以调用这些API来管理这些权限数据,但是,需要注意的是,Activiti本身并不会对权限进行检查,而是提供了相应的权限查询接口,让开发者决定展示何种数据给使用者,从而达到权限控制的作用。例如提供了根据用户来获取其有权限的流程定义,根据流程定义获取有权限的用户组或者用户。Activiti的这种设计,使得在开发流程权限功能时开发人员可以有更灵活的选择。
RepositoryService中提供了addCandidateStarterUser方法,给流程定义与用户绑定权限,该方法实际上是向一个中间表中加入数据,表示流程与用户之间的关系。addCandidateStarterUser方法的第一个参数为流程定义ID,第二个参数为用户的ID。

package org.crazyit.activiti;

import org.activiti.engine.IdentityService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.identity.User;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;

/**
 * 开始流程用户权限
 * 
 * @author yangenxiong
 *
 */
public class UserCandidate {

	public static void main(String[] args) {
		// 创建流程引擎
		ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
		// 得到流程存储服务实例
		RepositoryService repositoryService = engine.getRepositoryService();
		// 得到身份服务组件
		IdentityService identityService = engine.getIdentityService();
		// 部署流程描述文件
		Deployment dep = repositoryService.createDeployment()
				.addClasspathResource("bpmn/candidateUser.bpmn").deploy();
		// 查询流程定义实体
		ProcessDefinition def = repositoryService
				.createProcessDefinitionQuery().deploymentId(dep.getId())
				.singleResult();
		// 写入用户数据
		creatUser(identityService, "user1", "angus", "young", "abc@163.com",
				"123");
		creatUser(identityService, "user2", "angus2", "young2", "abc@163.com",
				"123");
		creatUser(identityService, "user3", "angus3", "young3", "abc@163.com",
				"123");
		// 设置用户组与流程定义的关系(设置权限)
		repositoryService.addCandidateStarterUser(def.getId(), "user1");
		repositoryService.addCandidateStarterUser(def.getId(), "user2");
	}

	// 创建用户方法
	static void creatUser(IdentityService identityService, String id,
			String first, String last, String email, String passwd) {
		// 使用newUser方法创建User实例
		User user = identityService.newUser(id);
		// 设置用户的各个属性
		user.setFirstName(first);
		user.setLastName(last);
		user.setEmail(email);
		user.setPassword(passwd);
		// 使用saveUser方法保存用户
		identityService.saveUser(user);
	}
}

创建activiti.cfg.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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/act" />
		<property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
		<property name="jdbcUsername" value="root" />
		<property name="jdbcPassword" value="root" />
		<property name="databaseSchemaUpdate" value="true"/>
	</bean>
</beans>

创建candidateUser.bpmn.xml

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn"
	xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
	xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema"
	expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
	<process id="vacationProcess" name="vacation">
		<startEvent id="startevent1" name="Start"></startEvent>
		<userTask id="usertask1" name="User Task"></userTask>
		<endEvent id="endevent1" name="End"></endEvent>
		<sequenceFlow id="flow1" name="" sourceRef="startevent1"
			targetRef="usertask1"></sequenceFlow>
		<sequenceFlow id="flow2" name="" sourceRef="usertask1"
			targetRef="endevent1"></sequenceFlow>
	</process>
	<bpmndi:BPMNDiagram id="BPMNDiagram_vacationProcess">
		<bpmndi:BPMNPlane bpmnElement="vacationProcess"
			id="BPMNPlane_vacationProcess">
			<bpmndi:BPMNShape bpmnElement="startevent1"
				id="BPMNShape_startevent1">
				<omgdc:Bounds height="35" width="35" x="160" y="170"></omgdc:Bounds>
			</bpmndi:BPMNShape>
			<bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
				<omgdc:Bounds height="55" width="105" x="280" y="160"></omgdc:Bounds>
			</bpmndi:BPMNShape>
			<bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
				<omgdc:Bounds height="35" width="35" x="450" y="170"></omgdc:Bounds>
			</bpmndi:BPMNShape>
			<bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
				<omgdi:waypoint x="195" y="187"></omgdi:waypoint>
				<omgdi:waypoint x="280" y="187"></omgdi:waypoint>
			</bpmndi:BPMNEdge>
			<bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
				<omgdi:waypoint x="385" y="187"></omgdi:waypoint>
				<omgdi:waypoint x="450" y="187"></omgdi:waypoint>
			</bpmndi:BPMNEdge>
		</bpmndi:BPMNPlane>
	</bpmndi:BPMNDiagram>
</definitions>

工作流第七篇之流程存储IdentityLink对象
一个IdentityLink实例表示一种身份数据与流程数据绑定的关系,此处所说的身份数据包括用户组和用户数据,流程数据包括流程定义、流程任务等数据。IdentityLink是一个接口,与其他数据库映射实体一样,其对应的实现类为IdentityLinkEntityImpl,对应的数据表为ACT_RU_IDENTITYLINK。它包含以下映射的属性。
➢ id:主键,对应ID_字段。
➢ type:数据类型,对应TYPE_字段,Activiti为该字段提供了5个值,分别为assignee、candidate、starter、participant和owner。本章中为用户或者用户组绑定流程定义时,该值为candidate,表示创建流程实例的请求者。
➢ groupId:绑定关系中的用户组ID,对应GROUP_ID_字段。
➢ userId:绑定关系中的用户ID,对应USER_ID_字段。
➢ taskId:绑定关系中的流程任务ID,对应TASK_ID_字段。
➢ processDefId:绑定关系中的流程定义ID,对应PROC_DEF_ID_字段。
在此需要注意的是,ACT_RU_IDENTITYLINK表中还有一个REV_字段,IdentityLink-EntityImpl并没有为该字段做相应的属性映射,在实体与数据表映射的配置文件中,该字段的值被设置为1。

查询权限数据
前面介绍了如何设置流程定义的权限,那么当需要使用这些权限数据时,则可以使用IdentityService中提供的获取流程角色权限数据的方法来获取这些数据,例如根据用户获取该用户有权限启动的流程定义,根据流程定义获取有权限申请的用户和用户组数据。这些获取权限数据的方法分布在各个不同的服务组件中,如果要根据流程定义获取有权限申请的角色数据,则需要使用IdentityService;如果要根据用户或者用户组得到相应的流程定义数据,则需要使用RepositoryService。

import java.util.List;

import org.activiti.engine.IdentityService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.identity.Group;
import org.activiti.engine.identity.User;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.task.IdentityLink;

/**
 * 查询流程定义的权限数据
 * 
 * @author yangenxiong
 *
 */
public class CandidateQuery {

	public static void main(String[] args) {
		// 创建流程引擎
		ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
		// 得到流程存储服务实例
		RepositoryService repositoryService = engine.getRepositoryService();
		// 得到身份服务组件
		IdentityService identityService = engine.getIdentityService();
		// 部署流程描述文件
		Deployment dep = repositoryService.createDeployment()
				.addClasspathResource("bpmn/candidateQuery.bpmn").deploy();
		// 添加2个用户
		creatUser(identityService, "user1", "张三", "张三", "mail1", "123");
		creatUser(identityService, "user2", "李四", "李四", "mail2", "123");
		// 添加2个用户组
		createGroup(identityService, "group1", "经理组", "manager");
		createGroup(identityService, "group2", "员工组", "employee");
		// 查询流程定义
		ProcessDefinition def = repositoryService
				.createProcessDefinitionQuery().deploymentId(dep.getId())
				.singleResult();
		// 设置权限数据
		repositoryService.addCandidateStarterGroup(def.getId(), "group1");
		repositoryService.addCandidateStarterGroup(def.getId(), "group2");
		repositoryService.addCandidateStarterUser(def.getId(), "user1");
		repositoryService.addCandidateStarterUser(def.getId(), "user2");
		// 根据用户查询用权限的流程定义
		List<ProcessDefinition> defs = repositoryService
				.createProcessDefinitionQuery().startableByUser("user1").list();
		System.out.println("用户张三有权限的流程定义为:");// 结果为1
		for (ProcessDefinition dft : defs) {
			System.out.println("   " + dft.getName());
		}
		// 根据流程定义查询用户组数据
		List<Group> groups = identityService.createGroupQuery()
				.potentialStarter(def.getId()).list();
		System.out.println("以下用户组对流程定义有权限:");
		for (Group group : groups) {
			System.out.println("   " + group.getName());
		}
		// 根据流程定义查询用户数据
		List<User> users = identityService.createUserQuery()
				.potentialStarter(def.getId()).list();
		System.out.println("以下用户对流程定义有权限:");// 结果为2
		for (User user : users) {
			System.out.println("   " + user.getFirstName());
		}
		// 根据流程定义查询全部的 IdentityLink(ACT_RU_IDENTITYLINK表) 数据
		List<IdentityLink> links = repositoryService
				.getIdentityLinksForProcessDefinition(def.getId());
		System.out.println("与流程定义相关的数据量: " + links.size());// 结果为4
	}

	// 将用户组数据保存到数据库中
	static void createGroup(IdentityService identityService, String id,
			String name, String type) {
		// 调用newGroup方法创建Group实例
		Group group = identityService.newGroup(id);
		group.setName(name);
		group.setType(type);
		identityService.saveGroup(group);
	}

	// 创建用户方法
	static void creatUser(IdentityService identityService, String id,
			String first, String last, String email, String passwd) {
		// 使用newUser方法创建User实例
		User user = identityService.newUser(id);
		// 设置用户的各个属性
		user.setFirstName(first);
		user.setLastName(last);
		user.setEmail(email);
		user.setPassword(passwd);
		// 使用saveUser方法保存用户
		identityService.saveUser(user);
	}
}

➢ ProcessDefinitionQuery的startableByUser方法:该方法用于根据用户ID查询该用户有权限启动的流程定义数据。
➢ GroupQuery的potentialStarter方法:根据流程定义ID查询有权限启动的用户组数据。
➢ UserQuery的potentialStarter方法:根据流程定义ID查询有权限启动的用户数据。
➢ RepositoryService的getIdentityLinksForProcessDefinition方法:根据流程定义ID查询与之相关的全部权限数据。

RepositoryService数据查询与删除
使用DeploymentBuilder对象将流程描述文件、流程资源等文件保存到数据库中,本节将讲述如何使用RepositoryService提供的方法管理这些资源数据,这些资源包括部署的文件、流程描述文件、流程图文件等。
查询部署资源
部署资源包括与部署相关的文件、流程描述文件、流程图等,可以使用DeploymentBuilder的addXXX方法将相关的资源文件保存到数据库中,如果需要使用这些文件,则可以调用RepositoryService的getResourceAsStream方法,只需要提供部署(Deployment)ID和资源名称,就可以返回资源的输入流对象
创建GetResource.txt文件

www
package org.crazyit.activiti;

import java.io.InputStream;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;

/**
 * 查询部署资源
 * 
 * @author yangenxiong
 * 
 */
public class GetResource {

	public static void main(String[] args) throws Exception {
		// 创建流程引擎
		ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
		// 得到流程存储服务对象
		RepositoryService repositoryService = engine.getRepositoryService();
		// 部署一份txt文件
		Deployment dep = repositoryService.createDeployment()
				.addClasspathResource("artifact/GetResource.txt").deploy();
		// 查询资源文件
		InputStream is = repositoryService.getResourceAsStream(dep.getId(), 
				"artifact/GetResource.txt");
		// 读取输入流
		int count = is.available();
		byte[] contents = new byte[count];
		is.read(contents);
		String result = new String(contents);
		//输入结果
		System.out.println(result);
	}

}

查询流程文件
部署流程描述文件的时候,Activiti会向资源表中写入该文件的内容,即先将其看作一份普通的文件进行解析与数据保存,然后再解析它的文件内容,并生成相应的流程定义数据。与查询部署资源的getResourceAsStream方法一样,RepositoryService提供了一个getProcessModel方法,调用该方法只需要提供流程定义的ID即可返回流程文件的InputStream实例。
创建getProcessModel.bpmn配置文件
工作流第七篇之流程存储
创建getProcessModel.bpmn.xml

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/test">
  <process id="vacationProcess" name="vacation">
    <startEvent id="startevent1" name="Start"></startEvent>
    <userTask id="usertask1" name="Write Vacation"></userTask>
    <endEvent id="endevent1" name="End"></endEvent>
    <sequenceFlow id="flow1" name="" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
    <sequenceFlow id="flow2" name="" sourceRef="usertask1" targetRef="endevent1"></sequenceFlow>
  </process>
</definitions>

查询流程图
在部署一个流程的时候,可以由Activiti生成流程图,也可以由我们提供,可以使用RepositoryService的getProcessDiagram方法返回该流程图的InputStream对象。调用getProcessDiagram方法同样需要提供流程定义ID,根据流程定义数据得到部署数据ID与部署资源名称,再到资源表中查询相应的文件数据返回。
工作流第七篇之流程存储

package org.crazyit.activiti;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;

import javax.imageio.ImageIO;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;

/**
 * 查询流程图
 * 
 * @author yangenxiong
 * 
 */
public class GetProcessDiagram {

	public static void main(String[] args) throws Exception {
		// 创建流程引擎
		ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
		// 得到流程存储服务对象
		RepositoryService repositoryService = engine.getRepositoryService();
		// 部署一份流程文件与相应的流程图文件
		Deployment dep = repositoryService.createDeployment()
				.addClasspathResource("bpmn/getProcessDiagram.bpmn")
				.addClasspathResource("bpmn/getProcessDiagram.png").deploy();
		// 查询流程定义
		ProcessDefinition def = repositoryService.createProcessDefinitionQuery()
				.deploymentId(dep.getId()).singleResult();
		// 查询资源文件
		InputStream is = repositoryService.getProcessDiagram(def.getId());
		// 将输入流转换为图片对象	
		BufferedImage image = ImageIO.read(is);
		// 保存为图片文件
		File file = new File("resource/artifact/result.png");
		if (!file.exists()) file.createNewFile();
		FileOutputStream fos = new FileOutputStream(file);
		ImageIO.write(image, "png", fos);
		fos.close();
		is.close();
	}
}

查询部署资源名称

package org.crazyit.activiti;

import java.util.List;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;

/**
 * 查询部署资源名称
 * 
 * @author yangenxiong
 * 
 */
public class GetResourceNames {

	public static void main(String[] args) throws Exception {
		// 创建流程引擎
		ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
		// 得到流程存储服务对象
		RepositoryService repositoryService = engine.getRepositoryService();
		// 部署一份流程文件与相应的流程图文件
		Deployment dep = repositoryService.createDeployment()
				.addClasspathResource("bpmn/GetResourceNames.bpmn")
				.addClasspathResource("bpmn/GetResourceNames.png").deploy();
		// 查询资源文件名称集合
		List<String> names = repositoryService.getDeploymentResourceNames(dep.getId());
		for (String name : names) {
			System.out.println(name);
		}
	}
}

删除部署资源
在前面章节,使用了RepositoryService的各个方法来查询部署所产生的相关资源数据。如果需要删除这些数据,则可以使用RepositoryService提供的两个删除方法,这两个方法的描述如下。
➢ deleteDeployment(String deploymentId):删除部署数据,不进行级联删除,这里所说的级联删除,是指与该部署相关的流程实例数据的删除。
➢ deleteDeployment(String deploymentId,boolean cascade):是否进行级联删除,由调用者决定。如果cascade参数为false,效果等同于deleteDeployment(String deploymentId)方法;如果cascade为true,则会删除部署相关的流程实例数据。
不管删除部署数据时是否指定级联删除,部署的相关数据均会被删除,包括身份数据(IdentityLink)、流程定义数据(ProcessDefinition)、流程资源(Resource)与部署数据(Deployment)。代码清单7-26示范了如何调用两个删除部署数据的方法。

package org.crazyit.activiti;

import java.util.List;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;

/**
 * 使用DeploymentQuery的deploymentId方法
 * @author yangenxiong
 *
 */
public class DeploymentQuery {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// 创建流程引擎
		ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
		// 得到流程存储服务实例
		RepositoryService repositoryService = engine.getRepositoryService();
		// 写入5条Deployment数据
		Deployment depA = repositoryService.createDeployment().addString("a1", "a1")
				.addString("a2", "a2").addString("a3", "a3").name("a").deploy();
		Deployment depB = repositoryService.createDeployment().addString("b1", "b1")
				.addString("b2", "b2").addString("b3", "b3").name("b").deploy();
		Deployment depC = repositoryService.createDeployment().addString("c1", "c1")
				.addString("c2", "c2").addString("c3", "c3").name("c").deploy();
		Deployment depD = repositoryService.createDeployment().addString("d1", "d1")
				.addString("d2", "d2").addString("d3", "d3").name("da").deploy();
		Deployment depE = repositoryService.createDeployment().addString("e1", "e1")
				.addString("e2", "e2").addString("e3", "e3").name("eb").deploy();
		//deploymentId方法
		Deployment depAQuery = repositoryService.createDeploymentQuery()
				.deploymentId(depA.getId()).singleResult();
		System.out.println("根据id查询:" + depAQuery.getName());
		//deploymentName方法
		Deployment depBQuery = repositoryService.createDeploymentQuery()
				.deploymentName("b").singleResult();
		System.out.println("查询名称为b:" + depBQuery.getName());
		//deploymentNameLike, 模糊查询,结果集为2
		List<Deployment> depCQuery = repositoryService.createDeploymentQuery()
				.deploymentNameLike("%b%").list();
		System.out.println("模糊查询b,结果数量:" + depCQuery.size());
	}
}

DeploymentQuery对象
Activiti中的每个查询对象(XXXQuery)均有自己相应的查询方法和排序方法(详细请见第6章),本章的DeploymentQuery对象包括如下方法。
➢ deploymentId(String id):添加ID查询条件,查询ID为参数值的数据记录。
➢ deploymentName(String name):添加名称查询条件,查询Deployment名称为参数值的数据记录。
➢ deploymentNameLike(String name):添加模糊查询条件,查询Deployment名称含有参数值的数据记录。
➢ orderByDeploymentId:设置查询结果按照Deployment的ID进行排序,排序方式由asc与desc方法决定。
➢ orderByDeploymentTime:设置查询结果按照DEPLOY_TIME_字段排序。
➢ orderByDeploymentName:设置查询结果按照Deployment名称排序。

package org.crazyit.activiti;

import java.util.List;

import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngineConfiguration;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;

/**
 * 使用DeploymentQuery的deploymentId方法
 * @author yangenxiong
 *
 */
public class DeploymentQuery {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// 创建流程引擎
		ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
		// 得到流程存储服务实例
		RepositoryService repositoryService = engine.getRepositoryService();
		// 写入5条Deployment数据
		Deployment depA = repositoryService.createDeployment().addString("a1", "a1")
				.addString("a2", "a2").addString("a3", "a3").name("a").deploy();
		Deployment depB = repositoryService.createDeployment().addString("b1", "b1")
				.addString("b2", "b2").addString("b3", "b3").name("b").deploy();
		Deployment depC = repositoryService.createDeployment().addString("c1", "c1")
				.addString("c2", "c2").addString("c3", "c3").name("c").deploy();
		Deployment depD = repositoryService.createDeployment().addString("d1", "d1")
				.addString("d2", "d2").addString("d3", "d3").name("da").deploy();
		Deployment depE = repositoryService.createDeployment().addString("e1", "e1")
				.addString("e2", "e2").addString("e3", "e3").name("eb").deploy();
		//deploymentId方法
		Deployment depAQuery = repositoryService.createDeploymentQuery()
				.deploymentId(depA.getId()).singleResult();
		System.out.println("根据id查询:" + depAQuery.getName());
		//deploymentName方法
		Deployment depBQuery = repositoryService.createDeploymentQuery()
				.deploymentName("b").singleResult();
		System.out.println("查询名称为b:" + depBQuery.getName());
		//deploymentNameLike, 模糊查询,结果集为2
		List<Deployment> depCQuery = repositoryService.createDeploymentQuery()
				.deploymentNameLike("%b%").list();
		System.out.println("模糊查询b,结果数量:" + depCQuery.size());
	}

}
上一篇:更快的Maven来了,我的天,速度提升了8倍!


下一篇:Spring定时任务动态取消/创建/修改