专栏名称: 武哥聊编程
这里有技术,有段子,有生活,也有资源,要不然怎么叫 “私房菜” 呢?
目录
相关文章推荐
半月谈  ·  国内首个!AI儿科医生正式“上岗” ·  5 小时前  
湛江日报  ·  停运通知! ·  8 小时前  
中国航务周刊  ·  一家中外合资新物流公司成立 ·  昨天  
政事儿  ·  中方:敦促美日立即停止干涉中国内政! ·  3 天前  
51好读  ›  专栏  ›  武哥聊编程

SpringBoot整合Activiti工作流(附源码)

武哥聊编程  · 公众号  ·  · 2019-12-28 09:00

正文

点击关注上方“ 程序员私房菜 ”,设为“置顶或星标”,第一时间送达技术干货。


来源:my.oschina.net/silenceyawen/blog/1609603

依赖:

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

<dependency>
    <groupId>org.activitigroupId>
    <artifactId>activiti-spring-boot-starter-basicartifactId>
    <version>6.0.0version>
dependency>

配置:

数据源和activiti配置:

server:
  port: 8081

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/act5?useSSL=true
    driver-class-namecom.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后,启动项目,activiti 的各个服务组件就已经被加入到spring容器中了,所以就可以直接注入使用了。如果在未自动配置的spring环境中,可以使用通过指定bean的init-method来配置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<StringObject> 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 taskList = taskService.createTaskQuery().taskCandidateUser(userName)
                .orderByTaskCreateTime().desc().list();
//        / 多此一举 taskList中包含了以下内容(用户的任务中包含了所在用户组的任务)
//        Group group = identityService.createGroupQuery().groupMember(userName).singleResult();
//        List list = taskService.createTaskQuery().taskCandidateGroup(group.getId()).list();
//        taskList.addAll(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);
        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<StringObject> 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 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;
    }

请假记录即查出历史流程实例,再查出关联的历史参数,将历史流程实例和历史参数设置到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  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();
        }
    }
}

此外,以上是查询历史流程实例和历史参数后,设置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






请到「今天看啥」查看全文


推荐文章
湛江日报  ·  停运通知!
8 小时前
中国航务周刊  ·  一家中外合资新物流公司成立
昨天
艺恩数据  ·  2月12日网络播放量
8 年前
思维阶梯数学  ·  2017年希望杯2试参考答案
7 年前