回传结构(基于观察者模式+spring事件机制)

在这里插入图片描述
统一回传入口
(1)getCallBackHandlerByBiz():根据业务系统获取callBackHandler
(2)callBack():
A、调用getCallBackHandlerByBiz()
B、将标准的msgType 转成对应的业务消息类型
C、根据消息类型拿到对应的回传处理器【这个回传处理器的先构建消息对象,再保存日志,最后再调用callBackHandler; 】
D、执行callBackHandler的execute

在这里插入图片描述
1、监听spring的事件【上下文已经准备完毕】,将某一种类放进map里
2、CallbackHandlerContext 和 CallbackMessageContext 都是从上面的map中根据业务类型或消息类型获取相应的handler和 回传处理器

在这里插入图片描述
回传处理器 是 继承于AbstractPushEventMessageCallback【为了公用方法有默认的实现】,而 AbstractPushEventMessageCallback 实现了 IPushEventMessageCallback 接口【为了私有方法各自实现】

1、PushEventMessageCallbackHelper——统一回传入口

@Slf4j
@Component
@Lazy
public class PushEventMessageCallbackHelper {

    @Resource
    private CallbackMessageContext callbackContext;

    @Resource
    private CallbackHandlerContext callbackHandlerContext;

    /**
     * 统一回传入口
     *
     * @param event 消息类型,bizNo   包裹唯一编码、或者容器唯一编码、装载计划唯一编码
     */
    @Async("callbackTaskExecutor")
    public void  callBack(PushEvent<?> event) {

        if (null == event || StringUtils.isEmpty(event.getBizNo()) || null == event.getPushEventMsgType() || null == event.getBizSystem()) {
            log.error("参数异常,参数信息:{}", new Object[]{JSON.toJSONString(event)});
            throw new BusinessRuntimeException(ExceptionCode.System.PARAM_VALIDA_ERROR, "参数不能为空.");
        }
        try {
            ICallbackHandler callbackHandler = getCallBackHandlerByBiz(event.getBizSystem());
            // 将标准的msgType 转成对应的业务消息类型
            String bizSysMsgType = BizSysAndMsgTypeMappingRelation.getBizSysMsgType(event.getBizSystem(), event.getPushEventMsgType().getType());
            AbstractPushEventMessageCallback pushEventMessageCallback = callbackContext.getPushEventCallback(bizSysMsgType);
            pushEventMessageCallback.execute(callbackHandler, event);
        } catch (Exception e) {
            log.error("回传上游系统异常,报文:{},异常信息:{}", JSON.toJSONString(event), e.getMessage());
        }
    }

    /**
     * 根据业务系统获取callBackHandler
     *
     * @param biz 业务系统
     * @return 对应系统的callBackHandler
     */
    public ICallbackHandler getCallBackHandlerByBiz(String biz) {
        return callbackHandlerContext.getCallbackHandler(biz);
    }
}

2、CallbackListener——spring事件监听器

@Component
@Slf4j
public class CallbackListener implements ApplicationListener<ApplicationReadyEvent> {


    @Override
    public void onApplicationEvent(ApplicationReadyEvent applicationPreparedEvent) {

        ConfigurableApplicationContext applicationContext = applicationPreparedEvent.getApplicationContext();
        ConfigurableListableBeanFactory listableBeanFactory = applicationContext.getBeanFactory();

        Map<String, ICallbackHandler> callbackHandlerMap = new HashMap<>(36);
        Map<String, ICallbackHandler> callbackHandlerBeanMap = applicationContext.getBeansOfType(ICallbackHandler.class);

        if (MapUtils.isEmpty(callbackHandlerBeanMap)) {
            log.error("初始化回传服务异常.");
        }
        callbackHandlerBeanMap.forEach((clazzName, callback) -> {
            CallbackHandler chAnnotation = callback.getClass().getAnnotation(CallbackHandler.class);
            String bizType = chAnnotation.bizSystem().getSystem();
            if (chAnnotation.active()) {
                callbackHandlerMap.put(bizType, callback);
            }
        });

        CallbackHandlerContext callbackHandlerContext = new CallbackHandlerContext(callbackHandlerMap);
        listableBeanFactory.registerSingleton(CallbackHandlerContext.class.getName(), callbackHandlerContext);

        // 将所有的回传服务保存到map中
        Map<String, AbstractPushEventMessageCallback<?, ?>> callbackMap = new HashMap<>(36);
        Map<String, AbstractPushEventMessageCallback> contextBeanMap = applicationContext.getBeansOfType(AbstractPushEventMessageCallback.class);

        if (MapUtils.isEmpty(contextBeanMap)) {
            log.error("初始化回传消息封装器服务异常.");
        }
        contextBeanMap.forEach((clazzName, callback) -> {
            String bizType = callback.getClass().getAnnotation(CallbackMessage.class).msgType().getType();
            callbackMap.put(bizType, callback);
        });
        CallbackMessageContext callbackMessageContext = new CallbackMessageContext(callbackMap);
        listableBeanFactory.registerSingleton(CallbackMessageContext.class.getName(), callbackMessageContext);


        // 裹裹回传消息消费逻辑
        Map<String, IPushEventHandler> pushEventHandlerMap = new HashMap<>(36);
        Map<String, IPushEventHandler> pushEventHandleBeanMap = applicationContext.getBeansOfType(IPushEventHandler.class);
        if (MapUtils.isEmpty(pushEventHandleBeanMap)) {
            log.error("初始化裹裹消息处理器异常.");
        }

        pushEventHandleBeanMap.forEach((clazzName, callback) -> {
            String eventType = callback.getClass().getAnnotation(PushEventHandler.class).eventType().getType();
            pushEventHandlerMap.put(eventType, callback);
        });
        PushEventHandlerContext pushEventHandlerContext = new PushEventHandlerContext(pushEventHandlerMap);
        listableBeanFactory.registerSingleton(PushEventHandlerContext.class.getName(), pushEventHandlerContext);
    }

}

