SpringBoot+Activiti 创建自定义业务审批框架

流程开发主要分成两部分:

  1. 通用的流程操作(基于Activiti 本身)。
  2. 独立的业务开发。
    而在业务开发中,会伴随着很多与Activiti的代码耦合,会出现大量的同等功能的业务代码,但是由于操作的业务对象不同,又需要写很多冗余的CRUD操作。这样增加了大量低质量的耦合代码。
    为了减少业务代码中的通用性操作代码,可以编写一套自定义的业务代码审批框架。
    项目代码:
    GitHub https://github.com/oldguys/ActivitiDemo
结构类图:
框架设计图 .jpg
设计思路:
  1. 基于设计模式规则: 依赖倒置原则 , 里氏代换原则,将通用的接口方法进行抽象,完成高层接口:WorkEntityMapperProcessInstanceService 设计。
  2. 使用类似于 抽象工厂模式桥梁模式,对系统进行 解耦多态
    CommonWorkEntityService:进行通用的服务调度,像桥梁一样来适配调度多个ProcessInstanceService
    ProcessInstanceService由基于不同业务对象进行实现,通过不同实例,再关联到DAO层的不同业务对象上。
  3. CommonWorkEntityService 继承于 AbstractWorkEntityService,通过调用 init 方法来通用注入业务对象,而实现类则成为统一调度入口。
调度方式:

TaskController 调用 CommonWorkEntityService的getWorkEntityInfo(),最终可以分别获取到Entity1ProcessEntity实体或Entity2ProcessEntity实体

调用图.jpg
关联与对象注入:

由于基于SpringBoot,自然要利用Spring的容器进行管理。
Step1: 由于服务对象实现于接口 ProcessInstanceService,可以去Spring容器中,获取所有实现于该接口的对象。
Step2: 利用泛型来获取:
Entity1ProcessInstanceService 继承于 AbstractProcessInstanceService<T> 实现于 ProcessInstanceService<T>
获取实现类上的泛型,就可以知道业务实体为 Entity1Process,利用Map将对象与业务类别进行关联标识。同理可使用于 DAO层。

@Service
public class Entity1ProcessInstanceService extends AbstractProcessInstanceService<Entity1Process> {

}

Step3: 注入对象,依赖倒置中,注入方法有:设值注入,构造注入,接口注入。这里使用设值注入来实现,关联 ProcessInstanceServiceDAOMapper

Step4: 巧用多态,根据 **里氏代换原则 **,基类可以调用子类,而我们扩展业务对象,一般都采用继承来实现DTO对象,就可以实现不同的子类对象来满足数据的多态。

@Service
public class Entity1ProcessInstanceService extends AbstractProcessInstanceService<Entity1Process> {
    @Override
    public Entity1Process getTarget(Long id) {
        // Entity1ProcessInfo 继承于 Entity1Process 
        return new Entity1ProcessInfo();
    }
}
package com.oldguy.example.modules.workflow.service;


import com.oldguy.example.modules.common.dao.jpas.WorkEntityMapper;
import com.oldguy.example.modules.common.exceptions.FormValidException;
import com.oldguy.example.modules.common.utils.SpringContextUtils;
import com.oldguy.example.modules.workflow.configs.WorkFlowConfiguration;
import com.oldguy.example.modules.workflow.dto.TaskEntityInfo;
import com.oldguy.example.modules.workflow.dto.WorkBtn;
import com.oldguy.example.modules.workflow.dto.WorkEntityInfo;
import com.oldguy.example.modules.workflow.service.entities.ProcessAuditStatusService;
import com.oldguy.example.modules.workflow.service.entities.ProcessTaskConfigService;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.RuntimeService;
import org.apache.commons.lang3.ClassUtils;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

/**
 * @author ren
 * @date 2018/12/6
 */
public abstract class AbstractWorkEntityService {

