欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

在 Spring Boot 项目中使用 activiti

程序员文章站 2023-11-09 18:20:58
新建springBoot项目时勾选activiti,或者在已建立的springBoot项目添加以下依赖: org.activiti activiti-spring-boot-starter-basic

新建springboot项目时勾选activiti,或者在已建立的springboot项目添加以下依赖:

<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数组,表示描述文件的默认后缀名,默认以上两种。

 

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的服务组件。

以以下请假流程为例:

 

在 Spring Boot 项目中使用 activiti

 

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表中查询。

 

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

 

在 Spring Boot 项目中使用 activiti

 

<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