3、CallbackMessageContext—— 获取生成报文对象处理器

public class CallbackMessageContext {

    /**
     * 业务类型,回传处理类
     */
    private Map<String, AbstractPushEventMessageCallback<?, ?>> callbackMap;


    public CallbackMessageContext(Map<String, AbstractPushEventMessageCallback<?, ?>> callbackMap) {
        this.callbackMap = callbackMap;
    }

    /**
     * 获取生成报文对象处理器
     *
     * @param msgType 消息类型
     * @return 消息报文生成器
     * @throws IllegalArgumentException 对应报文生成器不存在
     */
    AbstractPushEventMessageCallback<?, ?> getPushEventCallback(String msgType) throws IllegalArgumentException {

        if (callbackMap == null) {
            throw new BeanInitializationException("callback initialization exception");
        }
        if (null == msgType) {
            // msgType mapping has not been yet configured.
            throw new IllegalArgumentException("msgType does not empty.");
        }
        AbstractPushEventMessageCallback<?, ?> callback = callbackMap.get(msgType);
        if (callback == null) {
            throw new IllegalArgumentException("not found callback handler for msgType:" + msgType);
        }
        return callback;
    }
}

4、CallbackHandlerContext—— 获取消息回传处理器

public class CallbackHandlerContext {

    /**
     * 业务类型,回传处理类
     */
    private Map<String, ICallbackHandler> callbackHandlerMap;


    public CallbackHandlerContext(Map<String, ICallbackHandler> callbackHandlerMap) {
        this.callbackHandlerMap = callbackHandlerMap;
    }

    /**
     * 获取生成报文对象处理器
     *
     * @param bizSystem 业务系统代码
     * @return 消息回传处理器
     * @throws IllegalArgumentException 消息回传处理器没有定义
     */
    public ICallbackHandler getCallbackHandler(String bizSystem) throws IllegalArgumentException {

        if (callbackHandlerMap == null) {
            throw new BeanInitializationException("callback initialization exception");
        }
        ICallbackHandler callbackHandler = callbackHandlerMap.get(bizSystem);
        if (callbackHandler == null) {
            throw new IllegalArgumentException("not found callback handler for bizSystem:" + bizSystem);
        }
        return callbackHandler;
    }
}

5、自定义注解 CallbackHandler

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface CallbackHandler {

    /**
     * 业务系统,对应系统dataSource
     *
     * @return 业务系统编码
     */
    EnumBizSystem bizSystem();

    /**
     * 实现方式还有待完善
     * 处理方式: http mq etc
     *
     * @return handler type
     */
    String type();

    /**
     * 是否有效,默认有效
     *
     * @return true 有效,false 无效
     */
    boolean active() default true;
}

6、自定义注解 CallbackHandler 的使用

@Slf4j
@Component("aeCallbackHandler")
@CallbackHandler(bizSystem = EnumBizSystem.AE, type = "SYNC")
public class AeCallbackHandler implements ICallbackHandler {

    @Resource
    private AeProperties aeProperties;

    @Resource
    private IMqProvider pmsMqProvider;

