spring-rabbitmq.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/rabbit
http://www.springframework.org/schema/rabbit/spring-rabbit-2.0.xsd">
<!-- 连接配置 -->
<rabbit:connection-factory id="connectionFactory" host="${rabbitmq.host}" port="${rabbitmq.port}" username="${rabbitmq.username}" password="${rabbitmq.password}" />
<rabbit:admin connection-factory="connectionFactory" />
<!-- 消息对象json转换类 -->
<bean id="jsonMessageConverter" class="org.springframework.amqp.support.converter.SimpleMessageConverter" />
<!-- ===========================================OMS mq队列配置 START=========================================== -->
<rabbit:template exchange="PUSH_WMS_DIRECT_EXCHANGE" id="omsAmqpTemplate" connection-factory="connectionFactory" message-converter="jsonMessageConverter" />
<!-- oms推单队列 -->
<rabbit:queue id="PUSH_WMS_ORDER" name="PUSH_WMS_ORDER" durable="true" auto-delete="false" exclusive="false" />
<!-- wms消费oms推单队列成功后通知oms不需要继续推送apv消息队列 -->
<rabbit:queue id="PUSH_SALE_ORDER_RESULT" name="PUSH_SALE_ORDER_RESULT" durable="true" auto-delete="false" exclusive="false" />
<!-- 仓库状态改变推送销售平台 -->
<rabbit:queue id="PUSH_SALE_STATUS_CHANGE" name="PUSH_SALE_STATUS_CHANGE" durable="true" auto-delete="false" exclusive="false" />
<!-- 仓库包装流程推送销售平台 -->
<rabbit:queue id="PUSH_SALE_PACK_STEP" name="PUSH_SALE_PACK_STEP" durable="true" auto-delete="false" exclusive="false" />
<!-- wms推送国内快递单号 -->
<rabbit:queue id="PUSH_SALE_INLAND_EXPRESS_ORDER_NUMBER" name="PUSH_SALE_INLAND_EXPRESS_ORDER_NUMBER" durable="true" auto-delete="false" exclusive="false" />
<!-- wms推送交运图片 -->
<rabbit:queue id="PUSH_SALE_PACKAGE_PIC_URL" name="PUSH_SALE_PACKAGE_PIC_URL" durable="true" auto-delete="false" exclusive="false" />
<!-- oms交换机 -->
<rabbit:direct-exchange id="PUSH_WMS_DIRECT_EXCHANGE" name="PUSH_WMS_DIRECT_EXCHANGE" durable="true" auto-delete="false">
<rabbit:bindings>
<rabbit:binding queue="PUSH_WMS_ORDER" key="PUSH_WMS_ORDER" />
<rabbit:binding queue="PUSH_SALE_ORDER_RESULT" key="PUSH_SALE_ORDER_RESULT" />
<rabbit:binding queue="PUSH_SALE_STATUS_CHANGE" key="PUSH_SALE_STATUS_CHANGE" />
<rabbit:binding queue="PUSH_SALE_PACK_STEP" key="PUSH_SALE_PACK_STEP" />
<rabbit:binding queue="PUSH_SALE_INLAND_EXPRESS_ORDER_NUMBER" key="PUSH_SALE_INLAND_EXPRESS_ORDER_NUMBER" />
<rabbit:binding queue="PUSH_SALE_PACKAGE_PIC_URL" key="PUSH_SALE_PACKAGE_PIC_URL" />
</rabbit:bindings>
</rabbit:direct-exchange>
<!-- ===========================================OMS mq队列配置 END=========================================== -->
<!-- =========================================== FMS mq队列配置 START =========================================== -->
<rabbit:template exchange="DIRECT_EXCHANGE" id="fmsAmqpTemplate" connection-factory="connectionFactory" message-converter="jsonMessageConverter" />
<rabbit:queue id="OTHER_FMS_SKU_CRUD_QUEUE" name="OTHER_FMS_SKU_CRUD_QUEUE" durable="true" auto-delete="false" exclusive="false" />
<rabbit:direct-exchange id="DIRECT_EXCHANGE" name="DIRECT_EXCHANGE" durable="true" auto-delete="false">
<rabbit:bindings>
<rabbit:binding queue="OTHER_FMS_SKU_CRUD_QUEUE" key="OTHER_FMS_SKU_CRUD_KEY" />
</rabbit:bindings>
</rabbit:direct-exchange>
<!-- =========================================== FMS mq队列配置 END =========================================== -->
<!-- =========================================== PMS mq队列配置 START =========================================== -->
<rabbit:template exchange="PMS_WMS_DIRECT_EXCHANGE" id="pmsAmqpTemplate" connection-factory="connectionFactory" message-converter="jsonMessageConverter" />
<!-- pms消息发送队列 -->
<rabbit:queue id="PMS_WH_EXCEPTION_PMS_QUEUE" name="PMS_WH_EXCEPTION_PMS_QUEUE" durable="true" auto-delete="false" exclusive="false" />
<!-- wms消息发送队列 -->
<rabbit:queue id="PMS_WH_EXCEPTION_WMS_QUEUE" name="PMS_WH_EXCEPTION_WMS_QUEUE" durable="true" auto-delete="false" exclusive="false" />
<rabbit:direct-exchange id="PMS_WMS_DIRECT_EXCHANGE" name="PMS_WMS_DIRECT_EXCHANGE" durable="true" auto-delete="false">
<rabbit:bindings>
<rabbit:binding queue="PMS_WH_EXCEPTION_WMS_QUEUE" key="PMS_WH_EXCEPTION_WMS_QUEUE" />
</rabbit:bindings>
</rabbit:direct-exchange>
<!-- =========================================== PMS mq队列配置 END =========================================== -->
<!-- queues:监听的队列,多个的话用逗号(,)分隔 ref:监听器 。配置监听 acknowledeg = "manual" 设置手动应答 当消息处理失败时:会一直重发 直到消息处理成功 -->
<rabbit:listener-container connection-factory="connectionFactory" acknowledge="manual">
<!-- OMS推单wms消费监听 -->
<!-- <rabbit:listener queues="PUSH_WMS_ORDER" ref="omsPushApvQueueListener" /> -->
<!-- PMS推送异常消息至wms消费监听 -->
<!-- <rabbit:listener queues="PMS_WH_EXCEPTION_PMS_QUEUE" ref="pmsPushCheckInExceptionQueueListener" /> -->
</rabbit:listener-container>
</beans>
handle
import java.io.IOException;
import org.apache.log4j.Logger;
import org.springframework.amqp.core.Message;
import org.springframework.stereotype.Service;
import com.rabbitmq.client.Channel;
@Service("serviceMessageHandle")
public class ServiceMessageHandle {
private Logger logger = Logger.getLogger(ServiceMessageHandle.class);
/**
* @Title: basicACK
* @Description: 正常消费掉后通知mq服务器移除此条mq
* @Date 2018年12月28日_下午5:00:00
* @param message
* @param channel
*/
public void basicACK(Message message, Channel channel) {
try {
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
catch (IOException e) {
logger.error(message.getMessageProperties().getConsumerQueue() + "消费成功,通知服务器移除mq时异常,异常信息:" + e);
}
}
/**
* @Title: basicNACK
* @Description: 处理异常,mq重回队列
* @Date 2018年12月28日_下午5:00:15
* @param message
* @param channel
*/
public void basicNACK(Message message, Channel channel) {
try {
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
}
catch (IOException e) {
logger.error(message.getMessageProperties().getConsumerQueue() + "消费失败,mq重新进入服务器时出现异常,异常信息:" + e);
}
}
listener
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.json.JSONObject;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.estone.apv.bean.WhApv;
import com.estone.apv.bean.WhApvItem;
import com.estone.apv.bean.WhApvQueryCondition;
import com.estone.apv.common.ApvStatus;
import com.estone.apv.service.WhApvItemService;
import com.estone.apv.service.WhApvService;
import com.estone.sku.bean.WhSku;
import com.estone.sku.bean.WhSkuQueryCondition;
import com.estone.sku.service.WhSkuService;
import com.estone.system.rabbitmq.common.RabbitmqListenerSqlInit;
import com.estone.system.rabbitmq.handle.ServiceMessageHandle;
import com.estone.system.rabbitmq.model.PushOrderResultMessage;
import com.estone.system.rabbitmq.producer.RabbitmqProducerService;
import com.rabbitmq.client.Channel;
/**
* @ClassName: OmsPushApvQueueListener
* @Description: oms推单消费者监听器
* @Author huzy
* @Date 2018年12月31日
*/
@Component("omsPushApvQueueListener")
public class OmsPushApvQueueListener extends MessageListenerAdapter {
private Logger logger = Logger.getLogger(OmsPushApvQueueListener.class);
private boolean isInit = false;
@Resource
private WhApvService whApvService;
@Resource
private WhApvItemService whApvItemService;
@Resource
private WhSkuService whSkuService;
@Resource
private ServiceMessageHandle serviceMessageHandle;
@Resource
private RabbitmqProducerService rabbitmqProducerService;
@Override
public void onMessage(Message message, Channel channel) throws Exception {
// 校验容器加载时所有bean是否均已实例化
if (!isInit) {
RabbitmqListenerSqlInit.validateSqlerInit(this.getClass());
this.isInit = true;
}
// 获取消息体
String body = new String(message.getBody(), "UTF-8");
logger.warn("omsPushApvQueueListener message body -> " + body);
// 回传PMS消息体
PushOrderResultMessage returnMessage = new PushOrderResultMessage();
// 业务处理
doService(body, returnMessage);
// 一次性消费,移除队列
serviceMessageHandle.basicACK(message, channel);
// 处理结果回传oms
rabbitmqProducerService.notifyOmsOnPushOrder(returnMessage);
}
/**
* @Title: doService
* @Description: oms推单业务处理
* @Date 2019年1月3日_上午9:26:47
* @param body 消息体
* @param returnMessage
* @return
*/
public boolean doService(String body, PushOrderResultMessage returnMessage) {
try {
JSONObject obj = new JSONObject(body);
String jsonBody = obj.getString("body");
if (StringUtils.isBlank(jsonBody)) {
returnMessage.setStatus(false);
returnMessage.setApvNo(null);
returnMessage.setDdNo(null);
returnMessage.setPushTime(null);
returnMessage.setMessage("消息体为空");
return false;
}
WhApv whApv = JSON.parseObject(jsonBody, WhApv.class);
/** 若有相同的apvNo,则认为oms推单成功。 相同平台订单号的单pms和oms不可同时推送 */
WhApvQueryCondition query = new WhApvQueryCondition();
query.setApvNo(whApv.getApvNo());
query.setPlatformOrderId(whApv.getPlatformOrderId());
query.setShipService("PMS");
List<WhApv> pushList = whApvService.queryPushOrderConditionList(query);
if (pushList.size() > 0) {
WhApv pushApv = pushList.get(0);
returnMessage.setStatus(true);
returnMessage.setApvNo(whApv.getApvNo());
returnMessage.setDdNo(whApv.getSalesRecordNumber());
returnMessage.setPushTime(pushApv.getCreationDate());
if (pushList.size() == 1) {
if (pushApv.getApvNo().equals(whApv.getApvNo())) {
returnMessage.setMessage("wms存在该发货单,推送成功");
}
else {
returnMessage.setMessage("PMS已推送。平台订单号:" + whApv.getPlatformOrderId() + ",推送成功");
}
}
else {
returnMessage.setMessage("PMS已推送。平台订单号:" + whApv.getPlatformOrderId() + ",推送成功");
}
return true;
}
return doService(whApv, returnMessage);
}
catch (Exception e) {
logger.error("解析mq消息体异常!", e);
returnMessage.setStatus(false);
returnMessage.setApvNo(null);
returnMessage.setDdNo(null);
returnMessage.setPushTime(null);
returnMessage.setMessage("解析mq消息体异常");
return false;
}
}
/**
* @Title: doService
* @Description: wms写入apv发货单信息
* @Date 2019年1月3日_上午9:48:29
* @param whApv
* @param returnMessage
* @return
*/
public boolean doService(WhApv whApv, PushOrderResultMessage returnMessage) {
try {
if (!assembleData(whApv, returnMessage)) {
return false;
}
whApvService.createWhApv(whApv);
List<WhApvItem> whApvItems = whApv.getWhApvItems();
for (WhApvItem whApvItem : whApvItems) {
if (StringUtils.isNotBlank(whApvItem.getSku())) {
WhSkuQueryCondition whSkuQueryCondition = new WhSkuQueryCondition();
whSkuQueryCondition.setSku(whApvItem.getSku());
WhSku whSku = whSkuService.queryWhSku(whSkuQueryCondition);
if (whSku != null) {
whApvItem.setSkuId(whSku.getId());
}
whApvItem.setApvId(whApv.getId());
whApvItemService.createWhApvItem(whApvItem);
}
}
returnMessage.setStatus(true);
returnMessage.setApvNo(whApv.getApvNo());
returnMessage.setDdNo(whApv.getSalesRecordNumber());
returnMessage.setPushTime(new Timestamp(System.currentTimeMillis()));
returnMessage.setMessage("WMS处理成功");
return true;
}
catch (Exception e) {
logger.error("oms推单" + whApv.getApvNo() + "写入数据库失败", e);
returnMessage.setStatus(false);
returnMessage.setApvNo(whApv.getApvNo());
returnMessage.setDdNo(whApv.getSalesRecordNumber());
returnMessage.setPushTime(new Timestamp(System.currentTimeMillis()));
returnMessage.setMessage("oms推单" + whApv.getApvNo() + "写入数据库失败");
return false;
}
}
/**
* @Title: assembleData
* @Description: 组装apv发货单参数
* @Date 2019年1月3日_上午9:48:07
* @param whApv
* @param returnMessage
* @return
*/
public boolean assembleData(WhApv whApv, PushOrderResultMessage returnMessage) {
try {
whApv.setShipStatus(whApv.getShipStatus() == null ? 0 : whApv.getShipStatus());
whApv.setShipService("OMS");
whApv.setStatus(ApvStatus.WAITING_ALLOT.intCode());
whApv.setOriginalOrderId(0);// 频次设置为0
int skuCount = 0;
List<WhApvItem> whApvItemList = whApv.getWhApvItems();
boolean isSku = false; // 是否存在重复SKU条目
List<WhApvItem> createItem = new ArrayList<>();
Map<String, WhApvItem> skuMap = new HashMap<>();
for (WhApvItem whApvItem : whApvItemList) {
skuCount += whApvItem.getSaleQuantity();
if (StringUtils.isNotBlank(whApvItem.getSku())) {
WhApvItem item = skuMap.get(whApvItem.getSku());
if (item != null) {
isSku = true; // 存在重复SKU条目
item.setSaleQuantity(item.getSaleQuantity() + whApvItem.getSaleQuantity());
}
else {
createItem.add(whApvItem);
skuMap.put(whApvItem.getSku(), whApvItem);
}
}
}
// 存在重复SKU条目
if (isSku) {
whApvItemList = createItem;
if (whApvItemList.size() > 1) {
whApv.setApvType("MM");
}
else {
whApv.setApvType("SM");
}
}
// ITEM数量和SKU数量
whApv.setFeeOrCredit(Double.valueOf(whApvItemList.size()));
whApv.setSystemPrice(Double.valueOf(skuCount));
returnMessage.setStatus(true);
returnMessage.setApvNo(whApv.getApvNo());
returnMessage.setDdNo(whApv.getSalesRecordNumber());
returnMessage.setPushTime(new Timestamp(System.currentTimeMillis()));
returnMessage.setMessage("组装参数成功");
return true;
}
catch (Exception e) {
logger.error("组装apv发货单参数异常", e);
returnMessage.setStatus(false);
returnMessage.setApvNo(whApv.getApvNo());
returnMessage.setDdNo(whApv.getSalesRecordNumber());
returnMessage.setPushTime(new Timestamp(System.currentTimeMillis()));
returnMessage.setMessage("组装apv发货单参数异常");
return false;
}
}
producer
import javax.annotation.Resource;
import org.apache.log4j.Logger;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.stereotype.Service;
/**
* @ClassName: ServiceMessageProducer
* @Description: Rabbitmq消息生产者
* @Author huzy
* @Date 2018年12月31日
*/
@Service("serviceMessageProducer")
public class ServiceMessageProducer {
private Logger logger = Logger.getLogger(ServiceMessageProducer.class);
@Resource
private AmqpTemplate omsAmqpTemplate;
@Resource
private AmqpTemplate fmsAmqpTemplate;
@Resource
private AmqpTemplate pmsAmqpTemplate;
/**
* @Title: sendDataToOmsQueue
* @Description: OMS发送消息
* @Date 2018年12月31日_上午10:26:25
* @param queueKey 消息队列绑定交换机的key
* @param object 消息体
*/
public void sendDataToOmsQueue(String queueKey, Object object) {
try {
omsAmqpTemplate.convertAndSend(queueKey, object);
}
catch (Exception e) {
logger.error("发送消息失败", e);
}
}
/**
* @Title: sendDataToFmsQueue
* @Description: FMS发送消息
* @Date 2018年12月31日_上午10:26:25
* @param queueKey 消息队列绑定交换机的key
* @param object 消息体
*/
public void sendDataToFmsQueue(String queueKey, Object object) {
try {
fmsAmqpTemplate.convertAndSend(queueKey, object);
}
catch (Exception e) {
logger.error("发送消息失败", e);
}
}
/**
* PMS发送消息
* @param queueKey
* @param object
*/
public void sendDataToPmsQueue(String queueKey, Object object) {
try {
pmsAmqpTemplate.convertAndSend(queueKey, object);
}
catch (Exception e) {
logger.error("发送消息失败", e);
}
}