From 9e4740027f98ab255c09998b2788b30e45d08c31 Mon Sep 17 00:00:00 2001 From: Sum1Dream <418471657@qq.com> Date: Mon, 31 May 2021 23:58:33 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=88=86=E8=B4=A6=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/dev/application.yml | 2 +- .../controller/pay/WechatPayController.java | 43 ++++ .../java/com/hai/common/utils/HttpsUtils.java | 48 ++++- .../java/com/hai/common/utils/WxUtils.java | 203 ++++++++++++++++++ .../hai/model/WxSharingOrderRequestModel.java | 162 ++++++++++++++ .../com/hai/model/WxSharingOrderResp.java | 147 +++++++++++++ .../com/hai/model/WxSharingReceiversVO.java | 71 ++++++ 7 files changed, 673 insertions(+), 3 deletions(-) create mode 100644 hai-service/src/main/java/com/hai/common/utils/WxUtils.java create mode 100644 hai-service/src/main/java/com/hai/model/WxSharingOrderRequestModel.java create mode 100644 hai-service/src/main/java/com/hai/model/WxSharingOrderResp.java create mode 100644 hai-service/src/main/java/com/hai/model/WxSharingReceiversVO.java diff --git a/hai-bweb/src/main/resources/dev/application.yml b/hai-bweb/src/main/resources/dev/application.yml index 58dd9a45..3412b88f 100644 --- a/hai-bweb/src/main/resources/dev/application.yml +++ b/hai-bweb/src/main/resources/dev/application.yml @@ -9,7 +9,7 @@ debug: false #datasource数据源设置 spring: datasource: - url: jdbc:mysql://139.159.177.244:3306/hsg_pre?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8 + url: jdbc:mysql://139.159.177.244:3306/hsg_pre?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false username: root password: HF123456. type: com.alibaba.druid.pool.DruidDataSource diff --git a/hai-cweb/src/main/java/com/cweb/controller/pay/WechatPayController.java b/hai-cweb/src/main/java/com/cweb/controller/pay/WechatPayController.java index 7908936e..359d503c 100644 --- a/hai-cweb/src/main/java/com/cweb/controller/pay/WechatPayController.java +++ b/hai-cweb/src/main/java/com/cweb/controller/pay/WechatPayController.java @@ -1,14 +1,21 @@ package com.cweb.controller.pay; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; import com.cweb.config.SysConst; import com.hai.common.pay.WechatPayUtil; import com.hai.common.pay.util.IOUtil; import com.hai.common.pay.util.SignatureUtil; import com.hai.common.pay.util.XmlUtil; +import com.hai.common.utils.HttpsUtils; +import com.hai.common.utils.WxUtils; +import com.hai.model.WxSharingOrderRequestModel; +import com.hai.model.WxSharingReceiversVO; import com.hai.service.pay.NotifyService; import com.hai.service.pay.PayRecordService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import net.sf.cglib.beans.BeanMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; @@ -19,6 +26,8 @@ import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedOutputStream; +import java.util.ArrayList; +import java.util.List; import java.util.SortedMap; @Controller @@ -148,4 +157,38 @@ public class WechatPayController { return key; }*/ + @RequestMapping(value = "/addLedgerReceiver", method = RequestMethod.POST) + @ApiOperation(value = "微信支付 -> 添加分账接收方") + public void addLedgerReceiver(HttpServletRequest request, HttpServletResponse response) { + try { + + WxSharingOrderRequestModel wxSharingOrderRequest = new WxSharingOrderRequestModel(); + + wxSharingOrderRequest.setMch_id("1289663601"); + wxSharingOrderRequest.setSub_mch_id("1609882817"); + wxSharingOrderRequest.setAppid("wx637bd6f7314daa46"); + wxSharingOrderRequest.setNonce_str(WxUtils.makeNonStr()); + + List list = new ArrayList<>(); + WxSharingReceiversVO receiversVO = new WxSharingReceiversVO(); + receiversVO.setAccount(wxSharingOrderRequest.getSub_mch_id()); + receiversVO.setType("MERCHANT_ID"); + receiversVO.setRelation_type("SERVICE_PROVIDER"); + list.add(receiversVO); + wxSharingOrderRequest.setReceivers(JSONObject.toJSONString(list)); + + BeanMap beanMap = BeanMap.create(wxSharingOrderRequest); + wxSharingOrderRequest.setSign(WxUtils.makeSign(beanMap, "SHA256" ,"SHA256")); + + String url = "https://api.mch.weixin.qq.com/pay/profitsharingaddreceiver"; + String xm = XmlUtil.toSplitXml(wxSharingOrderRequest); + JSONObject jsonObject = HttpsUtils.postData(url, xm); + + System.out.println(jsonObject); + log.info("微信支付 -> 添加分账接收方:处理开始"); + } catch (Exception e) { + log.error("WechatPayController --> wechatNotify() error!", e); + } + } + } diff --git a/hai-service/src/main/java/com/hai/common/utils/HttpsUtils.java b/hai-service/src/main/java/com/hai/common/utils/HttpsUtils.java index 006feccb..f09a3479 100644 --- a/hai-service/src/main/java/com/hai/common/utils/HttpsUtils.java +++ b/hai-service/src/main/java/com/hai/common/utils/HttpsUtils.java @@ -342,8 +342,6 @@ public class HttpsUtils { * 发送 POST 请求,JSON形式 * * @param apiUrl - * @param json - * json对象 * @return */ public static JSONObject doPost(String apiUrl, String str) { @@ -421,6 +419,52 @@ public class HttpsUtils { return null; } + /** + + * + * @param url API地址 + * @return + */ + public static JSONObject postData(String url, String str) { + CloseableHttpClient httpClient = null; + if (url.startsWith("https")) { + httpClient = HttpClients.custom().setSSLSocketFactory(createSSLConnSocketFactory()) + .setConnectionManager(connMgr).setDefaultRequestConfig(requestConfig).build(); + } else { + httpClient = HttpClients.createDefault(); + } + String httpStr = null; + CloseableHttpResponse response = null; + + try { + HttpPost httpPost = new HttpPost(url); + httpPost.setConfig(requestConfig); + + StringEntity stringEntity = new StringEntity(str, "UTF-8");// 解决中文乱码问题 + stringEntity.setContentEncoding("UTF-8"); + httpPost.addHeader("Content-Type", "text/xml"); + stringEntity.setContentType("application/json"); + httpPost.setEntity(stringEntity); + response = httpClient.execute(httpPost); + HttpEntity entity = response.getEntity(); + httpStr = EntityUtils.toString(entity, "UTF-8"); + return JSON.parseObject(httpStr); + } catch (Exception e) { + log.error(e.getMessage(),e); + } finally { + if (response != null) { + try { + EntityUtils.consume(response.getEntity()); + } catch (IOException e) { + log.error(e.getMessage(),e); + } + } + } + return null; + } + + + /** * 创建SSL安全连接 * diff --git a/hai-service/src/main/java/com/hai/common/utils/WxUtils.java b/hai-service/src/main/java/com/hai/common/utils/WxUtils.java new file mode 100644 index 00000000..7dc733bc --- /dev/null +++ b/hai-service/src/main/java/com/hai/common/utils/WxUtils.java @@ -0,0 +1,203 @@ +package com.hai.common.utils; + +import com.google.common.collect.Maps; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.naming.NoNameCoder; +import com.thoughtworks.xstream.io.xml.XppDriver; +import net.sf.cglib.beans.BeanMap; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.security.MessageDigest; +import java.security.SecureRandom; +import java.util.*; + +public class WxUtils { + + private static final Random RANDOM = new SecureRandom(); + + private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + /** + * 生成签名 + * + * @param signMaps + * @return + * @throws Exception + */ + public static String generateSign(SortedMap signMaps, String mchKey) { + StringBuffer sb = new StringBuffer(); + + // 字典序 + for (Map.Entry signMap : signMaps.entrySet()) { + String key = (String) signMap.getKey(); + String value = (String) signMap.getValue(); + + // 为空不参与签名、参数名区分大小写 + if (null != value && !"".equals(value) && !"sign".equals(key) && !"key".equals(key)) { + sb.append(key).append("=").append(value).append("&"); + } + } + + // 拼接key + sb.append("key=").append(mchKey); + // MD5加密 + String sign = MD5Encode(sb.toString(), "UTF-8").toUpperCase(); + return sign; + } + + public static String generateSignSHA256(SortedMap signMaps,String mchKey)throws Exception{ + StringBuffer sb = new StringBuffer(); + + // 字典序 + for (Map.Entry signMap : signMaps.entrySet()) { + String key = (String) signMap.getKey(); + String value = (String) signMap.getValue(); + + // 为空不参与签名、参数名区分大小写 + if (null != value && !"".equals(value) && !"sign".equals(key) && !"key".equals(key)) { + sb.append(key).append("=").append(value).append("&"); + } + } + + // 拼接key + sb.append("key=").append(mchKey); + // MD5加密 + String sign = HMACSHA256(sb.toString(), mchKey).toUpperCase(); + return sign; + } + + private static String byteArrayToHexString(byte b[]) { + StringBuffer resultSb = new StringBuffer(); + for (int i = 0; i < b.length; i++) + resultSb.append(byteToHexString(b[i])); + + return resultSb.toString(); + } + + private static String byteToHexString(byte b) { + int n = b; + if (n < 0) + n += 256; + int d1 = n / 16; + int d2 = n % 16; + return hexDigits[d1] + hexDigits[d2]; + } + + public static String MD5Encode(String origin, String charsetname) { + String resultString = null; + try { + resultString = new String(origin); + MessageDigest md = MessageDigest.getInstance("MD5"); + if (charsetname == null || "".equals(charsetname)) + resultString = byteArrayToHexString(md.digest(resultString + .getBytes())); + else + resultString = byteArrayToHexString(md.digest(resultString + .getBytes(charsetname))); + } catch (Exception exception) { + } + return resultString; + } + + private static final String[] hexDigits = { "0", "1", "2", "3", "4", "5", + "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" }; + + + + private static HashMap sortAsc(Map map) { + HashMap tempMap = new LinkedHashMap(); + List> infoIds = new ArrayList>(map.entrySet()); + //排序 + infoIds.sort(new Comparator>() { + @Override + public int compare(Map.Entry o1, Map.Entry o2) { + return o1.getKey().compareTo(o2.getKey()); + } + }); + + for (int i = 0; i < infoIds.size(); i++) { + Map.Entry item = infoIds.get(i); + tempMap.put(item.getKey(), item.getValue()); + } + return tempMap; + } + + + + /** + * 生成 HMACSHA256 + * @param data 待处理数据 + * @param key 密钥 + * @return 加密结果 + * @throws Exception + */ + public static String HMACSHA256(String data, String key) throws Exception { + String hash = ""; + try { + Mac sha256_HMAC = Mac.getInstance("HmacSHA256"); + SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(), "HmacSHA256"); + sha256_HMAC.init(secret_key); + byte[] bytes = sha256_HMAC.doFinal(data.getBytes()); + hash = byteArrayToHexString(bytes); + } catch (Exception e) { + System.out.println("Error HmacSHA256 ===========" + e.getMessage()); + } + return hash.toUpperCase(); + } + + /** + * 获取随机字符串 Nonce Str + * + * @return String 随机字符串 + */ + public static String makeNonStr() { + char[] nonceChars = new char[32]; + for (int index = 0; index < nonceChars.length; ++index) { + nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length())); + } + return new String(nonceChars); + } + + /** + * 拼接签名数据 + * + */ + public static String makeSign(BeanMap beanMap, String mchKey, String signType)throws Exception { + SortedMap signMaps = Maps.newTreeMap(); + + for (Object key : beanMap.keySet()) { + Object value = beanMap.get(key); + + // 排除空数据 + if (value == null) { + continue; + } + signMaps.put(key + "", String.valueOf(value)); + } + if(signType.equals("MD5")) { + // 生成签名 + return generateSign(signMaps, mchKey); + }else if(signType.equals("SHA256")){ + return generateSignSHA256(signMaps, mchKey); + }else{ + return null; + } + } + + /** + * 数据转换为xml格式 + * + * @param object + * @param obj + * @return + */ + public static String truncateDataToXML(Class object, Object obj) { + XStream xStream = new XStream(new XppDriver(new NoNameCoder())); + xStream.alias("xml", object); + return xStream.toXML(obj); + } + + + +} diff --git a/hai-service/src/main/java/com/hai/model/WxSharingOrderRequestModel.java b/hai-service/src/main/java/com/hai/model/WxSharingOrderRequestModel.java new file mode 100644 index 00000000..78842c49 --- /dev/null +++ b/hai-service/src/main/java/com/hai/model/WxSharingOrderRequestModel.java @@ -0,0 +1,162 @@ +package com.hai.model; + +/** + * 分账请求类 + */ +public class WxSharingOrderRequestModel { + + /** + * 服务商商户号 + */ + private String mch_id; + + /** + * 子商户号 + */ + private String sub_mch_id; + + /** + * 服务商appid + */ + private String appid; + + /** + * 子商户appid + */ + private String sub_appid; + + /** + * 随机字符串 + */ + private String nonce_str; + + /** + * 签名 + */ + private String sign; + /** + * 签名类型(只支持HMAC-SHA256) + */ + private String sign_type; + + /** + * 微信订单号 + */ + private String transaction_id; + + /** + * 商家订单号 + */ + private String out_trade_no; + + /** + * 商户分账单号(同一个单号多次提交只算一次) + */ + private String out_order_no; + + /** + * 商户分账金额(小于等于订单金额*(1-手续费)*最大分账比例) + */ + private Integer amount; + + /** + * 分账接收方列表(单次分账不能即是支付商户又是接收商户,多次分账没有限制) + */ + private String receivers; + + public String getMch_id() { + return mch_id; + } + + public void setMch_id(String mch_id) { + this.mch_id = mch_id; + } + + public String getSub_mch_id() { + return sub_mch_id; + } + + public void setSub_mch_id(String sub_mch_id) { + this.sub_mch_id = sub_mch_id; + } + + public String getAppid() { + return appid; + } + + public void setAppid(String appid) { + this.appid = appid; + } + + public String getSub_appid() { + return sub_appid; + } + + public void setSub_appid(String sub_appid) { + this.sub_appid = sub_appid; + } + + public String getNonce_str() { + return nonce_str; + } + + public void setNonce_str(String nonce_str) { + this.nonce_str = nonce_str; + } + + public String getSign() { + return sign; + } + + public void setSign(String sign) { + this.sign = sign; + } + + public String getSign_type() { + return sign_type; + } + + public void setSign_type(String sign_type) { + this.sign_type = sign_type; + } + + public String getTransaction_id() { + return transaction_id; + } + + public void setTransaction_id(String transaction_id) { + this.transaction_id = transaction_id; + } + + public String getOut_trade_no() { + return out_trade_no; + } + + public void setOut_trade_no(String out_trade_no) { + this.out_trade_no = out_trade_no; + } + + public String getOut_order_no() { + return out_order_no; + } + + public void setOut_order_no(String out_order_no) { + this.out_order_no = out_order_no; + } + + public Integer getAmount() { + return amount; + } + + public void setAmount(Integer amount) { + this.amount = amount; + } + + public String getReceivers() { + return receivers; + } + + public void setReceivers(String receivers) { + this.receivers = receivers; + } +} diff --git a/hai-service/src/main/java/com/hai/model/WxSharingOrderResp.java b/hai-service/src/main/java/com/hai/model/WxSharingOrderResp.java new file mode 100644 index 00000000..af5a1b6e --- /dev/null +++ b/hai-service/src/main/java/com/hai/model/WxSharingOrderResp.java @@ -0,0 +1,147 @@ +package com.hai.model; + +// 分账返回 +public class WxSharingOrderResp { + + //返回状态码,通信标识,SUCCESS/FAIL + private String return_code; + //返回信息,通信标识OK + private String return_msg; + //业务结果,交易标识,SUCCESS/FAIL + private String result_code; + //错误代码 + private String err_code; + //错误代码描述 + private String err_code_des; + //商户号 + private String mch_id; + //子商户号 + private String sub_mch_id; + //公众账号id + private String appid; + + private String sub_appid; + + //随机字符串 + private String nonce_str; + //签名 + private String sign; + //微信支付订单号 + private String transaction_id; + //商户分账单号(商户订单号) + private String out_order_no; + //商户分账单号 + private String order_id; + + public String getReturn_code() { + return return_code; + } + + public void setReturn_code(String return_code) { + this.return_code = return_code; + } + + public String getReturn_msg() { + return return_msg; + } + + public void setReturn_msg(String return_msg) { + this.return_msg = return_msg; + } + + public String getResult_code() { + return result_code; + } + + public void setResult_code(String result_code) { + this.result_code = result_code; + } + + public String getErr_code() { + return err_code; + } + + public void setErr_code(String err_code) { + this.err_code = err_code; + } + + public String getErr_code_des() { + return err_code_des; + } + + public void setErr_code_des(String err_code_des) { + this.err_code_des = err_code_des; + } + + public String getMch_id() { + return mch_id; + } + + public void setMch_id(String mch_id) { + this.mch_id = mch_id; + } + + public String getSub_mch_id() { + return sub_mch_id; + } + + public void setSub_mch_id(String sub_mch_id) { + this.sub_mch_id = sub_mch_id; + } + + public String getAppid() { + return appid; + } + + public void setAppid(String appid) { + this.appid = appid; + } + + public String getSub_appid() { + return sub_appid; + } + + public void setSub_appid(String sub_appid) { + this.sub_appid = sub_appid; + } + + public String getNonce_str() { + return nonce_str; + } + + public void setNonce_str(String nonce_str) { + this.nonce_str = nonce_str; + } + + public String getSign() { + return sign; + } + + public void setSign(String sign) { + this.sign = sign; + } + + public String getTransaction_id() { + return transaction_id; + } + + public void setTransaction_id(String transaction_id) { + this.transaction_id = transaction_id; + } + + public String getOut_order_no() { + return out_order_no; + } + + public void setOut_order_no(String out_order_no) { + this.out_order_no = out_order_no; + } + + public String getOrder_id() { + return order_id; + } + + public void setOrder_id(String order_id) { + this.order_id = order_id; + } +} diff --git a/hai-service/src/main/java/com/hai/model/WxSharingReceiversVO.java b/hai-service/src/main/java/com/hai/model/WxSharingReceiversVO.java new file mode 100644 index 00000000..2de697f8 --- /dev/null +++ b/hai-service/src/main/java/com/hai/model/WxSharingReceiversVO.java @@ -0,0 +1,71 @@ +package com.hai.model; + +/** + * 分账接收方 + */ +public class WxSharingReceiversVO { + /** + * 分账接收方类型 + */ + private String type; + + /** + * 分账接收方帐号 + */ + private String account; + + /** + * 分账金额 + */ + private Integer amount; + + /** + * 分账描述 + */ + private String description; + + /** + * 与分账方的关系类型 + */ + private String relation_type; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getAccount() { + return account; + } + + public void setAccount(String account) { + this.account = account; + } + + public Integer getAmount() { + return amount; + } + + public void setAmount(Integer amount) { + this.amount = amount; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getRelation_type() { + return relation_type; + } + + public void setRelation_type(String relation_type) { + this.relation_type = relation_type; + } +}