工作流-Activiti 开发
工作流概述
工作流(workflow)就是工作流程的计算模型,我们常见的请假电子流就是一个简单的工作流。
JavaWeb 工作流开发准备
使用Eclipse开发,需要安排工作流插件
离线安装安装步骤:Eclipse插件安装
new->other 检查安装是否成功
简单开发流程
1.新建一个项目
2.添加配置文件-创建数据库表
新建一个配置文件,名为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">
<!-- 配置 ProcessEngineConfiguration -->
<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?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=utf8"></property>
<property name="jdbcUsername" value="root"></property>
<property name="jdbcPassword" value="rootxxx"></property>
<!-- 配置创建表策略 :没有表时,自动创建 测试方式 -->
<property name="databaseSchemaUpdate" value="true"></property>
</bean>
</beans>
数据库支持:需要创建的23张表
ACT_RE_*: 'RE'表示repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。
ACT_RU_*: 'RU'表示runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Activiti只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快。
ACT_ID_*: 'ID'表示identity。 这些表包含身份信息,比如用户,组等等。
ACT_HI_*: 'HI'表示history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。
ACT_GE_*: 通用数据, 用于不同场景下,如存放资源文件。
生产环境采用手动创建-按如下路径获取相应数据库的脚本
建表并创建流程引擎
public void createTableXml()
{
// 创建Activiti配置对象的实例-加载数据库-创建表
//ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
//默认获取类路径下的activiti.cfg.xml文件与上面等价
ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResourceDefault();
// 使用配置对象创建流程引擎实例
ProcessEngine processEngine = configuration.buildProcessEngine();
System.out.println(processEngine);
}
3.流程图设计
线的设计:
4.部署
public void deployMentProcess(){
Deployment deployment = processEngine.getRepositoryService()
.createDeployment()
.name("fristActive")
.addClasspathResource("diagrams/fristActive.bpmn")
.addClasspathResource("diagrams/fristActive.png")
.deploy();
System.out.println(deployment.getId()+":"+deployment.getName());
}
// ZIP 方式部署(将上面两个文件压缩为zip)
@Test
public void deployProcessDefiByZip(){
InputStream in=getClass().getClassLoader().getResourceAsStream("fristActive.zip");
Deployment deploy = processEngine.getRepositoryService()
.createDeployment()
.name("fristActive")
.addZipInputStream(new ZipInputStream(in))
.deploy();
System.out.println("部署名称:"+deploy.getName());
System.out.println("部署id:"+deploy.getId());
}
表操作
5.启动流程
public void statProcess(){
// 当前流程的名称
String processName = "fristActive";
// 流程启动服务
RuntimeService ru = processEngine.getRuntimeService();
// 流程参数
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("areaer", "区域主管");
variables.put("Creater", "创建人");
variables.put("leader", "直接主管");
variables.put("caiwuyuan", "财务");
variables.put("isPass", true);
variables.put("day", 3);
// 带参启动
ProcessInstance pi = ru.startProcessInstanceByKey(processName,variables);
System.out.println("流程实例id:"+pi.getId());//流程实例id
System.out.println("流程定义id:"+pi.getProcessDefinitionId());//输出流程定义的id
}
操作表:act_ru_execution.ID_=act_ru_execution.Execution_ID_,一一对应关系、
判断流程结束:act_ru_execution表中的proc_inst_id_ 不存在
6.审批
//执行任务
public void compileTask(String taskId){
//taskId:任务id
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("areaer", "区域主管");
variables.put("Creater", "创建人");
variables.put("leader", "直接主管");
variables.put("caiwuyuan", "财务");
variables.put("day", 4);
variables.put("isPass", true);
boolean haveDay = scan.nextBoolean();
variables.put("haveDay", true);
processEngine.getTaskService().complete(taskId,variables);
System.out.println("当前任务执行完毕");
queryTaskAll();
}
7.查询
//获取流程实例的状态
//判断流程结束:act_ru_execution表中的proc_inst_id_ 不存在
@Test
public void getProcessInstanceState(){
String processInstanceId="301";
ProcessInstance pi = processEngine.getRuntimeService()
.createProcessInstanceQuery()
.processInstanceId(processInstanceId)
.singleResult();//返回的数据要么是单行,要么是空 ,其他情况报错
//判断流程实例的状态
if(pi!=null){
System.out.println("该流程实例"+processInstanceId+"正在运行... "+"当前活动的任务:"+pi.getActivityId());
}else{
System.out.println("当前的流程实例"+processInstanceId+" 已经结束!");
}
}
//查询当前代办
public void queryTask(){
//任务的办理人
String assignee="创建人";
//取得任务服务
TaskService taskService = processEngine.getTaskService();
//创建一个任务查询对象
TaskQuery taskQuery = taskService.createTaskQuery();
//办理人的任务列表
List<Task> list = taskQuery.taskAssignee(assignee)//指定办理人
.list();
//遍历任务列表
if(list!=null&&list.size()>0){
for(Task task:list){
System.out.println("任务的办理人:"+task.getAssignee());
System.out.println("任务的id:"+task.getId());
System.out.println("任务的名称:"+task.getName());
}
}
}
//查看历史执行流程任务信息
@Test
public void queryHistoryTask(){
String processInstanceId="101";// 实例id
List<HistoricTaskInstance> list = processEngine.getHistoryService()
.createHistoricTaskInstanceQuery()
.processInstanceId(processInstanceId)
.list();
if(list!=null&&list.size()>0){
for(HistoricTaskInstance temp:list){
System.out.print("历史流程实例任务id:"+temp.getId());
System.out.print("历史流程定义的id:"+temp.getProcessDefinitionId());
System.out.print("历史流程实例任务名称:"+temp.getName());
System.out.println("历史流程实例任务处理人:"+temp.getAssignee());
}
}
}
//查看历史执行流程实例信息
@Test
public void queryHistoryProcInst(){
List<HistoricProcessInstance> list = processEngine.getHistoryService()
.createHistoricProcessInstanceQuery()
.list();
if(list!=null&&list.size()>0){
for(HistoricProcessInstance temp:list){
System.out.println("历史流程实例id:"+temp.getId());
System.out.println("历史流程定义的id:"+temp.getProcessDefinitionId());
System.out.println("历史流程实例开始时间--结束时间:"+temp.getStartTime()+"-->"+temp.getEndTime());
}
}
}
8.附加工能
(1)设置下一层处理人
- 在bpmn 设计直接写死
- 当前执行完指定下层审批人(配置如下,代码指定为步骤6)
- 使用监听指定当前任务的当前处理人
public class TaskListenerImpl implements TaskListener {
/**
* 不仅可以指定当前处理人,可以获取当前任务的参数
*/
private static final long serialVersionUID = 1L;
/**指定个人任务和组任务的办理人*/
@Override
public void notify(DelegateTask delegateTask) {
String assignee = "当前责任人";
//指定个人任务
delegateTask.setAssignee(assignee);
}
}
- 责任人转移
//使用任务ID和办理人重新指定办理人:
processEngine.getTaskService().setAssignee(taskId, userId);
SpringBoot整合
步骤1
pom.xml引入jar包(只引入主要的jar包,其他略)
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.xxx</groupId>
<artifactId>xxx</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter-basic</artifactId>
<version>6.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
步骤2 主配置文件application,设计好bpmn流程图
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/activity?characterEncoding=utf8&useSSL=true
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.show-sql=true
server.port=8081
server.context-path=/activity
server.session.timeout=10
server.tomcat.uri-encoding=UTF-8
3.实现简要代码,主类这里省略不写,主要写具体实现
(1)页面创建提交流程服务接口
@RestController
@RequestMapping("/submitService")
public interface ActivityConsumerService {
/**
* 流程提交
* @return
*/
@RequestMapping(value="/submitActive",method=RequestMethod.GET)
public boolean submitActive();
}
(2) 提交服务实现
@Service("submitService")
public class ActivityConsumerServiceImpl implements ActivityConsumerService {
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Override
public boolean submitActive() {
System.out.println("method submitActivebegin....");
Map<String,Object> map = new HashMap<String,Object>();
map.put("apply","zhangsan");
map.put("approve","lisi");
//流程启动
ExecutionEntity pi1 = (ExecutionEntity) runtimeService.startProcessInstanceByKey("leave",map);
String processId = pi1.getId();
String taskId = pi1.getTasks().get(0).getId();
taskService.complete(taskId, map);//完成第一步申请
Task task = taskService.createTaskQuery().processInstanceId(processId).singleResult();
String taskId2 = task.getId();
map.put("pass", false);
taskService.complete(taskId2, map);//驳回申请
System.out.println("method submitActive end....");
return false;
}
}
测试一下就可以了
参考文献
Activiti 5.16 用户手册: http://www.mossle.com/docs/activiti/index.html#N1007D