    @Override
    public AbstractResult callback(PmsCallbackMessage<?> message) {

        if (log.isDebugEnabled()) {
            log.debug("回传操作信息到菜鸟系统,原始报文{}", JSON.toJSONString(message, true));
        }
        AeMessage aeMessage = new AeMessage();
        aeMessage.setMsgType(message.getMsgType());
        // 对菜鸟原始报文统一签名
        String msgDataStr = JaxBeanAndXmlConvertUtils.bean2Xml(message.getMsgData());
        aeMessage.setDataDigest(Md5Utils.encodeMd5Digest(msgDataStr + aeProperties.getSecretKey()));
        aeMessage.setBizNo(message.getEvent().getAttribute("bizPrimaryKey"));
        aeMessage.setLogisticsInterface(msgDataStr);
        // 这里是xms定义的类型,根据菜鸟消息类型,转换成xms消息类型
        aeMessage.setEventType(EnumXmsEventType.getXmsEventType(message.getMsgType()));
        aeMessage.setOgCode(aeProperties.getCpCode());
        if (log.isDebugEnabled()) {
            log.debug("回传操作信息到菜鸟系统,封装后报文{}", JSON.toJSONString(aeMessage, true));
        }
        pmsMqProvider.send(QueueConstants.ExchangeName.PICKUP_HANDOVER_CALLBACK_INFO, QueueConstants.RoutingKey.PICKUP_HANDOVER_CALLBACK_INFO, aeMessage);
        return new PmsCallbackResult.Builder().success().create();
    }
}

7、自定义注解CallbackMessage

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface CallbackMessage {
    /**
     * 回传消息类型
     *
     * @return 回传消息类型
     */
    EnumPushEventMsgType msgType();

    /**
     * 消息描述信息
     *
     * @return 消息描述信息
     */
    String desc();
}

8、自定义注解CallbackMessage的使用

@Slf4j
@Component
@CallbackMessage(msgType = EnumPushEventMsgType.PMS_GUOGUO_PACKAGE_PICKUP_FINISH_CALLBACK, desc = "包裹揽收完结事件回传")
public class GuoGuoPackageFINPushEventMessage extends AbstractPushEventMessageCallback<PushEvent<?>, GuoGuoPackageFINMessage> {

    @Resource
    private IContainerService containerService;

    @Override
    public PmsCallbackMessage<GuoGuoPackageFINMessage> buildPushEventMessage(PushEvent<?> event) throws BusinessRuntimeException {
        log.info("GuoGuo包裹揽收完结事件回传结果:{},开始封装回传信息.", event.getAttribute("opCode"));

        ContainerExt containerExt = containerService.getContainerDetail(event.getBizNo());
        if (null == containerExt) {
            throw new BusinessRuntimeException(ExceptionCode.Biz.CONTAINER_DOES_NOT_EXIST, "容器信息不存在.");
        }
        // 补充event信息
        event.addAttribute("bizPrimaryKey", containerExt.getContainerNo());
        // 封装回传消息体
        GuoGuoPackageFINMessage finMessage = new GuoGuoPackageFINMessage();
        PmsCallbackMessage<GuoGuoPackageFINMessage> callbackMessage = new PmsCallbackMessage<>(EnumPushEventMsgType.PMS_GUOGUO_PACKAGE_PICKUP_FINISH_CALLBACK.getType(), event);
        callbackMessage.setMsgData(finMessage);
        finMessage.setContainerNo(containerExt.getContainerNo());
        finMessage.setTrackingNumber(containerExt.getTrackingNumber());
        finMessage.setPickupHandoverNo(containerExt.getPickupHandoverNo());
        finMessage.setCode(event.getAttribute("opCode"));
        finMessage.setDesc(event.getAttribute("desc"));
        finMessage.setOperator(event.getOperator());
        finMessage.setOpTime(DateTimeUtil.formatTime(event.getOpTime(), CharacterConstant.Date.TIME_PATTERN_TRACK));
        finMessage.setTimeZone(8);
        finMessage.setMailNo(event.getAttribute("mailNo"));
        finMessage.setTrackingNumber(event.getAttribute("mailNo"));
        if (isNotBlank(event.getAttribute("courierAdjustFee"))) {
            finMessage.setCourierAdjustFee(Long.valueOf(event.getAttribute("courierAdjustFee")));
        }
        finMessage.setLogisticsCompanyCode(event.getAttribute("logisticsCompanyCode"));
        finMessage.setLogisticsCompanyName(event.getAttribute("logisticsCompanyName"));
        if (isNotBlank(event.getAttribute("totalPrice"))) {
            finMessage.setTotalPrice(Long.valueOf(event.getAttribute("totalPrice")));
        }
        if (isNotBlank(event.getAttribute("weight"))) {
            finMessage.setWeight(Long.valueOf(event.getAttribute("weight")));
        }
        if (isNotBlank(event.getAttribute("basePrice"))) {
            finMessage.setBasePrice(Long.valueOf(event.getAttribute("basePrice")));
        }
        if (log.isDebugEnabled()) {
            log.debug("GuoGuo包裹揽收完结事件回传结果,封装信息:{}", JSON.toJSONString(finMessage, true));
        }
        return callbackMessage;
    }

9、AbstractPushEventMessageCallback

@Slf4j
public abstract class AbstractPushEventMessageCallback<E extends AbstractEvent, T> implements IPushEventMessageCallback<E, T> {