    /**
     * 工作流实体集合
     */
    protected Map<String, ProcessInstanceService> processInstanceServiceMap = Collections.emptyMap();

    /**
     * DAO Mapper
     */
    protected Map<String, WorkEntityMapper> workEntityMapperMap = Collections.emptyMap();

    protected UserTaskService userTaskService;

    protected ProcessService processService;

    protected RuntimeService runtimeService;

    protected ProcessTaskConfigService processTaskConfigService;

    protected ProcessAuditStatusService processAuditStatusService;

    /**
     * 获取抽象类型的泛型类
     *
     * @param object
     * @return
     */
    public static Class getActualTypeArgumentByClassAbstractClass(Object object) {
        Class typeClass = (Class) ((ParameterizedType) object.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        return typeClass;
    }

    /**
     * 获取接口的泛型类型
     *
     * @param object
     * @return
     */
    public static Class getActualTypeArgumentByClassInterface(Object object) {

        Type[] types = object.getClass().getGenericInterfaces();
        ParameterizedType parameterizedType = (ParameterizedType) types[0];
        Class typeClass = (Class) parameterizedType.getActualTypeArguments()[0];
        return typeClass;
    }

    /**
     * 获取Mapper接口上的实现泛型
     *
     * @param object
     * @return
     */
    public static Class getActualTypeArgumentByInterface(Object object) {

        List<Class<?>> list = ClassUtils.getAllInterfaces(object.getClass());

        Class clazz = list.get(0);
        Type[] types = clazz.getGenericInterfaces();
        Class typeClass = (Class) ((ParameterizedType) types[0]).getActualTypeArguments()[0];

        return typeClass;
    }

    protected void init() {
        if (null == userTaskService) {
            userTaskService = SpringContextUtils.getBean(UserTaskService.class);
        }
        if (null == processService) {
            processService = SpringContextUtils.getBean(ProcessService.class);
        }
        if (null == runtimeService) {
            runtimeService = SpringContextUtils.getBean(RuntimeService.class);
        }
        if (null == processTaskConfigService) {
            processTaskConfigService = SpringContextUtils.getBean(ProcessTaskConfigService.class);
        }
        if (null == processAuditStatusService) {
            processAuditStatusService = SpringContextUtils.getBean(ProcessAuditStatusService.class);
        }

        // 注入DAO Mapper
        if (workEntityMapperMap.isEmpty()) {
            String[] baseEntityMapperNames = SpringContextUtils.getBeanNamesForType(WorkEntityMapper.class);
            workEntityMapperMap = new HashMap<>(baseEntityMapperNames.length);

            for (String name : baseEntityMapperNames) {
                WorkEntityMapper workEntityMapper = SpringContextUtils.getBean(name, WorkEntityMapper.class);

                // 获取返修类
                Class typeClass = getActualTypeArgumentByInterface(workEntityMapper);
                workEntityMapperMap.put(typeClass.getSimpleName(), workEntityMapper);
            }
        }

        // 注入ProcessInstanceService
        if (processInstanceServiceMap.isEmpty()) {
            String[] workflowNames = SpringContextUtils.getBeanNamesForType(ProcessInstanceService.class);
            processInstanceServiceMap = new HashMap<>(workflowNames.length);

            for (String name : workflowNames) {
                AbstractProcessInstanceService workFlow = SpringContextUtils.getBean(name, AbstractProcessInstanceService.class);

                // 获取返修类
                Class typeClass = getActualTypeArgumentByClassAbstractClass(workFlow);

                // 注入类别名称
                workFlow.setClassName(typeClass.getSimpleName());
                workFlow.setWorkEntityMapper(workEntityMapperMap.get(typeClass.getSimpleName()));
                workFlow.setProcessTaskConfigService(processTaskConfigService);
                workFlow.setProcessAuditStatusService(processAuditStatusService);

                processInstanceServiceMap.put(typeClass.getSimpleName(), workFlow);
            }
        }
    }
}

推荐阅读更多精彩内容