新建springBoot項(xiàng)目時(shí)勾選activiti瞎疼,或者在已建立的springBoot項(xiàng)目添加以下依賴:
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter-basic</artifactId>
<version>6.0.0</version>
</dependency>
數(shù)據(jù)源和activiti配置:
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
在activiti的默認(rèn)配置中科乎,process-definition-location-prefix 是指定activiti流程描述文件的前綴(即路徑),啟動(dòng)時(shí)贼急,activiti就會(huì)去尋找此路徑下的流程描述文件茅茂,并且自動(dòng)部署;suffix 是一個(gè)String數(shù)組太抓,表示描述文件的默認(rèn)后綴名空闲,默認(rèn)以上兩種。
springMVC配置:
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);
}
}
這里配置靜態(tài)資源和直接訪問(wèn)的頁(yè)面:在本示例項(xiàng)目中走敌,添加了thymeleaf依賴解析視圖碴倾,主要采用異步方式獲取數(shù)據(jù),通過(guò)angularJS進(jìn)行前端數(shù)據(jù)的處理和展示。
配置了數(shù)據(jù)源和activiti后跌榔,啟動(dòng)項(xiàng)目异雁,activiti 的各個(gè)服務(wù)組件就已經(jīng)被加入到spring容器中了,所以就可以直接注入使用了僧须。如果在未自動(dòng)配置的spring環(huán)境中纲刀,可以使用通過(guò)指定bean的init-method來(lái)配置activiti的服務(wù)組件。
以以下請(qǐng)假流程為例:
1. 開(kāi)始流程并“申請(qǐng)請(qǐng)假”(員工)
private static final String PROCESS_DEFINE_KEY = "vacationProcess";
public Object startVac(String userName, Vacation vac) {
identityService.setAuthenticatedUserId(userName);
// 開(kāi)始流程
ProcessInstance vacationInstance = runtimeService.startProcessInstanceByKey(PROCESS_DEFINE_KEY);
// 查詢當(dāng)前任務(wù)
Task currentTask = taskService.createTaskQuery().processInstanceId(vacationInstance.getId()).singleResult();
// 申明任務(wù)
taskService.claim(currentTask.getId(), userName);
Map<String, Object> vars = new HashMap<>(4);
vars.put("applyUser", userName);
vars.put("days", vac.getDays());
vars.put("reason", vac.getReason());
// 完成任務(wù)
taskService.complete(currentTask.getId(), vars);
return true;
}
在此方法中担平,Vaction 是申請(qǐng)時(shí)的具體信息示绊,在完成“申請(qǐng)請(qǐng)假”任務(wù)時(shí),可以將這些信息設(shè)置成參數(shù)暂论。
2. 審批請(qǐng)假(老板)
(1)查詢需要自己審批的請(qǐng)假
public Object myAudit(String userName) {
List<Task> taskList = taskService.createTaskQuery().taskCandidateUser(userName)
.orderByTaskCreateTime().desc().list();
// / 多此一舉 taskList中包含了以下內(nèi)容(用戶的任務(wù)中包含了所在用戶組的任務(wù))
// 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() ? "申請(qǐng)結(jié)束" : "等待審批");
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 ...
}
老板查詢自己當(dāng)前需要審批的任務(wù)面褐,并且將任務(wù)和參數(shù)設(shè)置到一個(gè)VacTask對(duì)象,用于頁(yè)面的展示空另。
(2)審批請(qǐng)假
public Object passAudit(String userName, VacTask vacTask) {
String taskId = vacTask.getId();
String result = vacTask.getVac().getResult();
Map<String, Object> 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;
}
同理盆耽,result是審批的結(jié)果,也是在完成審批任務(wù)時(shí)需要傳入的參數(shù)扼菠;taskId是剛才老板查詢到的當(dāng)前需要自己完成的審批任務(wù)ID。(如果流程在這里設(shè)置分支坝咐,可以通過(guò)判斷result的值來(lái)跳轉(zhuǎn)到不同的任務(wù))
3. 查詢記錄
由于已完成的請(qǐng)假在數(shù)據(jù)庫(kù)runtime表中查不到(runtime表只保存正在進(jìn)行的流程示例信息)循榆,所以需要在history表中查詢。
(1) 查詢請(qǐng)假記錄
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("申請(qǐng)結(jié)束");
List<HistoricVariableInstance> varInstanceList = historyService.createHistoricVariableInstanceQuery()
.processInstanceId(hisInstance.getId()).list();
ActivitiUtil.setVars(vacation, varInstanceList);
vacList.add(vacation);
}
return vacList;
}
請(qǐng)假記錄即查出歷史流程實(shí)例墨坚,再查出關(guān)聯(lián)的歷史參數(shù)秧饮,將歷史流程實(shí)例和歷史參數(shù)設(shè)置到Vcation對(duì)象(VO對(duì)象)中去,即可返回泽篮,用來(lái)展示盗尸。
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 {
/**
* 將歷史參數(shù)列表設(shè)置到實(shí)體中去
* @param entity 實(shí)體
* @param varInstanceList 歷史參數(shù)列表
*/
public static <T> 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();
}
}
}
此外,以上是查詢歷史流程實(shí)例和歷史參數(shù)后帽撑,設(shè)置VO對(duì)象的通用方法:可以根據(jù)參數(shù)列表中的參數(shù)泼各,將與VO對(duì)象屬性同名的參數(shù)設(shè)置到VO對(duì)象中去。
4. 前端展示和操作
(1)審批列表和審批操作示例
<div ng-controller="myAudit">
<h2 ng-init="myAudit()">待我審核的請(qǐng)假</h2>
<table border="0">
<tr>
<td>任務(wù)名稱</td>
<td>任務(wù)時(shí)間</td>
<td>申請(qǐng)人</td>
<td>申請(qǐng)時(shí)間</td>
<td>天數(shù)</td>
<td>事由</td>
<td>操作</td>
</tr>
<tr ng-repeat="vacTask in vacTaskList">
<td>{{vacTask.name}}</td>
<td>{{vacTask.createTime | date:'yyyy-MM-dd HH:mm:ss'}}</td>
<td>{{vacTask.vac.applyUser}}</td>
<td>{{vacTask.vac.applyTime | date:'yyyy-MM-dd HH:mm:ss'}}</td>
<td>{{vacTask.vac.days}}</td>
<td>{{vacTask.vac.reason}}</td>
<td>
<button type="button" ng-click="passAudit(vacTask.id, 1)">審核通過(guò)</button>
<button type="button" ng-click="passAudit(vacTask.id, 0)">審核拒絕</button>
</td>
</tr>
</table>
</div>
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 ? "審核通過(guò)" : "審核拒絕"
}
}
).then(function (response) {
if (response.data === true) {
alert("操作成功亏拉!");
$window.location.reload();
} else {
alert("操作失斂垓摺!");
}
})
}
});
本人免費(fèi)整理了Java高級(jí)資料及塘,涵蓋了Java莽使、Redis、MongoDB笙僚、MySQL芳肌、Zookeeper、Spring Cloud、Dubbo高并發(fā)分布式等教程亿笤,一共30G翎迁,需要自己領(lǐng)取。
傳送門:https://mp.weixin.qq.com/s/igMojff-bbmQ6irCGO3mqA