Veronique 11 hónapja
szülő
commit
2fac301187

+ 1 - 0
.gitignore

@@ -37,3 +37,4 @@ build/
 ### Mac OS ###
 .DS_Store
 /.idea/
+/logs/

+ 95 - 0
conf/script/1000/callThird/BE_Call_QueryFee.groovy

@@ -0,0 +1,95 @@
+import com.sweetfish.convert.json.JsonConvert
+import com.sweetfish.service.RetResult
+import com.yinjie.heating.common.api.BusinessExecutor
+import com.yinjie.heating.common.datas.ERPModule
+import com.yinjie.heating.common.datas.HeatingAppInvokerCode
+import com.yinjie.heating.common.entity.base.ProcessMapItem
+import com.yinjie.heating.common.entity.callthird.QueryFeeResponse
+import com.yinjie.heating.common.entity.heating.HeatingApp
+import com.yinjie.heating.common.entity.heating.HeatingAppInvoker
+import com.yinjie.heating.common.http.HttpTools
+import com.yinjie.heating.common.tool.PaySignatureUtil
+import org.apache.commons.lang3.StringUtils
+import org.apache.logging.log4j.LogManager
+import org.apache.logging.log4j.Logger
+import org.rex.RMap
+
+import javax.annotation.Resource
+import java.time.LocalDateTime
+import java.util.concurrent.ExecutionException
+import java.util.concurrent.TimeUnit
+import java.util.concurrent.TimeoutException
+
+class BE_Call_QueryFee implements BusinessExecutor<ProcessMapItem, QueryFeeResponse> {
+    private final Logger logger = LogManager.getLogger(this.getClass().getSimpleName())
+
+    @Resource
+    private JsonConvert jsonConvert
+
+    @Override
+    String scriptName() {
+        return "调用外部热力服务商接口-查询欠费"
+    }
+
+    @Override
+    ERPModule module() {
+        return ERPModule.CALL_THIRD
+    }
+
+    RetResult<QueryFeeResponse> execute(ProcessMapItem source) {
+        long currentTime = LocalDateTime.now().toDate().time
+        RMap params = source.itemData
+        String dataSourceId = source.dataSourceId
+        long supplierCode = source.supplierCode
+
+        String billKey = params.getString("billKey")
+        HeatingApp app = params.get("app") as HeatingApp
+
+
+        //接口均返回正确,错误放在result里
+        if (StringUtils.isBlank(billKey) || app == null) {
+            logger.error("传入参数不正确")
+            return RetResult.<QueryFeeResponse> successT().result(new QueryFeeResponse.Builder()
+                    .respCode("DEF0006")
+                    .respMsg("系统错误")
+                    .build())
+
+        }
+
+        Map<String, String> header = new HashMap<>()
+        header.put("Content-Type", "application/json")
+
+        Map<String, String> body = [
+                appId    : app.appId,
+                billKey  : billKey,
+                nonceStr : UUID.randomUUID().toString().replace("-", ""),
+                timeStamp: currentTime as String
+        ]
+
+        //签名
+        String sign = PaySignatureUtil.generateSign(body, "RSA_1_256", app.appPrivateKey)
+        body.put("sign", sign)
+
+        HeatingAppInvoker invoker = app.invokerList.find { it.invokerCode == HeatingAppInvokerCode.queryFee.code }
+        if (invoker == null) {
+            logger.error(app.appName + "未配置[查询欠费]接口")
+            return RetResult.<QueryFeeResponse> successT().result(new QueryFeeResponse.Builder()
+                    .respCode("DEF0006")
+                    .respMsg("系统错误")
+                    .build())
+        }
+
+        try {
+            String resp = HttpTools.postHttpContentAsync(invoker.invokerUrl, header, jsonConvert.convertTo(body)).get(20, TimeUnit.SECONDS)
+
+            QueryFeeResponse response = jsonConvert.convertFrom(resp)
+            return RetResult.<QueryFeeResponse> successT().result(response)
+        } catch (InterruptedException | ExecutionException | TimeoutException e) {
+            logger.error(app.appName + "请求[查询欠费]接口失败")
+            return RetResult.<QueryFeeResponse> successT().result(new QueryFeeResponse.Builder()
+                    .respCode("DEF0006")
+                    .respMsg("系统错误")
+                    .build())
+        }
+    }
+}

+ 103 - 0
conf/script/1000/callThird/BE_Call_RequestPay.groovy

@@ -0,0 +1,103 @@
+import com.sweetfish.convert.json.JsonConvert
+import com.sweetfish.service.RetResult
+import com.yinjie.heating.common.api.BusinessExecutor
+import com.yinjie.heating.common.datas.ERPModule
+import com.yinjie.heating.common.datas.HeatingAppInvokerCode
+import com.yinjie.heating.common.entity.base.ProcessMapItem
+import com.yinjie.heating.common.entity.callthird.BaseResponse
+import com.yinjie.heating.common.entity.callthird.QueryFeeResponse
+import com.yinjie.heating.common.entity.heating.HeatingApp
+import com.yinjie.heating.common.entity.heating.HeatingAppInvoker
+import com.yinjie.heating.common.http.HttpTools
+import com.yinjie.heating.common.tool.CommonUtils
+import com.yinjie.heating.common.tool.PaySignatureUtil
+import org.apache.commons.lang3.StringUtils
+import org.apache.logging.log4j.LogManager
+import org.apache.logging.log4j.Logger
+import org.rex.RMap
+
+import javax.annotation.Resource
+import java.time.LocalDateTime
+import java.util.concurrent.ExecutionException
+import java.util.concurrent.TimeUnit
+import java.util.concurrent.TimeoutException
+
+class BE_Call_RequestPay implements BusinessExecutor<ProcessMapItem, BaseResponse> {
+    private final Logger logger = LogManager.getLogger(this.getClass().getSimpleName())
+
+    @Resource
+    private JsonConvert jsonConvert
+
+    @Override
+    String scriptName() {
+        return "调用外部热力服务商接口-请求销账"
+    }
+
+    @Override
+    ERPModule module() {
+        return ERPModule.CALL_THIRD
+    }
+
+    RetResult<BaseResponse> execute(ProcessMapItem source) {
+        long currentTime = LocalDateTime.now().toDate().time
+        RMap params = source.itemData
+        String dataSourceId = source.dataSourceId
+        long supplierCode = source.supplierCode
+
+        String billKey = params.getString("billKey")
+        HeatingApp app = params.get("app") as HeatingApp
+        String payDate = params.getString("payDate")
+        String bankBillNo = params.getString("bankBillNo")
+        String payAmount = params.getString("payAmount")
+
+
+        //接口均返回正确,错误放在result里
+        if (StringUtils.isBlank(billKey) || app == null) {
+            logger.error("传入参数不正确")
+            return RetResult.<BaseResponse> successT().result(new BaseResponse.Builder()
+                    .respCode("DEF0006")
+                    .respMsg("系统错误")
+                    .build())
+
+        }
+
+        Map<String, String> header = new HashMap<>()
+        header.put("Content-Type", "application/json")
+
+        Map<String, String> body = [
+                appId     : app.appId,
+                billKey   : billKey,
+                payDate   : payDate,
+                bankBillNo: bankBillNo,
+                payAmount : CommonUtils.money100(new BigDecimal(payAmount)) as String,
+                nonceStr  : UUID.randomUUID().toString().replace("-", ""),
+                timeStamp : currentTime as String
+        ]
+
+        //签名
+        String sign = PaySignatureUtil.generateSign(body, "RSA_1_256", app.appPrivateKey)
+        body.put("sign", sign)
+
+        HeatingAppInvoker invoker = app.invokerList.find { it.invokerCode == HeatingAppInvokerCode.requestPay.code }
+        if (invoker == null) {
+            logger.error(app.appName + "未配置[请求销账]接口")
+            return RetResult.<BaseResponse> successT().result(new BaseResponse.Builder()
+                    .respCode("DEF0006")
+                    .respMsg("系统错误")
+                    .build())
+        }
+
+        try {
+            String resp = HttpTools.postHttpContentAsync(invoker.invokerUrl, header, jsonConvert.convertTo(body)).get(20, TimeUnit.SECONDS)
+
+            BaseResponse response = jsonConvert.convertFrom(resp)
+            return RetResult.<BaseResponse> successT().result(response)
+        } catch (InterruptedException | ExecutionException | TimeoutException e) {
+            logger.error(app.appName + "请求[请求销账]接口失败")
+            return RetResult.<BaseResponse> successT().result(new BaseResponse.Builder()
+                    .respCode("DEF0006")
+                    .respMsg("系统错误")
+                    .build())
+        }
+    }
+}

BIN
doc/公缴单位接入光大银行统一接口_公网版V1.7(含开票)(2).docx


+ 3 - 2
yjBusiness/src/main/java/com/yinjie/heating/business/service/heating/CallThirdAppServiceImpl.java

@@ -6,6 +6,7 @@ import com.yinjie.heating.common.base.BaseService;
 import com.yinjie.heating.common.datas.ERPModule;
 import com.yinjie.heating.common.entity.base.ProcessMapItem;
 import com.yinjie.heating.common.entity.callthird.BaseResponse;
+import com.yinjie.heating.common.entity.callthird.QueryFeeResponse;
 import com.yinjie.heating.common.entity.heating.HeatingApp;
 import org.rex.RMap;
 
