Backend Development 11 min read

Integrating Activiti 6.0 with Spring Boot: Configuration, Code Samples, and Example Workflow

This article demonstrates how to integrate the Activiti 6.0 workflow engine into a Spring Boot application, covering Maven dependencies, YAML configuration, Spring MVC setup, Java service methods for starting, auditing, and querying leave processes, as well as an AngularJS front‑end for task handling.

Java Captain
Java Captain
Java Captain
Integrating Activiti 6.0 with Spring Boot: Configuration, Code Samples, and Example Workflow

The guide explains how to embed the Activiti 6.0 BPM engine into a Spring Boot project, providing a complete example of a leave‑request workflow.

Dependency – Add the Activiti starter to the Maven pom:

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

Application configuration – Configure the MySQL datasource and Activiti settings in application.yml (or application.properties ):

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:
  database-schema-update: true
  check-process-definitions: true
  process-definition-location-prefix: classpath:/processes/
  history-level: full

Spring MVC configuration – A Java class enables static resources and view controllers:

package com.yawn.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;

@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");
        super.addViewControllers(registry);
    }
}

Starting a leave process – Service method creates a process instance, sets variables, claims the task and completes it:

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

Boss audit – Query pending tasks, map them to VacTask objects, and retrieve historic variables:

public Object myAudit(String userName) {
    List
taskList = taskService.createTaskQuery()
        .taskCandidateUser(userName)
        .orderByTaskCreateTime().desc().list();
    List
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);
    vac.setApplyTime(instance.getStartTime());
    vac.setApplyStatus(instance.isEnded() ? "申请结束" : "等待审批");
    return vac;
}

Utility for historic variables – ActivitiUtil.setVars uses reflection to copy historic variable values into a POJO:

public class ActivitiUtil {
    public static
void setVars(T entity, List
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();
        }
    }
}

Querying historic records – After a process finishes, its data is stored in the history tables; the following method retrieves completed leave records:

public Object myVacRecord(String userName) {
    List
hisProInstance = historyService
        .createHistoricProcessInstanceQuery()
        .processDefinitionKey(PROCESS_DEFINE_KEY)
        .startedBy(userName)
        .finished()
        .orderByProcessInstanceEndTime().desc()
        .list();
    List
vacList = new ArrayList<>();
    for (HistoricProcessInstance hisInstance : hisProInstance) {
        Vacation vacation = new Vacation();
        vacation.setApplyUser(hisInstance.getStartUserId());
        vacation.setApplyTime(hisInstance.getStartTime());
        vacation.setApplyStatus("申请结束");
        List
varInstanceList = historyService
            .createHistoricVariableInstanceQuery()
            .processInstanceId(hisInstance.getId()).list();
        ActivitiUtil.setVars(vacation, varInstanceList);
        vacList.add(vacation);
    }
    return vacList;
}

Front‑end display – An AngularJS view lists pending audits in a table and provides “Approve” and “Reject” buttons:

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

The corresponding Angular controller sends HTTP requests to the back‑end to fetch tasks and to submit audit decisions.

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("操作失败!");
            }
        });
    };
});

The complete source code for this demo project is available at https://gitee.com/yawensilence/activiti-demo6-springboot .

JavaworkflowSpring BootActivitiBPMAngularJS
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.