ソースを参照

req_2021-07-19: 新增清关时效性时间点

lhm 3 年 前
コミット
967ef5c2ba

+ 12 - 0
kmall-admin/pom.xml

@@ -142,6 +142,18 @@
             <version>2.8.2</version>
         </dependency>
 
+        <!--    rabbitmq 相关依赖    -->
+        <dependency>
+            <groupId>org.springframework.amqp</groupId>
+            <artifactId>spring-rabbit</artifactId>
+            <version>${spring-rabbitmq-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.rabbitmq</groupId>
+            <artifactId>amqp-client</artifactId>
+            <version>${amqp-client-version}</version>
+        </dependency>
+
 
     </dependencies>
 

+ 20 - 0
kmall-admin/src/main/java/com/kmall/admin/biz/CustomsClearanceTimeliness.java

@@ -0,0 +1,20 @@
+package com.kmall.admin.biz;
+
+import java.util.List;
+
+/**
+ * 清关放行业务处理
+ * @author lhm
+ * @version 1.0
+ * 2021-09-09 17:59
+ */
+public interface CustomsClearanceTimeliness {
+
+    /**
+     * 发送到清关时效性mq
+     * @param list      需要发送的订单编号数据
+     * @param timeType  清关时间点
+     */
+    void send(List<String> list, String timeType);
+
+}

+ 60 - 0
kmall-admin/src/main/java/com/kmall/admin/biz/clearance/CustomsClearanceTimelinessBiz.java

@@ -0,0 +1,60 @@
+package com.kmall.admin.biz.clearance;
+
+import com.kmall.admin.biz.CustomsClearanceTimeliness;
+import com.kmall.admin.dto.CustomsClearanceHandleDto;
+import com.kmall.admin.utils.oms.result.Result;
+import com.kmall.common.utils.DateUtils;
+import com.kmall.common.utils.JacksonUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.stream.Collectors;
+
+/**
+ * @author lhm
+ * @version 1.0
+ * 2021-09-09 18:01
+ */
+@Component
+public class CustomsClearanceTimelinessBiz implements CustomsClearanceTimeliness {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(CustomsClearanceTimelinessBiz.class);
+
+    @Autowired
+    private ThreadPoolExecutor threadPoolExecutor;
+
+    @Autowired
+    private RabbitTemplate clearRabbitTemplate;
+
+    /**
+     * 发送到清关时效性mq
+     *
+     * @param list     需要发送的订单编号数据
+     * @param timeType 清关时间点
+     */
+    @Override
+    public void send(List<String> list, String timeType) {
+        threadPoolExecutor.execute(() -> {
+            try {
+                List<CustomsClearanceHandleDto> clearanceHandleDtos = list.stream().map(orderSn -> {
+                    CustomsClearanceHandleDto customsClearanceHandleDto = new CustomsClearanceHandleDto();
+                    customsClearanceHandleDto.setTime(DateUtils.format(new Date(), DateUtils.DATE_TIME_PATTERN));
+                    customsClearanceHandleDto.setTimeType(timeType);
+                    customsClearanceHandleDto.setMerchOrderSn(orderSn);
+                    return customsClearanceHandleDto;
+                }).collect(Collectors.toList());
+                Result result = Result.success(clearanceHandleDtos);
+                clearRabbitTemplate.convertAndSend(JacksonUtils.toJson(result));
+            } catch (Exception e) {
+                LOGGER.error("----- 清关时效性: 类型【{}】发送失败! -----", timeType);
+            }
+        });
+    }
+}

+ 33 - 0
kmall-admin/src/main/java/com/kmall/admin/config/ThreadPoolConfig.java

@@ -0,0 +1,33 @@
+package com.kmall.admin.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author lhm
+ * @version 1.0
+ * 2021-09-08 19:18
+ */
+@Configuration
+public class ThreadPoolConfig {
+
+    @Bean
+    public ThreadPoolExecutor threadPoolExecutor () {
+
+        return new ThreadPoolExecutor(
+                4,
+                8,
+                60,
+                TimeUnit.SECONDS,
+                new LinkedBlockingQueue<>(50),
+                Executors.defaultThreadFactory(),
+                new ThreadPoolExecutor.CallerRunsPolicy());
+
+    }
+
+}

+ 142 - 0
kmall-admin/src/main/java/com/kmall/admin/config/mq/CustomRabbitMQProperties.java

@@ -0,0 +1,142 @@
+package com.kmall.admin.config.mq;
+
+/**
+ * 自定义的rabbitmq属性
+ * @author lhm
+ * @version 1.0
+ * 2021-09-08 17:36
+ */
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.stereotype.Component;
+
+/**
+ * 队列配置
+ * req_20210826_001
+ * @author lhm
+ * @version 1.0
+ * 2021-08-26 17:08
+ */
+@PropertySource(value = {"classpath:conf/mq.properties"})
+@Component
+public class CustomRabbitMQProperties {
+
+    /**
+     * 主要配置
+     */
+    @Value("${mq.username}")
+    private String username;
+
+    @Value("${mq.password}")
+    private String password;
+
+    @Value("${mq.host}")
+    private String host;
+
+    @Value("${mq.port}")
+    private int port;
+
+    @Value("${mq.virtual.host}")
+    private String virtualHost;
+
+    @Value("${mq.channel.cache.size}")
+    private int channelCacheSize;
+
+    /**
+     * 是否开启
+     */
+    @Value("${mq.open}")
+    private Boolean open;
+
+
+    /**
+     * 队列配置
+     */
+    @Value("${k.normal.oms.order.to.handle.customs.clearance}")
+    private String k_normal_oms_order_to_handle_customs_clearance;
+    @Value("${q.normal.oms.order.to.handle.customs.clearance}")
+    private String q_normal_oms_order_to_handle_customs_clearance;
+    @Value("${e.normal.oms.order.to.handle.customs.clearance}")
+    private String e_normal_oms_order_to_handle_customs_clearance;
+
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    public String getVirtualHost() {
+        return virtualHost;
+    }
+
+    public void setVirtualHost(String virtualHost) {
+        this.virtualHost = virtualHost;
+    }
+
+    public int getChannelCacheSize() {
+        return channelCacheSize;
+    }
+
+    public void setChannelCacheSize(int channelCacheSize) {
+        this.channelCacheSize = channelCacheSize;
+    }
+
+    public Boolean getOpen() {
+        return open;
+    }
+
+    public void setOpen(Boolean open) {
+        this.open = open;
+    }
+
+    public String getK_normal_oms_order_to_handle_customs_clearance() {
+        return k_normal_oms_order_to_handle_customs_clearance;
+    }
+
+    public void setK_normal_oms_order_to_handle_customs_clearance(String k_normal_oms_order_to_handle_customs_clearance) {
+        this.k_normal_oms_order_to_handle_customs_clearance = k_normal_oms_order_to_handle_customs_clearance;
+    }
+
+    public String getQ_normal_oms_order_to_handle_customs_clearance() {
+        return q_normal_oms_order_to_handle_customs_clearance;
+    }
+
+    public void setQ_normal_oms_order_to_handle_customs_clearance(String q_normal_oms_order_to_handle_customs_clearance) {
+        this.q_normal_oms_order_to_handle_customs_clearance = q_normal_oms_order_to_handle_customs_clearance;
+    }
+
+    public String getE_normal_oms_order_to_handle_customs_clearance() {
+        return e_normal_oms_order_to_handle_customs_clearance;
+    }
+
+    public void setE_normal_oms_order_to_handle_customs_clearance(String e_normal_oms_order_to_handle_customs_clearance) {
+        this.e_normal_oms_order_to_handle_customs_clearance = e_normal_oms_order_to_handle_customs_clearance;
+    }
+}

+ 112 - 0
kmall-admin/src/main/java/com/kmall/admin/config/mq/RabbitMQConfig.java

@@ -0,0 +1,112 @@
+package com.kmall.admin.config.mq;
+
+import com.kmall.admin.config.mq.callback.SimpleClearConfirmCallback;
+import com.kmall.admin.config.mq.callback.SimpleClearReturnCallback;
+import org.springframework.amqp.core.*;
+import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
+import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
+import org.springframework.amqp.rabbit.connection.ConnectionFactory;
+import org.springframework.amqp.rabbit.core.RabbitAdmin;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;
+import org.springframework.amqp.support.converter.MessageConversionException;
+import org.springframework.amqp.support.converter.MessageConverter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 队列相关配置
+ * req_20210826_001
+ * @author lhm
+ * @version 1.0
+ * 2021-08-26 17:07
+ */
+@Configuration
+public class RabbitMQConfig {
+
+    @Autowired
+    private CustomRabbitMQProperties customRabbitMQProperties;
+
+    /* ----------------------------------------------- 基础配置 --------------------------------------------- */
+    @Bean
+    public ConnectionFactory connectionFactory () {
+        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
+        connectionFactory.setUsername(customRabbitMQProperties.getUsername());
+        connectionFactory.setPassword(customRabbitMQProperties.getPassword());
+        connectionFactory.setHost(customRabbitMQProperties.getHost());
+        connectionFactory.setVirtualHost(customRabbitMQProperties.getVirtualHost());
+        connectionFactory.setPort(customRabbitMQProperties.getPort());
+        // 共用同一个Channel
+        connectionFactory.setCacheMode(CachingConnectionFactory.CacheMode.CHANNEL);
+        // 获取配置的Channel缓存大小
+        connectionFactory.setChannelCacheSize(customRabbitMQProperties.getChannelCacheSize());
+        // 消息到达broke后触发回调
+        connectionFactory.setPublisherConfirms(true);
+        return connectionFactory;
+    }
+
+    /**
+     * SimpleRabbitListenerContainerFactory发现消息中有content_type有text就会默认将其转换成string类型
+     * @return rabbit监听器容器工厂
+     */
+    @Bean
+    public RabbitListenerContainerFactory<?> rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
+        SimpleRabbitListenerContainerFactory containerFactory = new SimpleRabbitListenerContainerFactory();
+        containerFactory.setConnectionFactory(connectionFactory);
+        containerFactory.setConcurrentConsumers(3);
+        containerFactory.setMessageConverter(new MessageConverter() {
+            @Override
+            public Message toMessage(Object object, MessageProperties messageProperties) throws MessageConversionException {
+                return new Message(object.toString().getBytes(), messageProperties);
+            }
+
+            @Override
+            public Object fromMessage(Message message) throws MessageConversionException {
+                return new String(message.getBody());
+            }
+        });
+        // 手动ack
+        containerFactory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
+        return containerFactory;
+    }
+
+    @Bean
+    public AmqpAdmin amqpAdmin () {
+        AmqpAdmin amqpAdmin = new RabbitAdmin(connectionFactory());
+
+        amqpAdmin.declareExchange(clearDirectExchange());
+        amqpAdmin.declareQueue(clearQueue());
+        amqpAdmin.declareBinding(clearBinding());
+
+        return amqpAdmin;
+    }
+
+    /* ----------------------------------------------- 队列配置 --------------------------------------------- */
+    @Bean
+    public RabbitTemplate clearRabbitTemplate (ConnectionFactory connectionFactory) {
+        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
+
+        rabbitTemplate.setExchange(customRabbitMQProperties.getE_normal_oms_order_to_handle_customs_clearance());
+        rabbitTemplate.setRoutingKey(customRabbitMQProperties.getK_normal_oms_order_to_handle_customs_clearance());
+        rabbitTemplate.setConfirmCallback(new SimpleClearConfirmCallback());
+        rabbitTemplate.setReturnCallback(new SimpleClearReturnCallback());
+
+        return rabbitTemplate;
+    }
+
+    @Bean
+    public DirectExchange clearDirectExchange () {
+        return new DirectExchange(customRabbitMQProperties.getE_normal_oms_order_to_handle_customs_clearance());
+    }
+
+    @Bean
+    public Queue clearQueue () {
+        return new Queue(customRabbitMQProperties.getQ_normal_oms_order_to_handle_customs_clearance());
+    }
+
+    @Bean
+    public Binding clearBinding () {
+        return BindingBuilder.bind(clearQueue()).to(clearDirectExchange()).with(customRabbitMQProperties.getK_normal_oms_order_to_handle_customs_clearance());
+    }
+}

