Spring Boot集成Activity7实现简单的审批流

由于客户对于系统里的一些新增数据,例如照片墙、照片等,想实现上级逐级审批通过才可见的效果,于是引入了Acitivity7工作流技术来实现,本文是对实现过程的介绍讲解,由于我是中途交接前同事的这块需求,所以具体实现方式和代码编写我暂时先按前同事的思路简单介绍,不代表我个人看法。
参考文章:

springboot+Activiti7整合实践 (一)_vue2集成activit7-CSDN博客

org.springframework.security.core.userdetails.UsernameNotFoundException,三步解决Activiti7和Security冲突问题_cause: org.springframework.security.core.userdetai-CSDN博客

Activiti7笔记(二)Activiti7一共涉及到25张表,哪些操作会涉及哪些表,每张表的作用是什么_activiti7数据表详细解读-CSDN博客

Activiti7笔记(一)Activiti7是什么,入门流程操作的代码实现-腾讯云开发者社区-腾讯云 (tencent.com)

文章目录

一、引入依赖

xml 复制代码
        <!--activity7工作流-->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring-boot-starter</artifactId>
            <version>${activity.starter.version}</version>
            <exclusions>
                <exclusion>
                    <!-- 项目引入了mybatis-plus,则需要排除 -->
                    <groupId>org.mybatis</groupId>
                    <artifactId>mybatis</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.activiti.dependencies</groupId>
            <artifactId>activiti-dependencies</artifactId>
            <version>${activity.starter.version}</version>
            <type>pom</type>
        </dependency>

        <!-- 生成流程图 -->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-image-generator</artifactId>
            <version>${activity.starter.version}</version>
        </dependency>

二、修改配置文件

yml 复制代码
  spring:
      #activity工作流配置
      activiti:
        # 自动部署验证设置:true-开启(默认)、false-关闭
        check-process-definitions: false
        # 保存历史数据
        history-level: full
        # 检测历史表是否存在
        db-history-used: true
        # 关闭自动部署
        deployment-mode: never-fail
        # 对数据库中所有表进行更新操作,如果表不存在,则自动创建
        # create_drop:启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)
        # drop-create:启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)
        database-schema-update: true
        # 解决频繁查询SQL问题
        async-executor-activate: false

db-history-userdhistory-level,建议按图中配置,方便查询工作流历史记录

三、解决Activity7和Security框架冲突

场景:由于Activity升级到7版本后,引入了Security来用于权限校验,但是本项目自身已经引入了Security框架,于是发生了冲突

【如果项目用的不是security框架,例如用的shiro,需要在启动项排除,参考:springboot+Activiti7整合实践 (一)_vue2集成activit7-CSDN博客

本项目

网上其他做法(用的activity原生的api):

从Activiti工作流中检索所有用户任务_在activiti 7中获取流程实例的所有任务_如何在Activiti工作流中的单独实例中强制顺序执行任务 - 腾讯云开发者社区 - 腾讯云 (tencent.com)

四、启动项目,生成activity的数据库表

引入依赖、配置好后,第一次启动会在数据库生成相关的表

具体介绍:Activiti7笔记(二)Activiti7一共涉及到25张表,哪些操作会涉及哪些表,每张表的作用是什么_activiti7数据表详细解读-CSDN博客

本项目主要用到的表:

  • 流程部署表 :[ACT_RE_PROCDEF]

    每对一个流程图部署后,会记录在该表里(部署过程下面会讲到)

  • 历史流程实例表:[ACT_HI_PROCINST]

    流程一次从头到尾执行,对应一个流程实例,流程结束时会保留下来

  • 运行时流程执行对象表 :[ACT_RU_EXECUTION]

    流程实例与执行对象的关系:‌一个流程实例在执行过程中,‌如果流程包含分支或聚合,‌那么执行对象的数量可以多个【至少有2条数据,其中第1条是对应历史流程实例表】。‌这是因为流程实例在运行过程中可能会产生多个并行的执行路径,‌每个路径上的任务或活动都可以视为一个执行对象。‌例如,‌在一个具有多个分支的审批流程中,‌不同的审批人可能会同时处理不同的分支任务,‌这些分支任务就代表了多个执行对象

    Activiti工作流学习(二)流程实例、执行对象、任务 - 百度文库 (baidu.com)

    这个表里面主要记录的是当前已经执行到哪个节点了,把对应的节点对象记录到这个里面

    流程结束后,这张表对应的数据会清除

  • 运行时节点人员数据信息表 :[ACT_RU_IDENTITYLINK]

    运行时用户关系信息,存储任务节点与参与者的相关信息

    也就是只要当前任务有参与者,就会将参与者的信息保存到这个表,多个人参与,保存多个信息

  • **运行时任务节点表:[ACT_RU_TASK] **

    一个流程有多个节点,到某一个节点的时候,都会更新这个表,将当前节点的数据更新到这个表

