初玩Activiti7一套组合拳,连连败退之下竟突破神功,且看SpringBoot整治Activiti7小老弟!

15.SpringBoot-Activiti技术

1.1 技术介绍

​ Activiti 7是Alfresco经过实战考验的Activiti工作流引擎的演变,完全被采用在云环境中运行。它是根据 Cloud Native 应用程序概念构建的,与之前的Activiti版本在架构方面有所不同。

​ 基于我的理解,帮助开发人员进行流程控制,而工作流的概念就是一个制度的体现,管理体系的体现。

​ 举例来讲:小到家庭琐事,现在有个老李想和朋友,可是他身上没有钱,他需要得到老婆的同意,然后再由老婆拨款,才能出门和朋友吃饭。

​ 更一步案例,现在老李正在读小学,马上要考试了,可是他今天生病了,需要请假,但是这次考试又很重要,他不想放弃。这时就是学校的管理制度起作用了,老师不仅同意了老李的病假,还为老李破例开通第二套试卷考试,老李在休息得当的情况下,顺利的完成了考试,考出高分。

​ 而上升到公司,行业管理等等,其实也是人与人之间的确认信息。

· 较多使用场合

​ 订单、报价处理、合同审核、客户电话处理、供应链管理。

​ 土地开发审核、资源开发审核、人力资源、办公软件之类。

1.2 技术注意点
1.2.1 流程图
  1. 流程图必须有一个或多个默认流
  2. 流程判断必须带有参数条件
  3. 流程图的权限控制:assignee(不包括)、candidateUsers(哪些用户)、candidateGroups(哪些角色)
1.2.2 流程图ID

​ 这个一定要修改,不能出现同名,否则就会出现这个错误。

The deployment contains process definitions with the same key (process id attribute), this is not…

https://blog.csdn.net/qq_41520636/article/details/118304495

1.3 技术具体demo文件路径
1.4 demo的UML图
1.5 demo的技术代码实现
1.5.1 环境准备

​ SpringBoot:2.0.4.RELEASE

​ JDK:1.8

​ Activiti:7.1.0.M2

​ MySQL:8.0.21

​ 开发软件:IDEA

​ 流程插件:actiBPM

1.5.2 安装插件

​ Files → Settings → Plugins → 搜索actiBPM → 下载安装 → 搜索JBoss jBPM → 下载安装

1.5.3 插件试玩

在这里插入图片描述

创建bpnmFile文件
在这里插入图片描述
在这里插入图片描述

创建好后,可以通过修改文件后缀名查看里面的代码
在这里插入图片描述
打开team01.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" xmlns:tns="http://www.activiti.org/test" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:yaoqiang="http://bpmn.sourceforge.net" expressionLanguage="http://www.w3.org/1999/XPath" id="m1544167269809" name="" targetNamespace="http://www.activiti.org/test" typeLanguage="http://www.w3.org/2001/XMLSchema">
  <process id="myProcess_1" isClosed="false" isExecutable="true" processType="None">
    <extensionElements>
      <yaoqiang:description/>
      <yaoqiang:pageFormat height="841.8897637795276" imageableHeight="831.8897637795276" imageableWidth="588.1102362204724" imageableX="5.0" imageableY="5.0" orientation="0" width="598.1102362204724"/>
      <yaoqiang:page background="#FFFFFF" horizontalCount="1" verticalCount="1"/>
    </extensionElements>
    <startEvent id="_2" isInterrupting="true" name="StartEvent" parallelMultiple="false"/>
    <userTask activiti:candidateGroups="activitiTeam" activiti:exclusive="true" completionQuantity="1" id="_3" implementation="##unspecified" isForCompensation="false" name="填写申请单" startQuantity="1"/>
    <userTask activiti:candidateGroups="activitiTeam" activiti:exclusive="true" completionQuantity="1" id="_4" implementation="##unspecified" isForCompensation="false" name="审核" startQuantity="1"/>
    <endEvent id="_5" name="EndEvent"/>
    <sequenceFlow id="_6" sourceRef="_2" targetRef="_3"/>
    <sequenceFlow id="_7" sourceRef="_3" targetRef="_4"/>
    <sequenceFlow id="_8" sourceRef="_4" targetRef="_5"/>
  </process>
  <bpmndi:BPMNDiagram documentation="background=#3C3F41;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0" id="Diagram-_1" name="New Diagram">
    <bpmndi:BPMNPlane bpmnElement="myProcess_1">
      <bpmndi:BPMNShape bpmnElement="_2" id="Shape-_2">
        <omgdc:Bounds height="32.0" width="32.0" x="65.0" y="80.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_3" id="Shape-_3">
        <omgdc:Bounds height="55.0" width="85.0" x="170.0" y="115.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_4" id="Shape-_4">
        <omgdc:Bounds height="55.0" width="85.0" x="310.0" y="155.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="_5" id="Shape-_5">
        <omgdc:Bounds height="32.0" width="32.0" x="505.0" y="220.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="_6" id="BPMNEdge__6" sourceElement="_2" targetElement="_3">
        <omgdi:waypoint x="97.0" y="96.0"/>
        <omgdi:waypoint x="170.0" y="142.5"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="18.96" width="6.0" x="130.5" y="109.77"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_7" id="BPMNEdge__7" sourceElement="_3" targetElement="_4">
        <omgdi:waypoint x="255.0" y="142.5"/>
        <omgdi:waypoint x="310.0" y="182.5"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="18.96" width="6.0" x="279.5" y="153.02"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="_8" id="BPMNEdge__8" sourceElement="_4" targetElement="_5">
        <omgdi:waypoint x="395.0" y="182.5"/>
        <omgdi:waypoint x="505.0" y="236.0"/>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="18.96" width="6.0" x="447.0" y="199.77"/>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