+ 27 - 0
kmall-admin/src/main/java/com/kmall/admin/config/mq/callback/SimpleClearConfirmCallback.java

@@ -0,0 +1,27 @@
+package com.kmall.admin.config.mq.callback;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.amqp.rabbit.support.CorrelationData;
+
+/**
+ * 发送至broke回调
+ * req_20210826_001
+ * @author lhm
+ * @version 1.0
+ * 2021-09-08 18:04
+ */
+public class SimpleClearConfirmCallback implements RabbitTemplate.ConfirmCallback {
+
+    private static final Logger log = LoggerFactory.getLogger(SimpleClearConfirmCallback.class);
+
+    @Override
+    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
+        if (ack) {
+            log.info("----- 消息发送至broke成功! -----");
+        } else {
+            log.error("----- 消息发送至broke错误! 原因: {} -----", cause);
+        }
+    }
+}

+ 23 - 0
kmall-admin/src/main/java/com/kmall/admin/config/mq/callback/SimpleClearReturnCallback.java

@@ -0,0 +1,23 @@
+package com.kmall.admin.config.mq.callback;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+
+/**
+ * 消息路由没有到queue会回调
+ * req_20210826_001
+ * @author lhm
+ * @version 1.0
+ * 2021-09-08 18:07
+ */
+public class SimpleClearReturnCallback implements RabbitTemplate.ReturnCallback {
+
+    private static final Logger log = LoggerFactory.getLogger(SimpleClearReturnCallback.class);
+
+    @Override
+    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
+        log.error("----- 改消息【{}】没有被路由到队列! 交换机: 【{}】 路由键: 【{}】 其它参数, replyCode: {}, replyText: {} -----", new String(message.getBody()), exchange, routingKey, replyCode, replyText);
+    }
+}

