activiti5工作流+微服务

开头

公司要求使用开发出一套基础的流程设计,目前项目处于demo阶段,but整个流程是通了的。
初学者完全可以借鉴一下
spring cloud + activiti5
话不多说开始整。

activiti 开发者api文档

api文档

先说一说整个流程

请添加图片描述
以上是我总结的整个工作流的基础流程,当然,你也可以根据这个流程衍生出复杂的流程

工作流专门的表

工作流专门的表一共有23张表,具体表结构我这里就不说了太多了,可以去看看这篇文章
工作流表结构详解

生成流程图的工具

idea 需要下载流程设计器camunda-modeler
可以去看看这篇文章点击
这个工具我后面会讲

上代码

依赖

<dependency>
	<groupId>org.activiti</groupId>
	<artifactId>activiti-image-generator</artifactId>
	<version>5.23.0</version>
</dependency>

使用流程设计器camunda-modeler
请添加图片描述
上图这个几个是我们要用到的

第一个圆圈是开始节点
第二个加粗的圆圈是结束节点
第三个矩形是需要审批的节点
请添加图片描述

这个就是一个正常的开始—>审批—>结束的流程图
上面说了矩形是审批节点,所以这里我们要选着是谁审批
双击矩形框输入节点名称
请添加图片描述
如图,but光这样是不行滴这只是给节点取了个名字。设置审批人:
单机矩形框
请添加图片描述
看到了吗,旁边有个扳手对点他会出现一个列表点击User Task,然后矩形框左上角会出现一个小人的标志(没错老板就是小人)
然后再次单机矩形框
请添加图片描述
我们只用管Assignee。这里输入审批人的用户id,然后点击空白,旁边列表id下面那个name 是这个流程的名称。
保存后缀为bpmn的文件,可以自行去百度bpmn的内容

bpmn部署

/**
     * bpmn部署
     * @param file bpmn 文件
     * @param png 图片
     * @param deployName 部署名称
     * @param formId 外置表单id
     * @return
     * */
    @Override
    public boolean deploymentBPMN(MultipartFile file, MultipartFile png, String deployName, String formId) {
        if (file == null) {
            throw new MyException("部署文件不能为空");
        }
        String fileName = file.getOriginalFilename();
        if (StrUtil.isNotBlank(fileName)) {
            fileName = fileName.substring(0, fileName.indexOf("."));
        }
        log.info("部署流程名称:" + fileName);
        DeploymentBuilder deployment = repositoryService.createDeployment();

        //部署名称
        deployment.name(deployName);
//        deployment.name(fileName);
        try {
            //加上后缀不然流程设计表会为空
            deployment.addInputStream(fileName + ".bpmn", file.getInputStream());
            if (png != null) {
                String name = png.getOriginalFilename();
                if (StrUtil.isNotBlank(name)) {
                    name = name.substring(name.lastIndexOf(".") + 1, name.length());
                    if (!name.equalsIgnoreCase("PNG")) {
                        throw new MyException("图片格式错误");
                    }
                }
                deployment.addInputStream(png.getName(), png.getInputStream());
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw new MyException("流程部署IO错误");
        } catch (MyException e) {
            e.printStackTrace();
            throw new MyException(e.getMsg(), e.getCode());
        }
        Deployment deploy = deployment.deploy();

        //向流程设计绑定表单
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploy.getId())
                .singleResult();
        FormProcdef f = new FormProcdef();
        f.setProcessKey(processDefinition.getKey());
        f.setFormId(formId);
        f.setActReProcdefId(processDefinition.getId());
        formProcdefService.save(f);


        log.info("【部署流程成功】部署id:" + deploy.getId());
        log.info("【部署流程成功】部署名称:" + deploy.getName());
        log.info("【部署流程成功】部署时间:" + DateUtil.format(deploy.getDeploymentTime(), "yyyy-MM-dd HH:mm:ss"));
        log.info("【部署流程成功】部署类别:" + deploy.getCategory());
        return true;
    }