审批流过程

  1. 部署流程 ,到ACT_RE_PROCDEF表看有没有新增一条对应的数据
  2. 启动流程实例,执行流程对象(可能多个) ,到ACT_HI_PROCINSTACT_RU_EXECUTION表看有没有新增对应数据
  3. 完成整个流程 ,过程主要看ACT_RU_TASKACT_RU_IDENTITYLINK表的更新情况

五、画流程图

  • IDEA安装插件:

  • 在resource下创建一个目录process存放流程图文件

  • 右键,新建流程图文件

  • 具体画图过程省略,这里介绍画完之后的流程图的重点信息

    2个审批节点的流程图为例(增加、减少节点都需要另外画图部署)

    1. 定义流程的id和名字(后续代码可以取到)

    2. 开始节点

    3. 审批节点

      第1个审批节点:

      第2个审批节点,同上

    4. 结束节点

    5. 二级节点之后的网关

      这里二级审批完之后,会出现2种不同的可能走向(审批通过,继续到一级审批节点;审批不通过,直接结束),所以需要加上一个网关

      【由于时间较赶等原因,本项目不做回退的实现,所以审核不通过都是直接走向结束节点(一级审批节点通过或不通过都是走向结束节点)】

    6. 节点之间或节点与网关之间的连接线

      重点注意:网关后的线

      定义一个条件变量,当SecondJudge=true时(代码赋值),即审核通过,会走向 一级审核 节点,否则走向结束节点,如下图所示

      【当二级组织发起审核,但是选择最终审批组织也是二级的时候,审核通过会赋值SecondJudge=false,直接走结束节点】

六、部署流程

本项目采用的是通过接口,手动部署的方式【每新建或修改流程图都要调用一次接口来部署(后续打算优化成自动部署或者定时任务调用接口部署)】

java 复制代码
    @ApiOperation("手动部署照片审核")
    @GetMapping("/photo/process/{typeLevel}")
    public String auditingPhotoProcessByTypeLevel(@PathVariable("typeLevel") Integer typeLevel, @RequestParam("force") Boolean force) {
        return auditingPhotoService.auditingPhotoProcessByTypeLevel(typeLevel,force);
    }
java 复制代码
    /**
     * 手动部署
     * @param typeLevel 组织等级
     * @param force 是否强制部署(当修改了流程图的时候需要传true)
     * @return 部署结果
     */
    public String auditingPhotoProcessByTypeLevel(Integer typeLevel, Boolean force);
java 复制代码
    @Override
    public String auditingPhotoProcessByTypeLevel(Integer typeLevel, Boolean force) {
        switch (typeLevel) {
            case 6:
                auditingPhotoSixService.process(force);
                break;
            case 5:
                auditingPhotoFiveService.process(force);
                break;
            case 4:
                auditingPhotoFourService.process(force);
                break;
            case 3:
                auditingPhotoThreeService.process(force);
                break;
            case 2:
                auditingPhotoTwoService.process(force);
                break;
            case 1:
                auditingPhotoOneService.process(force);
                break;
            default:
                throw new ServicesException(ResultStatus.ARGS_VALID_ERROR);
        }
        return typeLevel + "级照片流程部署成功";
    }
java 复制代码
    /**
     * 部署流程
     * @param force
     * @return
     */
    public void process(Boolean force);
java 复制代码
    public void process(Boolean force) {
        //判断流程是否已经部署,当force=0时,
        if (force == null || force) {
            //部署流程
            DeploymentBuilder builder = repositoryService.createDeployment();
            builder.addClasspathResource(AuditingConstant.BpmnXmlPhotoPathConstant.AUDITING_PHOTO_SIX_XML).disableSchemaValidation();
            String id = builder.deploy().getId();
            repositoryService.setDeploymentKey(id, AuditingConstant.BpmnIdConstant.AUDITING_PHOTO_SIX_ID);
        } else {
            //检测流程是否已经部署过
            List<ProcessDefinition> definitions = repositoryService.createProcessDefinitionQuery()
                    .processDefinitionKey(AuditingConstant.BpmnIdConstant.AUDITING_PHOTO_SIX_ID)
                    .list();
            if (!definitions.isEmpty()) {
                // 已经部署过流程定义
                throw new ServicesException(ResultStatus.AUDITING_PROCESS_DUPLICATE);
            } else {
                //部署流程
                DeploymentBuilder builder = repositoryService.createDeployment();
                builder.addClasspathResource(AuditingConstant.BpmnXmlPhotoPathConstant.AUDITING_PHOTO_SIX_XML).disableSchemaValidation();
                String id = builder.deploy().getId();
                repositoryService.setDeploymentKey(id, AuditingConstant.BpmnIdConstant.AUDITING_PHOTO_SIX_ID);
            }
        }
    }

这里AuditingConstant.BpmnXmlPhotoPathConstant.AUDITING_PHOTO_SIX_XML是流程图的路径,如下图所示

部署好后,查看数据表 ACT_RE_PROCDEF 即可判断是否成功部署

