在 Spring Boot 項目中使用 activiti

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

<dependency>
  <groupId>org.activiti</groupId>
  <artifactId>activiti-spring-boot-starter-basic</artifactId>
  <version>6.0.0</version>
</dependency>

 

數據源和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的默認配置中,process-definition-location-prefix 是指定activiti流程描述文件的前綴(即路徑),啓動時,activiti就會去尋找此路徑下的流程描述文件,而且自動部署;suffix 是一個String數組,表示描述文件的默認後綴名,默認以上兩種。java

 

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);
    }
}

 

 

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

配置了數據源和activiti後,啓動項目,activiti 的各個服務組件就已經被加入到spring容器中了,因此就能夠直接注入使用了。若是在未自動配置的spring環境中,能夠使用經過指定bean的init-method來配置activiti的服務組件。mysql

以如下請假流程爲例:web

 

 

1. 開始流程並「申請請假」(員工)

 

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, Object> 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;
    }

 

 

在此方法中,Vaction 是申請時的具體信息,在完成「申請請假」任務時,能夠將這些信息設置成參數。

 

2. 審批請假(老闆)

(1)查詢須要本身審批的請假

 

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對象,用於頁面的展現。

 

(2)審批請假

 

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是審批的結果,也是在完成審批任務時須要傳入的參數;taskId是剛纔老闆查詢到的當前須要本身完成的審批任務ID。(若是流程在這裏設置分支,能夠經過判斷result的值來跳轉到不一樣的任務)

 

3. 查詢記錄

 

因爲已完成的請假在數據庫runtime表中查不到(runtime表只保存正在進行的流程示例信息),因此須要在history表中查詢。spring

 

(1) 查詢請假記錄

 

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;
    }
 

 

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

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 <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();
        }
    }
}

 

 

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

 

4. 前端展現和操做

 

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

 

 

<div ng-controller="myAudit">
        <h2 ng-init="myAudit()">待我審覈的請假</h2>
        <table border="0">
            <tr>
                <td>任務名稱</td>
                <td>任務時間</td>
                <td>申請人</td>
                <td>申請時間</td>
                <td>天數</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)">審覈經過</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 ? "審覈經過" : "審覈拒絕"
                }
            }
        ).then(function (response) {
            if (response.data === true) {
                alert("操做成功!");
                $window.location.reload();
            } else {
                alert("操做失敗!");
            }
        })
    }
});

本人免費整理了Java高級資料,涵蓋了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo高併發分佈式等教程,一共30G,須要本身領取。
傳送門:https://mp.weixin.qq.com/s/igMojff-bbmQ6irCGO3mqA

相關文章
相關標籤/搜索