12.21 在 Spring Boot 項目中使用 activiti


在 Spring Boot 項目中使用 activiti


新建springBoot項目時勾選activiti,或者在已建立的springBoot項目添加以下依賴:

<code><dependency>
<groupid>org.activiti/<groupid>
<artifactid>activiti-spring-boot-starter-basic/<artifactid>
<version>6.0.0/<version>
/<dependency>/<code>

數據源和activiti配置:

<code>server:
port: 8081

spring:
datasource:
url: jdbc:mysql://localhost:3306/act5?useSSL=true
driver-class-name: com.mysql.jdbc.Driver
username: root
password: root

# activiti default configuration
activiti:
database-schema-update: true
check-process-definitions: true
process-definition-location-prefix: classpath:/processes/
# process-definition-location-suffixes:
# - **.bpmn
# - **.bpmn20.xml
history-level: full/<code>

在activiti的默認配置中,process-definition-location-prefix 是指定activiti流程描述文件的前綴(即路徑),啟動時,activiti就會去尋找此路徑下的流程描述文件,並且自動部署;suffix 是一個String數組,表示描述文件的默認後綴名,默認以上兩種。


springMVC配置:


<code>package com.yawn.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.config.annotation.*;

/**
* Created by yawn on 2017/8/5.
*/
@EnableWebMvc
@Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
registry.addResourceHandler("/templates/**").addResourceLocations("classpath:/templates/");
super.addResourceHandlers(registry);
}

@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/index");
registry.addViewController("/user");
registry.addRedirectViewController("/","/templates/login.html");
// registry.addStatusController("/403", HttpStatus.FORBIDDEN);
super.addViewControllers(registry);
}
}/<code>


這裡配置靜態資源和直接訪問的頁面:在本示例項目中,添加了thymeleaf依賴解析視圖,主要採用異步方式獲取數據,通過angularJS進行前端數據的處理和展示。

配置了數據源和activiti後,啟動項目,activiti 的各個服務組件就已經被加入到spring容器中了,所以就可以直接注入使用了。如果在未自動配置的spring環境中,可以使用通過指定bean的init-method來配置activiti的服務組件。

以以下請假流程為例:


在 Spring Boot 項目中使用 activiti


1. 開始流程並“申請請假”(員工)


<code>private static final String PROCESS_DEFINE_KEY = "vacationProcess";


public Object startVac(String userName, Vacation vac) {

identityService.setAuthenticatedUserId(userName);
// 開始流程
ProcessInstance vacationInstance = runtimeService.startProcessInstanceByKey(PROCESS_DEFINE_KEY);
// 查詢當前任務
Task currentTask = taskService.createTaskQuery().processInstanceId(vacationInstance.getId()).singleResult();
// 申明任務
taskService.claim(currentTask.getId(), userName);

Map<string> vars = new HashMap<>(4);
vars.put("applyUser", userName);
vars.put("days", vac.getDays());
vars.put("reason", vac.getReason());
// 完成任務
taskService.complete(currentTask.getId(), vars);

return true;
}/<string>/<code>


在此方法中,Vaction 是申請時的具體信息,在完成“申請請假”任務時,可以將這些信息設置成參數。


2. 審批請假(老闆)

(1)查詢需要自己審批的請假


<code>public Object myAudit(String userName) {
List<task> taskList = taskService.createTaskQuery().taskCandidateUser(userName)
.orderByTaskCreateTime().desc().list();
// / 多此一舉 taskList中包含了以下內容(用戶的任務中包含了所在用戶組的任務)
// Group group = identityService.createGroupQuery().groupMember(userName).singleResult();
// List<task> list = taskService.createTaskQuery().taskCandidateGroup(group.getId()).list();
// taskList.addAll(list);
List<vactask> vacTaskList = new ArrayList<>();
for (Task task : taskList) {
VacTask vacTask = new VacTask();
vacTask.setId(task.getId());
vacTask.setName(task.getName());
vacTask.setCreateTime(task.getCreateTime());
String instanceId = task.getProcessInstanceId();
ProcessInstance instance = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).singleResult();
Vacation vac = getVac(instance);
vacTask.setVac(vac);
vacTaskList.add(vacTask);
}
return vacTaskList;
}

private Vacation getVac(ProcessInstance instance) {
Integer days = runtimeService.getVariable(instance.getId(), "days", Integer.class);
String reason = runtimeService.getVariable(instance.getId(), "reason", String.class);
Vacation vac = new Vacation();
vac.setApplyUser(instance.getStartUserId());
vac.setDays(days);
vac.setReason(reason);
Date startTime = instance.getStartTime(); // activiti 6 才有
vac.setApplyTime(startTime);
vac.setApplyStatus(instance.isEnded() ? "申請結束" : "等待審批");
return vac;
}