外置表单id 大家可以不用管直接去掉
(这里就是增加一个外置表单表部署的时候可以选择自己设定的外置表单,然后和这个你设计的这个流程进行关联,
外置表单作用在于多个流程的表单填写,比如说有请假流程,报销流程等
ok ,请假流程是需要你填写开始时间结束时间等信息的,而报销流程又不一样,懂我意思吧,所以大家可以自行忽略

查看部署列表
你部署了流程,坑定有部署列表对吧

/**
     * 部署列表
     * @param req
     * */
    @Override
    public Page<ResProcessDeploymentListDto> processDeploymentList(ReqProcessDeploymentListDto req) {
        DeploymentQuery deploymentQuery = repositoryService.createDeploymentQuery();
        if (StrUtil.isNotBlank(req.getName())) {
            deploymentQuery.deploymentTenantIdLike("%" + req.getName() + "%");
        }
        //数据总条数
        long count = deploymentQuery.count();
        //分页查询
        List<Deployment> data = deploymentQuery.listPage(req.toFirstResult(), req.toLimitInteger());
        List<ResProcessDeploymentListDto> pageData = data.stream().map(e -> {
            DeploymentEntity entity = (DeploymentEntity) e;
            ResProcessDeploymentListDto res = new ResProcessDeploymentListDto();
            BeanUtils.copyProperties(entity, res);
            return res;
        }).collect(Collectors.toList());
        Page<ResProcessDeploymentListDto> page = new Page<>();
        page.setTotal(count);
        page.setRecords(pageData);
        return page;
    }

这里我把参数(Req前缀)和返回参数(Res)都封装成了dto的

@Data
public class ReqProcessDeploymentListDto extends PageDto {
    @ApiModelProperty(value = "部署名称")
    private String name;
}
@Data
public class ResProcessDeploymentListDto {
    @ApiModelProperty(value = "部署id")
    private String id;
    @ApiModelProperty(value = "部署名称")
    private String name;
    @ApiModelProperty(value = "部署时间")
    @JsonFormat(shape =JsonFormat.Shape.STRING,pattern ="yyyy-MM-dd HH:mm:ss",timezone ="GMT+8")
    private Date deploymentTime;
    @ApiModelProperty(value = "部署类别")
    private String category;
}

列表里面都继承了分页dto,这个也是自己定义了的不多说
删除部署
注意:删除部署会导致流程设计也会被删除

/**
     * 删除部署
     * @param req
     * */
    @Override
    public void deleteDeployment(ReqDeleteDeploymentDto req) {

        //删除外置表单关联
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(req.getId())
                .singleResult();
        formProcdefService.remove(
                new LambdaQueryWrapper<FormProcdef>()
                        .eq(FormProcdef::getActReProcdefId, processDefinition.getId())
        );

        //删除流程定义
        repositoryService.deleteDeployment(req.getId(), req.isCascade());
    }

@Data
public class ReqDeleteDeploymentDto {
    @ApiModelProperty(value = "部署id")
    @NotBlank(message = "部署id不能为空")
    private String id;
    @ApiModelProperty(value = "删除模式(false:普通 true:级联)")
    private boolean cascade=false;
}

流程列表
上面说了部署一个流程的时候activiti会自动生成一条流程设计的数据

/**
     * 流程定义列表
     * @param req
     * */
    @Override
    public Page<ResProcessDefinitionListDto> processDefinitionList(ReqProcessDefinitionListDto req) {
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();

        long count = processDefinitionQuery.count();
        List<ProcessDefinition> data = processDefinitionQuery.listPage(req.toFirstResult(), req.toLimitInteger());
        List<ResProcessDefinitionListDto> pageData = data.stream().map(e -> {
            ProcessDefinitionEntity entity = (ProcessDefinitionEntity) e;
            ResProcessDefinitionListDto res = new ResProcessDefinitionListDto();
            BeanUtils.copyProperties(entity, res);
            return res;
        }).collect(Collectors.toList());
        Page<ResProcessDefinitionListDto> page = new Page<>();
        page.setRecords(pageData);
        page.setTotal(count);
        return page;
    }

这里的req里就只有分页

@Data
public class ResProcessDefinitionListDto {
    @ApiModelProperty(value = "流程定义id")
    private String id;
    @ApiModelProperty(value = "流程定义key(bpmn定义的最外层id)")
    private String key;
    @ApiModelProperty(value = "版本")
    private int version;
    @ApiModelProperty(value = "类别")
    private String category;
    @ApiModelProperty(value = "部署id")
    private String deploymentId;
    @ApiModelProperty(value = "资源名称")
    private String name;
    @ApiModelProperty(value = "图资源名称")
    private String diagramResourceName;
    @ApiModelProperty(value = "暂停状态")
    private int suspensionState;
}

流程挂起或激活
可以理解为禁用,

 /**
     * 激活或挂起流程定义
     * @param req
     * */
    @Override
    public void processDefinitionSuspendOrActivate(ReqProcessSuspendOrActivateDto req) {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(req.getProcessDefinitionId()).singleResult();
        if (processDefinition != null) {
            if (req.getType().equals("1")) {
                //激活区
                repositoryService.activateProcessDefinitionById(req.getProcessDefinitionId());
            } else if (req.getType().equals("2")) {
                //挂起区
                repositoryService.suspendProcessDefinitionById(req.getProcessDefinitionId());
            }
        }
    }

流程实例
现在就要选着你要的一个流程进行申请了
(你要请假,ok 你就选着请假流程)

/**
     * 启动流程实例
     * @param req
     * */
    @Override
    public ResStartProcessInstanceDto startProcessInstance(ReqStartProcessInstanceDto req) {
        //启动流程实例
        RuntimeService runtimeService = pe.getRuntimeService();
        //根据流程设计key
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(req.getProcessDefinitionKey());

        //获取流程设计名称
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(processInstance.getProcessDefinitionId()).singleResult();

        //创建申请
        RuntimeProcess process = new RuntimeProcess();
        process.setBusinessKey(req.getBusinessKey());
        process.setExecutionId(processInstance.getProcessInstanceId());
        process.setActReProcdefId(processInstance.getProcessDefinitionId());
        process.setProcessName(processDefinition.getName());
        process.setProcessKey(req.getProcessDefinitionKey());
        process.setStartUserId(req.getApplyUser());
        process.setStartUserName(req.getApplyUserName());
        process.setCreateTime(LocalDateTime.now());
        process.setState("1");
        process.setFormComponent(req.getFormComponent());
        process.setTitle(req.getTitle());
        runtimeProcessService.save(process);

        ResStartProcessInstanceDto res = new ResStartProcessInstanceDto();
        BeanUtils.copyProperties(process, res);
        return res;
    }
@Data
public class ReqStartProcessInstanceDto {

    @ApiModelProperty(value = "标题", required = true)
    @NotBlank(message = "请输入标题")
    private String title;
    @ApiModelProperty(value = "流程定义id")
    @NotBlank(message = "流程定义id不能为空")
    private String processDefinitionId;
    @ApiModelProperty(value = "流程定义key")
    @NotBlank(message = "流程定义id不能为空")
    private String processDefinitionKey;
    @ApiModelProperty(value = "业务id")
    @NotBlank(message = "业务id不能为空")
    private String businessKey;
    @ApiModelProperty(value = "当前登录用户id(前端不用管)")
    private String applyUser;
    @ApiModelProperty(value = "当前登录用户名称(前端不用管)")
    private String applyUserName;
    @ApiModelProperty(value = "外置表单JSON字符串")
    private String formComponent;
}
@Data
public class ResStartProcessInstanceDto {
    @ApiModelProperty(value = "业务ID")
    private String businessKey;
    @ApiModelProperty(value = "流程实例id(act_ru_execution的id)")
    private String executionId;
    @ApiModelProperty(value = "流程定义id (act_re_procdef表的id)")
    private String actReProcdefId;
    @ApiModelProperty(value = "流程定义名称")
    private String processName;
    @ApiModelProperty(value = "流程key")
    private String processKey;
    @ApiModelProperty(value = "发起人姓名")
    private String startUserName;
    @ApiModelProperty(value = "发起时间")
    private LocalDateTime createTime;
    @ApiModelProperty(value = "(1:进行中,2:已结束)")
    private String state;

}

这里根据业务需要有个自己的申请列表(所有申请的数据都在这里)
我的设计是新增一张表申请表

表结构
请添加图片描述

选着流程设计的时候会在里面加一条申请数据,也就是自己的申请数据。我查了很多资料貌似activiti我的申请是要去历史表里面去查询的,我觉得太麻烦了直接新增表来记录
注意:流程设计和流程实例不是一个东西哦(我当时写的时候就被绕晕了)
我的申请列表
这里我就不贴代码了直接插自己新增的表
获取实例列表
公司里领导要看这个月哪些人请假了,会展示所有人的流程实例列表

 /**
     * 流程实例列表
     * @param req
     * */
    @Override
    public Page<ResProcessInstancelistsDto> processInstancelists(ReqProcessInstancelistsDto req) {
        Page<RuntimeProcess> page = runtimeProcessService.page(new Page<>(req.getPage(), req.getLimit()), new LambdaQueryWrapper<RuntimeProcess>()
                .like(StrUtil.isNotBlank(req.getProcessName()), RuntimeProcess::getProcessName, req.getProcessName())
                .like(StrUtil.isNotBlank(req.getStartUserName()), RuntimeProcess::getStartUserName, req.getStartUserName()));

        List<ResProcessInstancelistsDto> pageData = page.getRecords().stream().map(e -> {
            ResProcessInstancelistsDto res = new ResProcessInstancelistsDto();
            BeanUtils.copyProperties(e, res);
            return res;
        }).collect(Collectors.toList());

        Page<ResProcessInstancelistsDto> dtoPage = new Page<>();
        dtoPage.setTotal(dtoPage.getTotal());
        dtoPage.setRecords(pageData);
        return dtoPage;
    }

@Data
public class ReqProcessInstancelistsDto extends PageDto {
    @ApiModelProperty(value = "流程定义名称")
    private String processName;
    @ApiModelProperty(value = "发起人姓名")
    private String startUserName;
}


@Data
public class ResProcessInstancelistsDto {
    @ApiModelProperty(value = "操作id")
    private String runtimeProcessId;
    @ApiModelProperty(value = "业务ID")
    private String businessKey;
    @ApiModelProperty(value = "流程实例id(act_ru_execution的id)")
    private String executionId;
    @ApiModelProperty(value = "流程定义id (act_re_procdef表的id)")
    private String actReProcdefId;
    @ApiModelProperty(value = "流程定义名称")
    private String processName;
    @ApiModelProperty(value = "流程key")
    private String processKey;
    @ApiModelProperty(value = "发起人姓名")
    private String startUserName;
    @ApiModelProperty(value = "发起时间")
    private LocalDateTime createTime;
    @ApiModelProperty(value = "结束时间")
    private LocalDateTime endTime;
    @ApiModelProperty(value = "(1:进行中,2:已结束)")
    private String state;
}

业务核心

接下来就是整个业务的核心部分了
获取待办列表
老板要对你的请假进行审批,还记得流程图矩形填写老板的用户id吗,没错老板登录,请假流程的节点就会自己跑到老板的待办列表里面去(快给老子同意)

    @Override
    public Page<ResMyToDoListPo> myToDoList(ReqMyToDoListPo po) {

        Page<ResMyToDoListPo> pageDto = new Page<ResMyToDoListPo>();
        List<ResMyToDoListPo> resDto = new ArrayList<>();

        //获取任务列表
        TaskService taskService = pe.getTaskService();
        TaskQuery taskQuery = taskService.createTaskQuery();
//        HttpSession session = request.getSession();
        taskQuery.taskAssignee(po.getUserId());//用户的id
        //名称模糊查询
        taskQuery.processDefinitionNameLike("%"+po.getProcessName()+"%");
        //获取总条数
        long count = taskQuery.count();
        //分页查询待办任务列表
        List<Task> taskList = taskQuery.listPage(po.toPageInteger()-1, po.toLimitInteger());
        for (Task task : taskList){
            //通过流程实例id查询发起人
            RuntimeProcess runtimeProcess = this.getOne(
                    new LambdaQueryWrapper<RuntimeProcess>()
                    .eq(RuntimeProcess::getExecutionId, task.getExecutionId())
            );

            ResMyToDoListPo resMyToDoListPo = new ResMyToDoListPo();
            BeanUtil.copyProperties(runtimeProcess, resMyToDoListPo);

            resMyToDoListPo.setExecutionId(task.getExecutionId());
            resMyToDoListPo.setBusinessKey(task.getTaskDefinitionKey());
            resMyToDoListPo.setTaskId(task.getId());
            resMyToDoListPo.setCurrentNodeName(task.getName());
            resDto.add(resMyToDoListPo);
        }
        pageDto.setRecords(resDto);
        pageDto.setTotal(count);
        return pageDto;
    }
@Data
public class ReqMyToDoListPo extends PageDto {
    @ApiModelProperty(value = "当前登录用户id")
    @NotBlank(message = "用户id不能为空")
    private String userId;
    @ApiModelProperty(value = "流程名称")
    private String processName;
    @ApiModelProperty(value = "发起人集合")
    private List<String> originators;
}

@Data
public class ResMyToDoListPo {
    @ApiModelProperty(value = "任务id")
    private String taskId;
    @ApiModelProperty(value = "业务ID")
    private String businessKey;
    @ApiModelProperty(value = "流程实例id(act_ru_execution的id)")
    private String executionId;
    @ApiModelProperty(value = "流程定义id (act_re_procdef表的id)")
    private String actReProcdefId;
    @ApiModelProperty(value = "标题")
    private String title;
    @ApiModelProperty(value = "流程名称")
    private String processName;
    @ApiModelProperty(value = "当前节点名称")
    private String currentNodeName;
    @ApiModelProperty(value = "发起人姓名")
    private String startUserName;;
    @ApiModelProperty(value = "发起时间")
    private LocalDateTime createTime;
    @ApiModelProperty(value = "完成时间")
    private LocalDateTime endTime;
    @ApiModelProperty(value = "当前状态(1:进行中,2:已结束)")
    private String state;
}

这里我是和我的申请表拼接了一些数据的
然后拿到老板需要干的事情
emm 目前条件查询只有流程名称可以进行查询其他的还没写

通过审批
老板说这个人工作认真,允许他装病请假,批了

 /**
     * 完成节点
     * @param taskId 任务id
     * @param flag 默认turn
     * @param applyUser 完成人
     * @param message 意见
     */
    @Override
    public void completeUserTaskNode(String taskId, boolean flag, String applyUser, String message) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            throw new MyException("任务不存在");
        }
        if (task.isSuspended()) {
            throw new MyException("流程已被挂起,操作失败");
        }
        String flagName = "flag";
        //需要添加此句否则审批意见表中ACT_HI_COMMENT,审批人的userId是空的
        Authentication.setAuthenticatedUserId(applyUser);
        //审核状态变量
        Map<String, Object> map = new HashMap<>();
        map.put(flagName, flag);
        //将当前任务受理人
