工作流-activiti

概念:

流程:整体工作流程。

实例:ProcessInstance。启动一个流程实例表示开始一次业务的运行。

查询待办任务:业务流程都交给activiti管理,通过activiti就可以查询当前流程执行到哪里了,当前用户需要办理什么任务。

用户办理任务:查询到任务 就可以办理任务了

流程结束:当前任务办理完成没有下一个任务节点了。

生成表配置:

依赖版本

<properties>
    <activiti.version>5.22.0</activiti.version>
</properties>

<dependencies>
<!-- Activiti 启动器 -->
    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-spring-boot-starter-basic</artifactId>
        <version>${activiti.version}</version>
        <exclusions>
            <exclusion>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <!-- Activiti 流程图 -->
    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-diagram-rest</artifactId>
        <version>${activiti.version}</version>
    </dependency>
    <!-- Activiti 在线设计 -->
    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-modeler</artifactId>
        <version>${activiti.version}</version>
    </dependency>
</dependencies>

 配置文件:

@Configuration
public class ActivitiDataSourceConfig extends AbstractProcessEngineAutoConfiguration {

    @Resource
    private ActivitiDataSourceProperties activitiDataSourceProperties;

    @Bean
    public DataSource activitiDataSource() {
        DruidDataSource DruiddataSource = new DruidDataSource();
        DruiddataSource.setUrl(activitiDataSourceProperties.getUrl());
        DruiddataSource.setDriverClassName(activitiDataSourceProperties.getDriverClassName());
        DruiddataSource.setPassword(activitiDataSourceProperties.getPassword());
        DruiddataSource.setUsername(activitiDataSourceProperties.getUsername());
        return DruiddataSource;
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(activitiDataSource());
    }

    @Bean
    public SpringProcessEngineConfiguration springProcessEngineConfiguration() {
        SpringProcessEngineConfiguration configuration = new SpringProcessEngineConfiguration();
        configuration.setDataSource(activitiDataSource());
        //如果当前数据库 有相关表 就不管 没有就创建
        configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
        configuration.setJobExecutorActivate(false);
        configuration.setTransactionManager(transactionManager());
        configuration.setActivityFontName("宋体");
        configuration.setLabelFontName("宋体");
        configuration.setAnnotationFontName("宋体");
        //id生成器
        //configuration.setIdGenerator(new MyUUIDgenerator());
        return configuration;
    }
}

数据库连接设置:如果使用mysql-connect 8.0以上版本,必须要加nullCatalogMeansCurrent=true的配置,否则会扫描整个服务器的库。(这里如果不加,如果有多个数据库实例,就有可能报找不到表)

spring:
  datasource:
    dynamic:
      datasource:
        master:
          url: jdbc:mysql://localhost:3306/activiti?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&useAffectedRows=true&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
          username: root
          password: root
          driver-class-name: com.mysql.cj.jdbc.Driver

表结构说明

  • act_ge(general): 一般数据
  • act_hi(history): 流程历史记录
  • act_re(repository): 流程定义表
  • act_ru(runtime): 运行实例表
  • act_id(identity):组织架构信息
表分类表名

说明

一般数据
ACT_GE_BYTEARRAY通用的流程定义和流程资源
ACT_GE_PROPERTY系统相关属性
流程历史记录
ACT_HI_ACTINST 历史的流程实例
ACT_HI_ATTACHMENT历史的流程附件
ACT_HI_COMMENT历史的说明性信息
ACT_HI_DETAIL历史的流程运行中的细节信息
ACT_HI_IDENTITYLINK历史的流程运行过程中用户信息
ACT_HI_PROCINST历史的流程实例
ACT_HI_TASKINST历史的任务实例
ACT_HI_VARINST历史的流程运行中的变量信息
流程定义表
ACT_RE_DEPLOYMENT部署单元信息
ACT_RE_MODEL模型信息
ACT_RE_PROCDEF已部署的流程定义
运行实例表
ACT_RU_EVENT_SUBSCR运行时事件
ACT_RU_EXECUTION运行时流程执行实例
ACT_RU_IDENTITYLINK运行时用户关系信息,存储任务节点与参与者的相关信息
ACT_RU_JOB运行时作业
ACT_RU_TASK运行时任务
ACT_RU_VARIABLE运行时变量表

