SpringBoot 结合Activiti 进行单条实例工作流审批

1.建立maven项目,引入maven依赖

#因为我的项目单独引入了mybatis-plus所以这里对activiti排除一下mybatis的依赖
<dependency>
   <groupId>org.activiti</groupId>
    <artifactId>activiti-engine</artifactId>
    <version>7.1.0.M6</version>
    <exclusions>
        <exclusion>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.activiti</groupId>
    <artifactId>activiti-image-generator</artifactId>
    <version>7.1.0.M6</version>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.27</version>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.2</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.8</version>
</dependency>
logging:
  level:
    #日志输出
    org.activiti.engine.impl.persistence.entity: trace

2.我使用的是idea,所以需要引入插件,如果是eclipse也需要引入插件,在我之前的文章里有记录

在这里插入图片描述

3.使用idea的插件画一下流程图

idea对activiti的兼容性不如eclipse方便
3.1 右键创建文件
在这里插入图片描述
3.2创建一个文件后,在文件内部继续右击
在这里插入图片描述
3.3 出现画图的小页面,继续在小页面里边右击
在这里插入图片描述
3.4 流程指向 status 用于后边审批时候的条件
在这里插入图片描述
3.5 流程审批人 用于后边代码赋值
在这里插入图片描述
3.6 排他网关
在这里插入图片描述

4.增加Activiti的配置文件

import com.alibaba.druid.pool.DruidDataSource;
import org.activiti.engine.*;
import org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration;
import org.activiti.engine.impl.history.HistoryLevel;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import javax.sql.DataSource;

@Configuration
public class ActivitiConfig {


    /**
     * 数据源
     * @return
     */
    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource dataSource(){
        return new DruidDataSource();
    }

    /**
     * 工作流流程引擎配置文件
     * @param dataSource
     * @return
     */
    @Bean
    public ProcessEngineConfiguration processEngineConfiguration(DataSource dataSource){
        StandaloneProcessEngineConfiguration standaloneProcessEngineConfiguration = new StandaloneProcessEngineConfiguration();
        standaloneProcessEngineConfiguration.setDataSource(dataSource);
        //自动更新表结构,数据库表不存在时会自动创建表
        standaloneProcessEngineConfiguration.setDatabaseSchemaUpdate("true");
        //保存历史数据级别设置为full最高级别,便于历史数据的追溯
        standaloneProcessEngineConfiguration.setHistoryLevel(HistoryLevel.FULL);
        //关闭activiti自动部署(使用流程设计器部署,不使用具体文件访问方式)
        standaloneProcessEngineConfiguration.setDbHistoryUsed(true);
        return standaloneProcessEngineConfiguration;
    }

    /**
     * 工作流流程引擎
     * @param processEngineConfiguration
     * @return
     */
    @Bean
    public ProcessEngine processEngine(ProcessEngineConfiguration processEngineConfiguration){
        return processEngineConfiguration.buildProcessEngine();
    }

    @Bean
    @DependsOn("processEngine")
    public RepositoryService repositoryService(ProcessEngine processEngine){
        return processEngine.getRepositoryService();
    }

    @Bean
    @DependsOn("processEngine")
    public RuntimeService runtimeService(ProcessEngine processEngine){
        return processEngine.getRuntimeService();
    }

    @Bean
    @DependsOn("processEngine")
    public TaskService taskService(ProcessEngine processEngine){
        return processEngine.getTaskService();
    }

    @Bean
    @DependsOn("processEngine")
    public HistoryService historyService(ProcessEngine processEngine){
        return processEngine.getHistoryService();
    }

5.创建一个接收参数的实体类,参数自己定义就可以,根据实际情况来

@Data
public class ProcessParam {
    /**
     * 流程定义id
     */
    String processDefinitionId;
    /**
     * 流程实例id
     */
    String processInstanceId;
    /**
     * 任务id
     */
    String taskId;
    /**
     * 流程定义key
     */
    String deploymentKey;
    /**
     * 流程定义名称
     */
    String deploymentName;
    /**
     * 用户名称
     */
    String userName;
    /**
     * 用户名称批量 英文逗号间隔
     */
    String userNames;
    /**
     * 审批意见
     */
    String comment;
    /**
     * 职位
     */
    String position;
    /**
     * 审批状态
     */
    Integer status;
    /**
     * 抄送人
     */
    List<ProcessParam> processParamList;
}

6.创建工作流资源方面的控制类

具体查询或增删改操作都需要根据实际业务进行改动,以下代码仅供参考
上传资源后会在ACT_RE_PROCDEF、ACT_RE_DEPLOYMENT、ACT_GE_BYTEARRAY表中生成信息,如果同一资源上传多次会在ACT_RE_PROCDEF表中的版本号字段加1,

@RestController
public class RepositoryController {

