Activiti7工作流引擎:通用审批模版

关于审批方法,工作中不同的人有不同的写法,下面推荐一种我觉得算是比较优雅的一种写法,可以将业务逻辑和审批逻辑进行解耦,代码看起来也比较清爽。

一:请求参数

@Getter
@Setter
@ToString
@NoArgsConstructor
@Builder
public class ApprovalReq {
    /** 业务数据主键 */
    private String id;

    /** 流程实例id */
    private String processInstanceId;

    /** 任务id */
    private String taskId;

    /** 审批结果 ApprovalResultEnum */
    private String voteResult;

    /** 下一节点key */
    private String nextNode;

    /** 下一处理人列表 */
    private List<String> assigneeList;

    /** 审批意见 */
    private String suggestion;
}

二:审批结果枚举

public enum ApprovalResultEnum {

    BACK("0", "退回"),
    AGREE("1", "同意")
    ;

    private String code;
    private String name;

    ApprovalResultEnum(String code, String name) {
        this.code = code;
        this.name = name;
    }
}

三:通用审批模版方法

这里是一种简单的实现,可以根据自己的业务做一些适当调整和增强。
这里主要就是利用模版设计模式将审批逻辑确定下来,将不确定的业务逻辑分离出来。

@Slf4j
@Service
public class CommonApprovalService {
    @Autowired
    protected TaskService taskService;

    @Autowired
    protected HistoryService historyService;

    /**
     * 通用操作:无论审批结果是什么都会调用改方法(如业务检查,状态更新等操作)
     */
    public void common(UserEntity user, ApprovalReq neq) {
    }

    /**
     * 审批结果为“退回”时会调用该方法
     */
    public void back(UserEntity user, ApprovalReq req) {
    }

    /**
     * 审批结果为“同意”时会调用该方法
     */
    public void agree(UserEntity user, ApprovalReq req) {
    }

    /**
     * 流程审批结束后会调用该方法
     */
    public void finished(UserEntity user, ApprovalReq req) {
    }

    /**
     * 审批完成后发送邮件
     */
    public void sendEmail(UserEntity user, ApprovalReq req) {
    }

    /**
     * 模版审批方法
     * @param user 当前登录的用户
     * @param req 审批参数
     */
    @Transactional(rollbackFor = Exception.class)
    public void approval(UserEntity user, ApprovalReq req)  {
        Assert.isTrue(user != null && req != null, "参数校验失败");
        log.info("AbstractApprovalServiceImpl#approval user={},req={}", user, req);

        // 工作流常规检查
        Task task = taskService.createTaskQuery().processInstanceId(req.getProcessInstanceId()).list().get(0);
        this.checkProcessInstance(user, req.getProcessInstanceId(), req.getTaskId());
        log.info("checkProcessInstance success");

        //添加审批意见
        this.addcomment(req.getProcessInstanceId(), task.getId(), user.getUserId(), req.getVoteResult(), req.getSuggestion());
        log.info("addComment success");

        // 公共操作
        this.common(user, req);
        log.info("common success");

        if (Objects.equals(ApprovalResultEnum.BACK.getCode(), req.getVoteResult())) {
            // 退回操作
            log.info("back task: taskId={} taskDefKey={}", task.getId(), req.getNextNode());
            // TODO 通过自定义命令实现
            // actTaskManager.jumpTask(task.getId(), req.getNextNode());
            Task nextTask = taskService.createTaskQuery().processInstanceId(req.getProcessInstanceId()).list().get(0);
            taskService.setAssignee(nextTask.getId(), req.getAssigneeList().stream().collect(Collectors.joining(",")));
            this.back(user, req);
            log.info("back success user={}, req={}", user, req);
        } else if (Objects.equals(ApprovalResultEnum.AGREE.getCode(), req.getVoteResult())) {
            // 同意操作
            log.info("agree task: taskId={} taskDefKey={}", task.getId(), req.getNextNode());
            taskService.complete(task.getId());
            log.info("completeUserTask success");
            if (!CollectionUtils.isEmpty(req.getAssigneeList())) {
                //设置下一任务负责人
                Task nextTask = taskService.createTaskQuery().processInstanceId(req.getProcessInstanceId()).list().get(0);
                taskService.setAssignee(nextTask.getId(), req.getAssigneeList().stream().collect(Collectors.joining(",")));
            }
            this.agree(user, req);
            log.info("agree success user={}, req={}", user, req);
        }

        // 发送邮件(无论审批结果是什么都会发送邮件)
        this.sendEmail(user, req);

        // 审批结束操作
        if (isFinished(req.getProcessInstanceId())) {
            // 更新工作流完成时间
            log.info("处理其他公共逻辑,如记录审批完成的时间等");
            this.finished(user, req);
        }

        log.info("approval success user={}, req={}", user, req);
    }

    public boolean isFinished(String processInstanceId) {
        // act_hi_procinst.END_TIME_
        List<HistoricProcessInstance> hiProcInstList = historyService
                .createHistoricProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .list();
        if (CollectionUtils.isEmpty(hiProcInstList)) {
            return false;
        }

        if (hiProcInstList.get(0).getEndTime() != null) {
            return true;
        }

        return false;
    }

    public void addcomment(String processInstanceId, String taskId, String userId, String voteResult, String suggestion) {
        Map<String, Object> commentMap = new HashMap<>();
        commentMap.put("userId", userId);
        commentMap.put("voteResult", voteResult);
        commentMap.put("suggestion", suggestion);
        String commentJSON = new JSONObject(commentMap).toJSONString();

        taskService.addComment(taskId, processInstanceId, commentJSON);
        log.info("addTaskComment success, processInstanceId={}, voteResult={}", processInstanceId, commentJSON);
    }

    public void checkProcessInstance(UserEntity user, String processInstanceId, String taskId) {
        // 1.判断工作流是否完成
        Assert.isTrue(this.isFinished(processInstanceId), "该流程已结束,请刷新重试!");

        // 2. 检查当前节点是否已经审批过
        Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).list().get(0);
        Assert.isTrue(Objects.equals(task.getId(), taskId), "当前审批节点已完成 !");

        // 3. 检查当前登录用户是否为审批人
        boolean isAssignee = false;
        List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
        for (Task item : taskList) {
            String assignee = item.getAssignee();
            if (!ObjectUtils.isEmpty(assignee)) {
                List<String> assigneeList = Arrays.asList(assignee.split(","));
                if (assigneeList.contains(user.getUserId())) {
                    isAssignee = true;
                    break;
                }
            }
        }
        Assert.isTrue(isAssignee, "当前用户没有权限审批!");
    }
}

四:使用方法

自己的业务审批Service类来继承CommonApprovalService,在自己的业务类中只需要实现预留的方法即可。这样多个类型的审批对应多个Service,每个不同的Service不用具体关注审批相关的代码,只需要关注和审批相关的业务方法即可。这样业务代码和工作流代码解耦了。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

风流 少年

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

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

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

打赏作者

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

抵扣说明:

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

余额充值