转自:http://blog.csdn.net/zjx86320/article/details/50234707
流程资源可以是各种类型的文件,在启动流程或流程实例运行过程中会被读取。下面介绍常用的流程资源。
一、流程资源
流程定义文件:扩展名为bpmn20.xml和bpmn;
流程定义的图片:用BPMN2.0规范的各种图形描绘,一般用PNG的格式;
表单文件:把表单内容保存在一个文件中,其扩展名为drl;
规则文件:其扩展名为drl;
二、部署流程资源
部署流程资源有很多种方法,包括classpath、InputStream、字符串、zip格式压缩包,下面将一一介绍。
1.classpath方式
- public class ProcessDefinitionTest {
- /**流程引擎(核心对象),默认加载类路径下命名为activiti.cfg.xml*/
- ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
- //部署流程定义
- @Test
- public void deployementProcessDefinition(){
- Deployment deployment = processEngine.getRepositoryService()//获取流程定义和部署对象相关的Service
- .createDeployment()//创建部署对象
- .name("helloworld演示")//声明流程的名称
- .addClasspathResource("diagrams/helloworld.bpmn")//加载资源文件,一次只能加载一个文件
- .addClasspathResource("diagrams/helloworld.png")//
- .deploy();//完成部署
- System.out.println("部署ID:"+deployment.getId());//1
- System.out.println("部署时间:"+deployment.getDeploymentTime());
- }
- }
2.InputStream方式
使用InputStream方式部署流程资源需要传入一个输入流及资源的名称,输入流的来源不限,可以从classpath读取,也可以从一个绝对路径文件读取,也可以是从网络上读取。
- //Inputstream方式
- @Test
- public void deployementProcessDefinitionByInputStream() throws FileNotFoundException{
- //获取资源相对路径
- String bpmnPath = "diagrams/helloworld.bpmn";
- String pngPath = "diagrams/helloworld.png";
- //读取资源作为一个输入流
- FileInputStream bpmnfileInputStream = new FileInputStream(bpmnPath);
- FileInputStream pngfileInputStream = new FileInputStream(pngPath);
- Deployment deployment = processEngine.getRepositoryService()//获取流程定义和部署对象相关的Service
- .createDeployment()//创建部署对象
- .addInputStream("helloworld.bpmn",bpmnfileInputStream)
- .addInputStream("helloworld.png", pngfileInputStream)
- .deploy();//完成部署
- System.out.println("部署ID:"+deployment.getId());//1
- System.out.println("部署时间:"+deployment.getDeploymentTime());
- }
3.字符串方式
利用字符串方式可以直接传入纯文本作为资源的来源,和前两种方式类似,字符串方式的实现原理是把一组字符串的内容转化为字节流后再部署。
- //字符串方式
- @Test
- public void deployementProcessDefinitionByString() throws FileNotFoundException{
- //字符串
- String text = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><definitions>...</definitions>";
- Deployment deployment = processEngine.getRepositoryService()//获取流程定义和部署对象相关的Service
- .createDeployment()//创建部署对象
- .addString("helloworld.bpmn",text)
- .deploy();//完成部署
- System.out.println("部署ID:"+deployment.getId());//1
- System.out.println("部署时间:"+deployment.getDeploymentTime());
- }
4.zip/bar格式压缩包方式
以上3种部署方式一次只能部署一个资源,除非执行多次deployment.addXxx()方法,如何一次部署多个资源呢?很简单,是我们可以使用zip/bar格式压缩包方式。将资源文件手动或使用Ant脚本,打包文件扩展名可以是Activiti官方推荐的bar或普通的zip。
- //部署流程定义(zip)
- @Test
- public void deployementProcessDefinitionByzip(){
- //从classpath路径下读取资源文件
- InputStream in = this.getClass().getClassLoader().getResourceAsStream("diagrams/helloworld.zip");
- ZipInputStream zipInputStream = new ZipInputStream(in);
- Deployment deployment = processEngine.getRepositoryService()//获取流程定义和部署对象相关的Service
- .createDeployment()//创建部署对象
- .addZipInputStream(zipInputStream)//使用zip方式部署,将helloworld.bpmn和helloworld.png压缩成zip格式的文件
- .deploy();//完成部署
- System.out.println("部署ID:"+deployment.getId());//1
- System.out.println("部署时间:"+deployment.getDeploymentTime());
- }
三、数据库表变更
在部署流程定义这一步,数据库中操作三张表:
1)ACT_RE_DEPLOYMENT(部署对象表)
存放流程定义的显示名和部署时间,每部署一次增加一条记录
2)ACT_RE_PROCDEF(流程定义表)
存放流程定义的属性信息,部署每个新的流程定义都会在这张表中增加一条记录。
注意:当流程定义的key相同的情况下,使用的是版本升级
3)ACT_GE_BYTEARRAY(资源文件表)
存储流程定义相关的部署信息。即流程定义文档的存放地。每部署一次就会增加两条记录,一条是关于bpmn规则文件的,一条是图片的(如果部署时只指定了bpmn一个文件,activiti会在部署时解析bpmn文件内容自动生成流程图)。两个文件不是很大,都是以二进制形式存储在数据库中。
4)ACT_GE_PROPERTY(主键生成表)
主张表将生成下次流程部署的主键ID。
四、Activiti业务键(businessKey)
ProcessInstance 有个方法getBusinessKey()可以得到一个businessKey。ProcessInstance 对应数据库中的表act_ru_execution有个字段BUSINESS_KEY_对应类中的businessKey,这个字段在创建表时自动被设置为unique。
businessKey使用方法如下:
1、保证流程的ID和业务对象的类名一致。例如:流程id为LeaveBill,我们的业务对象的类名也创建为LeaveBill。
2、在流程启动的时候获取业务对象执行方法的时候传入businessKey,workflowService.startProcess(key,businessKey,vars);(这里vars为一些变量根据实际情况可有可无)businessKey 产生规则: className+“.”+objId
public void startProcess(Long id) { //1. 获取业务对象 LeaveBill bill = this.get(id); if(bill!=null){ // 修改业务对象状态 bill.setState(1);// 请假单状态 0初始录入,1.开始审批,2为审批通过 this.update(bill); //2. 添加流程变量(Map) Map<String,Object> vars = new HashMap<>(); vars.put("inputUser", bill.getUser().getName()); // 添加变量来描述业务对象的信息 String classType =bill.getClass().getSimpleName(); vars.put("classType", classType); vars.put("objId", bill.getId()); //3. 启动流程 // 获取流程定义key String key = classType; // 获取业务键 产生规则: className+“.”+objId String businessKey = classType +"." + bill.getId(); this.workflowService.startProcess(key,businessKey,vars); } }
3、根据以下方法就可以用taskId获取业务对象id
public String getBusinessObjId(String taskId) { //1 获取任务对象 Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); //2 通过任务对象获取流程实例 ProcessInstance pi = runtimeService.createProcessInstanceQuery()
.processInstanceId(task.getProcessInstanceId()).singleResult(); //3 通过流程实例获取“业务键” String businessKey = pi.getBusinessKey(); //4 拆分业务键,拆分成“业务对象名称”和“业务对象ID”的数组 // a=b LeaveBill.1 String objId = null; if(StringUtils.isNotBlank(businessKey)){ objId = businessKey.split("\\.")[1]; } return objId; }
4、根据业务键获取流程实例和任务
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceBusinessKey("LeaveBill.1").singleResult(); List<Task> task = taskService.createTaskQuery().processInstanceBusinessKey("LeaveBill.1").list();