//        taskService.setAssignee(taskId, applyUser);
//        List<Comment> comments = taskService.getTaskComments(taskId);
//        if (comments.size() != 0){
//            taskService.deleteComment(taskId);
//        }
        taskService.addComment(taskId, task.getProcessInstanceId(), "0" + message);
        taskService.complete(taskId, map);//完成任务
        Execution execution = runtimeService.createExecutionQuery().executionId(task.getExecutionId()).singleResult();
        //任务已结束
        if (execution == null) {
        	//老板审批过了我的申请是不是就结束啦,该状态
            RuntimeProcess runtimeProcess = runtimeProcessService.getOne(new LambdaQueryWrapper<RuntimeProcess>().eq(RuntimeProcess::getExecutionId, task.getExecutionId()), false);
            runtimeProcess.setState("2");
            runtimeProcess.setEndTime(LocalDateTime.now());
            runtimeProcessService.updateById(runtimeProcess);
        }
    }

这里也是结合了我的申请,

拒绝审批
老板说这么多人都装病请假,妈的还干不干,全部拒绝

/**
     * 拒绝
     * @param req
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refuse(ReqRefuseDto req) {
        //任务id
        String taskId = req.getTaskId();
        //驳回意见
        String opinion = req.getOpinion();


        //获取任务
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        ActivityImpl endActivity = findActivitiImpl(taskId, "end");
        if (endActivity == null) {
            throw new MyException("当前节点不存在");
        }
        //我的申请状态变为 拒绝
        RuntimeProcess runtimeProcess = runtimeProcessService.getOne(
                new LambdaQueryWrapper<RuntimeProcess>()
                        .eq(RuntimeProcess::getExecutionId, task.getExecutionId())
        );
        //拒绝状态
        runtimeProcess.setPassState("2");
        runtimeProcess.setReason(req.getOpinion() + "");
        runtimeProcess.setEndTime(LocalDateTime.now());
        runtimeProcess.setState("2");
        runtimeProcessService.updateById(runtimeProcess);

        // 获取当前活动节点ID
        //String activityId = task.getTaskDefinitionKey();

        Map<String, Object> variables = new HashMap<String, Object>();
        if (!StringUtils.isEmpty(opinion)) {  //审核意见
            variables.put("驳回意见", opinion);
        }
        // 跳转节点为空,默认提交操作
        if (StringUtils.isEmpty(endActivity.getId())) {

            if (!StringUtils.isEmpty(task.getOwner())) {
                // 被委派人处理完成任务
                taskService.resolveTask(task.getId(), variables);
            }
            taskService.complete(taskId, variables);
        } else {// 流程转向操作
            //turnTransition(taskId, activityId, variables);
            // 当前节点
            ActivityImpl currActivity = findActivitiImpl(taskId, null);

            // 清空当前流向
            // 存储当前节点所有流向临时变量
            List<PvmTransition> oriPvmTransitionList = new ArrayList<PvmTransition>();
            // 获取当前节点所有流向,存储到临时变量,然后清空
            List<PvmTransition> pvmTransitionList = currActivity
                    .getOutgoingTransitions();
            for (PvmTransition pvmTransition : pvmTransitionList) {
                oriPvmTransitionList.add(pvmTransition);
            }
            pvmTransitionList.clear();

            // 创建新流向
            TransitionImpl newTransition = currActivity.createOutgoingTransition();
            // 目标节点
            ActivityImpl pointActivity = findActivitiImpl(taskId, endActivity.getId());
            // 设置新流向的目标节点
            newTransition.setDestination(pointActivity);

            if (!StringUtils.isEmpty(task.getOwner())) {
                // 被委派人处理完成任务
                taskService.resolveTask(task.getId(), variables);
            }
            // 执行转向任务
            taskService.complete(taskId, variables);
            // 删除目标节点新流入
            pointActivity.getIncomingTransitions().remove(newTransition);

            // 还原以前流向
            //restoreTransition(currActivity, oriPvmTransitionList);
            // 清空现有流向
            List<PvmTransition> pvmTransitionListC = currActivity.getOutgoingTransitions();
            pvmTransitionListC.clear();
            // 还原以前流向
            for (PvmTransition pvmTransition : oriPvmTransitionList) {
                pvmTransitionListC.add(pvmTransition);
            }
        }
    }

@Data
public class ReqRefuseDto {

    @ApiModelProperty(value = "任务id", required = true)
    @NotNull(message = "请选者任务")
    private String taskId;

    @ApiModelProperty(value = "原因", required = true)
    @NotNull(message = "请填写原因")
    private String opinion;

    @ApiModelProperty(value = "当前用户id(前端不用传)")
    private String userId;
}

ok ,整个流程也就完了
but ,假如公司老板要求经理也要给我审批(这么多人我一个老板怎么搞的过来)
所以结合上面的流程图我们同样在第一个矩形图前面增加一个矩形图:经理审批;在增加一个矩形图组长审批

驳回至上一级
现在组长觉得你可以请假,但是经理看到不让你请直接把你的请假退回到组长哪里

/**
     * 退回任务到上一级
     * @param req
     * */
    @Override
    public void returnNode(ReqTaskIdDto req){
        String taskId = req.getTaskId();
        String executionId = req.getExecutionId();
        String message = req.getMessage();

        Authentication.setAuthenticatedUserId(req.getUserId());
        taskService.addComment(taskId, executionId,"3" + message);
        try {
            Map<String, Object> variables;
            // 取得当前任务
            HistoricTaskInstance currTask = historyService
                    .createHistoricTaskInstanceQuery().taskId(taskId)
                    .singleResult();
            // 取得流程实例
            ProcessInstance instance = runtimeService
                    .createProcessInstanceQuery()
                    .processInstanceId(currTask.getProcessInstanceId())
                    .singleResult();
            if (instance == null) {

                //流程结束
                throw new MyException("流程结束");
            }
            variables = instance.getProcessVariables();
            // 取得流程定义
            ProcessDefinitionEntity definition = (ProcessDefinitionEntity) (pe.getRepositoryService().getProcessDefinition(currTask
                    .getProcessDefinitionId()));

            if (definition == null) {

                //log.error("流程定义未找到");
                throw new MyException("流程定义未找到");
            }
            // 取得上一步活动
            ActivityImpl currActivity = ((ProcessDefinitionImpl) definition)
                    .findActivity(currTask.getTaskDefinitionKey());
            List<PvmTransition> nextTransitionList = currActivity
                    .getIncomingTransitions();
            // 清除当前活动的出口
            List<PvmTransition> oriPvmTransitionList = new ArrayList<PvmTransition>();
            List<PvmTransition> pvmTransitionList = currActivity
                    .getOutgoingTransitions();
            for (PvmTransition pvmTransition : pvmTransitionList) {
                oriPvmTransitionList.add(pvmTransition);
            }
            pvmTransitionList.clear();

            // 建立新出口
            List<TransitionImpl> newTransitions = new ArrayList<TransitionImpl>();
            for (PvmTransition nextTransition : nextTransitionList) {
                PvmActivity nextActivity = nextTransition.getSource();
                ActivityImpl nextActivityImpl = ((ProcessDefinitionImpl) definition)
                        .findActivity(nextActivity.getId());
                TransitionImpl newTransition = currActivity
                        .createOutgoingTransition();
                newTransition.setDestination(nextActivityImpl);
                newTransitions.add(newTransition);
            }
            // 完成任务
            List<Task> tasks = taskService.createTaskQuery()
                    .processInstanceId(instance.getId())
                    .taskDefinitionKey(currTask.getTaskDefinitionKey()).list();
            for (Task task : tasks) {
                taskService.complete(task.getId(), variables);
//                historyService.deleteHistoricTaskInstance(task.getId());
            }
            // 恢复方向
            for (TransitionImpl transitionImpl : newTransitions) {
                currActivity.getOutgoingTransitions().remove(transitionImpl);
            }
            for (PvmTransition pvmTransition : oriPvmTransitionList) {
                pvmTransitionList.add(pvmTransition);
            }
        } catch (Exception e) {
            throw new MyException("退回失败,请重试");
        }
    }

