SpringBoot入门建站全系列(十九)集成Activiti做工作流

SpringBoot入门建站全系列(十九)集成Activiti做工作流

一、概述

Activiti作为一个流行的开源工作流引擎,正在不断发展,其6.0版本以API形式提供服务,而之前版本基本都是要求我们的应用以JDK方式与其交互,只能将其携带到我们的应用中,而API方式则可以服务器独立运行方式,能够形成一个专网内工作流引擎资源共享的方式。

本篇activiti工作流基于5.22.0。

首发地址:
品茗IT-同步发布

品茗IT 提供在线支持:

一键快速构建Spring项目工具

一键快速构建SpringBoot项目工具

一键快速构建SpringCloud项目工具

一站式Springboot项目生成

Mysql一键生成Mybatis注解Mapper

代码可以在SpringBoot组件化构建https://www.pomit.cn/java/spring/springboot.html中的Activiti组件中查看,并下载。

如果大家正在寻找一个java的学习环境,或者在开发中遇到困难,可以加入我们的java学习圈,点击即可加入,共同学习,节约学习时间,减少很多在学习中遇到的难题。

二、配置

本文假设你已经引入spring-boot-starter-web。已经是个SpringBoot项目了,如果不会搭建,可以打开这篇文章看一看《SpringBoot入门建站全系列(一)项目建立》。

使用activiti前,首先要在数据库中将activiti需要的sql导入到数据库中。

可以去官网:https://www.activiti.org/下载个activiti,把下载好的文件中的sql导入;

也可以不管它,启动的时候会自动生成表的。。。

2.1 Maven依赖

需要引入activiti-spring-boot-starter-basic,这里要访问数据库对工作流数据进行操作,所以要依赖数据库相关jar包。


    org.activiti
    activiti-spring-boot-starter-basic
    5.22.0


    org.mybatis.spring.boot
    mybatis-spring-boot-starter


    mysql
    mysql-connector-java


    org.apache.commons
    commons-dbcp2

5.22版本是可以正常运行的一个版本,但是存在一个bug,就是jar包下载之后提示损坏,如果出现这个提示,直接到maven中央仓库下载下来jar包覆盖本地的即可。

2.2 配置文件

在application.properties 中需要添加下面的配置:

spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource
spring.datasource.dbcp2.max-wait-millis=60000
spring.datasource.dbcp2.min-idle=20
spring.datasource.dbcp2.initial-size=2
spring.datasource.dbcp2.validation-query=SELECT 1
spring.datasource.dbcp2.connection-properties=characterEncoding=utf8
spring.datasource.dbcp2.validation-query=SELECT 1
spring.datasource.dbcp2.test-while-idle=true
spring.datasource.dbcp2.test-on-borrow=true
spring.datasource.dbcp2.test-on-return=false

spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/cff?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
spring.datasource.username=cff
spring.datasource.password=123456

mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
mybatis.mapper-locations=classpath:mapper/*.xml

spring.autoconfigure.exclude=org.activiti.spring.boot.SecurityAutoConfiguration

这里的配置主要就是数据库及数据源、mybatis的配置。

spring.autoconfigure.exclude,这个配置比较特殊,是activiti的bug导致启动失败,需要将org.activiti.spring.boot.SecurityAutoConfiguration排除掉。

2.3 Activiti流程配置

下面是工作流流程配置文件,配置了一个流程,Start--》commit--》CustomerServiceApproval--》ManagerApproval--》End。



  
    
    
    
    
    
    
      
        
      
    
    
    
    
  
  
    
      
        
      
      
        
      
      
        
      
      
        
      
      
        
      
      
        
        
      
      
        
        
      
      
        
        
      
      
        
        
      
    
  

这里,activiti:executionListener 配置了一个监听器,监听流程流转。

三、Activiti工作流功能

流程监听器,我这里啥也不监听了,但是还是要写出来。

CommitExecutionListener:

package com.cff.springbootwork.activiti.listener;

import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;

public class CommitExecutionListener implements ExecutionListener{

    /**
     * 
     */
    private static final long serialVersionUID = 6482750935517963649L;

    @Override
    public void notify(DelegateExecution execution) throws Exception {
        String eventName = execution.getEventName();
        System.out.println("BeforCommitExecutionListener:"+eventName);
        
        
    }

}


