学习目的
- 为了解决项目中某些特殊的业务场景,流程审批业务(请假审批,出差审批,申请单审批,报销单审批,公文的流转)。
设计思想
- 比如开发请假流程(员工请假申请apply–>部门经理审批–>if(请假天数>3天)–>总经理审批–>结束
-->if(请假天数<=3天)–>结束)。
-
第一步:提供了ide插件,可视化流程定义,以bpmn流程定义描述性语言(xml描述)。
-
第二步:提供api服务接口,进行部署流程定义(解析xml, 把xml流程数据保存到数据库)。
-
第三步:开发请假申请业务(增删改查),调用组件api服务去驱动流程向下一步步的执行。
使用
- 搭建activiti数据库环境(各种组件内的表)
- 运行三个sql脚本创建数据库表
- act_ge_*:元数据表(存储引擎版本信息,流程定义xml文件数据)
- act_id_*:用户与角色表(存储系统用户与用户组信息)
- act_re_*:流程部署表(存储流程部署信息,流程定义文件信息)
- act_ru_*:正在执行当中的流程数据表(存储流程实例与任务信息)
- act_hi_*:执行完结的流程数据历史表(存储历史流程实例与历史任务信息)
- 运行三个sql脚本创建数据库表
- 搭建代码环境 (依赖jar包)与spring集成使用,依赖mybatis
- 引入依赖jar
- 创建activiti的xml配置文件,注入spring容器相关的bean对象(ProcessEngineConfiguration,ProcessEngine,5个核心服务bean)
pom
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring</artifactId>
<version>5.22.0</version>
</dependency>
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.spring.SpringProcessEngineConfiguration">
<property name="dataSource" ref="dataSource"/>
<property name="transactionManager" ref="transactionManager"/>
<property name="databaseSchemaUpdate" value="false"/>
<property name="jobExecutorActivate" value="false"/>
</bean>
<!-- 这个是activiti的核心类,这个类依赖另一个类processEngineConfiguration -->
<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
<property name="processEngineConfiguration" ref="processEngineConfiguration"/>
</bean>
<bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService"/>
<bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService"/>
<bean id="identityService" factory-bean="processEngine" factory-method="getIdentityService"/>
<bean id="taskService" factory-bean="processEngine" factory-method="getTaskService"/>
<bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService"/>
</beans>
- 设计流程定义文件并进行部署
-
安装插件:actiBpm
-
流程定义的节点(id,name,assignee|candidate users|candidate groups(节点的执行人))
-
生成png图片
-
进行流程部署
-
自己建立的任务表,一定要有对应的任务id字段(processid)
流程变量
流程定义中的表达式,称为流程变量
-
${loginUser}
-
groups: deptMgr
-
users:mgr1,mgr2
-
${days<=3}
-
${approveResult}:审批通过与否
流程部署及执行
测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring.xml")
public class activitiTest {
@Resource
private LeaveService leaveService;
@Resource
private RepositoryService rs;
@Resource
private IdentityService is;
/**
* 流程部署,正式开发中在系统管理-流程定义(增删查)
*/
@Test
public void deployTest() {
DeploymentBuilder deployment = rs.createDeployment();
deployment.name("请假申请");
deployment.addClasspathResource("bpmn/LeaveApply.bpmn");
deployment.addClasspathResource("bpmn/LeaveApply.png");
Deployment deploy = deployment.deploy(); // 执行数据库的insert操作
String id = deploy.getId();
System.out.println(id);
}
// 查询流程
@Test
public void deployQueryTest() {
DeploymentQuery deploymentQuery = rs.createDeploymentQuery();
List<Deployment> list = deploymentQuery.list();
System.out.println(list);
}
/**
* 维护用户信息与组信息,流程审核权限的分配;
* 实现系统用户表的人,除了自身的系统用户表以外,还需要在流程控制组件内的用户表维护一份
*/
@Test
public void addUser() {
User wj = is.newUser("wj"); // 普通员工
User deptMgr1 = is.newUser("deptMgr1"); // 部门经理1
User deptMgr2 = is.newUser("deptMgr2"); // 部门经理2
User mgr1 = is.newUser("mgr1"); // 总经理1
User mgr2 = is.newUser("mgr2"); // 总经理2
is.saveUser(wj);
is.saveUser(deptMgr1);
is.saveUser(deptMgr2);
is.saveUser(mgr1);
is.saveUser(mgr2);
}
// 维护组信息
@Test
public void addGroup() {
Group employee = is.newGroup("employee");
Group deptMgr = is.newGroup("deptMgr");
Group mgr = is.newGroup("mgr");
is.saveGroup(employee);
is.saveGroup(deptMgr);
is.saveGroup(mgr);
}
@Test
public void addMemberShip() {
is.createMembership("wj", "employee");
is.createMembership("deptMgr1", "deptMgr");
is.createMembership("deptMgr2", "deptMgr");
is.createMembership("mgr1", "mgr");
is.createMembership("mgr2", "mgr");
}
/**
* 开始流程
*/
// 保存草稿
@Test
public void addLeaveApplyTest() {
LeaveApply apply = new LeaveApply();
apply.setLapplyuser("张三");
apply.setLreason("探亲");
apply.setLdays("10");
leaveService.addLeaveApply(apply);
}
// 保存请假申请单并开始流程审批
@Test
public void addLeaveApplyAndStartProcessTest() {
String loginUser = "wj"; // 当前系统登录人
LeaveApply apply = new LeaveApply();
apply.setLapplyuser("wj");
apply.setLreason("探亲");
apply.setLdays("10");
leaveService.startProcess(apply, loginUser);
}
//获取代办任务列表,deptMgr1与deptMgr2登录系统后都能看到部门经理审批的任务
@Test
public void getTodoTask(){
String loginUser="deptMgr2";
List<Task> todoTask = leaveService.getTodoTask(loginUser);
System.out.println(todoTask);
}
//在页面添加签收操作
@Test
public void claimTask(){
String loginUser="mgr2";
String taskid = "17505";
ls.claimTask(loginUser,taskid);
}
// 总经理审批
@Test
public void approve(){
String loginUser="mgr2";
String taskid = "17505";
boolean approveResult = true;
ls.approveTask(loginUser,taskid,"回家吧",approveResult);
}
}
LeaveService
public interface ILeaveService {
public void addLeaveApply(LeaveApply apply);
// 启动流程
void startProcess(LeaveApply la,String loginUser);
// 获得代办任务
List<ProcessTask> getTodoTask(String loginUser);
// 签收任务
void claimTask(String loginUser, String taskid);
void approveTask(String loginUser, String taskid,String comment,boolean approveResult);
}
LeaveServiceImpl
@Service
public class LeaveServiceImpl implements ILeaveService {
@Resource
private LeaveApplyMapper lm;
@Resource
private RuntimeService rs;
@Resource
private TaskService ts;
@Override
public void addLeaveApply(LeaveApply apply) {
lm.insertSelective(apply);
}
@Transactional
@Override
public void startProcess(LeaveApply la,String loginUser) {
//保存请假申请单
addLeaveApply(la);
//开始流程(流程定义的key,流程依赖的变量)
Map<String,Object> valiables = new HashMap<>();
valiables.put("loginUser",loginUser);
valiables.put("days",la.getLdays());
ProcessInstance processInstance = rs.startProcessInstanceByKey("LEAVE_APPLY",valiables);//
String processInstanceId = processInstance.getId();
//把请假申请task继续向下执行
String taskid = querySingTaskByAssigneeAndPid(processInstanceId,loginUser).getId();
ts.complete(taskid);//完成某个task
//把processInstanceId作为外键关联到请假申请单
la.setProcessid(processInstanceId);
updateProcessId(la);
}
//获取所有的代办任务列表(包含申请单信息以及Task对象信息)
@Override
public List<ProcessTask> getTodoTask(String loginUser) {
List<ProcessTask> result = new ArrayList<>();
TaskQuery taskQuery = ts.createTaskQuery();
taskQuery.taskCandidateOrAssigned(loginUser);
taskQuery.processDefinitionKey("LEAVE_APPLY");//不指定该条件是得到所有的流程定义下的代办任务列表,适合于放欢迎页面
List<Task> list = taskQuery.list();
for (Task t:list){
String processInstanceId = t.getProcessInstanceId();
//根据流程实例id,去查询申请单详情。
LeaveApply leaveApply = queryLeaveApplyByProcessId(processInstanceId);
ProcessTask pt = new ProcessTask();
pt.setOrder(leaveApply);
pt.setTask(t);
result.add(pt);
}
return result;
}
@Override
public void claimTask(String loginUser, String taskid) {
ts.claim(taskid,loginUser);
}
public LeaveApply queryLeaveApplyByProcessId(String processid){
LeaveApply la = lm.selectByProcessId(processid);
return la;
}
public void updateProcessId(LeaveApply la){
lm.updateByPrimaryKeySelective(la);
}
//根据流程实例id与执行人查询task对象
public Task querySingTaskByAssigneeAndPid(String processInstanceId,String assignee){
TaskQuery taskQuery = ts.createTaskQuery();
taskQuery.processInstanceId(processInstanceId);
taskQuery.taskAssignee(assignee);//指定了执行人
Task task = taskQuery.singleResult();
return task;
}
//审批任务(审批结果,审批意见,审批人)
@Override
public void approveTask(String loginUser,String taskid,String comment, boolean approveResult) {
TaskQuery taskQuery = ts.createTaskQuery();
taskQuery.taskId(taskid);
String processInstanceId = taskQuery.singleResult().getProcessInstanceId();
Map<String,Object> valiables = new HashMap<>();
valiables.put("approveResult",approveResult);
ts.addComment(taskid,processInstanceId,"通过",comment);
ts.complete(taskid,valiables);
}
}