    @Autowired
    private RepositoryService repositoryService;


    @ApiOperation("上传工作流资源")
    @PostMapping("/uploadRepository")
    public Map<String,Object> uploadRepository(@RequestParam String processName,MultipartFile file){
        Map<String,Object> resultMap = new HashMap<>();
        InputStream inputStream = null;
        try {
            inputStream = file.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        if(inputStream == null){
            resultMap.put("error","请上传文件");
            return resultMap;
        }
        boolean contains = file.getOriginalFilename().endsWith(".zip");
        if(!contains){
            resultMap.put("error","请上传压缩文件");
            return resultMap;
        }
        Deployment deployment = repositoryService.createDeployment().name(processName).addZipInputStream(new ZipInputStream(inputStream)).deploy();
        resultMap.put("data",deployment);
        return resultMap;
    }

    @ApiOperation("删除工作流资源")
    @GetMapping("/deleteRepository")
    public Map<String,Object> deleteRepository(@RequestParam String id){
        Map<String,Object> resultMap = new HashMap<>();
        try {
            repositoryService.deleteDeployment(id);
        } catch (Exception e) {
            e.printStackTrace();
            resultMap.put("error","删除失败");
            return resultMap;
        }
        resultMap.put("data","删除成功");
        return resultMap;
    }

    @ApiOperation("查询工作流资源")
    @GetMapping("/searchRepository")
    public Map<String,Object> searchRepository(ProcessParam param,
                                               @RequestParam(name = "page",defaultValue = "1") Integer page,
                                               @RequestParam(name = "size",defaultValue = "10") Integer size){
        Map<String,Object> resultMap = new HashMap<>();
        DeploymentQuery deploymentQuery = repositoryService.createDeploymentQuery();
        if(StringUtils.isNotEmpty(param.getProcessDefinitionId())){
            deploymentQuery.deploymentId(param.getProcessDefinitionId());
        }
        if(StringUtils.isNotEmpty(param.getDeploymentKey())){
            deploymentQuery.deploymentKeyLike(param.getDeploymentKey());
        }
        if(StringUtils.isNotEmpty(param.getDeploymentName())){
            deploymentQuery.deploymentNameLike(param.getDeploymentName());
        }
        List<Deployment> deployments = deploymentQuery.listPage(page, size);
        resultMap.put("data",deployments);
        return resultMap;
    }
}

7.创建工作流发起的控制类

工作流发起后会在ACT_RU_EXECUTION、ACT_RU_TASK、ACT_RU_IDENTITYLINK、ACT_RU_VARIABLE、ACT_HI_ACTINST、ACT_HI_DETAIL、ACT_HI_IDENTITYLINK、ACT_HI_PROCINST、ACT_HI_TASKINST、ACT_HI_VARINST生成数据,当工作流程结束后,对应的ACT_RU**系列表中对应数据会清空,在历史表中数据会完善

@RestController
public class RuntimeController {
	@Autowired
    private RuntimeService runtimeService;

    @ApiOperation("根据流程定义id发起流程")
    @PostMapping("/startProcess")
    public Map<String,Object> startProcess(@RequestBody ProcessParam param){
        Map<String,Object> resultMap = new HashMap<>();
        if(param == null){
            resultMap.put("error","参数错误");
            return resultMap;
        }
        Map<String,Object> paramMap = new HashMap<>();
        paramMap.put("username",param.getUserName());
        paramMap.put("status",param.getStatus());
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(param.getProcessDefinitionId(), paramMap);
        resultMap.put("data",processInstance);
        return resultMap;
    }
    
    @ApiOperation("根据流程定义id查看发起的流程实例")
    @GetMapping("/searchRunTime")
    public Object searchRunTime(@RequestParam String processDefinitionId){
        List<ProcessInstance> processInstanceList = runtimeService.createProcessInstanceQuery().processDefinitionId(processDefinitionId).list();
        return processInstanceList;
    }

    @ApiOperation("根据流程实例id删除工作流")
    @GetMapping("/deleteRunTime")
    public void deleteRunTime(@RequestParam String processInstanceId,@RequestParam(required = false) String deleteReason){
        runtimeService.deleteProcessInstance(processInstanceId,deleteReason);
    }
}

8.创建工作流审批控制类

@RestController
public class RuntimeController {
	@Autowired
    private TaskService taskService;
    