@Data
public class ReqTaskIdDto{
    @ApiModelProperty(value = "taskID", required = true)
    @NotEmpty(message = "任务id不能为空")
    private String taskId;

    @ApiModelProperty(value = "流程实例id", required = true)
    @NotNull(message = "实例id不能为空")
    private String executionId;

    @ApiModelProperty(value = "原因", required = true)
    @NotNull(message = "请输入原因")
    private String message;

    @ApiModelProperty(value = "操作人(前端不用管)")
    private String userId;
}

拒绝审批
然后是不是组长该考虑一下是不是不让这小子过

 /**
     * 拒绝
     * @param req
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refuse(ReqRefuseDto req) {
        //任务id
        String taskId = req.getTaskId();
        //驳回意见
        String opinion = req.getOpinion();


        //获取任务
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        ActivityImpl endActivity = findActivitiImpl(taskId, "end");
        if (endActivity == null) {
            throw new MyException("当前节点不存在");
        }
        //我的申请状态变为 拒绝
        RuntimeProcess runtimeProcess = runtimeProcessService.getOne(
                new LambdaQueryWrapper<RuntimeProcess>()
                        .eq(RuntimeProcess::getExecutionId, task.getExecutionId())
        );
        //拒绝状态
        //我的申请的状态
        runtimeProcess.setPassState("2");
        runtimeProcess.setReason(req.getOpinion() + "");
        runtimeProcess.setEndTime(LocalDateTime.now());
        runtimeProcess.setState("2");
        runtimeProcessService.updateById(runtimeProcess);

        // 获取当前活动节点ID
        //String activityId = task.getTaskDefinitionKey();

        Map<String, Object> variables = new HashMap<String, Object>();
        if (!StringUtils.isEmpty(opinion)) {  //审核意见
            variables.put("驳回意见", opinion);
        }
        // 跳转节点为空,默认提交操作
        if (StringUtils.isEmpty(endActivity.getId())) {

            if (!StringUtils.isEmpty(task.getOwner())) {
                // 被委派人处理完成任务
                taskService.resolveTask(task.getId(), variables);
            }
            taskService.complete(taskId, variables);
        } else {// 流程转向操作
            //turnTransition(taskId, activityId, variables);
            // 当前节点
            ActivityImpl currActivity = findActivitiImpl(taskId, null);

            // 清空当前流向
            // 存储当前节点所有流向临时变量
            List<PvmTransition> oriPvmTransitionList = new ArrayList<PvmTransition>();
            // 获取当前节点所有流向,存储到临时变量,然后清空
            List<PvmTransition> pvmTransitionList = currActivity
                    .getOutgoingTransitions();
            for (PvmTransition pvmTransition : pvmTransitionList) {
                oriPvmTransitionList.add(pvmTransition);
            }
            pvmTransitionList.clear();

            // 创建新流向
            TransitionImpl newTransition = currActivity.createOutgoingTransition();
            // 目标节点
            ActivityImpl pointActivity = findActivitiImpl(taskId, endActivity.getId());
            // 设置新流向的目标节点
            newTransition.setDestination(pointActivity);

            if (!StringUtils.isEmpty(task.getOwner())) {
                // 被委派人处理完成任务
                taskService.resolveTask(task.getId(), variables);
            }
            // 执行转向任务
            taskService.complete(taskId, variables);
            // 删除目标节点新流入
            pointActivity.getIncomingTransitions().remove(newTransition);

            // 还原以前流向
            //restoreTransition(currActivity, oriPvmTransitionList);
            // 清空现有流向
            List<PvmTransition> pvmTransitionListC = currActivity.getOutgoingTransitions();
            pvmTransitionListC.clear();
            // 还原以前流向
            for (PvmTransition pvmTransition : oriPvmTransitionList) {
                pvmTransitionListC.add(pvmTransition);
            }
        }
    }

@Data
public class ReqRefuseDto {

    @ApiModelProperty(value = "任务id", required = true)
    @NotNull(message = "请选者任务")
    private String taskId;

    @ApiModelProperty(value = "原因", required = true)
    @NotNull(message = "请填写原因")
    private String opinion;

    @ApiModelProperty(value = "当前用户id(前端不用传)")
    private String userId;
}

驳回至起点

/**
     * 驳回到最初节点
     * @param req
     */
    @Override
    public void rejectToTop(@RequestBody @Valid ReqTaskIdDto req) {
        String taskId = req.getTaskId();
        String executionId = req.getExecutionId();
        String message = req.getMessage();
        Authentication.setAuthenticatedUserId(req.getUserId());
        taskService.addComment(taskId, executionId,"2" + message);

        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        TaskService taskService = processEngine.getTaskService();
        HistoryService historyService = processEngine.getHistoryService();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Map variables = new HashMap<>();
        //获取当前任务
        List<HistoricTaskInstance> currTasks = historyService.createHistoricTaskInstanceQuery()
                .taskId(taskId).list();
        if (currTasks.size() == 0) {
            throw new MyException("当前任务不存在");
        }
        HistoricTaskInstance currTask = currTasks.get(currTasks.size() - 1);

        //获取流程实例
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(currTask.getProcessInstanceId())
                .singleResult();
        //获取流程定义
        ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
                .getDeployedProcessDefinition(currTask.getProcessDefinitionId());
        if (processDefinitionEntity == null) {
            throw new MyException("不存在的流程定义");

        }
        //获取当前activity
        ActivityImpl currActivity = ((ProcessDefinitionImpl) processDefinitionEntity)
                .findActivity(currTask.getTaskDefinitionKey());

        //获取当前任务流入
        List<PvmTransition> histTransitionList = currActivity
                .getIncomingTransitions();
        //清除当前活动出口
        List<PvmTransition> originPvmTransitionList = new ArrayList<PvmTransition>();
        List<PvmTransition> pvmTransitionList = currActivity.getOutgoingTransitions();
        for (PvmTransition pvmTransition : pvmTransitionList) {
            originPvmTransitionList.add(pvmTransition);
        }
        pvmTransitionList.clear();

        //查找上一个user task节点
        List<HistoricActivityInstance> historicActivityInstances = historyService
                .createHistoricActivityInstanceQuery().activityType("userTask")
                .processInstanceId(processInstance.getId())
                .finished()
                .orderByHistoricActivityInstanceEndTime().asc().list();
        TransitionImpl transitionImpl = null;
        if (historicActivityInstances.size() > 0) {
            ActivityImpl lastActivity = ((ProcessDefinitionImpl) processDefinitionEntity)
                    .findActivity(historicActivityInstances.get(0).getActivityId());
            //创建当前任务的新出口
            transitionImpl = currActivity.createOutgoingTransition(lastActivity.getId());
            transitionImpl.setDestination(lastActivity);
        } else {
            throw new MyException("上级节点不存在");
        }
        variables = processInstance.getProcessVariables();
        // 完成任务
        List<Task> tasks = taskService.createTaskQuery()
                .processInstanceId(processInstance.getId())
                .taskDefinitionKey(currTask.getTaskDefinitionKey()).list();
        for (Task task : tasks) {
            taskService.complete(task.getId(), variables);
//            historyService.deleteHistoricTaskInstance(task.getId());
        }

        // 恢复方向
        currActivity.getOutgoingTransitions().remove(transitionImpl);

        for (PvmTransition pvmTransition : originPvmTransitionList) {
            pvmTransitionList.add(pvmTransition);
        }

    }