package com.yawn.entity;

import java.util.Date;

/**
* @author Created by yawn on 2018-01-09 14:31
*/
public class VacTask {

private String id;
private String name;
private Vacation vac;
private Date createTime;

// getter setter ...
}/<vactask>/<task>/<task>/<code>


老闆查詢自己當前需要審批的任務,並且將任務和參數設置到一個VacTask對象,用於頁面的展示。


(2)審批請假


<code>public Object passAudit(String userName, VacTask vacTask) {
String taskId = vacTask.getId();
String result = vacTask.getVac().getResult();
Map<string> vars = new HashMap<>();
vars.put("result", result);
vars.put("auditor", userName);
vars.put("auditTime", new Date());
taskService.claim(taskId, userName);
taskService.complete(taskId, vars);
return true;
}/<string>/<code>


同理,result是審批的結果,也是在完成審批任務時需要傳入的參數;taskId是剛才老闆查詢到的當前需要自己完成的審批任務ID。(如果流程在這裡設置分支,可以通過判斷result的值來跳轉到不同的任務)


3. 查詢記錄


由於已完成的請假在數據庫runtime表中查不到(runtime表只保存正在進行的流程示例信息),所以需要在history表中查詢。


(1) 查詢請假記錄


<code>public Object myVacRecord(String userName) {
List<historicprocessinstance> hisProInstance = historyService.createHistoricProcessInstanceQuery()
.processDefinitionKey(PROCESS_DEFINE_KEY).startedBy(userName).finished()
.orderByProcessInstanceEndTime().desc().list();

List<vacation> vacList = new ArrayList<>();
for (HistoricProcessInstance hisInstance : hisProInstance) {
Vacation vacation = new Vacation();
vacation.setApplyUser(hisInstance.getStartUserId());
vacation.setApplyTime(hisInstance.getStartTime());
vacation.setApplyStatus("申請結束");
List<historicvariableinstance> varInstanceList = historyService.createHistoricVariableInstanceQuery()
.processInstanceId(hisInstance.getId()).list();
ActivitiUtil.setVars(vacation, varInstanceList);
vacList.add(vacation);
}
return vacList;
}/<historicvariableinstance>/<vacation>/<historicprocessinstance>/<code>


請假記錄即查出歷史流程實例,再查出關聯的歷史參數,將歷史流程實例和歷史參數設置到Vcation對象(VO對象)中去,即可返回,用來展示。

<code>package com.yawn.util;

import org.activiti.engine.history.HistoricVariableInstance;

import java.lang.reflect.Field;
import java.util.List;

/**
* activiti中使用得到的工具方法
* @author Created by yawn on 2018-01-10 16:32
*/
public class ActivitiUtil {

/**
* 將歷史參數列表設置到實體中去
* @param entity 實體
* @param varInstanceList 歷史參數列表
*/
public static void setVars(T entity, List<historicvariableinstance> varInstanceList) {
Class> tClass = entity.getClass();
try {
for (HistoricVariableInstance varInstance : varInstanceList) {
Field field = tClass.getDeclaredField(varInstance.getVariableName());
if (field == null) {
continue;
}
field.setAccessible(true);
field.set(entity, varInstance.getValue());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}/<historicvariableinstance>
/<code>


此外,以上是查詢歷史流程實例和歷史參數後,設置VO對象的通用方法:可以根據參數列表中的參數,將與VO對象屬性同名的參數設置到VO對象中去。


4. 前端展示和操作


(1)審批列表和審批操作示例


在 Spring Boot 項目中使用 activiti


<code>

待我審核的請假


<table>

任務名稱
任務時間
申請人
申請時間
天數
事由
操作


{{vacTask.name}}
{{vacTask.createTime | date:'yyyy-MM-dd HH:mm:ss'}}
{{vacTask.vac.applyUser}}
{{vacTask.vac.applyTime | date:'yyyy-MM-dd HH:mm:ss'}}
{{vacTask.vac.days}}
{{vacTask.vac.reason}}


<button>審核通過/<button>
<button>審核拒絕/<button>


/<table>


app.controller("myAudit", function ($scope, $http, $window) {
$scope.vacTaskList = [];

$scope.myAudit = function () {
$http.get(
"/myAudit"
).then(function (response) {
$scope.vacTaskList = response.data;
})
};

$scope.passAudit = function (taskId, result) {
$http.post(
"/passAudit",
{
"id": taskId,
"vac": {
"result": result >= 1 ? "審核通過" : "審核拒絕"
}
}
).then(function (response) {
if (response.data === true) {
alert("操作成功!");
$window.location.reload();
} else {
alert("操作失敗!");
}
})
}
});/<code>


分享到:


相關文章: