在 Spring Boot 項(xiàng)目中使用 activiti

新建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)假流程為例:

image

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)審批列表和審批操作示例

image
<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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末责嚷,一起剝皮案震驚了整個(gè)濱河市鸳兽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌罕拂,老刑警劉巖揍异,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異爆班,居然都是意外死亡衷掷,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門柿菩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)戚嗅,“玉大人,你說(shuō)我怎么就攤上這事枢舶∨嘲” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵凉泄,是天一觀的道長(zhǎng)躏尉。 經(jīng)常有香客問(wèn)我,道長(zhǎng)后众,這世上最難降的妖魔是什么胀糜? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮蒂誉,結(jié)果婚禮上教藻,老公的妹妹穿的比我還像新娘。我一直安慰自己右锨,他們只是感情好括堤,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著陡蝇,像睡著了一般痊臭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上登夫,一...
    開(kāi)封第一講書(shū)人閱讀 49,741評(píng)論 1 289
  • 那天广匙,我揣著相機(jī)與錄音,去河邊找鬼恼策。 笑死鸦致,一個(gè)胖子當(dāng)著我的面吹牛潮剪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播分唾,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼抗碰,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了绽乔?” 一聲冷哼從身側(cè)響起弧蝇,我...
    開(kāi)封第一講書(shū)人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎折砸,沒(méi)想到半個(gè)月后看疗,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡睦授,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年两芳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片去枷。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡怖辆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出删顶,到底是詐尸還是另有隱情竖螃,我是刑警寧澤,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布逗余,位于F島的核電站斑鼻,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏猎荠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一蜀备、第九天 我趴在偏房一處隱蔽的房頂上張望关摇。 院中可真熱鬧,春花似錦碾阁、人聲如沸输虱。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)宪睹。三九已至,卻和暖如春蚕钦,著一層夾襖步出監(jiān)牢的瞬間亭病,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工嘶居, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留罪帖,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像整袁,于是被迫代替她去往敵國(guó)和親菠齿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容