+ 77 - 0
kmall-admin/src/main/java/com/kmall/admin/dto/CustomsClearanceHandleDto.java

@@ -0,0 +1,77 @@
+package com.kmall.admin.dto;
+
+import java.io.Serializable;
+
+/**
+ * @author lhm
+ * @version 1.0
+ * 2021-09-08 18:26
+ */
+public class CustomsClearanceHandleDto implements Serializable {
+
+    private static final long serialVersionUID = -1;
+
+    private String orderSn;
+
+    private String merchOrderSn;
+
+    private String merchSn;
+
+    private String timeType;
+
+    private String time ;
+
+
+    public String getOrderSn() {
+        return orderSn;
+    }
+
+    public void setOrderSn(String orderSn) {
+        this.orderSn = orderSn;
+    }
+
+    public String getMerchOrderSn() {
+        return merchOrderSn;
+    }
+
+    public void setMerchOrderSn(String merchOrderSn) {
+        this.merchOrderSn = merchOrderSn;
+    }
+
+    public String getMerchSn() {
+        return merchSn;
+    }
+
+    public void setMerchSn(String merchSn) {
+        this.merchSn = merchSn;
+    }
+
+    public String getTimeType() {
+        return timeType;
+    }
+
+    public void setTimeType(String timeType) {
+        this.timeType = timeType;
+    }
+
+    public String getTime() {
+        return time;
+    }
+
+    public void setTime(String time) {
+        this.time = time;
+    }
+
+
+    @Override
+    public String toString() {
+        return "CustomsClearanceHandleDto{" +
+                "orderSn='" + orderSn + '\'' +
+                ", merchOrderSn='" + merchOrderSn + '\'' +
+                ", merchSn='" + merchSn + '\'' +
+                ", timeType='" + timeType + '\'' +
+                ", time='" + time + '\'' +
+                '}';
+    }
+
+}

