若依框架SpringBoot+Activiti工作流的使用
作者:mmseoamin日期:2023-12-14

使用简介:本技术点主要是针对类审批的业务流程的建模,可以有:任务发布(即流程开始)到一级一级的审批到最终结束(即流程结束)一整套完备的模型

1、idea下载activiti插件

  1. ider以前版本下载actiBPM,但是新版ider这个插件已经被淘汰,已经被下面这个替代

 若依框架SpringBoot+Activiti工作流的使用,第1张

 若依框架SpringBoot+Activiti工作流的使用,第2张

2、单独起一个activiti服务

3、添加依赖在activiti服务中:


   org.springframework.boot
   spring-boot-starter-web


   org.springframework.boot
   spring-boot-starter-jdbc


   org.springframework.boot
   spring-boot-starter-test


   org.activiti
   activiti-spring-boot-starter
   7.0.0.Beta2


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


   mysql
   mysql-connector-java


   org.projectlombok
   lombok

4、添加配置

我这里的服务结构:

 若依框架SpringBoot+Activiti工作流的使用,第3张

a、activiti.cfg.xml的配置(直接粘,需要修改为自己的数据库):

xml version="1.0" encoding="UTF-8"?>

      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

      xmlns:context="http://www.springframework.org/schema/context"

      xmlns:tx="http://www.springframework.org/schema/tx"

      xsi:schemaLocation="http://www.springframework.org/schema/beans
                   http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contex
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">

   
   
   

         >
       
       
       
       

       
       
   

配置讲解:

 若依框架SpringBoot+Activiti工作流的使用,第4张

b、添加log4j的配置(无需修改,直接粘):

# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r[%15.15t] %-5p %30.30c %x - %m\n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:\XX\activiti.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r[%15.15t] %-5p %30.30c %x - %m\n

  1. 创建流程图文件:

 若依框架SpringBoot+Activiti工作流的使用,第5张