创建流程

  1. 定义流程  按照BPMN的规范,使用流程定义工具,用流程符号把整个流程描述出来
  2. 部署流程   把画好的流程定义文件,加载到数据库中, 生成表的数据
  3. 启动流程    使用java代码来操作数据库表中的内容

流程符号:

事件Event

 

活动Activity

        一个活动可以是一个任务,还可以是一个当前流程的子处理流程,还可以为活动指定不同的类型

 

网关Gateway

        网关用来处理决策

  • 排他网关

        只有一条路径会被选择。流程执行到该网关时,按照输出流的顺序逐个计算,当条件的计算结果为true时,继续执行当前网关的输出流;

        如果多条路线计算结果都是true,则会执行第一个值为true的线路,如果所有网关计算结果没有true,则引擎会抛出异常。

        排他网关需要和条件顺序流结合使用,default属性指定默认顺序流,当所有的条件不满足时会执行默认顺序流。

  • 并行网关

        所有路径会被同事选择

                拆分:并行执行所有输出顺序流,为每一条顺序流创建一个并行执行路线

                合并:所有从并行网关拆分并执行完成的线路均在此等候,直到所有的线路都执行完成才继续向下执行。

  • 包容网关

        可以同时执行多条线路,也可以在网关上设置条件

                拆分:计算每条线路上的表达式,当表达式计算结果为true时,创建一个并行线路并继续执行。

                合并:所有从并行网关拆分并执行完成的线路均在此等候,直到所有的线路都执行完成才继续向下执行。

  • 事件网关

        专门为中间捕获事件设置的,允许设置多个输出流指向多个不同的中间捕获事件。当流程执行到事件网关后,流程处于等待状态,需要等待抛出事件才能将等待状态转换为活动状态。

流向Flow

        流是连接两个流程节点的连线。

        常见的流向包含以下几种:

                顺序流 (Sequence Flow) 消息流(Message Flow) 关联(Association) 数据关联(Data Association)

代码流程:

  1. 创建模型
 //初始化一个空模型
Model model = repositoryService.newModel();
//保存模型
repositoryService.saveModel(model);
//保存设计流程资源
repositoryService.addModelEditorSource(id, editorNode.toString().getBytes("utf-8"));

涉及更新/新增的表:act_ge_property、act_re_model、act_ge_bytearray 

2. 部署流程

Deployment deployment = repositoryService.createDeployment()
                    .name(modelData.getName())
                    .addString(processName, new String(bpmnBytes, "UTF-8"))
                    .deploy();

 涉及到的表:ACT_RE_PROCDEF、ACT_RE_DEPLOYMENT、ACT_GE_BYTEARRAY

 3. 激活流程定义

repositoryService.activateProcessDefinitionById(id, true, new Date());

 涉及到的表:ACT_RU_JOB

4. 启用流程实例,并分配任务

//启用实例
ProcessInstance pi = runtimeService.startProcessInstanceById(actBusiness.getProcDefId(), actBusiness.getId(), params);
// 设置流程实例名称
runtimeService.setProcessInstanceName(pi.getId(), actBusiness.getTitle());
//任务分配
taskService.addCandidateUser(task.getId(), user.getUsername());
// 设置任务优先级
taskService.setPriority(task.getId(), actBusiness.getPriority());

5. 查询任务

//构建查询条件
TaskQuery query = taskService.createTaskQuery();
//查询对应人
query.taskCandidateOrAssigned(userId);
//查询对应任务
List<Task> taskList = query.list();

6. 获取下一节点