七、发起流程

前提: 业务表(需要审批的)数据创建 ------> 点击提交审核

如下图的照片墙审核,创建一条新的数据,此时一开始没审核,状态是"草稿",点击发布后,才会触发审批流程

1.示例

二级组织用户 新增一个照片墙,点击发布(选择审核等级为 上级(一级)组织,即需要经过两个审批节点才截止

【只要是二级发起的,都走的是2个审批节点的流程图,只不过根据结束节点会有不同的走向逻辑,如果这里选择本级(二级)结束,则不论二级通过不通过,都会直接走向结束节点】

点击发布后,会启动一个流程实例,并执行流程对象,见表ACT_HI_PROCINSTACT_RU_EXECUTION

ACT_HI_PROCINST(历史流程实例表)

ACT_RU_EXECUTION(运行时流程执行对象表):

如下图,当二级用户点击发步后,会发起审核,先走到 "二级审核2" 节点,对应上图的第1条数据

2.相关代码

java 复制代码
    @ApiOperation("发起照片审核")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "query", name = "taskName", value = "任务名称", required = true),
            @ApiImplicitParam(type = "query", name = "priority", value = "优先级", required = true),
            @ApiImplicitParam(type = "query", name = "desc", value = "描述", required = true),
            @ApiImplicitParam(type = "query", name = "photoWallId", value = "照片墙id", required = true),
            @ApiImplicitParam(type = "query", name = "auditingOrganizeId", value = "审核的组织id", required = true)})
    @ApiResponses({@ApiResponse(response = ResponseResult.class, message = "1", code = 200),
            @ApiResponse(response = ServiceException.class, message = "系统错误,请稍等!", code = 4000)})
    @PostMapping("/startPhotoAuditProcess")
    public ResponseResult<String> photoStartAuditing(@RequestBody Map<String, Object> map) {
        return ResponseResult.success(auditingPhotoService.photoStartAuditing(map));
    }
java 复制代码
    /**
     * 启动流程
     * @param map
     * @return success
     */
    public String photoStartAuditing(Map<String,Object> map);

下面代码解释:根据当前用户的组织级别,走不同的实现方法【代码比较臃肿,后续再优化,后面的代码同理】

java 复制代码
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String photoStartAuditing(Map<String, Object> map) {
        //根据照片墙id查找照片墙,给照片墙设置审核的组织ID
        PhotoWall photoWall = photoWallService.selectPhotoWallDetail(map.get("photoWallId") + "");
        photoWall.setOrganizeAuditingId(Long.parseLong(map.get("auditingOrganizeId") + ""));
        photoWall.setOpinion("");
        OrganizeTreeVO userOrganize = iOrganizeService.getUserOrganize();
        photoWallService.updatePhotoWallForAuditing(photoWall);
        //当前组织的级别
        Integer typeLevel = userOrganize.getTypeLevel();
        Integer typeLevelSix = 6;
        Integer typeLevelFive = 5;
        Integer typeLevelFour = 4;
        Integer typeLevelThree = 3;
        Integer typeLevelTwo = 2;
        Integer typeLevelOne = 1;
        if (typeLevel.equals(typeLevelSix)) {
            auditingPhotoSixService.startAuditProcess(map);
        } else if (typeLevel.equals(typeLevelFive)) {
            auditingPhotoFiveService.startAuditProcess(map);
        } else if (typeLevel.equals(typeLevelFour)) {
            auditingPhotoFourService.startAuditProcess(map);
        } else if (typeLevel.equals(typeLevelThree)) {
            auditingPhotoThreeService.startAuditProcess(map);
        } else if (typeLevel.equals(typeLevelTwo)) {
            auditingPhotoTwoService.startAuditProcess(map);
        } else if (typeLevel.equals(typeLevelOne)) {
            auditingPhotoOneService.startAuditProcess(map);
        }
        return "success";
    }
java 复制代码
/**
 * 启动流程
 * @param map
 */
