通过流水线模式使代码具有职责单一、移植性高、扩展性强、代码复用性强、代码清晰。
将一个业务逻辑拆分为若干个小的逻辑单元,之后将这些小的逻辑单元按顺序添加到管道中,这样就组成一个有顺序的管道。
职责单一:将一个大的业务逻辑拆分为若干个小的逻辑单元。
移植性高:每个小的逻辑单元可以通过可拔插方式添加移除到管道中。
扩展性强:增强业务逻辑,只需向管道添加小的逻辑单元即可。
代码复用性强:将业务逻辑封装在若干个小的逻辑单元中,使得每一个单元块只聚合某一点功能,复用性大大增加。
代码清晰:将业务逻辑封装在若干个小的逻辑单元,使得代码聚合,如果代码有改动只需要改动某一个小的单元,而避免影响这个业务逻辑。
工作使用场景 功能简介列表查询/查询详情/业务系统用户菜单权限/业务系统查询全部菜单 ,他们都共用到MenuEntityToMenuDtoList这个单元块,这里体现到代码复用性强,又因为MenuEntityToMenuDtoList中职责单一和聚合才体现代码复用性强。
列表查询列表查询功能:首先从库中查询出菜单集合 ,之后将数据库实体对象MenuEntity转换为MenuDto,之后是对MenuDto的属性设置(SetResourceToMenuList/AddRecouceButtonToMenuList),接下来是校验用户是否对此采用有操作权限,最后是将MenuDto转换为菜单树。
QueryMenuList(从库中查询出菜单列表) -> MenuEntityToMenuDtoList(将MenuEntity实体转换为 MenuDto) -> SetResourceToMenuList(设置MenuDto关联表Resource额外属性,增强MenuDto) -> AddRecouceButtonToMenuList(添加资源按钮,增强MenuDto) -> CheckMenuResoucePerimissionList (校验用户是否对此菜单有操作权限) -> MenuListToTree(MenuDto转换菜单树)查询详情
MenuById(从库中通过id查询出菜单) -> MenuEntityToMenuDtoList(将MenuEntity实体转换为
MenuDto) -> SetResourceToMenuList(设置MenuDto关联表Resource额外属性,增强MenuDto)
public class Pipeline {
private final Handler currentHandler;
public Pipeline(Handler currentHandler) {
this.currentHandler = currentHandler;
}
public Pipeline addHandler(Handler newHandler) {
return new Pipeline<>(input -> newHandler.process(currentHandler.process(input)));
}
public boolean before(Object o){
return true;
}
public void after(O o){
}
public O execute(I input) {
return currentHandler.process(input);
}
}
public interface Handler {
O process(I input);
}
菜单列表查询代码
public class QueryMenuList implements Handler> { @Override public List process(String input) { SyMenuMapper syMenuMapper = SpringApplicationUtils.getBean(SyMenuMapper.class); QueryWrapper qw = Wrappers.query().eq("service_id", CurrentUserContext.getServiceId()); qw.eq("menu_source",input); List menus = syMenuMapper.selectList(qw); return menus; } }
public class MenuEntityToMenuDtoList implements Handler, List
> { @Override public List process(List input) { if (CollectionUtils.isEmpty(input)){ return Collections.emptyList(); } List dtos = input.stream().map(v ->{ SyMenuDto dto = new SyMenuDto(); BeanUtils.copyProperties(v,dto); dto.setResourceId(v.getResourceId()); dto.setId(v.getId()); dto.setParentId(v.getParentId()); return dto; }).collect(Collectors.toList()); return dtos; } }
public class SetResourceToMenuList implements Handler, List
> { @Override public List process(List input) { if (CollectionUtils.isEmpty(input)){ return Collections.emptyList(); } ResourceMapper resourceMapper = SpringApplicationUtils.getBean(ResourceMapper.class); for (SyMenuDto dto : input){ if (dto.getResourceId() != null && dto.getResourceId() != -1){ SyResource resource = resourceMapper.selectById(dto.getResourceId()); if (resource != null){ dto.setResourceName(resource.getResourceName()); } } } return input; } }
@Slf4j public class AddRecouceButtonToMenuList implements Handler, List
> { @Override public List process(List input) { ResourceMapper resourceMapper = SpringApplicationUtils.getBean(ResourceMapper.class); if (CollectionUtils.isEmpty(input)){ return Collections.emptyList(); } List resourceIds = input.stream().filter(v -> v.getResourceId() != null).map(v -> v.getResourceId()).collect(Collectors.toList()); if (CollectionUtils.isEmpty(resourceIds)){ return Collections.emptyList(); } List newMenuDto = Lists.newArrayList(); newMenuDto.addAll(input); Map > resouceUseMenuIds = getResouceUseMenuIds(input); List resouces = resourceMapper.selectBatchIds(resourceIds); for (SyResource resource : resouces){ QueryWrapper qw = Wrappers.query().eq("parent_id",resource.getId()).eq("resource_type","button"); List buttonResouces = resourceMapper.selectList(qw); if (CollectionUtils.isEmpty(buttonResouces)){ continue; } List menuIds = resouceUseMenuIds.get(resource.getId()); if (CollectionUtils.isEmpty(menuIds)){ continue; } for (Integer parentId : menuIds){ double i = 0; for (SyResource br : buttonResouces){ SyMenuDto bn = new SyMenuDto(); BeanUtils.copyProperties(br,bn); bn.setParentId(parentId); bn.setMenuName(br.getResourceName()); bn.setMenuType("button"); bn.setSortNum(i); bn.setWatermark(0); bn.setResourceId(br.getId()); newMenuDto.add(bn); i++; } } } return newMenuDto; } private Map > getResouceUseMenuIds(List input){ //标识资源拥有菜单 Map > resouceUseMenuIds = Maps.newHashMap(); for (SyMenuDto md : input){ List l = resouceUseMenuIds.get(md.getResourceId()); if (l == null){ l = new ArrayList<>(); resouceUseMenuIds.put(md.getResourceId(),l); } l.add(md.getId()); } return resouceUseMenuIds; } }
public class CheckMenuResoucePerimissionList implements Handler, List
> { @Override public List process(List input) { if(CollectionUtils.isEmpty(input)){ return Collections.emptyList(); } Handler > handler = new MenuResouceQueryList(MenuResoucePerimissionDataList.QUERY_PERIMISSION_BACK); Pipeline pipeline = new Pipeline<>(handler); List list = (List ) pipeline.execute(null); if (CollectionUtils.isNotEmpty(list)){ Map map = list.stream().distinct().collect(Collectors.toMap(v -> v.getId(), v ->v)); input.stream().forEach(v ->{ if (!StringUtils.equals(v.getMenuType(),"page")){ v.setIsUsePerimission(true); }else { SyResourceDto syResourceDto = map.get(v.getResourceId()); if (syResourceDto != null){ v.setIsUsePerimission(true); } } }); } return input; } }
public class MenuListToTree implements Handler, List
> { @Override public List process(List input) { List treeModels = AbstarctGenerateTree.buidTree(input); return treeModels; } }
public static void main(String[] args) {
String menuSource = "";
Handler> handler = new QueryMenuList();
Pipeline pipeline = new Pipeline<>(handler)
// .addHandler(new RecursionParentMenuList())
.addHandler(new MenuEntityToMenuDtoList())
.addHandler(new SetResourceToMenuList())
.addHandler(new AddRecouceButtonToMenuList())
.addHandler(new CheckMenuResoucePerimissionList())
.addHandler(new MenuListToTree());
List treeModels = (List) pipeline.execute(menuSource);
}
特殊需求扩展代码
继承Pipeline重新Pipeline内部方法before
public class EditResouceMenuPipeline extends Pipeline {
private final Handler currentHandler;
public EditResouceMenuPipeline(Handler currentHandler) {
super(currentHandler);
this.currentHandler = currentHandler;
}
@Override
public EditResouceMenuPipeline addHandler(Handler newHandler) {
return new EditResouceMenuPipeline<>(input -> newHandler.process(currentHandler.process(input)));
}
@Override
public boolean before(Object o) {
SyResource resource = (SyResource) o;
boolean b = checkEdit(resource);
if (b) {
throw BusinessException.withErrorMessage(resource.getResourceName() + ":已存在");
}
return false;
}
private boolean checkEdit(SyResource syResource) {
ResourceMapper resourceMapper = SpringApplicationUtils.getBean(ResourceMapper.class);
QueryWrapper qw = Wrappers.query()
.eq("resource_name", syResource.getResourceName())
.eq("resource_type", ResourceServiceImpl.RESOURCE_TYPE_PAGE)
.eq("service_id", CurrentUserContext.getServiceId());
SyResource selectOne = resourceMapper.selectOne(qw);
if (selectOne != null) {
boolean flag = true;
if (syResource.getId() != null && ObjectUtils.equals(selectOne.getId(), syResource.getId())) {
flag = false;
}
return flag;
}
return false;
}
}
public Integer save(SyResource resource) {
Handler handler = new EditAppIcon();
Pipeline pipeline = new EditResouceMenuPipeline<>(handler)
.addHandler(new EditMenuName())
.addHandler(new EditWebIcon())
.addHandler(new EditMenuResouce());
if (pipeline.before(resource)) {
throw BusinessException.withErrorMessage(resource.getResourceName() + ":已存在");
}
Integer id = (Integer) pipeline.execute(resource);
return id ;
}