工作流处理过程的service:

ProductService:

package com.cff.springbootwork.activiti.service;

import java.util.ArrayList;
import java.util.List;

import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import com.cff.springbootwork.activiti.dao.ProductMapper;
import com.cff.springbootwork.activiti.domain.ProductTask;
import com.cff.springbootwork.activiti.domain.UserInfo;

@Service
public class ProductService {
    protected Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    ProductMapper productMapper;

    @Autowired
    UserInfoService appUserService;

    /**
     * 产生工作流
     * 
     * @param userTask
     * @param userid
     */
    public void genTask(ProductTask userTask, String userid) {
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("productAdvice");
        Task tmp = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId())
                .singleResult();

        userTask.setInstanceId(processInstance.getProcessInstanceId());
        tmp.setAssignee(userid);
        taskService.complete(tmp.getId());

        userTask.setUserName(userid);
        productMapper.save(userTask);
    }

    /**
     * 获取提交的工作
     * 
     * @param userid
     * @return
     * @throws Exception
     */
    public List applyList(String userid) throws Exception {
        List tasks = productMapper.getUserTask(userid);
        return tasks;
    }

    /**
     * 获取待处理的工作
     * 
     * @param userid
     * @return
     * @throws Exception
     */
    public List waitList(String userid) throws Exception {
        String userType = findTaskType(userid);
        logger.info("准备查询userType为{}的任务", userType);
        List tasks = taskService.createTaskQuery().taskName(userType).orderByTaskCreateTime().asc().list();
        List utasks = new ArrayList();
        for (int i = 0; i < tasks.size(); i++) {
            ProductTask userTaskTmp = productMapper.getUserTaskByInstanceId(tasks.get(i).getProcessInstanceId());
            if (userTaskTmp != null) {
                userTaskTmp.setTaskId(tasks.get(i).getId());
                utasks.add(userTaskTmp);
            }
        }

        return utasks;
    }

    /**
     * 工作流流转
     * 
     * @param taskid
     * @param processid
     * @param userid
     * @return
     * @throws Exception
     */
    public synchronized Boolean processCommit(String taskid, String instanceId, String userid) throws Exception {
        logger.info("审批taskid:{},instanceId:{}", taskid, instanceId);
        try {
            ProductTask userTask = productMapper.getUserTaskByInstanceId(instanceId);
            taskService.complete(taskid);
            userTask.setCurviewer(userid);
            productMapper.updateStatus(userTask);
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * 根据用户类型获取任务名称
     * 
     * @param userId
     * @return
     */
    public String findTaskType(String userId) {
        UserInfo appUser = appUserService.getUserInfoByUserName(userId);
        String userType = appUser.getUserType();
        if (userType == null)
            return null;
        if (!StringUtils.isEmpty(userType)) {
            if ("2001".equals(userType)) {
                return "CustomerServiceApproval";
            } else if ("0000".equals(userType)) {
                return "ManagerApproval";
            } else {
                return "commit";
            }
        }
        return null;
    }

    /**
     * 获取处理过的任务
     * 
     * @param userid
     * @return
     */
    public List manageList(String userid) {
        List utasks = productMapper.getUserTaskByCurrentViwer(userid);

        return utasks;
    }
}

这个service中:

  • genTask 是工作流的开端,产生任务之后,即流转到下一个节点。

  • applyList,申请的任务列表。

  • waitList:待处理的任务。

  • processCommit: 让工作流流转起来。

四、测试Activiti工作流

我们定义一个web接口来做测试。

ActivitiRest:

package com.cff.springbootwork.activiti.web;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.cff.springbootwork.activiti.domain.ProductTask;
import com.cff.springbootwork.activiti.service.ProductService;

@RestController
@RequestMapping("/activiti")
public class ActivitiRest {

    @Autowired
    ProductService productService;

    @RequestMapping(value = "/add/{name}")
    public String add(@RequestBody ProductTask productTask, @PathVariable("name") String name) {
        productService.genTask(productTask, name);
        return "Success";
    }

    @RequestMapping(value = "/applyList/{name}")
    public List applyList(@PathVariable("name") String name) throws Exception {
        return productService.applyList(name);
    }

    @RequestMapping(value = "/waitList/{name}")
    public List waitList(@PathVariable("name") String name) throws Exception {
        return productService.waitList(name);
    }

    @RequestMapping(value = "/next/{name}")
    public Boolean processCommit(@PathVariable("name") String name, @RequestParam("instanceId") String instanceId,
            @RequestParam("taskId") String taskId) throws Exception {
        return productService.processCommit(taskId, instanceId, name);
    }
}

五、过程中用到的其他数据库相关service、mapper、实体

UserInfoService:

package com.cff.springbootwork.activiti.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.cff.springbootwork.activiti.dao.UserInfoMapper;
import com.cff.springbootwork.activiti.domain.UserInfo;

@Service
public class UserInfoService {
    @Autowired
    UserInfoMapper userInfoDao;
    public UserInfo getUserInfoByUserName(String userName){
        return userInfoDao.findByUserName(userName);
    }
}

ProductMapper :

package com.cff.springbootwork.activiti.dao;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import com.cff.springbootwork.activiti.domain.ProductTask;

@Mapper
public interface ProductMapper {

    public void save(ProductTask userTask);
    
    public List getUserTask(String userid);
    
    public ProductTask getUserTaskByInstanceId(String instanceId);
    
    public void updateStatus(ProductTask userTask);

    public List getUserTaskByCurrentViwer(String userid);
}

ProductMapper 对应的mybatis-productTask.xml:

  
  
  
      
          
         
        
          
          
        
      
      
        instance_id, user_name, title, task_type, content, curviewer
      
      
    
      
    
       
    
    
      insert into se_product_task(instance_id, user_name, title, task_type, content, curviewer) 
            values(#{instanceId}, #{userName}, #{title}, #{taskType}, #{content}, #{curviewer})
    
    
    
        update se_product_task
        
            curviewer=#{curviewer}
        
        where instance_id=#{instanceId}
    
  

ProductTask:


package com.cff.springbootwork.activiti.domain;

import java.io.Serializable;

public class ProductTask implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 3481818865839076537L;

    String instanceId;
    String userName;
    String taskType;
    String content;
    String title;
    String curviewer;
    String taskId;

    public String getInstanceId() {
        return instanceId;
    }

    public void setInstanceId(String instanceId) {
        this.instanceId = instanceId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getTaskType() {
        return taskType;
    }

    public void setTaskType(String taskType) {
        this.taskType = taskType;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getCurviewer() {
        return curviewer;
    }

    public void setCurviewer(String curviewer) {
        this.curviewer = curviewer;
    }

    public String getTaskId() {
        return taskId;
    }

    public void setTaskId(String taskId) {
        this.taskId = taskId;
    }

    public static long getSerialversionuid() {
        return serialVersionUID;
    }

}

UserInfoMapper :



UserInfoMapper 对应的mybatis-userInfo.xml:


UserInfo :



详细完整的实体及测试用例,可以访问品茗IT-博客《SpringBoot入门建站全系列(十九)集成Activiti做工作流》进行查看

快速构建项目

Spring组件化构建

SpringBoot组件化构建

SpringCloud服务化构建

喜欢这篇文章么,喜欢就加入我们的Java学习圈(点击加入或下方扫码)一起讨论SpringBoot技术吧!

SpringBoot入门建站全系列(十九)集成Activiti做工作流_第1张图片
品茗IT交流群

你可能感兴趣的:(SpringBoot入门建站全系列(十九)集成Activiti做工作流)