public void startAuditProcess(Map<String,Object> map);
java 复制代码
public void startAuditProcess(Map<String, Object> map) {
    String id = map.get("photoWallId") + "";
    //修改照片墙的状态
    PhotoWall photoWall = photoWallService.selectPhotoWallDetail(id);
    photoWall.setAuditState(1);
    photoWall.setOrganizeAuditingId(Long.parseLong(map.get("auditingOrganizeId") + ""));
    Boolean code = photoWallService.updatePhotoWallForAuditing(photoWall);

    if (code) {
        // 获取当前登录用户的组织信息
        OrganizeTreeVO userOrganize = iOrganizeService.getUserOrganize();
        //当前组织的级别
        Integer typeLevel = userOrganize.getTypeLevel();
        //用来封装存储每一级组织的审核人,key是integer,表示不同级的组织,value是个list集合,每一级组织的审核人
        HashMap<String, List<SysUser>> auditors = new HashMap<>(10);
        //找出每一级审批流人员
        activitiService.getAuditors(userOrganize,typeLevel,auditors);
        // 设置流程变量
        Map<String, Object> variables = new HashMap<>(10);
        //获得每级审核的审核人
        List<String> firstAuditor = getAuditorsId(auditors.get("1"));
        List<String> secondAuditor = getAuditorsId(auditors.get("2"));
        //审核人
        variables.put("firstAuditor", firstAuditor);
        variables.put("secondAuditor", secondAuditor);

        String formKey = AuditingConstant.BpmnIdConstant.AUDITING_PHOTO_TWO_ID + ":";
        String bussinessKey = formKey + id;
        variables.put("bussinessKey", bussinessKey);
        // 启动流程实例
        runtimeService.startProcessInstanceByKey(AuditingConstant.BpmnIdConstant.AUDITING_PHOTO_TWO_ID, bussinessKey, variables);

        //给接下来的每一个审核人都创建一个,在刚发起的时候,是同一级的审核人
        List<SysUser> auditorsTypeLevel = auditors.get(typeLevel + "");
        //获得和登录用户同一级的审核人的id
        List<String> auditorsTypeLevelIds = getAuditorsId(auditorsTypeLevel);
        for (int i = 0; i < auditorsTypeLevelIds.size(); i++) {
            SysTask sysTask = new SysTask();
            sysTask.setTaskName((String) map.get("taskName"));
            sysTask.setPriority(Integer.valueOf(map.get("priority") + ""));
            sysTask.setDescribe((String) map.get("desc"));
            sysTask.setPhotoWallId((String) map.get("photoWallId"));
            sysTask.setCreatorName(SecurityUtils.getLoginUser().getUsername());
            sysTask.setCreatorId(SecurityUtils.getLoginUser().getUserId());
            //审核人的名字  这里要怎么设置啊,审核人的名字和id,用的是候选用户啊
            sysTask.setAuditingPeople(auditorsTypeLevel.get(i).getUserName());
            //审核人的id
            sysTask.setAuditingPeopleid(Long.parseLong(auditorsTypeLevelIds.get(i)));
            sysTask.setState(1);
            sysTask.setAuditingType(2);
            //任务表添加
            iSysTaskService.addTask(sysTask);
            //审核人的消息
            Message message = new Message();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
            String date = sdf.format(new Date());
            message.setContent("你在" + date + "有一个照片墙的审核");
            message.setCreateTime(new Date());
            message.setState(1);
            message.setUserId(auditorsTypeLevelIds.get(i));
            message.setType(1);
            messageService.addMessage(message);
        }

        //登录用户的消息
        Message message = new Message();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
        String date = sdf.format(new Date());
        message.setContent("你在" + date + "发起了一个照片墙审核");
        message.setCreateTime(new Date());
        message.setState(1);
        message.setUserId(SecurityUtils.getLoginUser().getUserId() + "");
        message.setType(2);
        messageService.addMessage(message);
    }
}

上方代码重点

  • 设置变量,启动流程实例

    这里把每一级审核人提前都设置好(后续不变)【这里根据业务需求应该也可以设计成后续动态添加】

    业务id bussinessKey 规则在此设定,调用最后一行的activity api时候需要传递,同时将其设置到流程变量 variables 中,后续方便读取

  • 业务部分

    1. 修改 照片墙业务表 流程相关字段
    2. 新增 审核任务业务表
    3. 发送消息

八、审批过程

现在流程走到第一个审批节点,即 二级审核2

此时,运行时节点人员数据信息表 ACT_RU_IDENTITYLINK,存入二级审核2 节点的 是审核人角色 的 用户,尾号20用户和尾号52用户都是该节点的审批人【该项目里,只要其中一个审批通过,就算通过,反之,一个拒绝就算拒绝】,

且被分配到了任务(同个任务),见表ACT_RU_TASK,如下图

对应业务表 任务表里,也加了2条数据

他们之间通过 BUSINESS_KEY_ 来关联

1.审核通过

审批通过,在activity7框架中,只需要设置SecondJudge变量,然后将task任务完成即可

1.示例

二级组织人员 尾号52用户 创建了一个照片墙,点击发布后,生成本级人员(尾号52和尾号20)的任务,此时52用户进入"我的待办"里(业务表 任务表),找到对应任务,点击审批通过,如下图

2.相关代码

java 复制代码
@ApiOperation("照片墙审批通过")
@ApiImplicitParams({
        @ApiImplicitParam(type = "query", name = "id", value = "任务id", required = true),
        @ApiImplicitParam(type = "query", name = "opinion", value = "建议", required = false)
})
@PostMapping("/auditing/photo/approve/{id}")
public ResponseResult<String> auditingPhotoApprove(@PathVariable Integer id, @RequestParam(required = false) String opinion) {
    return ResponseResult.success(auditingPhotoService.auditingPhotoApprove(id, opinion));
}
java 复制代码
/**
 * 审核通过
 * @param id
 * @param opinion
 * @return success
 */
public String auditingPhotoApprove(Integer id,String opinion);

