在线办公系统之三 整合Activiti框架

工作流框架是什么?

工作流框架则是为了解决业务流程诞生的。对于同一件事件,从起始到结束中间会经历非常多的状态甚至事件回退等操作。通过业务代码的方式实现该套逻辑较为复杂,且不可复用。而工作流框架是针对此种情况(购物流程、请假流程等等)提取出来的通用解决方案,让开发省去事件流转状态的操作

现在绝大部分的工作流引擎都是根据2011年发布的BPMN2.0规范实现,BPMN2.0统一了业务流程图的标准,让各种工作流引擎的流程设计器可以通用。

Activiti又是什么

Activiti项目是一项新的基于Apache许可的开源BPM平台,从基础开始构建,旨在提供支持新的BPMN 2.0标准,包括支持对象管理组(OMG),面对新技术的机遇,诸如互操作性和云架构,提供技术实现。
创始人Tom Baeyens是JBoss jBPM的项目架构师,以及另一位架构师Joram Barrez,一起加入到创建Alfresco这项首次实现Apache开源许可的BPMN 2.0引擎开发中来。
Activiti是一个独立运作和经营的开源项目品牌,并将独立于Alfresco开源ECM系统运行。 Activiti将是一种轻量级,可嵌入的BPM引擎,而且还设计适用于可扩展的云架构。 Activiti将提供宽松的Apache许可2.0,以便这个项目可以广泛被使用,同时促进Activiti BPM引擎和BPMN 2.0的匹配,该项目现正由OMG通过标准审定。 加入Alfresco Activiti项目的是VMware的SpringSource分支,Alfresco的计划把该项目提交给Apache基础架构,希望吸引更多方面的BPM专家和促进BPM的创新。

工作流的个人理解

可能结合上述两个点,还没怎么明白Activiti工作流的作用吧,其实我最大的体会就在于流程理解,还在学习的同学可能会不清楚,但是工作中的同志们肯定是深有体会的,
例如,你出差了,自己先垫付一部分费用,需要报销,这时候财务就会一脸冷漠的跟你说:“在系统上走个报销流程”
再比如,某某地举办动漫展,不想工作了,去参展,你得请假,然后人事给你来了一句:“系统上走个请假流程吧~!”
其实工作流的最大特点是,我们的申请,需要审批,它将对应的每个工作节点具象化,让对应工作中需要参与的人员都聚到一个流程图上,通过流程图,就能找到相应的审批人,进行批复,到达流程终点,你就能得到相应的工作批示回复。

这是个人项目后的拙见,当然,如果我们不使用工作流,可不可以?当然可以,在如今的社会,有一个软件,已经可以做到外插式的工作流软件,同时可以大量降低公司在这部分的开销,那就是钉钉。

那这个项目嵌入工作流到底有什么意义啊?
既然我们都可以用钉钉代替了,那我们反过来想,如果企业比较大,它会不会考虑用外插式的工作流软件呢?公司员工信息容易外漏。所以,钉钉市场体量的确越来越大,那是相对于企业量级来说的,当然,对于程序员来说,其实这是为了更好的了解业务,当你的练手项目融入Activiti之后,不停地练习,你会对CURD(增删改查)有一个新的体会。

Activiti 的配置

我们首先要抓住大纲:
工作流都得以你系统上有它实例化之后的数据库为准。

@Test
	public void testJDBC(){
		
		ProcessEngineConfiguration config=ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();
		String jdbcUrl="jdbc:mysql://localhost:3306/activitidb?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=utf8";
		String jdbcDriver="com.mysql.jdbc.Driver";
		String jdbcUsername="root";
		String jdbcPassword="root";
		
		config.setJdbcUrl(jdbcUrl);
		config.setJdbcDriver(jdbcDriver);
		config.setJdbcUsername(jdbcUsername);
		config.setJdbcPassword(jdbcPassword);
		//默认
		config.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
		ProcessEngine engine=config.buildProcessEngine();
		System.out.println(engine);
		
	}

一个工作流如何形成规范,其实整个项目下来之后,我的体会就可以变成一条线:
部署流程---->任务实例(发起)---->任务推进---->任务完成—>查看历史等操作。
工作流首先要简历对应的数据库表格,每一块都有具体的作用,具体可以自行搜索,这里不做赘述。
那我们在嵌入框架的时候,还是那句话,不要死记硬背,要知道工作流为我们解决什么问题,怎么解决!
工作流既然有自己的独特的数据库配置,那么它也必须创建数据库表和连接数据库咯~! 根据上述TEST代码,我们可以将对应的配置按照如下文件进行配置

  • activiti.cfg.xml 数据库创建以及连接配置
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
	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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

	<bean id="processEngineConfiguration"
		class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
		<!-- 连接数据的配置 -->
		<property name="jdbcDriver" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl"
			value="jdbc:mysql://localhost:3306/activitidb?useUnicode=true&amp;characterEncoding=utf8"></property>
		<property name="jdbcUsername" value="root"></property>
		<property name="jdbcPassword" value="root"></property>
		<!-- 没有表创建表 -->
		<property name="databaseSchemaUpdate" value="true"></property>
	</bean>

</beans>

