Selaa lähdekoodia

统一配送平台回调入口,方便加平台不用重启

jlutt@163.com 2 vuotta sitten
vanhempi
commit
d3536bc9ff

+ 1 - 1
conf/script/1000/expressApi/BE_Express_OrderStatusInvoke_SFTC.groovy

@@ -15,7 +15,7 @@ import org.apache.logging.log4j.Logger
 
 import javax.annotation.Resource
 
-class BE_Express_OrderStatusInvoke_SFTC implements BusinessExecutor<InvokeCallParams, InvokeCallResult> {
+class BE_Express_CallBack_Invoke_SFTC implements BusinessExecutor<InvokeCallParams, InvokeCallResult> {
 
     private final Logger logger = LogManager.getLogger(this.getClass().getSimpleName())
 

+ 112 - 0
conf/script/1000/expressApi/BE_Express_CallBack_VerifySign_SFTC.groovy

@@ -0,0 +1,112 @@
+import com.dderp.common.api.BusinessExecutor
+import com.dderp.common.api.ERPLockDataService
+import com.dderp.common.api.NoSqlKeysService
+import com.dderp.common.datas.ERPModule
+import com.dderp.common.datas.RedisKeys
+import com.dderp.common.entity.base.InvokeCallParams
+import com.dderp.common.entity.base.InvokeCallResult
+import com.dySweetFishPlugin.sql.dao.OperatorWait
+import com.sweetfish.convert.json.JsonConvert
+import com.sweetfish.service.RetResult
+import groovy.json.JsonSlurper
+import org.apache.commons.lang3.StringUtils
+import org.apache.logging.log4j.LogManager
+import org.apache.logging.log4j.Logger
+
+import javax.annotation.Resource
+
+class BE_Express_CallBack_VerifySign_SFTC implements BusinessExecutor<InvokeCallParams, InvokeCallResult> {
+
+    private final Logger logger = LogManager.getLogger(this.getClass().getSimpleName())
+
+    @Resource
+    JsonConvert jsonConvert
+
+    @Resource
+    ERPLockDataService lockDataService
+
+    @Resource
+    NoSqlKeysService keysService
+
+    @Override
+    String scriptName() {
+        return "顺丰同城回调数据验证签名"
+    }
+
+    @Override
+    ERPModule module() {
+        return ERPModule.EXPRESS_API
+    }
+
+    @Override
+    OperatorWait getAWait(InvokeCallParams source) {
+        return OperatorWait.ASNYC
+    }
+
+    @Override
+    RetResult<InvokeCallParams> beforeExecute(InvokeCallParams source) {
+        //此回调post的数据看着没有子表,直接用groovy自带的json即可,如果有子表,还是应该建立一个类进行转换
+
+        //锁定下数据,防止重复提交
+        def jsonSlurper = new JsonSlurper()
+        def invokeOrder = jsonSlurper.parseText(source.params)
+
+        String urlIndex = invokeOrder["url_index"] as String
+
+        //这里除了店铺授权和店铺取消授权,其它都是订单,if-else先写着
+        if (StringUtils.equalsIgnoreCase("bindnotify", urlIndex)) {
+            //店铺授权回调
+            String shopId = invokeOrder["shop_id"] as String
+            if (lockDataService.hLockAdd(shopId, RedisKeys.KEY_ERP_WORKING_SF_STORE, source.supplierCode) > 1) {
+                return RetResult.<InvokeCallParams> errorT().retinfo(shopId + "提交工作中,请稍后刷新即可,无需重复操作")
+            }
+        } else if (StringUtils.equalsIgnoreCase("cancelbindnotify", urlIndex)) {
+            //店铺取消授权回调
+            String shopId = invokeOrder["shop_id"] as String
+            if (lockDataService.hLockAdd(shopId, RedisKeys.KEY_ERP_WORKING_SF_STORE, source.supplierCode) > 1) {
+                return RetResult.<InvokeCallParams> errorT().retinfo(shopId + "提交工作中,请稍后刷新即可,无需重复操作")
+            }
+        } else {
+            String invokeOrderId = invokeOrder["sf_order_id"] as String
+            if (lockDataService.hLockAdd(invokeOrderId, RedisKeys.KEY_ERP_WORKING_SF_ORDER, source.supplierCode) > 1) {
+                return RetResult.<InvokeCallParams> errorT().retinfo(invokeOrderId + "提交工作中,请稍后刷新即可,无需重复操作")
+            }
+        }
+
+        return RetResult.<InvokeCallParams> successT().result(source)
+    }
+
+    @Override
+    void afterExecute(boolean executeError, InvokeCallParams source, InvokeCallResult dest) {
+        def jsonSlurper = new JsonSlurper()
+        def invokeOrder = jsonSlurper.parseText(source.params)
+
+        String urlIndex = invokeOrder["url_index"] as String
+        if (StringUtils.equalsIgnoreCase("bindnotify", urlIndex)) {
+            //店铺授权回调
+            String shopId = invokeOrder["shop_id"] as String
+            lockDataService.hLockDel(shopId, RedisKeys.KEY_ERP_WORKING_SF_STORE, source.supplierCode)
+        } else if (StringUtils.equalsIgnoreCase("cancelbindnotify", urlIndex)) {
+            //店铺取消授权回调
+            String shopId = invokeOrder["shop_id"] as String
+            lockDataService.hLockDel(shopId, RedisKeys.KEY_ERP_WORKING_SF_STORE, source.supplierCode)
+        } else {
+            String invokeOrderId = invokeOrder["sf_order_id"] as String
+            lockDataService.hLockDel(invokeOrderId,RedisKeys.KEY_ERP_WORKING_SF_ORDER, source.supplierCode)
+        }
+    }
+
+    RetResult<InvokeCallResult> execute(InvokeCallParams source) {
+        def jsonSlurper = new JsonSlurper()
+        def invokeOrder = jsonSlurper.parseText(source.params)
+
+        logger.info(invokeOrder["url_index"])
+        logger.info(invokeOrder["sf_order_id"])
+        logger.info(invokeOrder["operator_name"])
+
+        return RetResult.<InvokeCallResult> successT().result(
+                InvokeCallResult.success()
+        )
+    }
+}
+

+ 5 - 1
ddBusiness/src/main/java/com/dderp/business/service/flycat/ExpressGeoServiceImpl.java

@@ -5,6 +5,7 @@ import com.dderp.common.api.PlatformService;
 import com.dderp.common.api.SupplierInitService;
 import com.dderp.common.api.flycat.ExpressGeoService;
 import com.dderp.common.api.flycat.ExpressOutService;
+import com.dderp.common.api.flycat.OrderService;
 import com.dderp.common.base.BaseService;
 import com.dderp.common.datas.RedisKeys;
 import com.dderp.common.entity.base.InvokeCallParams;
@@ -57,6 +58,9 @@ public class ExpressGeoServiceImpl extends BaseService implements ExpressGeoServ
     ExpressOutService expressOutService;
 
     @Resource
+    OrderService orderService;
+
+    @Resource
     SupplierInitService supplierService;
 
     private final List<ScheduledThreadPoolExecutor> scheduleScanThreadList = new ArrayList<>();
@@ -140,7 +144,7 @@ public class ExpressGeoServiceImpl extends BaseService implements ExpressGeoServ
                                     .businessMethod("Order_Sync_RiderLocation" + inPlatform.getPlatformCode())
                                     .params(geoResult.getResult().getData())
                                     .build();
-                            RetResult<InvokeCallResult> syncResult = expressOutService.callExpress(syncCallParams, ERPUtils.getSysTokenUser(), dataSourceId, supplierCode);
+                            RetResult<InvokeCallResult> syncResult = orderService.callOrder(syncCallParams, ERPUtils.getSysTokenUser(), dataSourceId, supplierCode);
                             if (!syncResult.isSuccess()) {
                                 logger.error("订单同步骑手位置出错:" + inPlatform.getPlatformName() + " " + syncResult.getRetinfo());
                             } else {

+ 10 - 0
ddCommon/src/main/java/com/dderp/common/datas/ERPHeader.java

@@ -29,4 +29,14 @@ public final class ERPHeader {
     public static final String DNYHEADER_SUPPLIER = "X-DNY-Supplier-Code";
 
     public static final String DNYHEADER_DATASOURCE = "X-DNY-DataSource-Id";
+
+    /**
+     * 配送平台代码
+     */
+    public static final String HTTPHEADER_EXPRESS_PLATFORM = "X-Deliver-Express-Platform";
+
+    /**
+     * 订单平台代码
+     */
+    public static final String HTTPHEADER_ORDER_PLATFORM = "X-Deliver-Order-Platform";
 }

+ 29 - 0
ddCommon/src/main/java/com/dderp/common/entity/base/InvokeCallParams.java

@@ -4,6 +4,7 @@ import com.dderp.common.entity.site.ERPTokenUser;
 import com.dySweetFishPlugin.tool.crypto.EncryptUtil;
 import com.sweetfish.convert.json.JsonConvert;
 import com.sweetfish.source.PageFlipper;
+import com.sweetfish.util.AnyValue;
 import org.apache.commons.lang3.StringUtils;
 
 import java.util.HashMap;
@@ -23,6 +24,11 @@ public class InvokeCallParams extends BaseEntity {
     private String params;
 
     /**
+     * 附加字符串,params不够用的情况下,增加附件参数
+     */
+    private AnyValue attach;
+
+    /**
      * 分页对象,这里还是把分页信息从params里面拆分出来,减少脚本中转换的次数
      */
     private PageFlipper page;
@@ -54,13 +60,16 @@ public class InvokeCallParams extends BaseEntity {
     public InvokeCallParams() {
     }
 
+
     private InvokeCallParams(Builder builder) {
         setBusinessMethod(builder.businessMethod);
         setTimeStamp(builder.timeStamp);
         setParams(builder.params);
+        setAttach(builder.attach);
         setPage(builder.page);
         setClientCode(builder.clientCode);
         setDigest(builder.digest);
+        setToken(builder.token);
         setCurrentUser(builder.currentUser);
         setDataSourceId(builder.dataSourceId);
         setSupplierCode(builder.supplierCode);
@@ -171,13 +180,23 @@ public class InvokeCallParams extends BaseEntity {
         this.token = token;
     }
 
+    public AnyValue getAttach() {
+        return attach;
+    }
+
+    public void setAttach(AnyValue attach) {
+        this.attach = attach;
+    }
+
     public static final class Builder {
         private String businessMethod;
         private String timeStamp;
         private String params;
+        private AnyValue attach;
         private PageFlipper page;
         private String clientCode;
         private String digest;
+        private String token;
         private ERPTokenUser currentUser;
         private String dataSourceId;
         private long supplierCode;
@@ -200,6 +219,11 @@ public class InvokeCallParams extends BaseEntity {
             return this;
         }
 
+        public Builder attach(AnyValue val) {
+            attach = val;
+            return this;
+        }
+
         public Builder page(PageFlipper val) {
             page = val;
             return this;
@@ -215,6 +239,11 @@ public class InvokeCallParams extends BaseEntity {
             return this;
         }
 
+        public Builder token(String val) {
+            token = val;
+            return this;
+        }
+
         public Builder currentUser(ERPTokenUser val) {
             currentUser = val;
             return this;

+ 60 - 3
ddWebCore/src/main/java/com/dderp/webcore/servlet/ExpressCallServlet.java

@@ -1,15 +1,15 @@
 package com.dderp.webcore.servlet;
 
-import com.alibaba.fastjson2.JSON;
-import com.alibaba.fastjson2.JSONObject;
 import com.dderp.common.api.flycat.ExpressOutService;
 import com.dderp.common.datas.ERPHeader;
 import com.dderp.common.entity.base.InvokeCallParams;
+import com.dderp.common.entity.base.InvokeCallResult;
 import com.dderp.common.entity.express.ExpressCallResult;
 import com.dderp.common.entity.site.ERPTokenUser;
 import com.dderp.common.tool.ERPUtils;
 import com.sweetfish.net.WorkThread;
 import com.sweetfish.net.http.*;
+import com.sweetfish.service.RetResult;
 import com.sweetfish.util.AnyValue;
 import com.sweetfish.util.AutoLoad;
 import org.apache.commons.codec.binary.Base64;
@@ -81,6 +81,63 @@ public class ExpressCallServlet extends HttpServlet {
         }
     }
 
+    @HttpMapping(url = "/express/call", methods = {"POST"}, comment = "回调入口")
+    public void expressCall(HttpRequest request, HttpResponse response) {
+        //如果是通用接口,如何区分是哪个平台传入的呢?
+        //查了顺丰同城、美团、达达、闪送、蜂鸟、UU跑腿,饿了么几个平台的开发文档,没有任何一个字段用于区分配送平台
+        //如果说用订单来查找,几个平台的订单字段也不一样,甚至有的是body传递过来,有的是form-data传递过来的数据
+        //感觉使用统一接口,调脚本的形式有些不行?
+        //想到有一个办法就是通过nginx做不同反向代理,添加header信息来区分,这样每个平台可以随便添加了,只需要重载一下nginx即可,无需重启服务端
+        logger.info(request);
+        logger.info(request.getBodyUTF8());
+
+        String platformCode = request.getHeader(ERPHeader.HTTPHEADER_EXPRESS_PLATFORM, "");
+        if (StringUtils.isEmpty(platformCode)) {
+            return;
+        }
+
+        //转大写,找脚本
+        platformCode = platformCode.toUpperCase();
+
+        //验证签名,本来用body好好的,都可以统一成InvokeCallParams,结果UU跑腿非要用form-data方式传递,非json,太恶心了,不过都可以通过getBodyUTF8获取到,
+        //还有类似顺丰同城这种,签名参数是放在参数里面的,也就是request.getParameter("sign", "");
+        //验证签名的脚本必须为同步,
+        String dataSourceId = request.getHeader(ERPHeader.HTTPHEADER_DATASOURCE, "");
+        long supplierCode = request.getLongHeader(ERPHeader.HTTPHEADER_SUPPLIER, 0L);
+        String body = request.getBodyUTF8();
+
+        InvokeCallParams callSignParams = InvokeCallParams.newBuilder()
+                .businessMethod("Express_CallBack_VerifySign_" + platformCode)
+                .params(body)
+                .attach(request.getParameters())
+                .currentUser(ERPUtils.getSysTokenUser())
+                .dataSourceId(dataSourceId)
+                .supplierCode(supplierCode)
+                .build();
+        RetResult<InvokeCallResult> callSignResult = expressOutService.callExpress(callSignParams, ERPUtils.getSysTokenUser(), dataSourceId, supplierCode);
+        if (callSignResult.isSuccess()) {
+            //签名成功,调用回调业务代码
+            InvokeCallParams callInvokeParams = InvokeCallParams.newBuilder()
+                    .businessMethod("Express_CallBack_Invoke_" + platformCode)
+                    .params(body)
+                    .currentUser(ERPUtils.getSysTokenUser())
+                    .dataSourceId(dataSourceId)
+                    .supplierCode(supplierCode)
+                    .build();
+            //此脚本异步调用算了,统一返回配送平台需要的返回值
+            RetResult<InvokeCallResult> callInvokeResult = expressOutService.callExpress(callInvokeParams, ERPUtils.getSysTokenUser(), dataSourceId, supplierCode);
+            //每个平台需要返回的玩意也不同,
+            if (callInvokeResult.isSuccess()) {
+                response.finish(200, callSignResult.getResult().getData());
+            } else {
+                response.finish(200, callSignResult.getRetinfo());
+            }
+        } else {
+            response.finish(200, callSignResult.getRetinfo());
+        }
+
+    }
+
     //当前查看顺丰的回调,没有字段体现出顺丰的接口,大概每个快递平台需要不同的地址提供回调,顺丰的回调可以通过url_index来判断回调的业务
 
     @HttpMapping(url = "/express/sfCall", methods = {"POST", "GET"}, comment = "回调入口")
@@ -108,7 +165,7 @@ public class ExpressCallServlet extends HttpServlet {
         //其它平台看了两个,好像都只有一个回调,就顺丰有一堆回调,这里统一,让脚本里面分开处理,脚本大点就大点吧
 
         InvokeCallParams callParams = InvokeCallParams.newBuilder()
-                .businessMethod("Express_OrderStatusInvoke_SFTC")
+                .businessMethod("Express_CallBack_Invoke_SFTC")
                 .params(body)
                 .currentUser(ERPUtils.getSysTokenUser())
                 .dataSourceId(dataSourceId)