+ 17 - 4
kmall-admin/src/main/java/com/kmall/admin/service/impl/OrderServiceImpl.java

@@ -1,6 +1,5 @@
 package com.kmall.admin.service.impl;
 
-import cn.hutool.core.io.IoUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.google.common.collect.ImmutableBiMap;
@@ -8,6 +7,7 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.gson.Gson;
 import com.google.gson.internal.LinkedTreeMap;
+import com.kmall.admin.biz.CustomsClearanceTimeliness;
 import com.kmall.admin.dao.*;
 import com.kmall.admin.dao.alarm.Mall2LowPriceWarningDao;
 import com.kmall.admin.dao.mk.Mk2GoodsTopicPriceDao;
@@ -82,9 +82,7 @@ import java.nio.charset.Charset;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.*;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
+import java.util.concurrent.*;
 
 
 @Service("orderService")
@@ -191,6 +189,9 @@ public class OrderServiceImpl implements OrderService {
     @Autowired
     private KtoEccsService ktoEccsService;
 
+    @Autowired
+    private CustomsClearanceTimeliness customsClearanceTimeliness;
+
 
     @Override
     public OrderEntity queryObject(Long id) {
@@ -2162,6 +2163,11 @@ public class OrderServiceImpl implements OrderService {
             //插入订单信息和订单商品
             orderDao.saveOrderVo(order);
 
+
+            // TODO req_2021-07-19 电商端下单时间 req_20210826_001
+            customsClearanceTimeliness.send(Arrays.asList(order.getOrder_sn()), "customerOrder");
+
+
             // TODO 订单流转表
             OrderProcessRecordEntity processRecordEntity = new OrderProcessRecordEntity();
             processRecordEntity.setOrderSn(order.getOrder_sn());
@@ -2201,6 +2207,9 @@ public class OrderServiceImpl implements OrderService {
             StoreEntity store = storeService.queryObject(order.getStore_id().intValue());
 
             // 设置支付单开始时间
+            // TODO req_2021-07-19 顾客付款时间 req_20210826_001
+            customsClearanceTimeliness.send(Arrays.asList(order.getOrder_sn()), "customerPay");
+
             processRecordEntity.setPaymentStartTime(new Date());
             // 判断是微信的支付码还是支付宝的支付码
             if (parCode.startsWith("28")) {
@@ -2220,6 +2229,10 @@ public class OrderServiceImpl implements OrderService {
                     throw e;
                 }
             }
+            // TODO req_2021-07-19 客户付款完成时间 req_20210826_001
+            customsClearanceTimeliness.send(Arrays.asList(order.getOrder_sn()), "customerPayFinished");
+
+            processRecordEntity.setPaymentStartTime(new Date());
 
 
             // TODO 到时候要注释掉,测试用而已

+ 31 - 0
kmall-admin/src/main/resources/conf/mq.properties

@@ -0,0 +1,31 @@
+# rabbitmq\u76F8\u5173\u914D\u7F6E req_20210826_001
+
+# \u5F00\u53D1\u73AF\u5883\u914D\u7F6E
+mq.host=127.0.0.1
+mq.username=guest
+mq.password=guest
+mq.port=5672
+mq.virtual.host=/
+
+# \u6D4B\u8BD5\u73AF\u5883mq\u76F8\u5173\u914D\u7F6E
+#mq.port=5672
+#mq.host=120.24.174.90
+#mq.username=admin
+#mq.password=Abc-123#
+#mq.virtual.host=/
+
+# \u751F\u4EA7\u73AF\u5883mq\u76F8\u5173\u914D\u7F6E
+#mq.port=5672
+#mq.host=120.76.26.84
+#mq.username=admin
+#mq.password=Abc-123#
+#mq.virtual.host=/
+
+# \u901A\u7528\u914D\u7F6E
+mq.open=false
+mq.channel.cache.size=50
+
+# \u6E05\u5173\u65F6\u6548\u6027\u961F\u5217\u914D\u7F6E
+k.normal.oms.order.to.handle.customs.clearance=k.normal.oms.order.to.handle.customs.clearance
+q.normal.oms.order.to.handle.customs.clearance=q.normal.oms.order.to.handle.customs.clearance
+e.normal.oms.order.to.handle.customs.clearance=e.normal.oms.order.to.handle.customs.clearance

+ 2 - 1
pom.xml

@@ -67,7 +67,8 @@
         <jstl-version>1.2</jstl-version>
         <taglibs-version>1.1.2</taglibs-version>
         <freemarker-version>2.3.23</freemarker-version>
-
+        <spring-rabbitmq-version>2.0.1.RELEASE</spring-rabbitmq-version>
+        <amqp-client-version>4.3.0</amqp-client-version>
     </properties>
 
     <!-- 阿里云maven仓库 -->