下面代码解释:

通过照片墙的创建者的组织等级,走不同的审核通过实现类

java 复制代码
@Override
@Transactional(rollbackFor = Exception.class)
public String auditingPhotoApprove(Integer id, String opinion) {
    //id是任务的id,可以获得照片墙的id
    //再去新建表中查询这个照片墙是哪级创建的,
    //这个级数直接判断吗,然后去调用哪个类的approve方法?
    SysTask sysTask = iSysTaskService.selectTaskById(id);
    //通过任务的informatinid来获得照片墙id
    String photoId = sysTask.getPhotoWallId();

    //根据照片墙的id去查询审核创建者的级别
    LambdaQueryWrapper<PhotoWall> lambdaQueryWrapper = new LambdaQueryWrapper<PhotoWall>();
    lambdaQueryWrapper.eq(PhotoWall::getPhotoWallId, photoId);
    PhotoWall photoWall = photoWallService.getOne(lambdaQueryWrapper);

    //获得当前等级
    Long organizeId = photoWall.getOrganizeId();
    Integer userOrganizeLevel = iOrganizeService.searchOrganizeById(organizeId).getOrganizeLevel();
    Integer userOrganizeLevelOne = 1;
    Integer userOrganizeLevelTwo = 2;
    Integer userOrganizeLevelThree = 3;
    Integer userOrganizeLevelFour = 4;
    Integer userOrganizeLevelFive = 5;
    Integer userOrganizeLevelSix = 6;

    //获得审核组织的级别
    Long auditingOrganizeId = photoWall.getOrganizeAuditingId();
    Integer auditingOrganizeLevel = iOrganizeService.searchOrganizeById(auditingOrganizeId).getOrganizeLevel();

    if (userOrganizeLevel.equals(userOrganizeLevelOne)) {
        auditingPhotoOneService.approve(id, opinion);
    } else if (userOrganizeLevel.equals(userOrganizeLevelTwo)) {
        auditingPhotoTwoService.approve(id, opinion, auditingOrganizeLevel);
    } else if (userOrganizeLevel.equals(userOrganizeLevelThree)) {
        auditingPhotoThreeService.approve(id, opinion, auditingOrganizeLevel);
    } else if (userOrganizeLevel.equals(userOrganizeLevelFour)) {
        auditingPhotoFourService.approve(id, opinion, auditingOrganizeLevel);
    } else if (userOrganizeLevel.equals(userOrganizeLevelFive)) {
        auditingPhotoFiveService.approve(id, opinion, auditingOrganizeLevel);
    } else if (userOrganizeLevel.equals(userOrganizeLevelSix)) {
        auditingPhotoSixService.approve(id, opinion, auditingOrganizeLevel);
    }
    return "success";
}
java 复制代码
/**
 * 审核通过
 * @param id
 * @param opinion
 * @param auditingOrganizeLevel
 */
