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