将xml更改为png格式
在这里插入图片描述
在这里插入图片描述

1.5.4 创建activiti特有数据库

​ 因为利用的是springboot,就不用使用xml配置,还要代码注入后,才能启动。

​ 启动流程

yml配置 → ProcessEngine(流程引擎)→ RuntimeService(流程运行管理类)

​ → TaskService(流程运行管理类)

​ → RepositoryService(资源管理类)

​ → HistoryService(历史管理类)

​ → ManagementService(引擎管理类)

​ 在此之前,你需要先知道Activiti7属于高版本,已经舍弃掉了三张表,这三张就是权限管理,由于过于简单舍弃,选择Spring Security来控制权限。

​ 你必须在你的本地创建一个activiti的数据库,来存放新增的表。

实战例子

1.创建pom
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.4.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
    <mysql.version>8.0.21</mysql.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- activiti 自动建表 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>

    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-spring-boot-starter</artifactId>
        <version>7.1.0.M2</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>${mysql.version}</version>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

    <!-- Thymeleaf依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>RELEASE</version>
        <scope>compile</scope>
    </dependency>

</dependencies>

<build>
    <finalName>my-springboot-activiti-demo</finalName>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>
2.准备application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/activiti
    username: root
    password: 123
    hikari:
      data-source-properties:
        useSSL: false
        serverTimezone: GMT+8
        useUnicode: true
        characterEncoding: utf8
        # 这个必须要加,否则 Activiti 自动建表会失败
        nullCatalogMeansCurrent: true
  activiti:
    # 保存历史数据级别设置为full最高级别,便于历史数据的追溯
    history-level: full
    db-history-used: true
    # 不启动检查activiti数据库版本是否匹配,提升应用启动效率
    database-schema-update: false
    #自动检查、部署流程定义文件
    check-process-definitions: true
    #流程定义文件存放目录,要具体到某个目录
    process-definition-location-prefix: classpath:/processes/
    # process-definition-location-suffixes: #流程文件格式
    #  - **.bpmn20.xml
    #  - **.bpmn