    @ApiOperation("审批流程")
    @PostMapping("/approvalTask")
    public Map<String,Object> approvalTask(@RequestBody ProcessParam param){
        Map<String,Object> resultMap = new HashMap<>();
        if(param == null){
            resultMap.put("error","参数错误");
            return resultMap;
        }
        Map<String,Object> paramMap = new HashMap<>();
        paramMap.put("username",param.getUserName());
        paramMap.put("status",param.getStatus());
        //添加审批意见
        if(StringUtils.isNotEmpty(param.getComment())){
            taskService.addComment(param.getTaskId(),param.getProcessInstanceId(),param.getComment());
        }
        //添加抄送人
        if(param.getProcessParamList() != null && param.getProcessParamList().size() > 0){
            List<ProcessParam> processParamList = param.getProcessParamList();
            for (ProcessParam processParam : processParamList) {
                Task task = taskService.newTask();
                task.setAssignee(processParam.getUserName());
                task.setParentTaskId(param.getTaskId());
                task.setName(processParam.getPosition());
                taskService.saveTask(task);
            }
        }
        //进行审批
        try {
            taskService.complete(param.getTaskId(),paramMap);
        } catch (Exception e) {
            e.printStackTrace();
            resultMap.put("error","操作失败");
            return resultMap;
        }
        resultMap.put("data","审批成功");
        return resultMap;
    }

    @ApiOperation("查询用户未完成任务")
    @GetMapping("/searchTask")
    public Object searchTask(ProcessParam param){
        List<Task> list = taskService.createTaskQuery().taskAssigneeLike(param.getUserName()).list();
        return list;
    }

    @ApiOperation("删除已审批节点或审批信息")
    @GetMapping("/deleteTask")
    public void deleteTask(ProcessParam param){
        taskService.deleteTask(param.getTaskId());
        taskService.deleteComments(param.getTaskId(),param.getProcessInstanceId());
    }
}

9.创建查看历史信息控制类

创建mapper已经对应的xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.config.controller.mapper.ActivitiMapper">
    <select id="unfinishedProcessByUserName" resultType="java.lang.String">
        select DISTINCT ahp.PROC_INST_ID_ from ACT_HI_PROCINST ahp INNER JOIN ACT_HI_TASKINST aht on ahp.PROC_INST_ID_ = aht.PROC_INST_ID_ where aht.ASSIGNEE_ = #{userName} and ahp.END_TIME_ is  null
    </select>
    <select id="endProcessByUserName" resultType="java.lang.String">
        select DISTINCT ahp.PROC_INST_ID_ from ACT_HI_PROCINST ahp INNER JOIN ACT_HI_TASKINST aht on ahp.PROC_INST_ID_ = aht.PROC_INST_ID_ where aht.ASSIGNEE_ = #{userName} and ahp.END_TIME_ is not null
    </select>
</mapper>
public interface ActivitiMapper {
    Set<String> unfinishedProcessByUserName(@Param("userName") String userName);
    Set<String> endProcessByUserName(@Param("userName") String userName);
}
@RestController
public class HistoryController {
	@Autowired
    private HistoryService historyService;
    @Autowired
    private ActivitiMapper activitiMapper;
    
    @ApiOperation("根据用户名查询当前用户已审批,单据未完结的工作流信息")
    @GetMapping("/searchHistory")
    public Object searchHistory(@RequestParam String userName){
        Set<String> processByUserName = activitiMapper.unfinishedProcessByUserName(userName);
        List<HistoricProcessInstance> historicProcessInstances = historyService.createHistoricProcessInstanceQuery().processInstanceIds(processByUserName).list();
        return historicProcessInstances;
    }

    @ApiOperation("根据用户名查询已经完结的工作流信息")
    @GetMapping("/searchendHistory")
    public Object searchendHistory(@RequestParam String userName){
        Set<String> processByUserName = activitiMapper.endProcessByUserName(userName);
        List<HistoricProcessInstance> historicProcessInstances = historyService.createHistoricProcessInstanceQuery().processInstanceIds(processByUserName).list();
        return historicProcessInstances;
    }
}

10.导出工作流信息

@Controller
public class HistoryController {
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private RuntimeService runtimeService;
    @GetMapping("/exportActiviti")
    public void exportActiviti(@RequestParam String processDefinitionId,
                               @RequestParam String executionId,
                               HttpServletResponse response) throws Exception {
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        List<String> activeActivityIds = runtimeService.getActiveActivityIds(executionId);
        ProcessDiagramGenerator processDiagramGenerator = new DefaultProcessDiagramGenerator();
        InputStream inputStream = processDiagramGenerator.generateDiagram(bpmnModel, activeActivityIds, activeActivityIds, "宋体", "宋体", "宋体", true,"png");
        OutputStream outputStream = response.getOutputStream();
        IOUtils.copy(inputStream,outputStream);
        outputStream.flush();
        inputStream.close();
        outputStream.close();
    }
}
  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值