工作流框架-Activiti

工作流日常的应用软件:钉钉
在这里插入图片描述
什么是工作流?

  • 多任务人协同完成一个复杂的业务流
  • 完成工作流的框架,称为工作流管理系统。
  • Activiti是一个业务框架。

Activiti的特点

  1. 把复杂的业务流进行图形化
  2. 图形化的业务部署数据库系统中(数据库化)
  3. 提供了流程数据库(23张表)
  4. 提供了业务层的API(service)
  5. 数据访问层使用mybatis实现

Activiti环境的搭建

  1. 安装BPMN插件,绘图插件
    下载插件安装包:

在这里插入图片描述
解压安装包:
在这里插入图片描述
把jars目录中的jar包复制到Eclipse的安装目录的plugins文件夹中。
使用归档文件方式安装插件:
在这里插入图片描述

  1. 应用要导入activiti的类库jar

  2. 安装流程数据库

public class TestCreateDB {
    
    

	@Test
	public void testJdbc(){
    
    	//第一种方式(java代码方式)
		
		ProcessEngineConfiguration config = ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();
		config.setJdbcDriver("com.mysql.jdbc.Driver");
		config.setJdbcUrl("jdbc:mysql://localhost:3306/activitileavedb2037?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=utf8");
		config.setJdbcUsername("agentsystem");
		config.setJdbcPassword("888");
		
		config.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
		
		ProcessEngine engine = config.buildProcessEngine();  //创建23张表
		System.out.println(engine);
		
	}
	
	@Test
	public void testSpring(){
    
    	//第二种方式(xml配置文件方式)
		
		ProcessEngineConfiguration config = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
		
		
		ProcessEngine engine = config.buildProcessEngine();  //创建23张表
		System.out.println(engine);
		
	}
}

23张表如下:
在这里插入图片描述
Activiti常用的流程数据库表

  • act_re_deployment 流程部署信息表
  • act_re_procdef 流程定义信息表
  • act_ge_bytearray 流程定义资源表 保存了二进制文件
  • act_ru_task 活动任务节点信息表
  • act_ru_execution 活动的任务执行表
  • act_hi_procinst 流程实例历史表
  • act_hi_taskinst 任务信息历史表
  • act_ru_variable 流程变量信息表
  • act_hi_varinst 流程变量历史表

Activiti入门程序
1.流程图的要素

  • 开始节点
  • 任务节点 UserTask
  • 结束节点
  • 任务节点的待办人
    分配方式:
    (1)固定名称
    (2)表达式
    (3)程序分配

2.流程业务的主要操作

  • getRepositoryService() 流程定义有关操作
  • getRuntimeService() 流程实例有关操作
  • getTaskService() 活动的流程任务的操作
  • getHistoryService() 查询历史记录的操作

(1) 部署流程图

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//会读取activiti.cfg.xml
	
	@Test //1.部署流程定义图
	public void testDeployDB() {
    
    
		
		Deployment deployment = processEngine.getRepositoryService()
								.createDeployment()
								.name("hello入门程序")
								.addClasspathResource("diagram/HelloProcess.bpmn")
								.addClasspathResource("diagram/HelloProcess.png")
								.deploy();
		System.out.println(deployment.getId());
		System.out.println(deployment.getName());
	}

(2) 启动流程实例

	@Test  //2. 启动流程实例   ProcessInstance
	public void startProcess() {
    
    
		 String processKey = "HelloProcess";
		 ProcessInstance pi = processEngine.getRuntimeService().startProcessInstanceByKey(processKey);
		 
		 System.out.println("流程实例id: " + pi.getId());
		 System.out.println("流程定义id: " + pi.getProcessDefinitionId());
	}
  • 区分流程定义和流程实例区别:
    流程定义相当于一种工作的“模板”,类似OOP中的“类”的概念。流程实例表示的是某一个正在运行的工作流程,相当于对象的概念。

(3) 查看个人的待办事务

	@Test  //3. 我的待办事务
	public void findMyTask() {
    
    
		
		String assignee = "zhang";
		List<Task> list = processEngine.getTaskService()
					.createTaskQuery()
					.taskAssignee(assignee )
					.list();
		for (Task task : list) {
    
    
			System.out.println("任务id:" + task.getId());
			System.out.println("任务名称 : " + task.getName());
			System.out.println("待办人: " + task.getAssignee());
			System.out.println("当前流程实例:" + task.getProcessInstanceId());
			System.out.println("当前流程定义:" + task.getProcessDefinitionId());
		}
	}

(4)完成个人任务

	@Test // 4. 完成个人任务
	public void finishMyTask() {
    
    
		String taskId = "302";
		processEngine.getTaskService().complete(taskId );
		System.out.println("完成任务");
	}