public void approve(Integer id, String opinion,Integer auditingOrganizeLevel);
java 复制代码
@Override
public void approve(Integer id, String opinion, Integer auditingOrganizeLevel) {
    //获取任务的候选人是登录用户的任务的方法
    List<Task> taskList = activitiService.getTaskIdByCandidate(SecurityUtils.getLoginUser().getUserId().toString());
    //当前登录用户的组织级别
    Integer typeLevel = iOrganizeService.getUserOrganize().getTypeLevel();
    //搜索出工作台选的任务id
    SysTask sysTask = iSysTaskService.selectTaskById(id);
    //通过任务的photoWallId来获得照片墙id
    PhotoWall photoWall = photoWallService.selectPhotoWallDetail(sysTask.getPhotoWallId() + "");
    String photoWallId = photoWall.getPhotoWallId();
    auditingInformTwoApproveService(taskList, photoWallId, typeLevel, photoWall, auditingOrganizeLevel, opinion);
    // 获取当前登录用户的组织信息
    OrganizeTreeVO userOrganize = iOrganizeService.getUserOrganize();
    //用来封装存储每一级组织的审核人,key是integer,表示不同级的组织,value是个list集合,每一级组织的审核人
    HashMap<String, List<SysUser>> auditors = new HashMap<>(10);
    //找出每一级审批流人员
    activitiService.getAuditors(userOrganize,typeLevel,auditors);
    List<String> auditorsList = new ArrayList<>();
    if(typeLevel.equals(AuditingConstant.Number.TWO)){
        auditorsList = getAuditorsId(auditors.get("2"));
    }
    if (typeLevel == 1) {
        auditorsList = getAuditorsId(auditors.get("1"));
    }

    sysTask.setState(2);
    sysTask.setOpinion(opinion);
    sysTask.setCompletionTime(new Date());
    iSysTaskService.updateTask(sysTask);
    Long userId1 = SecurityUtils.getLoginUser().getUserId();
    String photoWallId1 = sysTask.getPhotoWallId();
    //删除其他用户中关联这个照片墙id的任务
    //循环审核人列表
    for (String s : auditorsList) {
        //当审核人不等于登录用户时,即其他用户
        if (!Objects.equals(s, userId1 + "")) {
            //搜索出他的全部任务
            List<SysTask> sysTaskList = iSysTaskService.selectTaskByAuditorId(Long.parseLong(s));
            //循环任务
            for (SysTask task : sysTaskList) {
                //找出任务中关联的照片墙id等于当前登录用户审核的任务的关联的照片墙id
                if (photoWallId1.equals(task.getPhotoWallId())) {
                    //删除
                    iSysTaskService.deleteTask(task.getTaskId().intValue());
                }
            }
        }
    }

    if (typeLevel == 1 || typeLevel.equals(auditingOrganizeLevel)) {
        photoWall.setAuditState(2);
        photoWallService.updatePhotoWallForAuditing(photoWall);
        Message message = new Message();
        Date date = new Date();
        message.setContent("你的照片墙在" + typeLevel + "级审核通过");
        message.setCreateTime(date);
        message.setState(1);
        String userId = sysTask.getCreatorId() + "";
        message.setUserId(userId);
        message.setType(2);
        message.setTaskId(sysTask.getTaskId().intValue());
        messageService.addMessage(message);
        return;
    }
    if (typeLevel.equals(AuditingConstant.Number.TWO)) {
        auditorsList = getAuditorsId(auditors.get("1"));
    }
    for (String s : auditorsList) {
        SysTask sysTask1 = new SysTask();
        sysTask1.setTaskName(sysTask.getTaskName());
        sysTask1.setPriority(sysTask.getPriority());
        sysTask1.setDescribe(sysTask.getDescribe());
        sysTask1.setPhotoWallId(sysTask.getPhotoWallId());
        sysTask1.setCreatorName(SecurityUtils.getLoginUser().getUsername());
        sysTask1.setCreatorId(SecurityUtils.getLoginUser().getUserId());
        sysTask1.setAuditingPeopleid(Long.parseLong(s));
        SysUser sysUser = iSysUserService.selectUserById(Long.parseLong(s));
        sysTask1.setAuditingPeople(sysUser.getUserName());
        sysTask1.setState(1);
        sysTask1.setAuditingType(2);
        iSysTaskService.addTask(sysTask1);
        sendMessage(s, sysTask);
    }
    sendMessage(typeLevel, sysTask);
}
java 复制代码
private void auditingInformTwoApproveService(List<Task> taskList, String photoWallId, Integer typeLevel, PhotoWall photoWall, Integer auditingOrganizeLevel, String opinion) {
    if (!ObjectUtils.isEmpty(taskList)) {
        for (Task item : taskList) {
            ProcessInstance processInstance = runtimeService
                    .createProcessInstanceQuery()
                    .processInstanceId(item.getProcessInstanceId())
                    .singleResult();
            //根据流程实例得到bussinesskey,格式是formkey:id
            String a = processInstance.getBusinessKey();
            if (StringUtils.isNotBlank(a)) {
                String[] b = a.split(":");
                String photoId = b[1];
                //判断bussinesskey,bussinesskey是任务表中的记录的id,在发起流程的时候会插入任务表,任务表的id也会变成流程变量
                if (photoId.equals(photoWallId)) {
                    if (typeLevel == 2) {
                        if (typeLevel.equals(auditingOrganizeLevel)) {
                            taskService.setVariable(item.getId(), "SecondJudge", false);
                        } else {
                            taskService.setVariable(item.getId(), "SecondJudge", true);
                        }
                    } else if (typeLevel == 1) {
                        //如果当前审核人是一级组织的,那审核就结束了
                        photoWall.setAuditState(2);
                        photoWall.setOpinion(opinion);
                        photoWallService.updatePhotoWallForAuditing(photoWall);
                    }
                    taskService.addComment(item.getId(), item.getProcessInstanceId(), "审核通过");
                    taskService.complete(item.getId());
                    break;
                }
            }
        }
    }
}

上面代码重点

  • 找到activity的任务表中,当前该用户的所有任务

    java 复制代码
    @Override
    public List<Task> getTaskIdByCandidate(String userId) {
        List<ActivitiTaskId> activitiTaskId = activitiMapper.getTaskIdByCandidate(userId);
        List<String> activitiTaskIds = new ArrayList<>();
        for (com.znak.platform.entity.ActivitiTaskId taskId : activitiTaskId) {
            activitiTaskIds.add(taskId.getTaskId());
        }
        List<Task> taskList = new ArrayList<>();
        for (String taskId : activitiTaskIds) {
            Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
            taskList.add(task);
        }
        return taskList;
    }
    xml 复制代码
    <select id="getTaskIdByCandidate" resultType="com.znak.platform.entity.ActivitiTaskId">
        select distinct TASK_ID_ from ACT_RU_IDENTITYLINK
        where USER_ID_ = #{userId}  and TASK_ID_ != ""
    </select>
  • 根据bussinesskey找到对应的任务,修改变量SecondJudge,并完成任务

    这里注意,如果当前是走到一级审批节点了,则走下面的else if逻辑,直接将业务表修改审核通过(不用设置变量,因为没有网关了),如下图

  • 业务相关

    • 修改业务表的审批流相关字段,同时发送消息,同上

    • 然后删除同级别组织人员的 业务表 任务表,新建下一级的人员的业务表 任务表,见代码