public ProcessNodeVo getNextNode(String procDefId, String currActId) {
        ProcessNodeVo node = new ProcessNodeVo();

        // 当前执行节点id
        ProcessDefinitionEntity dfe = (ProcessDefinitionEntity) ((RepositoryServiceImpl)repositoryService).getDeployedProcessDefinition(procDefId);
        // 获取所有节点
        List<ActivityImpl> activitiList = dfe.getActivities();
        // 判断出当前流程所处节点,根据路径获得下一个节点实例
        for(ActivityImpl activityImpl : activitiList){
            if (activityImpl.getId().equals(currActId)) {
                // 获取下一个节点
                List<PvmTransition> pvmTransitions = activityImpl.getOutgoingTransitions();

                PvmActivity pvmActivity = pvmTransitions.get(0).getDestination();

                String type = pvmActivity.getProperty("type").toString();
                if("userTask".equals(type)){
                    // 用户任务节点
                    node.setType(ActivitiConstant.NODE_TYPE_TASK);
                    node.setTitle(pvmActivity.getProperty("name").toString());
                    // 设置关联用户
                    List<LoginUser> users = getNodetUsers(pvmActivity.getId());
                    node.setUsers(removeDuplicate(users));
                }else if("exclusiveGateway".equals(type)){
                    // 排他网关
                    node.setType(ActivitiConstant.NODE_TYPE_EG);
                }else if("parallelGateway".equals(type)){
                    // 平行网关
                    node.setType(ActivitiConstant.NODE_TYPE_PG);
                }else if("endEvent".equals(type)){
                    // 结束
                    node.setType(ActivitiConstant.NODE_TYPE_END);
                }else{
                    throw new JeecgBootException("流程设计错误,包含无法处理的节点");
                }
                break;
            }
        }

        return node;
    }

 7. 审核通过

public Result<Object> pass(@ApiParam("任务id") @RequestParam String id,
                               @ApiParam("流程实例id") @RequestParam String procInstId,
                               @ApiParam("下个节点审批人") @RequestParam(required = false) String assignees,
                               @ApiParam("优先级") @RequestParam(required = false) Integer priority,
                               @ApiParam("意见评论") @RequestParam(required = false) String comment,
                               @ApiParam("是否发送站内消息") @RequestParam(defaultValue = "false") Boolean sendMessage,
                               @ApiParam("是否发送短信通知") @RequestParam(defaultValue = "false") Boolean sendSms,
                               @ApiParam("是否发送邮件通知") @RequestParam(defaultValue = "false") Boolean sendEmail){

        if(StrUtil.isBlank(comment)){
            comment = "";
        }
        taskService.addComment(id, procInstId, comment);
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(procInstId).singleResult();
        Task task = taskService.createTaskQuery().taskId(id).singleResult();
        if(StrUtil.isNotBlank(task.getOwner())&&!("RESOLVED").equals(task.getDelegationState().toString())){
            // 未解决的委托任务 先resolve
            String oldAssignee = task.getAssignee();
            taskService.resolveTask(id);
            taskService.setAssignee(id, oldAssignee);
        }
        taskService.complete(id);
        LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        List<Task> tasks = taskService.createTaskQuery().processInstanceId(procInstId).list();
        // 判断下一个节点
        if(tasks!=null&&tasks.size()>0){
            ActBusiness actBusiness = actBusinessService.getById(pi.getBusinessKey());
            for(Task t : tasks){
                if(StrUtil.isBlank(assignees)){
                    // 如果下个节点未分配审批人为空 取消结束流程
                    List<LoginUser> users = actZprocessService.getNode(t.getTaskDefinitionKey()).getUsers();
                    if(users==null||users.size()==0){
                        runtimeService.deleteProcessInstance(procInstId, "canceled-审批节点未分配审批人,流程自动中断取消");
                       
                        break;
                    }else{
                        // 避免重复添加
                        List<String> list = actBusinessService.selectIRunIdentity(t.getId(), "candidate");
                        if(list==null||list.size()==0) {
                            // 分配了节点负责人分发给全部
                            for (LoginUser user : users) {
                                taskService.addCandidateUser(t.getId(), user.getId());
                             
                            }
                            taskService.setPriority(t.getId(), task.getPriority());
                        }
                    }
                }else{
                    // 避免重复添加
                    List<String> list = actBusinessService.selectIRunIdentity(t.getId(), "candidate");
                    if(list==null||list.size()==0) {

                        for(String assignee : assignees.split(",")){
                            taskService.addCandidateUser(t.getId(), assignee);
                       
                            taskService.setPriority(t.getId(), priority);
                        }
                    }
                }
            }
        } 
       
        return Result.ok(MessageUtils.message(I18nConstant.operateSuccess));
    }

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值