(5)查看流程定义列表

	@Test //5. 查看流程定义列表
	public void findProcessDefinitions() {
    
    
		List<ProcessDefinition> list = processEngine.getRepositoryService()
					.createProcessDefinitionQuery()
					.list();
		for (ProcessDefinition pd : list) {
    
    
			System.out.println(pd.getId());
			System.out.println(pd.getName());
			System.out.println(pd.getKey());
			System.out.println(pd.getResourceName()); // bpmn
			System.out.println(pd.getDiagramResourceName()); //png
			System.out.println(pd.getDeploymentId());
		}
		
	}

(6)删除流程定义

	@Test //6. 删除流程定义模板
	public void removeProcessDef() {
    
    
		
		String deploymentId = "501";
		//第个参数:true  表示强行删除,如果当前流程定义还有运行流程实例时,也要强行删除
		processEngine.getRepositoryService().deleteDeployment(deploymentId , true);
		System.out.println("删除成功");
	}

(7)查看流程定义图

	@Test //7. 查看流程定义图
	public void viewPic() throws IOException {
    
    
		String deploymentId = "1";
		String resourceName = "diagram/HelloProcess.png";
		InputStream is = processEngine.getRepositoryService().getResourceAsStream(deploymentId, resourceName);
		File file = new File("d:/"+resourceName);
		FileUtils.copyInputStreamToFile(is, file);
		
		System.out.println("复制成功");
	}

(8)判断流程是否结束

	//8. 判断流程实例是否结束
	@Test
	public void testProcessInsEnd() {
    
    
		String processId="701";
		ProcessInstance pi = processEngine.getRuntimeService()
								.createProcessInstanceQuery()
								.processInstanceId(processId)
								.singleResult();
		if (pi!=null) {
    
    
			System.out.println("流程正在运行。。。。。");
		} else {
    
    
			System.out.println("流程已经结束!");
		}
	}

流程变量

1.什么是流程变量?
保存在流程上下文中流转的业务数据。

作用:

  • 保存业务数据(建议另外保存业务表)
  • 分支连线判断
  • 启动流程实例分配待办人

2.流程变量的设置

	@Test
	public void testSet() {
    
    
		//processEngine.getTaskService().setVariable(taskId, key, value);
		//processEngine.getRuntimeService().setVariable(arg0, arg1, arg2);
		
		//processEngine.getTaskService().setVariables(taskId, map);
		
		Map<String, Object> map = new HashMap<>();
		map.put("money", 5000);
		map.put("remark", "出差报销");
		
		String taskId = "704";
		processEngine.getTaskService().setVariables(taskId, map);
		System.out.println("金额已经设置");
	}
	
	@Test
	public void testGet() {
    
    
		//processEngine.getTaskService().getVariables(taskId);
		//processEngine.getTaskService().getVariable(taskId, key);
		
		String taskId = "1002";
		int money = (int) processEngine.getTaskService().getVariable(taskId , "money");
		String remark = (String) processEngine.getTaskService().getVariable(taskId, "remark");
		
		System.out.println(money);
		System.out.println(remark);
	}

分支连线

  1. 流程图参考如下:
    在这里插入图片描述
  2. 流程图关键参数设置,设置连线的流程变量表达式:
    在这里插入图片描述
  3. 单元测试
    个人任务完成时传递流程变:
	@Test // 3. 完成个人任务
	public void finishMyTask() {
    
    
		String taskId = "1403";
		Map<String, Object> map = new HashMap<>();
		map.put("money", 120);
		processEngine.getTaskService().complete(taskId, map);
		System.out.println("完成任务");
	}

网关 gateway(了解)

  1. 排他网关

流程图以及默认路径的设置,参考下图:
在这里插入图片描述
测试代码,任务完成提供连线的流程变量:

	@Test // 3. 完成个人任务
	public void finishMyTask() {
    
    
		String taskId = "1904";
		Map<String, Object> map = new HashMap<>();
		map.put("money", 120);
		processEngine.getTaskService().complete(taskId, map);
		System.out.println("完成任务");
	}
  1. 并行网关
    流程图参考如下:
    在这里插入图片描述
    并行网关的特点: 有多个任务同时并行执行,这些任务必须全部完成才汇聚一起,走下面的流程。操作时要留意流程数据库表act_ru_execution和act_ru_task的变化。

任务人分配

  1. 表达式分配

流程图以及待办人分配表达式,如下图:
在这里插入图片描述
测试代码,启动流程时指定流程变量userId

	@Test  //2. 启动流程实例   ProcessInstance
	public void startProcess() {
    
    
		 String processKey = "assignProcess01";
		 Map<String, Object> map = new HashMap<>();
		 map.put("userId", "zhangsan");
		 ProcessInstance pi = processEngine.getRuntimeService().startProcessInstanceByKey(processKey, map);
		 System.out.println("流程实例id: " + pi.getId());
		 System.out.println("流程定义id: " + pi.getProcessDefinitionId());
	}
  1. 程序分配