2.审批不通过

过程和审批通过大致一样

1.相关代码

java 复制代码
@ApiOperation("照片审核不通过")
@ApiResponses({@ApiResponse(response = ResponseResult.class, message = "1", code = 200),
        @ApiResponse(response = ServiceException.class, message = "系统错误,请稍等!", code = 4000)})
@ApiImplicitParams({
        //发起资讯申请相关字段
        @ApiImplicitParam(type = "query", name = "id", value = "任务id", required = true),
        @ApiImplicitParam(type = "query", name = "opinion", value = "建议", required = false)
})
@PostMapping("/auditing/photo/reject/{id}")
public ResponseResult<String> auditingPhotoReject(@PathVariable Integer id, @RequestParam(required = false) String opinion) {
    return ResponseResult.success(auditingPhotoService.auditingPhotoReject(id, opinion));
}
java 复制代码
/**
 * 审核不通过
 * @param id
 * @param opinion
 * @return success
 */
public String auditingPhotoReject(Integer id,String opinion);
java 复制代码
@Override
@Transactional(rollbackFor = Exception.class)
public String auditingPhotoReject(Integer id, String opinion) {
    //id是任务的id,可以获得资讯的id
    //再去新建表中查询这个资讯是哪级创建的,
    //这个级数直接判断吗,然后去调用哪个类的approve方法?
    SysTask sysTask = iSysTaskService.selectTaskById(id);
    //通过任务的informatinid来获得资讯id
    String photoWallId = sysTask.getPhotoWallId();
    //根据资讯的id去查询审核创建者的级别
    LambdaQueryWrapper<PhotoWall> lambdaQueryWrapper = new LambdaQueryWrapper<PhotoWall>();
    lambdaQueryWrapper.eq(PhotoWall::getPhotoWallId, photoWallId);
    PhotoWall photoWall = photoWallService.getOne(lambdaQueryWrapper);

    //获得当前等级
    Long organizeId = photoWall.getOrganizeId();
    Integer userOrganizeLevel = iOrganizeService.searchOrganizeById(organizeId).getOrganizeLevel();
    Integer userOrganizeLevelOne = 1;
    Integer userOrganizeLevelTwo = 2;
    Integer userOrganizeLevelThree = 3;
    Integer userOrganizeLevelFour = 4;
    Integer userOrganizeLevelFive = 5;
    Integer userOrganizeLevelSix = 6;
    if (userOrganizeLevel.equals(userOrganizeLevelOne)) {
        auditingPhotoOneService.rej(id, opinion);
    } else if (userOrganizeLevel.equals(userOrganizeLevelTwo)) {
        auditingPhotoTwoService.rej(id, opinion);
    } else if (userOrganizeLevel.equals(userOrganizeLevelThree)) {
        auditingPhotoThreeService.rej(id, opinion);
    } else if (userOrganizeLevel.equals(userOrganizeLevelFour)) {
        auditingPhotoFourService.rej(id, opinion);
    } else if (userOrganizeLevel.equals(userOrganizeLevelFive)) {
        auditingPhotoFiveService.rej(id, opinion);
    } else if (userOrganizeLevel.equals(userOrganizeLevelSix)) {
        auditingPhotoSixService.rej(id, opinion);
    }
    return "success";
}
java 复制代码
/**
 * 审核不通过
 * @param id
 * @param opinion
 */
