【Java】金蝶数据推送设计

发布时间 2023-04-19 17:35:03作者: emdzz

 

金蝶系统的数据控制

先说金蝶对数据的几个状态控制:

新增一个凭证还是基础数据也好,都需要经过(保存 -> 提交 -> 审核)

同样的,如果要删除一条记录,需要(反审核 -> 删除)

我们系统的数据,推送到金蝶系统中,就要经历上述的3个步骤

然后还要支持可以重复推送,那就要先去操作前面的反审核和删除

所以一个推送就包括了5个步骤, 一份数据,调用五次接口

 

接口规律抽象

我们自己的业务功能可以和金蝶系统的业务功能进行一个关联,所有业务都可以被抽象出来统一管理,例如:

推送员工信息,项目信息,财务报销单...等等

老板的意思是集中在一个功能里面做推送,所有业务都放在其中,对选中的记录进行推送

对于行为的抽象,我的理解只有两件事情

- 这个业务需要翻页查询 

- 这个业务需要推送数据

于是我就定义了一个关于金蝶推送的行为接口,我更愿意称为一个“规范”

因为只有遵守规范的服务才能够正确的执行具体内容

package cn.hyite.amerp.system.push.manage.service;

import cn.hyite.amerp.system.push.kingdee.config.KingdeeApiSettings;
import com.baomidou.mybatisplus.core.metadata.IPage;

import java.util.Map;

/**
 * 业务推送管理规范
 * @author Cloud9
 * @version 1.0
 * @project amerp-server
 * @date 2023年03月11日 15:16
 */
public interface PushManageService {

    /* 业务标识 */
    String businessIdent();

    /* 翻页数据 */
    IPage<? extends Object> getPushDataPage(String json);

    /* 推送数据 */
    Map<String, Object> pushData(Map<String, Object> pushParam, KingdeeApiSettings settings);
}

 

在仔细查看其中推送接口的描述后发现,除了保存接口,其它接口只需要提供编号参数即可

也就是说,除了保存接口,其它接口在封装参数的方法上还是一样的

所以这里又有第二层规范,关于推送数据的规范:

package cn.hyite.amerp.system.push.manage.service;

import java.io.Serializable;

/**
 * 具体推送行为规范
 * @author Cloud9
 * @version 1.0
 * @project amerp-server
 * @date 2023年03月15日 14:15
 */
public interface PushStrategy {

    /* 业务标识 */
    String businessIdent();

    /* 获取保存操作的JSON参数 */
    String getSaveOperateFormJson(Serializable businessId);

    /* 获取提交操作的JSON参数 */
    String getSubmitOperateFormJson(Serializable businessId);

    /* 获取审核操作的JSON参数 */
    String getAuditOperateFormJson(Serializable businessId);

    /* 获取反审核操作的JSON参数 */
    String getUnAuditOperateFormJson(Serializable businessId);

    /* 获取删除操作的JSON参数 */
    String getDeleteOperateFormJson(Serializable businessId);
}

  

先解决页面翻页查询的问题:

每个业务实现翻页具体的逻辑,每个业务需要有自己唯一的业务标识

 

Controller控制器Bean只需要根据业务标识来知晓哪个服务Bean是具体要调用的

这是识别方法:

/**
  * @author Cloud9
  * @date 2023/3/11 15:47
  * @description 通过Spring类型集中注入推送的服务对象,根据设置的业务标识获取对应实例
  * @params [businessIdent]
  * @return cn.hyite.amerp.system.push.manage.service.PushManageService
  */
private PushManageService getSpecificInstance(final String businessIdent) {
    PushManageService pushManageService = pushManageServices.stream().filter(pm -> pm.businessIdent().equals(businessIdent)).findFirst().orElse(null);
    Assert.isTrue(Objects.isNull(pushManageService), ResultMessage.CUSTOM_ERROR, "没有这个业务的推送管理Bean! [" + businessIdent + "]");
    return pushManageService;
}

控制器通过Spring的自动装配@Autowired进行注入:

@Autowired
private List<PushManageService> pushManageServices;

接口方法:

/**
  * @author OnCloud9
  * @date 2023/3/11 15:45
  * @description 推送记录翻页查询
  * @params [businessIdent, json]
  * @return com.baomidou.mybatisplus.core.metadata.IPage<? extends java.lang.Object>
  */
@PostMapping("/{businessIdent}/page")
public PageResult<?> getPushDataPage(@PathVariable("businessIdent") final String businessIdent, @RequestBody final String json) {
    /* 推送业务的服务实例是否存在 */
    final PushManageService specificInstance = getSpecificInstance(businessIdent);
    return PageResult.toPageResult(specificInstance.getPushDataPage(json));
}

  

解决推送问题:

1、之前组长写过一版,太复杂了,使用抽象类来耦合公共部分,抽象部分就用抽象方法调用,但是我们都知道Java对多继承是不支持的

一个类只能有一个父类,我的开发经验认为是不用抽象类继承,而是接口来实现,因为抽象类对业务理解是不友好的,限制了服务类的继承

基于这几点内容,我对组长的推送逻辑进行了一个重构,不用抽象类,改为【处理器Bean】来完成

处理器Bean提供推送方法完成