3.创建Spring Security的授权用户
@Slf4j
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeRequests()
            .anyRequest()
            .authenticated()
            .and()
            .httpBasic();
    }

    /**
     * spring security 高版本自带
     * @return
     */
    @Bean
    protected UserDetailsService myUserDetailsService() {
        InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
        // 四个普通用户,一个管理员
        String[][] usersGroupsAndRoles = {
            {"salaboy", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
            {"ryandawsonuk", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
            {"erdemedeiros", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
            {"other", "password", "ROLE_ACTIVITI_USER", "GROUP_otherTeam"},
            {"admin", "password", "ROLE_ACTIVITI_ADMIN"}};

        for (String[] user : usersGroupsAndRoles) {
            List<String> authoritiesStrings = Arrays.asList(Arrays.copyOfRange(user, 2, user.length));
            log.info("> Registering new user: " + user[0] + " with the following Authorities[" + authoritiesStrings + "]");
            inMemoryUserDetailsManager.createUser(new User(user[0], passwordEncoder().encode(user[1]),
                authoritiesStrings.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList())));
        }
        return inMemoryUserDetailsManager;
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
4.创建一个授权认证

注意:这只是测试环境,真是环境并不是怎么操作,还是需要用户正常登录授权,这里只是写了死值,方便测试。

@Component
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class SecurityUtil {

    private final UserDetailsService userDetailsService;

    public void logInAs(String username) {

        UserDetails user = userDetailsService.loadUserByUsername(username);
        if (user == null) {
            throw new IllegalStateException("User " + username + " doesn't exist, please provide a valid user");
        }

        SecurityContextHolder.setContext(new SecurityContextImpl(new Authentication() {
            @Override
            public Collection<? extends GrantedAuthority> getAuthorities() {
                return user.getAuthorities();
            }

            @Override
            public Object getCredentials() {
                return user.getPassword();
            }

            @Override
            public Object getDetails() {
                return user;
            }

            @Override
            public Object getPrincipal() {
                return user;
            }

            @Override
            public boolean isAuthenticated() {
                return true;
            }

            @Override
            public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {

            }

            @Override
            public String getName() {
                return user.getUsername();
            }
        }));
        org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username);
    }
}
5.测试代码
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootDemoActivitiApplicationTests {

    @Autowired
    private ProcessRuntime processRuntime; // 流程引擎的抽象,可以获取所有的服务
    
	/**
     * 列出所有流程定义
     */
    @Test
    public void contextLoads() {
        // 调用授权
        securityUtil.logInAs("salaboy");
        // 查询十条流程实例信息
        Page<ProcessDefinition> processDefinitionPage = processRuntime.processDefinitions(Pageable.of(0, 10));
        processDefinitionPage.getContent().forEach(System.out::println);
    }
}
6.结果

在这里插入图片描述
查询出来的结果
在这里插入图片描述
这里查询出的数据,对应的数据库中的act_re_procdef(流程定义数据表)。
在这里插入图片描述
其实,springboot只要把pom依赖导入,yml数据源配置好后,然后启动springbootapplication服务,数据库就能自动创建,而我们选择使用一个小案例,能够看到具体的调用流程实现。

当我启动springboot服务时,以下四张表会新增数据。

act_ge_property(属性数据表)
在这里插入图片描述
act_re_deployment(部署信息表)
在这里插入图片描述
act_ge_bytearray(二进制数据表)
在这里插入图片描述
act_re_procdef(流程定义数据表)
在这里插入图片描述
在这里插入图片描述

1.5.5 简单审批案例

在这里插入图片描述
详细图解流程运行过程
在这里插入图片描述

1.发起请假申请流程
 	@Test
    public void testProcessInstance(){
        // 流程名
        String key = "bohui";
        // 申请人
        String username = "zhangsan";

        HashMap<String, Object> map = new HashMap<>();
        // 启动流程实例时给变量赋值
        map.put("assignee1", username);
        // 启动流程,发送请假请求
        ActivitiUtil.startProcessInstanceWithVariables(username, key,"请假", map);
    }
	/**
     * 启动流程
     * @param username    用户名
     * @param processKey  流程 Key => 对应bpmn文件里的id
     * @param processName 流程实例名
     * @param variables   变量map
     */
    public static void startProcessInstanceWithVariables(String username,
                                                         String processKey, String processName,
                                                         HashMap<String,Object> variables) {
        // Security 授权用户(这里的代码上面的授权认证一样)
        activitiUtil.securityUtil.logInAs(username);
        // 创建一个运行时流程,并启动该流程
        ProcessInstance processInstance = activitiUtil.processRuntime
                .start(ProcessPayloadBuilder
                        .start() // 启动流程
                        .withProcessDefinitionKey(processKey) // 流程运行时定义流程实例
                        .withName(processName) // 流程事务,要做什么
                        .withVariables(variables) // 流程变量,一些额外的属性
                        .build());
        logger.info("流程实例启动成功: " + processInstance);
    }

执行结果:

流程实例启动成功: ProcessInstance{id=‘1bac6242-d8e3-11eb-abf7-04d3b0ccfa07’, name=‘请假’, processDefinitionId=‘bohui:1:e2f71a3c-d8bf-11eb-9c08-04d3b0ccfa07’, processDefinitionKey=‘bohui’, parentId=‘null’, initiator=‘zhangsan’, startDate=Tue Jun 29 22:05:49 CST 2021, businessKey=‘null’, status=RUNNING, processDefinitionVersion=‘1’}

数据库新增表

act_hi_actinst(历史节点表)

在这里插入图片描述

act_hi_detail(历史详情表)

在这里插入图片描述

act_hi_identitylink(历史流程人员表)

在这里插入图片描述

act_hi_procinst(历史流程实例表)

在这里插入图片描述

act_hi_taskinst(历史任务实例表)

在这里插入图片描述

act_hi_varinst(历史变量表)

在这里插入图片描述

act_ru_execution(运行时流程执行实例表)

在这里插入图片描述

act_ru_identitylink(运行时流程人员表)

在这里插入图片描述

act_ru_task(运行时任务节点表)

在这里插入图片描述

act_ru_variable(运行时流程变量数据表)

在这里插入图片描述

在这里插入图片描述

2.获取所有流程定义
	@Test
    public void testQueryTask(){
        String assignee = "zhangsan";
        // 获取所有流程定义
        ActivitiUtil.printTaskList(assignee, 0, 10);
    }
	/**
     * 打印指派人所有任务
     *
     * @param assignee 指派人
     * @param startNum 分页开始下标
     * @param endNum   分页结束下标
     */
    public static void printTaskList(String assignee, Integer startNum, Integer endNum) {
        // 获取所有任务list
        Page<org.activiti.api.task.model.Task> tasks = getTaskList(assignee, startNum, endNum);
        // 任务的总数大于0
        if (tasks.getTotalItems() > 0) {
            // 有任务时,完成任务
            for (org.activiti.api.task.model.Task task : tasks.getContent()) {
                logger.info("任务: " + task);
            }
        }
    }
    @Autowired
    private CustomTaskRuntimeImpl customTaskRuntimeImpl;

	private static ActivitiUtil activitiUtil;

	/**
     * 查询当前指派人的任务
     *
     * @param assignee 指派人
     * @param startNum 分页开始下标
     * @param endNum   分页结束下标
     * @return 任务list
     */
    public static Page<org.activiti.api.task.model.Task> getTaskList(String assignee, Integer startNum, Integer endNum) {
        // 授权用户
        activitiUtil.securityUtil.logInAs(assignee);
        // 
        return activitiUtil.customTaskRuntimeImpl.tasks(Pageable.of(startNum, endNum));
    }
@PreAuthorize("hasRole('ACTIVITI_USER')") // 控制一个方法需要权限调用
@Component
public class CustomTaskRuntimeImpl implements TaskRuntime {	
    
    // 安全管理器
    private final SecurityManager securityManager;
    // 流程运行管理类
    private final TaskService taskService;
    // API任务转换
    private final APITaskConverter taskConverter;

	/**
	 *
	 * @param pageable 可分页
	 */
	@Override
    public Page<Task> tasks(Pageable pageable) {
        // 获取认证用户id
        String authenticatedUserId = securityManager.getAuthenticatedUserId();
        // 认证用户id不为空的场合
        if (authenticatedUserId != null && !authenticatedUserId.isEmpty()) {
            // 获取认证用户组
            List<String> userGroups = securityManager.getAuthenticatedUserGroups();
            // 分页的任务
            return tasks(pageable,
                    TaskPayloadBuilder.tasks().withAssignee(authenticatedUserId).withGroups(userGroups).build());
        }
        throw new IllegalStateException("You need an authenticated user to perform a task query");
    }
    
    /** 
     *
     * @param pageable 可分页
     * @param getTasksPayload 获取多个任务负载
     */
    @Override
    public Page<Task> tasks(Pageable pageable,
                            GetTasksPayload getTasksPayload) {
        // 创建任务队列
        TaskQuery taskQuery = taskService.createTaskQuery();
        // 任务负载不为空的场合
        if (getTasksPayload == null) {
            // 生成任务负载
            getTasksPayload = TaskPayloadBuilder.tasks().build();
        }
        // 获取认证用户ID
        String authenticatedUserId = securityManager.getAuthenticatedUserId();
        // 认证用户ID不为空的场合
        if (authenticatedUserId != null && !authenticatedUserId.isEmpty()) {
            // 获取认证用户组
            List<String> userGroups = securityManager.getAuthenticatedUserGroups();
            // 任务负载设置指派人ID
            getTasksPayload.setAssigneeId(authenticatedUserId);
            // 任务负载设置用户组
            getTasksPayload.setGroups(userGroups);
        } else {
            throw new IllegalStateException("You need an authenticated user to perform a task query");
        }
        // 按照分配组 OR 指派人查询
        taskQuery = taskQuery.or()
                .taskCandidateOrAssigned(getTasksPayload.getAssigneeId(),
                        getTasksPayload.getGroups())
//                .taskOwner(authenticatedUserId)
                .endOr();
		// 获取流程实例ID不为空的场合
        if (getTasksPayload.getProcessInstanceId() != null) {
            // 为任务队列设置流程实例ID
            taskQuery = taskQuery.processInstanceId(getTasksPayload.getProcessInstanceId());
        }
        // 获取父任务ID不为空的场合
        if (getTasksPayload.getParentTaskId() != null) {
            // 为任务队列设置父任务ID
            taskQuery = taskQuery.taskParentTaskId(getTasksPayload.getParentTaskId());
        }
        // 将任务队列里的分页list转换为任务list
        List<Task> tasks = taskConverter.from(taskQuery.listPage(pageable.getStartIndex(),
                pageable.getMaxItems()));
        // 返回分页实现类
        return new PageImpl<>(tasks,
                Math.toIntExact(taskQuery.count()));
    }
}

Activiti 开发案例之 API 映射 SQL 查询

https://www.imooc.com/article/279591

查询结果:

任务: TaskImpl{id=‘1bae8529-d8e3-11eb-abf7-04d3b0ccfa07’, owner=‘null’, assignee=‘zhangsan’, name=‘发起’, description=‘null’, createdDate=Tue Jun 29 22:05:49 CST 2021, claimedDate=null, dueDate=null, priority=50, processDefinitionId=‘bohui:1:e2f71a3c-d8bf-11eb-9c08-04d3b0ccfa07’, processInstanceId=‘1bac6242-d8e3-11eb-abf7-04d3b0ccfa07’, parentTaskId=‘null’, formKey=‘null’, status=ASSIGNED, processDefinitionVersion=null, businessKey=null, taskDefinitionKey=_3}

3.进入审批阶段(指定审批人)
    @Test
    public void testCompleteTask(){
        // 申请人
        String assignee = "zhangsan";
        HashMap<String, Object> map = new HashMap<>();
        // 完成任务时同时指定之后流程的指派人(审批人)
        map.put("assignee2", "lisi");
        // 根据变量条件完成对应任务
        ActivitiUtil.completeTaskWithVariables(assignee, map);
    }
	/**
     * 完成任务
     *
     * @param assignee  指派人
     * @param variables 变量map
     */
    public static void completeTaskWithVariables(String assignee, HashMap<String,Object> variables) {
		// 获取默认前十条任务
        Page<org.activiti.api.task.model.Task> tasks = getTaskList(assignee, 0, 10);
        // 任务总数大于零的场合
        if (tasks.getTotalItems() > 0) {
            // 有任务时,完成任务
            for (org.activiti.api.task.model.Task task : tasks.getContent()) {
                System.out.println(task);
                // 完成任务
                activitiUtil.taskRuntime.complete(
                        TaskPayloadBuilder.complete()
                                .withTaskId(task.getId())
                                .withVariables(variables).build());
                logger.info(assignee + "完成任务");
            }
        }
    }

执行结果:

Logged in as: zhangsan
TaskImpl{id=‘1bae8529-d8e3-11eb-abf7-04d3b0ccfa07’, owner=‘null’, assignee=‘zhangsan’, name=‘发起’, description=‘null’, createdDate=Tue Jun 29 22:05:49 CST 2021, claimedDate=null, dueDate=null, priority=50, processDefinitionId=‘bohui:1:e2f71a3c-d8bf-11eb-9c08-04d3b0ccfa07’, processInstanceId=‘1bac6242-d8e3-11eb-abf7-04d3b0ccfa07’, parentTaskId=‘null’, formKey=‘null’, status=ASSIGNED, processDefinitionVersion=null, businessKey=null, taskDefinitionKey=_3}
2021-06-30 00:40:35.753 INFO 16368 — [ main] c.z.a.utils.ActivitiUtil : zhangsan完成任务

数据表出现的变化

在这里插入图片描述

4.进入审批阶段(审批人不通过申请,驳回请求)
    @Test
    public void testCompleteTask2(){
        // 审批人
        String assignee = "lisi";
        HashMap<String, Object> map = new HashMap<>();
        // 完成任务时同时指定审核为驳回
        map.put("audit", false);
        // 根据变量条件完成对应任务
        ActivitiUtil.completeTaskWithVariables(assignee, map);
    }

执行结果

Logged in as: lisi
TaskImpl{id=‘ba78a61b-d8f8-11eb-bb2a-04d3b0ccfa07’, owner=‘null’, assignee=‘lisi’, name=‘审核’, description=‘null’, createdDate=Wed Jun 30 00:40:35 CST 2021, claimedDate=null, dueDate=null, priority=50, processDefinitionId=‘bohui:1:e2f71a3c-d8bf-11eb-9c08-04d3b0ccfa07’, processInstanceId=‘1bac6242-d8e3-11eb-abf7-04d3b0ccfa07’, parentTaskId=‘null’, formKey=‘null’, status=ASSIGNED, processDefinitionVersion=null, businessKey=null, taskDefinitionKey=_4}
2021-06-30 00:45:05.008 INFO 1940 — [ main] c.z.a.utils.ActivitiUtil : lisi完成任务

数据表出现的变化

在这里插入图片描述

5.进入审批阶段(申请人重新申请请求)
@Test
public void testCompleteTask3(){
    // 申请人
    String assignee = "zhangsan";
    // 重新提交任务
    ActivitiUtil.completeTask(assignee);
}
/**
 * 完成指派人所有任务
 *
 * @param assignee 指派人
 */
public static void completeTask(String assignee) {
	// 获取默认前十条任务
    Page<org.activiti.api.task.model.Task> tasks = getTaskList(assignee, 0, 10);
    // 任务总数大于零的场合
    if (tasks.getTotalItems() > 0) {
        // 有任务时,完成任务
        for (org.activiti.api.task.model.Task task : tasks.getContent()) {
            System.out.println(task);
            // 完成任务
            activitiUtil.taskRuntime.complete(
                    TaskPayloadBuilder.complete().withTaskId(task.getId()).build());
            logger.info(assignee + "完成任务");
        }
    }
}
6.进入审批阶段(审批通过)
@Test
public void testCompleteTask4(){
    // 审批人
    String assignee = "lisi";
    HashMap<String, Object> map = new HashMap<>();
    // 完成任务时同时指定审核为通过
    map.put("audit", true);
    // 根据变量条件完成对应任务
    ActivitiUtil.completeTaskWithVariables(assignee, map);
}

执行结果

Logged in as: lisi
TaskImpl{id=‘d0cddac7-d8f9-11eb-8c91-04d3b0ccfa07’, owner=‘null’, assignee=‘lisi’, name=‘审核’, description=‘null’, createdDate=Wed Jun 30 00:48:22 CST 2021, claimedDate=null, dueDate=null, priority=50, processDefinitionId=‘bohui:1:e2f71a3c-d8bf-11eb-9c08-04d3b0ccfa07’, processInstanceId=‘1bac6242-d8e3-11eb-abf7-04d3b0ccfa07’, parentTaskId=‘null’, formKey=‘null’, status=ASSIGNED, processDefinitionVersion=null, businessKey=null, taskDefinitionKey=_4}
2021-06-30 00:48:44.667 INFO 9616 — [ main] c.z.a.utils.ActivitiUtil : lisi完成任务

数据表出现的变化

在这里插入图片描述
完结!原创不易,点个赞再走!

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hikktn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值