public void rej(Integer id, String opinion);
java 复制代码
public void rej(Integer id, String opinion) {
    //获取任务的候选人是登录用户的任务的方法
    List<Task> taskList = activitiService.getTaskIdByCandidate(SecurityUtils.getLoginUser().getUserId().toString());
    //当前登录用户的组织级别
    Integer typeLevel = iOrganizeService.getUserOrganize().getTypeLevel();

    //搜索出工作台选的任务id
    SysTask sysTask = iSysTaskService.selectTaskById(id);

    //通过任务的informatinid来获得资讯id
    PhotoWall photoWall = photoWallService.selectPhotoWallDetail(sysTask.getPhotoWallId());
    String photoWallId = photoWall.getPhotoWallId();
    auditingInformTwoRejService(taskList, photoWallId, typeLevel, photoWall,opinion);

    // 获取当前登录用户的组织信息
    OrganizeTreeVO userOrganize = iOrganizeService.getUserOrganize();
    //用来封装存储每一级组织的审核人,key是integer,表示不同级的组织,value是个list集合,每一级组织的审核人
    HashMap<String, List<SysUser>> auditors = new HashMap<>(4);
    //找出每一级审批流人员
    activitiService.getAuditors(userOrganize,typeLevel,auditors);
    //防止四级发起的审核,然后任务到达三级的时候调用此方法,会报错4级审核人找不到
    List<String> auditorsList = new ArrayList<>();

    Integer typeLevelTwo = 2;
    if (typeLevel.equals(typeLevelTwo)) {
        auditorsList = getAuditorsId(auditors.get("2"));

    }
    if (typeLevel == 1) {
        auditorsList = getAuditorsId(auditors.get("1"));
    }
    //这一个等级的组织的审核任务处理,处理上一阶段的任务
    //获得当前级别的审核人
    sysTask.setState(3);
    sysTask.setOpinion(opinion);
    sysTask.setCompletionTime(new Date());
    iSysTaskService.updateTask(sysTask);
    Long userId1 = SecurityUtils.getLoginUser().getUserId();
    String photoWallId1 = photoWall.getPhotoWallId();
    //删除其他用户中关联这个咨询id的任务
    //循环审核人列表
    for (String s : auditorsList) {
        //当审核人不等于登录用户时,即其他用户
        if (!Objects.equals(s, userId1 + "")){
            //搜索出他的全部任务
            List<SysTask> sysTaskList = iSysTaskService.selectTaskByAuditorId(Long.parseLong(s));
            //循环任务
            for(SysTask task : sysTaskList){
                //找出任务中关联的照片墙id等于当前登录用户审核的任务的关联的照片墙id
                if(photoWallId1.equals(task.getPhotoWallId())){
                    //删除
                    iSysTaskService.deleteTask(task.getTaskId().intValue());
                }
            }
        }
    }

    Message message = new Message();
    Date date = new Date();
    message.setContent("你的照片墙在" + typeLevel + "级审核没有通过");
    message.setCreateTime(date);
    message.setState(1);
    //这个审核的是谁的流程
    String userId = sysTask.getCreatorId() + "";
    message.setUserId(userId);
    message.setType(2);
    message.setTaskId(sysTask.getTaskId().intValue());
    messageService.addMessage(message);

}
java 复制代码
private void auditingInformTwoRejService(List<Task> taskList, String photoWallId, Integer typeLevel, PhotoWall photoWall,String opinion) {
    if (!ObjectUtils.isEmpty(taskList)) {
        for (Task item : taskList) {
            ProcessInstance processInstance = runtimeService
                    .createProcessInstanceQuery()
                    .processInstanceId(item.getProcessInstanceId())
                    .singleResult();
            //根据流程实例得到bussinesskey,格式是formkey:id
            String a = processInstance.getBusinessKey();
            if (StringUtils.isNotBlank(a)) {
                String[] b = a.split(":");
                String photoId = b[1];
                //判断bussinesskey,bussinesskey是任务表中的记录的id,在发起流程的时候会插入任务表,任务表的id也会变成流程变量
                if (photoId.equals(photoWallId)) {
                    //根据当前登录用户的组织级别判断是第几级判断,设置相关的流程变量
                    if (typeLevel == 2) {
                        photoWall.setAuditState(4);
                        photoWall.setOpinion(opinion);
                        photoWallService.updatePhotoWallForAuditing(photoWall);
                        taskService.setVariable(item.getId(), "SecondJudge", false);
                    } else if (typeLevel == 1) {
                        //如果当前审核人是一级组织的,那审核就结束了
                        photoWall.setAuditState(4);
                        photoWall.setOpinion(opinion);
                        photoWallService.updatePhotoWallForAuditing(photoWall);
                    }
                    taskService.addComment(item.getId(), item.getProcessInstanceId(), "审核不通过");
                    taskService.complete(item.getId());
                    break;
                }
            }
        }
    }
}

上面代码的重点:

  • 找到activity的任务表中,当前该用户的所有任务

    同上

  • 根据bussinesskey找到对应的任务,修改变量SecondJudge,并完成任务

    同上

  • 业务相关

    • 修改业务表的审批流相关字段,同时发送消息,同上

    • 然后删除同级别组织人员的 业务表 任务表,见代码

九、业务表相关字段

1.任务表

2.业务数据表

以 照片墙 为例

十、业务表数据权限变化

  • 审核前,即草稿状态的数据,只能看自己创建的
  • 审核通过,本级 到 最终审核组织 之间的用户都可见
相关推荐
m0_571957581 小时前
Java | Leetcode Java题解之第543题二叉树的直径
java·leetcode·题解
魔道不误砍柴功3 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
NiNg_1_2343 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
闲晨3 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
种树人202408193 小时前
如何在 Spring Boot 中启用定时任务
spring boot
Chrikk5 小时前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*5 小时前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue5 小时前
go语言连续监控事件并回调处理
开发语言·后端·golang
杜杜的man5 小时前
【go从零单排】go语言中的指针
开发语言·后端·golang
测开小菜鸟5 小时前
使用python向钉钉群聊发送消息
java·python·钉钉