流程图以及监听类的指定:
在这里插入图片描述
监听类AssigneeTaskListener,参考如下

public class AssigneeTaskListener implements TaskListener {
    
    

	@Override
	public void notify(DelegateTask delegateTask) {
    
    
		
		
		delegateTask.setAssignee("boss");
	}
}

在web上查看流程图片

1.查看流程定义图

  • 请求handler方法:
	@RequestMapping("/viewImage")
	public String  viewImage(String deploymentId,String imageName,HttpServletResponse response) throws IOException {
    
    
		InputStream in = workFlowService.findImageInputStream(deploymentId, imageName);
		
		OutputStream out = response.getOutputStream();
		
		//4:将输入流中的数据读取出来,写到输出流中
		for(int b=-1;(b=in.read())!=-1;){
    
    
			out.write(b);
		}
		out.close();
		in.close();
		
		return null;
	}


获取流程图片的业务方法:
	@Override
	public InputStream findImageInputStream(String deploymentId, String imageName) {
    
    		
		return this.repositoryService.getResourceAsStream(deploymentId, imageName);
	}

2.查看当前流程图

  • 请求的handler方法:
	@RequestMapping("/viewCurrentImage")
	public ModelAndView  viewCurrentImage(String taskId) {
    
    
		/**一:查看流程图*/
		//1:获取任务ID,获取任务对象,使用任务对象获取流程定义ID,查询流程定义对象
		ProcessDefinition pd = workFlowService.findProcessDefinitionByTaskId(taskId);
		
		ModelAndView mv = new ModelAndView();
		mv.addObject("deploymentId", pd.getDeploymentId());
		mv.addObject("imageName", pd.getDiagramResourceName());
		/**
		 * 二:查看当前活动,获取当期活动对应的坐标x,y,width,height,将4个值存放到Map<String,Object>中*/
		Map<String, Object> map = workFlowService.findCoordingByTask(taskId);

		mv.addObject("acs", map);
		mv.setViewName("viewimage");
		return mv;
	}
  • 根据流程任务id获取流程定义信息:
	@Override
	public ProcessDefinition findProcessDefinitionByTaskId(String taskId) {
    
    
		//使用任务ID,查询任务对象
		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
		//获取流程定义ID
		String processDefinitionId = task.getProcessDefinitionId();
		//查询流程定义的对象
		ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()//创建流程定义查询对象,对应表act_re_procdef 
					.processDefinitionId(processDefinitionId)//使用流程定义ID查询
					.singleResult();
		return pd;
	}
  • 查看当前活动的任务的坐标位置:
	@Override
	public Map<String, Object> findCoordingByTask(String taskId) {
    
    
		//存放坐标
		Map<String, Object> map = new HashMap<String,Object>();
		//使用任务ID,查询任务对象
		Task task = taskService.createTaskQuery()//
					.taskId(taskId)//使用任务ID查询
					.singleResult();
		//获取流程定义的ID
		String processDefinitionId = task.getProcessDefinitionId();
		//获取流程定义的实体对象(对应.bpmn文件中的数据)
		ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity)repositoryService.getProcessDefinition(processDefinitionId);
		//流程实例ID
		String processInstanceId = task.getProcessInstanceId();
		//使用流程实例ID,查询正在执行的执行对象表,获取当前活动对应的流程实例对象
		ProcessInstance pi = runtimeService.createProcessInstanceQuery()//创建流程实例查询
											.processInstanceId(processInstanceId)//使用流程实例ID查询
											.singleResult();
		//获取当前活动的ID
		String activityId = pi.getActivityId();
		//获取当前活动对象
		ActivityImpl activityImpl = processDefinitionEntity.findActivity(activityId);//活动ID
		//获取坐标
		map.put("x", activityImpl.getX());
		map.put("y", activityImpl.getY());
		map.put("width", activityImpl.getWidth());
		map.put("height", activityImpl.getHeight());
		return map;
	}
  • jsp页面显示当前流程图片:
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>查看当前流程图</title>
</head>
<body>
<!-- 1.获取到规则流程图 -->
<img style="position: absolute;top: 0px;left: 0px;" src="viewImage?deploymentId=${deploymentId}&imageName=${imageName}">

<!-- 2.根据当前活动的坐标,动态绘制DIV -->
<div style="position: absolute;border:2px solid red;top:${
       
       acs.y}px;left: ${
       
       acs.x}px;width:${
       
       acs.width}px;height:${
       
       acs.height}px;"></div></body>
</html>

猜你喜欢

转载自blog.csdn.net/weixin_45879810/article/details/108714499