在创建好的文件中任意位置右键,选择 View BPMN Diagram,打开可视化界面(流程定义的界面

若依框架SpringBoot+Activiti工作流的使用,第6张

任意右键选择定义流程:

若依框架SpringBoot+Activiti工作流的使用,第7张

 若依框架SpringBoot+Activiti工作流的使用,第8张

 若依框架SpringBoot+Activiti工作流的使用,第9张

 若依框架SpringBoot+Activiti工作流的使用,第10张

 若依框架SpringBoot+Activiti工作流的使用,第11张

解决图片乱码问题

1.打开 IDEA 安装路径,找到如下的安装目录

若依框架SpringBoot+Activiti工作流的使用,第12张

追加一条命令: -Dfile.encoding=UTF-8
如下所示

若依框架SpringBoot+Activiti工作流的使用,第13张

至此activiti的准备工作结束,一下是代码部分:

一、demo代码示例:
public class TestCreateTable {

   /**
    * 生成 activiti的数据库表
    */
   @Test

   public void testCreateDbTable() {

       //使用classpath下的activiti.cfg.xml中的配置创建processEngine
       //如果使用默认则需要上面activiti.cfg.xml配置
       ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

       System.out.println(processEngine);
   }

   //部署
   @Test

   public void test01() {

       //1、创建ProcessEngine
       ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

       //2、得到RepositoryService实例
       RepositoryService repositoryService = processEngine.getRepositoryService();

       //3、使用RepositoryService进行部署
       Deployment deploy = repositoryService.createDeployment().addClasspathResource("bpmn/chuchai.bpmn20.xml")
               .addClasspathResource("bpmn/diagram.png")
               .name("团购申请v1.0")
               .deploy();

       //4、输出部署信息
       System.out.println("部署id:"+deploy.getId());

       System.out.println("部署的任务名称:"+deploy.getName());
   }

   //启动流程
   @Test

   public void testDeploy() {

       //1.创建ProcessEngine对象
       ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

       //创建TaskService
       TaskService taskService = processEngine.getTaskService();

       Map variables = new HashMap<>();

       //张三就是在bpmnAssignee配置的参数
       variables.put("张三", "aaa");

       //3.创建流程实例  流程定义的key需要知道 holiday
       ProcessInstance processInstance = ProcessEngines.getDefaultProcessEngine()
               .getRuntimeService()
               .startProcessInstanceByKey("chuchai", variables);

       Task tmp = taskService.createTaskQuery()
               .processInstanceId(processInstance.getProcessInstanceId()).singleResult();

       tmp.setAssignee("张三");

       //完成此节点。由下一节点审批。完成后act_ru_task会创建一条由下节点审批的数据
       taskService.complete(tmp.getId(),variables);

       //4.输出实例的相关信息
       System.out.println( "流程部署ID:" + processInstance.getDeploymentId() );

       System.out.println( "流程定义ID:" + processInstance.getProcessDefinitionId());

       System.out.println( "流程实例ID:" + processInstance.getId() );

       System.out.println( "活动ID:" + processInstance.getActivityId() );
   }

   @Test

   //查询任务
   public void test(){

       ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

       //创建TaskService
       TaskService taskService = processEngine.getTaskService();

       //根据流程key 和 任务负责人 查询任务
       List list = taskService.createTaskQuery()
               .processDefinitionKey("chuchai") //流程Key
               .taskAssignee("张三")//只查询该任务负责人的任务
               .list();

       for (Task task : list) {

           System.out.println("流程实例id:" + task.getProcessInstanceId());
           System.out.println("任务id:" + task.getId());
           System.out.println("任务负责人:" + task.getAssignee());
           System.out.println("任务名称:" + task.getName());
       }

   }

   //审批流程
   @Test

   public void test1(){

       //1.创建ProcessEngine对象
       ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

       //创建TaskService
       TaskService taskService = processEngine.getTaskService();

       //根据角色信息获取自己的待办
       List T = taskService.createTaskQuery().taskAssignee("zs").list();

       if(!ObjectUtils.isEmpty(T)) {

           for (Task item : T) {
               Map variables = new HashMap<>();
               variables.put("张三", "zs");
               variables.put("isSuccess", true);
               item.setAssignee("李四");

               //增加审批备注
               taskService.addComment(item.getId(),item.getProcessInstanceId(),"部门经理同意");

               //完成此次审批。由下节点审批
               taskService.complete(item.getId(), variables);
           }
       }
   }

   // 结束流程
   @Test

   public void test02() {

       //1.创建ProcessEngine对象
       ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

       //        创建TaskService
       TaskService taskService = processEngine.getTaskService();

       //act_re_execution id
       String taskId = "42503";

       //        任务负责人
       String assingee = "李四";
       Task task = taskService.createTaskQuery()
               .taskId(taskId)
               .taskAssignee(assingee)
               .singleResult();

       if (task != null) {
           HashMap map = new HashMap<>();
           map.put("agree", 1);
           taskService.complete(taskId, map);

           System.out.println("完成任务");
       }

   }
}

二、项目代码示例:controller层代码(这里是运用到项目中的代码)


@RestController
@RequestMapping("/activiti")
@Slf4j
public class ActivitiController {

   @Autowired

   private IActivitiService iActivitiService;

   //生成25张表
   @GetMapping

   public Result getTables(){

       log.info("开始生成表................................................................");

       Result result = iActivitiService.getTable();

       return result;
   }

   //流程部署
   @GetMapping("/bushu")

   public Result bushu(){

       log.info("部署 ");
       return Result.success("ok");

   }

   //查询个人待执行的任务
   @GetMapping("/list")

   public Result list(){

       log.info("查询个人待执行的任务");

       Result result = iActivitiService.list();

       return result;
   }

   //结束
   @GetMapping("/complete")

   public Result complete(){

       log.info("结束");

       Result result = iActivitiService.complete();

       return result;
   }
}

Service层代码:


@Service
@Repository
@Slf4j
public class ActivitiServiceImpl implements IActivitiService {

   @Autowired

   public IActivitiMapper iActivitiMapper;

   @Override

   public Result getTable() {

       //使用classpath下的activiti.cfg.xml中的配置创建processEngine
       //如果使用默认则需要上面activiti.cfg.xml配置
       ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

       return Result.success("生成表成功");
   }

   @Override

   public Result bushu() {

       //1、创建ProcessEngine
       ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

       //2、得到RepositoryService实例
       RepositoryService repositoryService = processEngine.getRepositoryService();

       //3、使用RepositoryService进行部署
       Deployment deploy = repositoryService.createDeployment().addClasspathResource("activiti/groupactiviti.bpmn20.xml")
               .addClasspathResource("activiti/groupactiviti.png")
               .name("团购申请审批")
               .deploy();

       //4、输出部署信息
       log.info("部署id:"+deploy.getId());

       log.info("部署的任务名称:"+deploy.getName());

       //5、启动流程定义       根据流程定义的id启动流程                           key:act_re_procdef中的KEY
       //创建TaskService
       TaskService taskService = processEngine.getTaskService();

       Map variables = new HashMap<>();

       String username = SecurityUtils.getLoginUser().getSysUser().getUserName();
//        String username = "admin";
       //user就是在bpmnAssignee配置的参数
       variables.put("admin", username);

       //3.创建流程实例  流程定义的key需要知道 holiday
       ProcessInstance processInstance = ProcessEngines.getDefaultProcessEngine()
               .getRuntimeService()
               .startProcessInstanceByKey("groupactiviti", variables);

       System.out.println(processInstance+"=============================================");

       Task tmp = taskService.createTaskQuery()
               .processInstanceId(processInstance.getProcessInstanceId()).singleResult();

       tmp.setAssignee("ry");

       //完成此节点。由下一节点审批。完成后act_ru_task会创建一条由下节点审批的数据
       taskService.complete(tmp.getId(),variables);

       //4.输出实例的相关信息
       log.info("流程部署ID:" + processInstance.getDeploymentId() );

       log.info("流程定义ID:" + processInstance.getProcessDefinitionId());

       log.info("流程实例ID:" + processInstance.getId());

       log.info("活动ID:" + processInstance.getActivityId());

       return Result.success(true,"申请已提交");
   }

   //个人待执行任务
   @Override

   public Result list() {

       ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();

       TaskService taskService = defaultProcessEngine.getTaskService();

       // 查询当前登录人的任务 进行完成
       String username= SecurityUtils.getLoginUser().getSysUser().getUserName();

       System.out.println("当前登录人"+username);

       if (username == null){

           throw new CheckedException("当前登录人为空");
       }

       List task = taskService.createTaskQuery()
               .processDefinitionKey("groupactiviti")
               .taskAssignee(username)
               .list();

       System.out.println("==================="+task);

       if(!ObjectUtils.isEmpty(task)) {

           for (Task item : task) {

               Map variables = new HashMap<>();

               if (username.equals("ry")){

                   variables.put("ry", username);

                   variables.put("isSuccess", true);

                   item.setAssignee("aaa");

                   //增加审批备注
                   taskService.addComment(item.getId(),item.getProcessInstanceId(),"部门经理已同意");

                   //完成此次审批。由下节点审批  act_hi_taskinst会修改时间
                   taskService.complete(item.getId(), variables);
               }

               if (username.equals("aaa")){

                   variables.put("aaa", username);

                   variables.put("isSuccess", true);

                   item.setAssignee("aaa");

                   //增加审批备注
                   taskService.addComment(item.getId(),item.getProcessInstanceId(),"财务已同意");

                   //完成此次审批。由下节点审批  act_hi_taskinst会修改时间
                   taskService.complete(item.getId(), variables);
               }
           }
       }

       return Result.success(true,"审核成功");
   }

   // 结束
   @Override

   public Result complete() {

       //1.创建ProcessEngine对象
       ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

       //创建TaskService
       TaskService taskService = processEngine.getTaskService();

       // 获取当前登录人 判断是admin才结束任务
       String username = SecurityUtils.getLoginUser().getSysUser().getUserName();
//        String username = "aaa";
       if (username == null) {

           throw new CheckedException("当前登录人为空");
       }

       if (username.equals("aaa")) {

           //act_re_execution 任务id
           Task task = taskService.createTaskQuery()
                   .processDefinitionKey("groupactiviti")
                   .taskAssignee(username)
                   .singleResult();

           if (task != null) {

               HashMap map = new HashMap<>();

               map.put("agree", 1);

               taskService.complete(task.getId(), map);

               System.out.println("完成任务");
           }
       }

       return Result.success(true,"审核成功");
   }

}

定义远程调用remote供别的服务调用

结构:

若依框架SpringBoot+Activiti工作流的使用,第14张

  1. ActivitiRemoteFallback代码:



/**
* activiti服务降级处理
*
* @author 
*/
@Component
public class ActivitiRemoteFallback implements FallbackFactory
{

   private static final Logger log = LoggerFactory.getLogger(ActivitiRemoteFallback.class);

   @Override

   public ActivitiRemoteService create(Throwable cause) {

       log.error("工作流调用失败:{}", cause.getMessage());

       return new ActivitiRemoteService(){

           @Override

           public Result getTables() {

               return null;
           }

           @Override

           public Result bushu() {

               return Result.error("远程调用工作流部署失败");
           }

           @Override

           public Result list() {

               return Result.error("远程调用工作流审核失败");
           }

           @Override

           public Result complete() {

               return Result.error("远程调用工作流结束审核失败");
           }
       };
   }
}

  1. ActivitiRemoteService代码:



/**
* 用户服务
*
* @author bawei
*/
@FeignClient(contextId = "rctivitiRemoteService",
       value = ServiceNameConstants.****自己的文件名,
       fallbackFactory = ActivitiRemoteFallback.class,path = "/activiti")
public interface ActivitiRemoteService {

   //生成25张表
   @GetMapping

   public Result getTables();

   //流程部署
   @GetMapping("/bushu")

   public Result bushu();

   //查询个人待执行的任务
   @GetMapping("/list")

   public Result list();

   //结束
   @GetMapping("/complete")

   public Result complete();
}

  1. org.springframework.boot.autoconfigure.AutoConfiguration.imports配置的代码

最后:在需要使用Activiti的地方直接注入该服务即可