查看流程图
然后你要看你的申请到了哪里了

消费端

@ApiOperation(value = "获取流程图", notes = "魏科远")
    @GetMapping(value = "queryFlowChart")
    public void queryFlowChart(@RequestParam("id") String id, HttpServletResponse response) throws IOException {
        String base64string = activitiClient.queryFlowChart(id);
        ByteArrayInputStream stream = null;
        try {
            BASE64Decoder decoder = new BASE64Decoder();
            byte[] bytes1 = decoder.decodeBuffer(base64string);
            stream = new ByteArrayInputStream(bytes1);
        } catch (Exception e) {
            e.printStackTrace();
        }
        byte[] b = new byte[1024];
        int len;
        while ((len = stream.read(b, 0, 1024)) != -1) {
            response.getOutputStream().write(b, 0, len);
        }
    }

服务业务代码

/**
     * <p>
     * 查看实例流程图
     * </p>
     *
     * @Param 根据根据act_ru_execution表的ID_去触发
     */
    @Override
    public String queryFlowChart(String id) throws IOException {
        String processInstanceId = id;
        //获取历史流程实例
        HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
        processEngineConfiguration = pe.getProcessEngineConfiguration();
        Context.setProcessEngineConfiguration((ProcessEngineConfigurationImpl) processEngineConfiguration);

        ProcessDiagramGenerator diagramGenerator = processEngineConfiguration.getProcessDiagramGenerator();
        ProcessDefinitionEntity definitionEntity = (ProcessDefinitionEntity) repositoryService.getProcessDefinition(processInstance.getProcessDefinitionId());

        List<HistoricActivityInstance> highLightedActivitList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list();
        //高亮环节id集合
        List<String> highLightedActivitis = new ArrayList<String>();

        //高亮线路id集合
        List<String> highLightedFlows = getHighLightedFlows(definitionEntity, highLightedActivitList);

        for (HistoricActivityInstance tempActivity : highLightedActivitList) {
            String activityId = tempActivity.getActivityId();
            highLightedActivitis.add(activityId);
        }

        //中文显示的是口口口,设置字体就好了
        InputStream imageStream = diagramGenerator.generateDiagram(bpmnModel, "png", highLightedActivitis, highLightedFlows, "宋体", "宋体", "", null, 1.0);

        byte[] bytes = IOUtils.toByteArray(imageStream);

        String encoded = Base64.getEncoder().encodeToString(bytes);
        return encoded;
    }

