Using activiti in the Spring Boot project

Check activiti when creating a new springBoot project, or add the following dependencies to an established springBoot project:

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

 

Data source and activiti configuration:

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

 

In the default configuration of activiti, process-definition-location-prefix is the prefix (path) to the specified activiti process description file, and activiti will look for the process description file under this path at startup and deploy it automatically; suffix is a String array that represents the default suffix name of the description file, both of which are the default.

 

springMVC configuration:

 

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

 

 

Configure static resources and directly accessed pages here: In this example project, a thymeleaf dependency parsing view is added, data is obtained mainly asynchronously, and front-end data is processed and displayed through angular JS.

After configuring the data source and activiti, starting the project, activiti's service components are added to the spring container, so they can be injected directly into use.If you are in a spring environment that is not automatically configured, you can configure the active service components by specifying the init-method of the bean s.

Take the following vacation process as an example:

 

 

1. Start the process and "apply for leave" (employees)

 

private static final String PROCESS_DEFINE_KEY = "vacationProcess";


    public Object startVac(String userName, Vacation vac) {

        identityService.setAuthenticatedUserId(userName);
        // Start process
        ProcessInstance vacationInstance = runtimeService.startProcessInstanceByKey(PROCESS_DEFINE_KEY);
        // Query Current Task
        Task currentTask = taskService.createTaskQuery().processInstanceId(vacationInstance.getId()).singleResult();
        // Statement of Task
        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());
        // Complete Task
        taskService.complete(currentTask.getId(), vars);

        return true;
    }

 

 

In this method, Vacation is the specific information at the time of application, which can be set as a parameter when completing the Request Leave task.

 

2. Approve leave (owner)

(1) Query leave requests that require your own approval

 

public Object myAudit(String userName) {
        List<Task> taskList = taskService.createTaskQuery().taskCandidateUser(userName)
                .orderByTaskCreateTime().desc().list();
// / Carry coals to Newcastle taskList The following are included(User's tasks include those of the user group)
// 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 Only then
        vac.setApplyTime(startTime);
        vac.setApplyStatus(instance.isEnded() ? "End of application" : "Pending Approval");
        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 ...
}

 

 

The boss queries for tasks that he currently needs to approve and sets the tasks and parameters to a VacTask object for display on the page.

 

(2) Examine and approve leave requests

 

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

 

 

Similarly, result is the result of the approval and is the parameter that needs to be passed in when the approval task is completed; taskId is the ID of the approval task that the boss just queried that needs to be completed by himself.(If the process branches here, you can jump to different tasks by determining the value of the result)

 

3. Query records

 

Completed vacations are not found in the database runtime table (the runtime table holds only the process sample information in progress), so they need to be queried in the history table.

 

(1) Query leave records

 

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("End of application");
            List<HistoricVariableInstance> varInstanceList = historyService.createHistoricVariableInstanceQuery()
                    .processInstanceId(hisInstance.getId()).list();
            ActivitiUtil.setVars(vacation, varInstanceList);
            vacList.add(vacation);
        }
        return vacList;
    }
 

 

The leave record finds the instance of the historical process, then the associated historical parameters. Setting the instance of the historical process and the historical parameters into the Vcation object (VO object) returns them for display.

package com.yawn.util;

import org.activiti.engine.history.HistoricVariableInstance;

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

/**
 * activiti Use the resulting tool method
 * @author Created by yawn on 2018-01-10 16:32
 */
public class ActivitiUtil {

    /**
     * Set the list of historical parameters to the entity
     * @param entity entity
     * @param varInstanceList List of historical parameters
     */
    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();
        }
    }
}

 

 

In addition, the above is a common way to set VO objects after querying historical process instances and historical parameters: based on the parameters in the parameter list, parameters with the same name as the VO object properties can be set into VO objects.

 

4. Front End Display and Operation

 

(1) List of Approvals and Examples of Approval Operations

 

 

<div ng-controller="myAudit">
        <h2 ng-init="myAudit()">Leave pending my review</h2>
        <table border="0">
            <tr>
                <td>Task Name</td>
                <td>Task Time</td>
                <td>Applicant</td>
                <td>Time of application</td>
                <td>Days</td>
                <td>Subject matter</td>
                <td>operation</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)">Approval Passed</button>
                    <button type="button" ng-click="passAudit(vacTask.id, 0)">Audit Rejection</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 ? "Approval Passed" : "Audit Rejection"
                }
            }
        ).then(function (response) {
            if (response.data === true) {
                alert("Operation successful!");
                $window.location.reload();
            } else {
                alert("Operation failed!");
            }
        })
    }
});

I have compiled advanced Java materials for free, covering Java, Redis, MongoDB, MySQL, Zookeeper, Spring Cloud, Dubbo high concurrent and distributed tutorials, a total of 30G, which I need to collect.
Port: https://mp.weixin.qq.com/s/igMojff-bbmQ6irCGO3mqA

Keywords: Java Spring MySQL SpringBoot

Added by mortimerdude on Sat, 21 Dec 2019 10:44:20 +0200