那连接完毕之后,我们对应把数据库不同的表,划分一下区域
以下是个人理解
例如流程部署----->其实就是你发布一个怎样的流程,例如报销流程,请假流程,当用户需要走流程的时候,就按照你这个大纲来走

<bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" />

正在审批中的,或者已经发起的流程,需要推进的,都会在这里记录

	<bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService" />
	<bean id="taskService" factory-bean="processEngine" factory-method="getTaskService" />

正在进行或者已经审批完毕的,都会在历史记录里面产生记录。

<bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService" />

那么这些Service是从哪里来的呢?这就涉及我们的框架其中一个核心,就是流程引擎,我们在SSM中,可以按照如下配置,然后让对应的Service进行实例化,当我们要进行怎样的操作,就可以用这些封装好的业务进行操作。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

	<!-- spring负责创建流程引擎的配置文件 -->
	<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
		<!-- 数据源 -->
		<property name="dataSource" ref="dataSource" />
		<!-- 配置事务管理器,统一事务 -->
		<property name="transactionManager" ref="transManager" />
		<!-- 设置建表策略,如果没有表,自动创建表 -->
		<property name="databaseSchemaUpdate" value="true" />
	</bean>
	<!-- 创建流程引擎对象 -->
	<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
		<property name="processEngineConfiguration" ref="processEngineConfiguration" />
	</bean>
	
	<!-- 由流程引擎对象,提供的方法,创建项目中使用的Activiti工作流的Service -->
	<bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" />
	<bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService" />
	<bean id="taskService" factory-bean="processEngine" factory-method="getTaskService" />
	<bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService" />
	<bean id="formService" factory-bean="processEngine" factory-method="getFormService" />
	
</beans>

Eclipse 中的画图插件

这里的画图插件上网查询Eclipse的Activiti插件就可以,对了,对应IDEA也有,但是如果真的使用起来,强烈推荐Eclipse,IDEA有很多BUG,亲测痛苦。

在这里插入图片描述
当然了,工作流的其中最大的优点在于他是将对应的工作节点,通过图进行节点明确,其中每个节点都可以放置监听类,表名对应的审批人员是谁,这样能够让整体程序更灵活。

package com.activiti.ssm.utils;

import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;
import org.apache.shiro.SecurityUtils;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;
import com.activiti.ssm.pojo.ActiveUser;
import com.activiti.ssm.pojo.Employee;
import com.activiti.ssm.service.EmployeeService;


public class TaskAssignHandler implements TaskListener {
	
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Override
	public void notify(DelegateTask task) {
//	     查询当前任务代办人的上级,通过硬编码获取employeeService
//       通过SPRING容器,获取对应的SERVICE实例
       WebApplicationContext webApplicationContext= ContextLoader.getCurrentWebApplicationContext();
       EmployeeService employeeService= (EmployeeService) webApplicationContext.getBean("employeeService");
//       通过对应的Subject获取ActivitiUser,其中已经封装好了对应获取上级ID方法
//       获取上级
       ActiveUser user=(ActiveUser) SecurityUtils.getSubject().getPrincipal();
       Employee Man=employeeService.findManagerByMid(user.getManagerId());
       task.setAssignee(Man.getName());
	}

}

还有更为复杂的流程,多分支结构,但是如何走向和控制呢?其实在每个流程走向添加流程变量就可以了,会按照实际传入的对象进行判断走向。

@Override
	public void submitTask(Long id, String outcome, String taskId, String comment, String name) {
		// 历史评论表进行添加批注
		Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
		// 获取流程实例ID
		String processInstanceId = task.getProcessInstanceId();
		// ACTIVI底层-->认证--->CommentEntity comment=new Comment();
		// comment.setuserID=xxx
		// session中的emp有对应的ID
		Authentication.setAuthenticatedUserId(name);
		taskService.addComment(taskId, processInstanceId, comment);
		// 完成任务
		/**
		 * 2:如果连线的名称是“默认提交”,那么就不需要设置,如果不是,就需要设置流程变量
		 * 在完成任务之前,设置流程变量,按照连线的名称,去完成任务
		 * 流程变量的名称:outcome
		 * 流程变量的值:连线的名称
		 */
		Map<String, Object> variables = new HashMap<String, Object>();
		if (outcome != null && !outcome.equals("默认提交")) {
			variables.put("message", outcome);
			// 3:使用任务ID,完成当前人的个人任务,同时流程变量
			taskService.complete(taskId, variables);
		} else {
			taskService.complete(taskId);
		}
		// 获取流程实例 并且判断是否完成整个流程实例
		ProcessInstance instance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId)
				.singleResult();
		if (instance == null) {
			Expensebill expensebill = expensebillMapper.selectByPrimaryKey(Integer.parseInt(id + ""));
			// 将leavebill的状态修改为2,表示已经完成了
			expensebill.setState(2);
			expensebillMapper.updateByPrimaryKeySelective(expensebill);

		}

	}

其实整个项目下来,工作流在对应节点的处理方法千篇一律,但是最主要的还是确认好流程图,到了什么节点,需要做什么操作,这点比较关键。

总结

创建并数据库、流程引擎配置、画图、每个任务节点安放对应的审批人、流程线配置流程参数、对应流程引擎处理的方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值