请添加图片描述
这就是你的流程走到哪里了

查看流程进度
领导肯定要看你的申请走到哪里了吧


    /**
     * 流程进度
     * @param req
     * */
    @Override
    public List<ResProcessNodePo> processProgress(ReqProcessProgressDto req) {
        List<ResProcessNodePo> resDto = new ArrayList<>();
        ZoneId zoneId = ZoneId.systemDefault();
        String processInstanceId = req.getProcessInstanceId();
        //使用流程实例ID,查询历史任务,获取历史任务对应的每个任务ID
        List<HistoricActivityInstance>  list = pe.getHistoryService() // 历史相关Service
                .createHistoricActivityInstanceQuery() // 创建历史活动实例查询
                .processInstanceId(req.getProcessInstanceId()) // 执行流程实例id
                .finished()
                .list();
        //遍历集合,获取每个任务ID
        if (list != null && list.size() > 0) {
            int size = list.size();
            for (int i = 0; i< size ;i++){
                ResProcessNodePo resProcessNodePo = new ResProcessNodePo();
                String type = "2";
                if (i == 0){
                    type = "1";
                }
                resProcessNodePo.setType(type);
                HistoricActivityInstance hti = list.get(i);
                //任务ID
                String htaskId = hti.getTaskId();
                //获取批注信息
                List<Comment> taskList = taskService.getTaskComments(htaskId);//对用历史完成后的任务ID
                Comment comment = new CommentEntity();
                if (taskList.size() > 0){
                    comment = taskList.get(0);
                }
                resProcessNodePo.setProcessInstanceId(processInstanceId);

                if (hti.getStartTime() != null){
                    LocalDateTime startTime = hti.getStartTime().toInstant().atZone(zoneId).toLocalDateTime();
                    resProcessNodePo.setStarttime(startTime);
                }

//                resProcessNodePo.setSignNode(isSignNode(htaskId));
                resProcessNodePo.setAssignee(hti.getAssignee());

                if (hti.getEndTime() != null){
                    LocalDateTime endTime = hti.getEndTime().toInstant().atZone(zoneId).toLocalDateTime();
                    resProcessNodePo.setEndTime(endTime);
                }

                if (hti.getDurationInMillis() != null){
                    //耗时
                    resProcessNodePo.setTimeConsuming(hti.getDurationInMillis());
                }
                if (comment != null){
                    if (comment.getFullMessage() != null){
                        resProcessNodePo.setOpinions(comment.getFullMessage().substring(1));
                    }
                }
                if (resProcessNodePo.getType().equals("2")){
                    resProcessNodePo.setStatus(comment == null ? null :
                            (comment.getFullMessage() == null ? null : comment.getFullMessage().substring(0, 1)));
                }
                resDto.add(resProcessNodePo);
            }
        }
        return resDto;
    }

这个进度我写的很垃圾 你们可以去看看其他大佬的文章

最后
然后流程走完了,你也请假成功。

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值