统一回传入口
(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);
}
}