四、Activiti——使用任务监听器进行任务权限分配

作者: 小疯子 分类: Activiti 发布时间: 2020-03-11 14:38

一、说明

根据前面文章有提过,希望员工提报请假申请之后,下一步的总监审批除了是总监身份之外,还需要是和提报申请用户再同一个部们的总监才有权限进行审批,这里用到了任务监听器TaskListener来实现。其他实现方式还有JUEL分配权限,注意关于分配权限都是针对“用户任务”的

二、开发

2.1 编写一个类实现TaskListener

/**
 * @Author: Xiaofeng
 * @Date: 2020/3/11 11:44
 * @Description: 用户任务监听器进行权限分配
 */
public class UserTaskListener implements TaskListener {

    @Autowired //这个通过spring是注入不进来的,因为这个TaskListener是后注入的,或者或许在类上@Service应该也可以,这里我是直接通过SpringUtils通过ApplicationContext中获取bean
    private RuntimeService runtimeService;

    @Autowired
    private ISysDepartmentUserService departmentUserService;

    @Autowired
    private IRoleService roleService;

    @Autowired
    private IUserService userService;

    @Override
    public void notify(DelegateTask delegateTask) {
        if(roleService == null) {
            roleService = SpringUtils.getBean(IRoleService.class);
        }
        if(userService == null) {
            userService = SpringUtils.getBean(IUserService.class);
        }
        if(departmentUserService == null) {
            departmentUserService = SpringUtils.getBean(ISysDepartmentUserService.class);
        }
        if(runtimeService == null) {
            runtimeService = SpringUtils.getBean(RuntimeService.class);
        }
        // 使用任务监听器将总监or经理的审批限制在同一个部门
//        String processInstanceId = delegateTask.getProcessInstanceId();
//        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
//        processInstance.getStartUserId()
//        delegateTask.getTenantId()
        VacationBaseForm vacation = (VacationBaseForm)delegateTask.getVariable("arg");
        String userId = vacation.getUserId();// 获取此流程实例的申请用户
        String sysUserId = vacation.getSysUserId();// 系统用户id
        // 候选用户组和候选用户列表
        Set candidates = delegateTask.getCandidates();
        List actGroupIds = new ArrayList<>();
        if(candidates == null || candidates.size() == 0) {
            return;
        }
        for (IdentityLink cad : candidates) {
            String type = cad.getType();
            if(IdentityLinkType.CANDIDATE.equals(type)) {
                String groupId = cad.getGroupId();
                actGroupIds.add(groupId);
            }
        }

        if(ObjectUtils.isEmpty(actGroupIds)) {
            return;
        }
        QueryWrapper roleQueryWrapper = new QueryWrapper<>();
        roleQueryWrapper.in("act_group_id", actGroupIds);
        // 任务处理的候选角色列表
        List listRole = roleService.list(roleQueryWrapper);
        List roleIds = listRole.stream().map(v -> v.getId()).collect(Collectors.toList());
        QueryWrapper wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", sysUserId);
        // 获取请求用户所在的部门列表
        List departmentIds = departmentUserService.list(wrapper)
                .stream().map(w -> w.getDepartmentId()).collect(Collectors.toList());
        // 候选人呢,首先得属于候选组,另外还需要和申请人在相同的部门们里,sql实现

        List users = userService.getByRoleAndDepartment(roleIds, departmentIds);
        List actUserIds = new ArrayList<>();
        users.stream().forEach(v -> {
            if(v.getActUserId() != null) {
                actUserIds.add(v.getActUserId());
            }
        });
        if(actUserIds.size() == 0) {return;}
        delegateTask.addCandidateUsers(actUserIds);// 添加候选用户
        actGroupIds.forEach(v -> {
            delegateTask.deleteCandidateGroup(v); // 移除原有的候选用户组
        });
    }

}

2.2 关于上面根据部门和角色的查询sql语句

SELECT

        FROM
        sys_user uu
        INNER JOIN sys_user_role ur ON ur.user_id = uu.id
        WHERE
        ur.role_id IN

            #{item}

        AND uu.id IN (
        SELECT
        u.id
        FROM
        sys_user u
        INNER JOIN sys_department_user du ON du.user_id = u.id
        WHERE
        du.department_id IN

            #{item}

        )
        GROUP BY
        uu.id

2.3 bpmn中添加此任务监听器

<userTask activiti:candidateGroups="director" activiti:exclusive="true" id="_5" name="总监审批">
      <extensionElements>
        <activiti:taskListener event="create" class="com.xiaofeng.shop.serveractiviti.listener.UserTaskListener">
        </activiti:taskListener>
      </extensionElements>
    </userTask>

主要是其中的extensionElements,上面的candidateGroups仅仅是为了我们代码中进行判别的,其实最后有权限操作任务的都是在UserTaskListener的notify中指定的
注意这个bpmn更改后可能是需要重新部署一下的

repositoryService.deleteDeployment("1", true); // 级联删除原有的,下面重新部署
repositoryService.createDeployment().addClasspathResource("processes/vacate.bpmn").enableDuplicateFiltering().deploy();

2.4 获取总监用户的待办任务

之前实现过,但是是根据用户组获得的,现在改成根据activiti用户获取

public IPage getAgendaTasks(String userId, PageVo pageVo) {
        int pageNumber = pageVo.getPageNumber();
        int pageSize = pageVo.getPageSize();
        // pageNumber和pageSize都需要验证一下
        IPage page = new Page<>(pageNumber, pageSize);
        // 找到候选人对应的tasks
        Map<String, Object> maps = vacationProcessService.getAgendaTasks(userId, pageNumber, pageSize);
        // 然后进行转换
        List taskVoList = vacationProcessService.createTaskVoList((List)maps.get("records"));
        page.setRecords(taskVoList);
        page.setPages((Long) maps.get("pages"));
        page.setTotal((Long) maps.get("total"));
        return page;
    }

2.5 最终实现功能

step1. 更改或添加员工11,总监11,二者都在同一个部门测试部
step2. 再添加总监22,在设计部
step3. 员工11登录后进行请假申请,当然申请>3天先
step4. 总监11登录后查看待办任务可以看到员工11的请假申请
step5. 总监22登录后待办任务中没有员工11的请假申请,因为它们不在同一个部门下,以上就是实现的功能

0