    @Resource
    private IPushEventService pushEventService;

    /**
     * 回传信息给上游系统
     *
     * @param handler 处理请求handler
     * @param event   event
     */
    void execute(ICallbackHandler handler, E event) {
        PmsCallbackMessage<?> message = buildPushEventMessage(event);
        saveCallbackEvent(event, message);
        handler.callback(message);
    }

    /**
     * 保存回传消息到mongodb
     *
     * @param event   event
     * @param message 回传消息
     */
    void saveCallbackEvent(E event, PmsCallbackMessage<?> message) {
        CallbackEvent callbackEvent = new CallbackEvent();
        callbackEvent.setBizPrimaryKey(message.getEvent().getAttribute("bizPrimaryKey"));
        callbackEvent.setBizSystem(event.getBizSystem());
        callbackEvent.setCreateTime(new Date());
        callbackEvent.setRequestTime(new Date());
        String standardMsgType = BizSysAndMsgTypeMappingRelation.getStandardMsgType(event.getBizSystem(), message.getMsgType());
        callbackEvent.setMsgType(standardMsgType);
        callbackEvent.setMsgData(message.getMsgData());
        callbackEvent.setTimes(1);
        callbackEvent.setStatus(CharacterConstant.Char.CHAR_P);
        pushEventService.save(callbackEvent);
    }

    /**
     * 回传响应结果处理
     *
     * @param handler 各个业务系统处理逻辑
     * @param result  报文信息和上游返回信息
     * @throws BusinessRuntimeException 产生的业务异常
     */
    @Override
    public void afterExecute(ICallbackHandler handler, AbstractResult result) throws BusinessRuntimeException {

    }
}

10、IPushEventMessageCallback

public interface IPushEventMessageCallback<E extends AbstractEvent, T> {

    /**
     * 生成回传消息
     *
     * @param event 回传Event bizNo 包裹号、或者容器号
     * @return 需要回传的报文信息
     * @throws BusinessRuntimeException 业务处理异常
     */
    PmsCallbackMessage<T> buildPushEventMessage(E event) throws BusinessRuntimeException;

    /**
     * 回传完成后处理后续业务逻辑
     *
     * @param handler 各个业务系统处理逻辑
     * @param result  报文信息和上游返回信息
     * @throws BusinessRuntimeException 业务处理异常
     */
    void afterExecute(ICallbackHandler handler, AbstractResult result) throws BusinessRuntimeException;
}

11、PmsCallbackMessage——PMS 回传上游标准消息格式

@Getter
@Setter
public class PmsCallbackMessage<T> implements Serializable {

    private static final long serialVersionUID = -1553043539351154484L;

    /**
     * 消息类型,用来区分回传的是什么信息
     */
    private String msgType;

    /**
     * 消息内容
     */
    private T msgData;

    /**
     * 触发事件信息
     */
    private PushEvent<?> event;

    public PmsCallbackMessage() {
    }

    public PmsCallbackMessage(String msgType, PushEvent<?> event) {

        this.msgType = msgType;
        this.event = event;
    }
}

12、PushEvent

@Getter
@Setter
public class PushEvent<T> extends AbstractEvent {
    /**
     * 业务单号
     */
    private String bizNo;

    /**
     * 消息类型
     */
    private EnumPushEventMsgType pushEventMsgType;

    /**
     * 业务数据,例如大包
     */
    private T bizEntity;

    public PushEvent() {
    }

    public PushEvent(EnumPushEventMsgType pushEventMsgType) {
        this.pushEventMsgType = pushEventMsgType;
    }
}

13、AbstractEvent

@Data
public abstract class AbstractEvent {

    /**
     * 操作人员工号
     */
    private String opCode;
    /**
     * 操作人姓名
     */
    private String operator;
    /**
     * 操作时间
     */
    private Date opTime;
    /**
     * 业务操作源
     */
    private EnumBizEventSourceType bizEventSourceType;
    /**
     * 业务系统
     */
    private String bizSystem;
    /**
     * 其他属性
     */
    private Map<String, String> attribute;

    /**
     * 增加额外属性
     *
     * @param key   key
     * @param value value
     */
    public void addAttribute(String key, String value) {
        if (null == attribute) {
            attribute = new HashMap<>();
        }
        attribute.put(key, value);
    }

    /**
     * 获取属性
     *
     * @param key key
     * @return 属性值
     */
    public String getAttribute(String key) {
        if (null == attribute) {
            return "";
        }
        return attribute.get(key);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值