@@ -13,7 +14,7 @@ import java.util.Date;
 
 public class CallThirdAppServiceImpl extends BaseService implements CallThirdAppService {
     @Override
-    public RetResult<BaseResponse> callQueryFee(String billKey, HeatingApp heatingApp, String dataSourceId, long supplierCode) {
+    public RetResult<QueryFeeResponse> callQueryFee(String billKey, HeatingApp heatingApp, String dataSourceId, long supplierCode) {
         RMap reqBody = new RMap();
         reqBody.put("billKey", billKey);
         reqBody.put("app", heatingApp);
@@ -29,7 +30,7 @@ public class CallThirdAppServiceImpl extends BaseService implements CallThirdApp
     }
 
     @Override
-    public RetResult<BaseResponse> callRequestPay(String billKey, Date payDate, String bankBillNo, String payAmount,
+    public RetResult<BaseResponse> callRequestPay(String billKey, String payDate, String bankBillNo, String payAmount,
                                                   HeatingApp heatingApp, String dataSourceId, long supplierCode) {
         RMap reqBody = new RMap();
         reqBody.put("billKey", billKey);

+ 3 - 6
yjCommon/src/main/java/com/yinjie/heating/common/api/heating/CallThirdAppService.java

@@ -3,12 +3,9 @@ package com.yinjie.heating.common.api.heating;
 import com.sweetfish.service.RetResult;
 import com.sweetfish.util.AutoLoad;
 import com.yinjie.heating.common.api.ScriptService;
-import com.yinjie.heating.common.entity.callthird.BaseRequest;
 import com.yinjie.heating.common.entity.callthird.BaseResponse;
+import com.yinjie.heating.common.entity.callthird.QueryFeeResponse;
 import com.yinjie.heating.common.entity.heating.HeatingApp;
-import com.yinjie.heating.common.entity.heating.HeatingAppInvoker;
-import com.yinjie.heating.common.entity.system.LoginUser;
-import org.rex.RMap;
 
 import java.util.Date;
 
@@ -17,9 +14,9 @@ import java.util.Date;
  */
 @AutoLoad(false)
 public interface CallThirdAppService extends ScriptService {
-    RetResult<BaseResponse> callQueryFee(String billKey, HeatingApp heatingApp, String dataSourceId, long supplierCode);
+    RetResult<QueryFeeResponse> callQueryFee(String billKey, HeatingApp heatingApp, String dataSourceId, long supplierCode);
 
-    RetResult<BaseResponse> callRequestPay(String billKey, Date payDate, String bankBillNo, String payAmount,
+    RetResult<BaseResponse> callRequestPay(String billKey, String payDate, String bankBillNo, String payAmount,
                                            HeatingApp heatingApp, String dataSourceId, long supplierCode);
 
 }

+ 0 - 57
yjCommon/src/main/java/com/yinjie/heating/common/entity/callthird/BaseRequest.java

@@ -1,57 +0,0 @@
-package com.yinjie.heating.common.entity.callthird;
-
-import com.yinjie.heating.common.entity.base.BaseEntity;
-
-import java.util.HashMap;
-
-public class BaseRequest extends BaseEntity {
-    private String appId;
-
-    private HashMap<String, Object> params;
-
-    private String nonceStr;
-
-    private String sign;
-
-    private long timeStamp;
-
-    public String getAppId() {
-        return appId;
-    }
-
-    public void setAppId(String appId) {
-        this.appId = appId;
-    }
-
-    public HashMap<String, Object> getParams() {
-        return params;
-    }
-
-    public void setParams(HashMap<String, Object> params) {
-        this.params = params;
-    }
-
-    public String getNonceStr() {
-        return nonceStr;
-    }
-
-    public void setNonceStr(String nonceStr) {
-        this.nonceStr = nonceStr;
-    }
-
-    public String getSign() {
-        return sign;
-    }
-
-    public void setSign(String sign) {
-        this.sign = sign;
-    }
-
-    public long getTimeStamp() {
-        return timeStamp;
-    }
-
-    public void setTimeStamp(long timeStamp) {
-        this.timeStamp = timeStamp;
-    }
-}

+ 88 - 11
yjCommon/src/main/java/com/yinjie/heating/common/entity/callthird/BaseResponse.java

@@ -2,7 +2,7 @@ package com.yinjie.heating.common.entity.callthird;
 
 import com.yinjie.heating.common.entity.base.BaseEntity;
 
-import java.util.HashMap;
+import java.util.Date;
 
 public class BaseResponse extends BaseEntity {
     private String appId;
@@ -11,10 +11,24 @@ public class BaseResponse extends BaseEntity {
 
     private String respMsg;
 
-    private HashMap<String, Object> respData;
-
     private long timeStamp;
 
+    public BaseResponse() {
+    }
+
+    private BaseResponse(Builder builder) {
+        setCreateBy(builder.createBy);
+        setCreateTime(builder.createTime);
+        setCreateTimeLong(builder.createTimeLong);
+        setUpdateBy(builder.updateBy);
+        setUpdateTime(builder.updateTime);
+        setUpdateTimeLong(builder.updateTimeLong);
+        setAppId(builder.appId);
+        setRespCode(builder.respCode);
+        setRespMsg(builder.respMsg);
+        setTimeStamp(builder.timeStamp);
+    }
+
     public String getAppId() {
         return appId;
     }
@@ -39,14 +53,6 @@ public class BaseResponse extends BaseEntity {
         this.respMsg = respMsg;
     }
 
-    public HashMap<String, Object> getRespData() {
-        return respData;
-    }
-
-    public void setRespData(HashMap<String, Object> respData) {
-        this.respData = respData;
-    }
-
     public long getTimeStamp() {
         return timeStamp;
     }
@@ -54,4 +60,75 @@ public class BaseResponse extends BaseEntity {
     public void setTimeStamp(long timeStamp) {
         this.timeStamp = timeStamp;
     }
+
+
+    public static final class Builder {
+        private long createBy;
+        private Date createTime;
+        private long createTimeLong;
+        private long updateBy;
+        private Date updateTime;
+        private long updateTimeLong;
+        private String appId;
+        private String respCode;
+        private String respMsg;
+        private long timeStamp;
+
+        public Builder() {
+        }
+
+        public Builder createBy(long val) {
+            createBy = val;
+            return this;
+        }
+
+        public Builder createTime(Date val) {
+            createTime = val;
+            return this;
+        }
+
+        public Builder createTimeLong(long val) {
+            createTimeLong = val;
+            return this;
+        }
+
+        public Builder updateBy(long val) {
+            updateBy = val;
+            return this;
+        }
+
+        public Builder updateTime(Date val) {
+            updateTime = val;
+            return this;
+        }
+
+        public Builder updateTimeLong(long val) {
+            updateTimeLong = val;
+            return this;
+        }
+
+        public Builder appId(String val) {
+            appId = val;
+            return this;
+        }
+
+        public Builder respCode(String val) {
+            respCode = val;
+            return this;
+        }
+
+        public Builder respMsg(String val) {
+            respMsg = val;
+            return this;
+        }
+
+        public Builder timeStamp(long val) {
+            timeStamp = val;
+            return this;
+        }
+
+        public BaseResponse build() {
+            return new BaseResponse(this);
+        }
+    }
 }

+ 160 - 0
yjCommon/src/main/java/com/yinjie/heating/common/entity/callthird/QueryFeeResponse.java

@@ -0,0 +1,160 @@
+package com.yinjie.heating.common.entity.callthird;
+
+import java.util.Date;
+
+public class QueryFeeResponse extends BaseResponse {
+    private String billKey;
+
+    private String customerName;
+
+    private String balance;
+
+    private String payAmount;
+
+    public QueryFeeResponse() {
+    }
+
+    private QueryFeeResponse(Builder builder) {
+        setCreateBy(builder.createBy);
+        setCreateTime(builder.createTime);
+        setCreateTimeLong(builder.createTimeLong);
+        setUpdateBy(builder.updateBy);
+        setUpdateTime(builder.updateTime);
+        setUpdateTimeLong(builder.updateTimeLong);
+        setAppId(builder.appId);
+        setRespCode(builder.respCode);
+        setRespMsg(builder.respMsg);
+        setTimeStamp(builder.timeStamp);
+        setBillKey(builder.billKey);
+        setCustomerName(builder.customerName);
+        setBalance(builder.balance);
+        setPayAmount(builder.payAmount);
+    }
+
+    public String getBillKey() {
+        return billKey;
+    }
+
+    public void setBillKey(String billKey) {
+        this.billKey = billKey;
+    }
+
+    public String getCustomerName() {
+        return customerName;
+    }
+
+    public void setCustomerName(String customerName) {
+        this.customerName = customerName;
+    }
+
+    public String getBalance() {
+        return balance;
+    }
+
+    public void setBalance(String balance) {
+        this.balance = balance;
+    }
+
+    public String getPayAmount() {
+        return payAmount;
+    }
+
+    public void setPayAmount(String payAmount) {
+        this.payAmount = payAmount;
+    }
+
+
+    public static final class Builder {
+        private long createBy;
+        private Date createTime;
+        private long createTimeLong;
+        private long updateBy;
+        private Date updateTime;
+        private long updateTimeLong;
+        private String appId;
+        private String respCode;
+        private String respMsg;
+        private long timeStamp;
+        private String billKey;
+        private String customerName;
+        private String balance;
+        private String payAmount;
+
+        public Builder() {
+        }
+
+        public Builder createBy(long val) {
+            createBy = val;
+            return this;
+        }
+
+        public Builder createTime(Date val) {
+            createTime = val;
+            return this;
+        }
+
+        public Builder createTimeLong(long val) {
+            createTimeLong = val;
+            return this;
+        }
+
+        public Builder updateBy(long val) {
+            updateBy = val;
+            return this;
+        }
+
+        public Builder updateTime(Date val) {
+            updateTime = val;
+            return this;
+        }
+
+        public Builder updateTimeLong(long val) {
+            updateTimeLong = val;
+            return this;
+        }
+
+        public Builder appId(String val) {
+            appId = val;
+            return this;
+        }
+
+        public Builder respCode(String val) {
+            respCode = val;
+            return this;
+        }
+
+        public Builder respMsg(String val) {
+            respMsg = val;
+            return this;
+        }
+
+        public Builder timeStamp(long val) {
+            timeStamp = val;
+            return this;
+        }
+
+        public Builder billKey(String val) {
+            billKey = val;
+            return this;
+        }
+
+        public Builder customerName(String val) {
+            customerName = val;
+            return this;
+        }
+
+        public Builder balance(String val) {
+            balance = val;
+            return this;
+        }
+
+        public Builder payAmount(String val) {
+            payAmount = val;
+            return this;
+        }
+
+        public QueryFeeResponse build() {
+            return new QueryFeeResponse(this);
+        }
+    }
+}

+ 116 - 0
yjCommon/src/main/java/com/yinjie/heating/common/tool/PayMapUtil.java

@@ -0,0 +1,116 @@
+package com.yinjie.heating.common.tool;
+
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Field;
+import java.net.URLEncoder;
+import java.util.*;
+
+public class PayMapUtil {
+
+    /**
+     * Map key 排序
+     *
+     * @param map map
+     * @return map
+     */
+    public static Map<String, String> order(Map<String, String> map) {
+        HashMap<String, String> tempMap = new LinkedHashMap<>();
+        List<Map.Entry<String, String>> infoIds = new ArrayList<>(map.entrySet());
+
+        infoIds.sort((o1, o2) -> (o1.getKey()).toString().compareTo(o2.getKey()));
+
+        for (Map.Entry<String, String> item : infoIds) {
+            tempMap.put(item.getKey(), item.getValue());
+        }
+        return tempMap;
+    }
+
+
+    /**
+     * 转换对象为map
+     *
+     * @param object object
+     * @param ignore ignore
+     * @return map
+     */
+    public static Map<String, String> objectToMap(Object object, String... ignore) {
+        Map<String, String> tempMap = new LinkedHashMap<String, String>();
+        for (Field f : getAllFields(object.getClass())) {
+            if (!f.isAccessible()) {
+                f.setAccessible(true);
+            }
+            boolean ig = false;
+            if (ignore != null && ignore.length > 0) {
+                for (String i : ignore) {
+                    if (i.equals(f.getName())) {
+                        ig = true;
+                        break;
+                    }
+                }
+            }
+            if (ig) {
+                continue;
+            } else {
+                Object o = null;
+                try {
+                    o = f.get(object);
+                } catch (IllegalArgumentException e) {
+                    e.printStackTrace();
+                } catch (IllegalAccessException e) {
+                    e.printStackTrace();
+                }
+                tempMap.put(f.getName(), o == null ? "" : o.toString());
+            }
+        }
+        return tempMap;
+    }
+
+    /**
+     * 获取所有Fields,包含父类field
+     *
+     * @param clazz clazz
+     * @return list
+     */
+    private static List<Field> getAllFields(Class<?> clazz) {
+        if (!clazz.equals(Object.class)) {
+            List<Field> fields = new ArrayList<Field>(Arrays.asList(clazz.getDeclaredFields()));
+            List<Field> fields2 = getAllFields(clazz.getSuperclass());
+            if (fields2 != null) {
+                fields.addAll(fields2);
+            }
+            return fields;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * url 参数串连
+     *
+     * @param map            map
+     * @param keyLower       keyLower
+     * @param valueUrlencode valueUrlencode
+     * @return string
+     */
+    public static String mapJoin(Map<String, String> map, boolean keyLower, boolean valueUrlencode) {
+        StringBuilder stringBuilder = new StringBuilder();
+        for (String key : map.keySet()) {
+            if (map.get(key) != null && !"".equals(map.get(key))) {
+                try {
+                    String temp = (key.endsWith("_") && key.length() > 1) ? key.substring(0, key.length() - 1) : key;
+                    stringBuilder.append(keyLower ? temp.toLowerCase() : temp)
+                            .append("=")
+                            .append(valueUrlencode ? URLEncoder.encode(map.get(key), "utf-8").replace("+", "%20") : map.get(key))
+                            .append("&");
+                } catch (UnsupportedEncodingException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        if (stringBuilder.length() > 0) {
+            stringBuilder.deleteCharAt(stringBuilder.length() - 1);
+        }
+        return stringBuilder.toString();
+    }
+
+}

+ 100 - 0
yjCommon/src/main/java/com/yinjie/heating/common/tool/PayRSAUtil.java

@@ -0,0 +1,100 @@
+package com.yinjie.heating.common.tool;
+
+import org.apache.commons.codec.binary.Base64;
+
+import java.nio.charset.StandardCharsets;
+import java.security.*;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+
+/**
+ * Created by jlutt on 2019-07-23.
+ *
+ * @author jlutt
+ */
+public class PayRSAUtil {
+
+    public static enum SignatureSuite {
+        //SHA1("SHA1WithRSA"), MD5("MD5WithRSA");
+        SHA1("SHA1WithRSA"), SHA256("SHA256WithRSA");
+        private final String suite;
+
+        SignatureSuite(String suite) {
+            this.suite = suite;
+        }
+
+        public String val() {
+            return suite;
+        }
+    }
+
+    //private final static Logger logger = LoggerFactory.getLogger(RSAUtil.class);
+
+    private static KeyFactory getKeyFactory() {
+        try {
+            return KeyFactory.getInstance("RSA");
+        } catch (NoSuchAlgorithmException e) {
+            // 应该不会出现
+            throw new RuntimeException("初始化RSA KeyFactory失败");
+        }
+    }
+
+    public static byte[] sign(SignatureSuite suite, byte[] msgBuf, String privateKeyStr) {
+        Signature signature = null;
+        try {
+            signature = Signature.getInstance(suite.val());
+        } catch (Exception e) {
+            // 上线运行时套件一定存在
+            // 异常不往外抛
+        }
+
+        try {
+            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyStr));
+            PrivateKey privateKey = getKeyFactory().generatePrivate(keySpec);
+            signature.initSign(privateKey);
+        } catch (Exception e) {
+            //logger.warn("解析私钥失败:{}", e.getMessage());
+            throw new RuntimeException("INVALID_PRIKEY");
+        }
+        try {
+            signature.update(msgBuf);
+            return signature.sign();
+        } catch (SignatureException e) {
+            // 一般不会出现
+
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+    public static String signStr(String str, String privateKeyStr) {
+        byte[] signBuf = PayRSAUtil.sign(SignatureSuite.SHA256, str.getBytes(StandardCharsets.UTF_8), privateKeyStr);
+        return new String(Base64.encodeBase64(signBuf), StandardCharsets.UTF_8);
+    }
+
+    public static boolean verifySign(SignatureSuite suite, byte[] msgBuf, byte[] sign, String publicKeyStr) {
+        Signature signature = null;
+        try {
+            signature = Signature.getInstance(suite.val());
+        } catch (Exception e) {
+            // 上线运行时套件一定存在
+            // 异常不往外抛
+        }
+
+        try {
+            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyStr));
+            PublicKey publicKey = getKeyFactory().generatePublic(keySpec);
+            signature.initVerify(publicKey);
+        } catch (Exception e) {
+
+            throw new RuntimeException("INVALID_PUBKEY");
+        }
+        try {
+            signature.update(msgBuf);
+            return signature.verify(sign);
+        } catch (SignatureException e) {
+            // 一般不会出现
+
+            throw new RuntimeException("签名格式不合法");
+        }
+    }
+}

+ 257 - 0
yjCommon/src/main/java/com/yinjie/heating/common/tool/PaySignatureUtil.java

@@ -0,0 +1,257 @@
+package com.yinjie.heating.common.tool;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyFactory;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.*;
+
+public class PaySignatureUtil {
+
+    /**
+     * 生成sign HMAC-SHA256 或 MD5 签名
+     *
+     * @param map         map
+     * @param paternerKey paternerKey
+     * @return sign
+     */
+    public static String generateSign(Map<String, String> map, String paternerKey) {
+        return generateSign(map, null, paternerKey);
+    }
+
+    /**
+     * 生成sign HMAC-SHA256 或 MD5 签名
+     *
+     * @param map         map
+     * @param sign_type   HMAC-SHA256 或 MD5
+     * @param paternerKey paternerKey
+     * @return sign
+     */
+    public static String generateSign(Map<String, String> map, String sign_type, String paternerKey) {
+        Map<String, String> tmap = PayMapUtil.order(map);
+        tmap.remove("sign");
+        String str = PayMapUtil.mapJoin(tmap, false, false);
+        //System.out.println(str);
+        if (sign_type == null) {
+            sign_type = tmap.get("sign_type");
+        }
+        tmap.remove("sign_type");
+        if ("HMAC-SHA256".equalsIgnoreCase(sign_type)) {
+            try {
+                Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
+                SecretKeySpec secret_key = new SecretKeySpec(paternerKey.getBytes("UTF-8"), "HmacSHA256");
+                sha256_HMAC.init(secret_key);
+                return Hex.encodeHexString(sha256_HMAC.doFinal((str + "&key=" + paternerKey).getBytes("UTF-8"))).toUpperCase();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+            return null;
+        } else if ("RSA_1_256".equalsIgnoreCase(sign_type)) {
+            byte[] signBuf = PayRSAUtil.sign(PayRSAUtil.SignatureSuite.SHA256, str.getBytes(StandardCharsets.UTF_8), paternerKey);
+            return new String(Base64.encodeBase64(signBuf), StandardCharsets.UTF_8);
+        } else if ("MD5X".equalsIgnoreCase(sign_type)) {
+            return DigestUtils.md5Hex(str + "&" + paternerKey).toUpperCase();
+        } else {//default MD5
+//            System.out.println(str);
+            return DigestUtils.md5Hex(str + "&key=" + paternerKey).toUpperCase();
+        }
+    }
+
+    /**
+     * 生成事件消息接收签名
+     *
+     * @param token     token
+     * @param timestamp timestamp
+     * @param nonce     nonce
+     * @return str
+     */
+    public static String generateEventMessageSignature(String token, String timestamp, String nonce) {
+        String[] array = new String[]{token, timestamp, nonce};
+        Arrays.sort(array);
+        String s = String.join("", array);
+        //String s = StringUtils.arrayToDelimitedString(array, "");
+        return DigestUtils.shaHex(s);
+    }
+
+    private static Map<String, String> paraFilter(Map<String, String> sArray) {
+        Map<String, String> result = new HashMap<>(sArray.size());
+        if (sArray == null || sArray.size() <= 0) {
+            return result;
+        }
+        for (String key : sArray.keySet()) {
+            String value = sArray.get(key);
+            if (value == null || "".equals(value) || "sign".equalsIgnoreCase(key)) {
+                continue;
+            }
+            result.put(key, value);
+        }
+        return result;
+    }
+
+    private static String urlEncode(String str) {
+        try {
+            return URLEncoder.encode(str, StandardCharsets.UTF_8);
+        } catch (Throwable e) {
+            return str;
+        }
+    }
+
+    private static void buildPayParams(StringBuilder sb, Map<String, String> payParams, boolean encoding) {
+        List<String> keys = new ArrayList<>(payParams.keySet());
+        Collections.sort(keys);
+        for (String key : keys) {
+            sb.append(key).append("=");
+            if (encoding) {
+                sb.append(urlEncode(payParams.get(key)));
+            } else {
+                sb.append(payParams.get(key));
+            }
+            sb.append("&");
+        }
+        sb.setLength(sb.length() - 1);
+    }
+
+    public static boolean verifySign(String preStr, String sign, String signType, String platPublicKey) {
+        // 调用这个函数前需要先判断是MD5还是RSA
+        // 商户的验签函数要同时支持MD5和RSA
+        PayRSAUtil.SignatureSuite suite = null;
+
+        if ("RSA_1_1".equals(signType)) {
+            suite = PayRSAUtil.SignatureSuite.SHA1;
+        } else if ("RSA_1_256".equals(signType)) {
+            suite = PayRSAUtil.SignatureSuite.SHA256;
+        } else {
+            return false;
+        }
+
+        try {
+            return PayRSAUtil.verifySign(suite,
+                    preStr.getBytes(StandardCharsets.UTF_8),
+                    Base64.decodeBase64(sign.getBytes(StandardCharsets.UTF_8)),
+                    platPublicKey);
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    public static boolean verifyHuiFu(String data, String publicKeyBase64, String sign) {
+        // Base64 --> Key
+        try {
+            byte[] bytes = java.util.Base64.getDecoder().decode(publicKeyBase64);
+            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
+            KeyFactory keyFactory;
+            keyFactory = KeyFactory.getInstance("RSA");
+            PublicKey publicKey = keyFactory.generatePublic(keySpec);
+            // verify
+            Signature signature = Signature.getInstance("SHA256WithRSA");
+            signature.initVerify(publicKey);
+            signature.update(data.getBytes(StandardCharsets.UTF_8));
+            return signature.verify(java.util.Base64.getDecoder().decode(sign));
+        } catch (Exception e) {
+            return false;
+        }
+
+    }
+
+    public static boolean verifySign(String sign, String signType, Map<String, String> resultMap,
+                                     String platPublicKey,
+                                     String md5Key) {
+        if ("RSA_1_256".equals(signType)) {
+            Map<String, String> Reparams = paraFilter(resultMap);
+            StringBuilder Rebuf = new StringBuilder((Reparams.size() + 1) * 10);
+            buildPayParams(Rebuf, Reparams, false);
+            String RepreStr = Rebuf.toString();
+            return verifySign(RepreStr, sign, "RSA_1_256", platPublicKey);
+        } else if ("MD5".equals(signType)) {
+            String newSign = generateSign(resultMap, "MD5", md5Key);
+            return StringUtils.equals(newSign, sign);
+        } else if ("MD5X".equals(signType)) {
+            String newSign = generateSign(resultMap, "MD5X", md5Key);
+            return StringUtils.equals(newSign, sign);
+        }
+        return false;
+    }
+
+    /**
+     * 对json string进行排序, 排序规则如下:
+     * (1). 如果是对象, 则对对象中的所有的基本数据类型的属性按名称的ASCII升序排序;
+     * (2). 如果是数组, 数组里面的item不进行排序;
+     * (3). 若数组里面包含有对象,请参照规则1.
+     *
+     * @param sourceJson json字符串;
+     * @param maxLayer   json允许的最大嵌套层数;
+     * @return 排序好的json字符串.
+     */
+    @SuppressWarnings("rawtypes")
+    public static String sort4JsonString(String sourceJson, int maxLayer) throws Exception {
+        if (StringUtils.isBlank(sourceJson)) {
+            return "";
+        }
+
+        Map m = JSONObject.parseObject(sourceJson, TreeMap.class);
+
+        if (maxLayer > 0) {
+            //对array中的元素顺序进行单独处理;
+            for (Iterator it = m.entrySet().iterator(); it.hasNext(); ) {
+                Map.Entry entry = (Map.Entry) it.next();
+
+                int layer = 0;
+                if (entry.getValue() instanceof JSONArray) {
+                    JSONArray array = (JSONArray) entry.getValue();
+
+                    sortJsonArray(array, ++layer, maxLayer);
+                }
+            }
+        }
+        return JSON.toJSONString(m);
+    }
+
+    /**
+     * 对json Array中的对象进行排序, 基础数据类型不排序.
+     * <p>
+     * 如果有嵌套, 则递归进行排序.
+     *
+     * @param array    JSONArray实例.
+     * @param layer    json的当前处理的嵌套层数
+     * @param maxLayer json允许最大嵌套层数.
+     */
+    @SuppressWarnings("rawtypes")
+    private static void sortJsonArray(JSONArray array, int layer, int maxLayer) throws Exception {
+        if (layer >= maxLayer) {
+            throw new Exception(String.format("json嵌套层数不超过 %d 层.", maxLayer));
+        }
+
+        for (int i = 0; i < array.size(); i++) {
+            //如果数组中嵌套数组, 则递归排序;
+            if (array.get(i) instanceof JSONArray) {
+                sortJsonArray((JSONArray) array.get(i), ++layer, maxLayer);
+            } else if (!(array.get(i) instanceof Comparable)) {
+                //对数组中的对象进行排序;
+                Map map = JSON.parseObject(array.get(i).toString(), TreeMap.class);
+                array.set(i, map);
+
+                //如果对象中嵌套有数组, 则递归处理;
+                for (Iterator it = map.entrySet().iterator(); it.hasNext(); ) {
+                    Map.Entry entry = (Map.Entry) it.next();
+
+                    if (entry.getValue() instanceof JSONArray) {
+                        sortJsonArray((JSONArray) entry.getValue(), ++layer, maxLayer);
+                    }
+                }
+            }
+        }
+    }
+
+}

+ 11 - 12
yjWebCore/src/main/java/com/yinjie/heating/webcore/servlet/ThirdInvokeServlet.java

@@ -3,14 +3,13 @@ package com.yinjie.heating.webcore.servlet;
 import com.dySweetFishPlugin.tool.lang.DateUtil;
 import com.fasterxml.jackson.dataformat.xml.XmlMapper;
 import com.sweetfish.net.http.*;
-import com.sweetfish.service.RetResult;
 import com.sweetfish.util.AnyValue;
 import com.sweetfish.util.AutoLoad;
 import com.yinjie.heating.common.api.heating.CallThirdAppService;
 import com.yinjie.heating.common.api.heating.HeatingDocService;
 import com.yinjie.heating.common.base.ERPAdminHttpServlet;
-import com.yinjie.heating.common.entity.callthird.BaseRequest;
 import com.yinjie.heating.common.entity.callthird.BaseResponse;
+import com.yinjie.heating.common.entity.callthird.QueryFeeResponse;
 import com.yinjie.heating.common.entity.ceb.CEBInvokeHeader;
 import com.yinjie.heating.common.entity.ceb.CEBRequestItem;
 import com.yinjie.heating.common.entity.ceb.CEBResponseItem;
@@ -144,7 +143,7 @@ public class ThirdInvokeServlet extends ERPAdminHttpServlet {
         }
 
         String billKey = reqBody.get("billKey").toString();
-        BaseResponse orderResult = callThirdAppService.callQueryFee(billKey, heatingApp, DATA_SOURCE_ID, SUPPLIER_CODE).getResult();
+        QueryFeeResponse orderResult = callThirdAppService.callQueryFee(billKey, heatingApp, DATA_SOURCE_ID, SUPPLIER_CODE).getResult();
         if (!orderResult.getRespCode().equals("00000")) {
             //将我们的错误代码翻译成光大的
 //            switch (orderResult.getErrCode()) {
@@ -180,11 +179,11 @@ public class ThirdInvokeServlet extends ERPAdminHttpServlet {
             frame.put("contractNo", billKey);
 
             //三方返回 customerName 用户名称
-            frame.put("customerName", orderResult.getRespData().get("customerName"));
-            //三方返回 customerBalance 用户余额(分)
-            frame.put("balance", CommonUtils.money(Long.parseLong(orderResult.getRespData().get("customerBalance").toString())));
-            //三方返回 customerPayAmount 用户欠款(分)
-            frame.put("payAmount", CommonUtils.money(Long.parseLong(orderResult.getRespData().get("customerPayAmount").toString())));
+            frame.put("customerName", orderResult.getCustomerName());
+            //三方返回 balance 用户余额(分)
+            frame.put("balance", CommonUtils.money(Long.parseLong(orderResult.getBalance())));
+            //三方返回 payAmount 用户欠款(分)
+            frame.put("payAmount", CommonUtils.money(Long.parseLong(orderResult.getPayAmount())));
 
             respBody.put("Frame", frame);
         }
@@ -207,7 +206,7 @@ public class ThirdInvokeServlet extends ERPAdminHttpServlet {
         }
 
         String billKey = reqBody.get("billKey").toString();
-        String payDate = reqBody.get("payDate").toString();
+        String payDate = reqBody.get("payDate").toString();  //yyyyMMdd
         String bankBillNo = reqBody.get("bankBillNo").toString();
         String payAmount = reqBody.get("payAmount").toString();
 
@@ -219,7 +218,7 @@ public class ThirdInvokeServlet extends ERPAdminHttpServlet {
         }
 
         //光大要求缴费金额必须等于欠费金额
-        BaseResponse orderResult = callThirdAppService.callQueryFee(billKey, heatingApp, DATA_SOURCE_ID, SUPPLIER_CODE).getResult();
+        QueryFeeResponse orderResult = callThirdAppService.callQueryFee(billKey, heatingApp, DATA_SOURCE_ID, SUPPLIER_CODE).getResult();
         if (!orderResult.getRespCode().equals("00000")) {
             //将我们的错误代码翻译成光大的
 //            switch (orderResult.getErrCode()) {
@@ -247,7 +246,7 @@ public class ThirdInvokeServlet extends ERPAdminHttpServlet {
 
             return respBody;
         }
-        BigDecimal debtMoney = CommonUtils.money(Long.parseLong(orderResult.getRespData().get("customerPayAmount").toString()));
+        BigDecimal debtMoney = CommonUtils.money(Long.parseLong(orderResult.getPayAmount()));
 
         if (chargeMoney.compareTo(debtMoney) != 0) {
             respBody.put("ErrorCode", "DEF0013");
@@ -266,7 +265,7 @@ public class ThirdInvokeServlet extends ERPAdminHttpServlet {
 ////        customerCharge.setPayMode(chargeOrder.getPayMode());
 //        customerCharge.setCustomerCount(1);
 
-        BaseResponse chargeResult = callThirdAppService.callRequestPay(billKey, DateUtil.asDate(payDate, "yyyyMMdd"), bankBillNo,
+        BaseResponse chargeResult = callThirdAppService.callRequestPay(billKey, payDate, bankBillNo,
                 payAmount, heatingApp, DATA_SOURCE_ID, SUPPLIER_CODE).getResult();
         if (!chargeResult.getRespCode().equals("00000")) {
 //            switch (chargeResult.getErrCode()) {