|
|
@ -1,29 +1,51 @@ |
|
|
|
package com.cweb.controller.pay; |
|
|
|
package com.cweb.controller.pay; |
|
|
|
|
|
|
|
|
|
|
|
import com.alibaba.fastjson.JSONObject; |
|
|
|
import com.alibaba.fastjson.JSONObject; |
|
|
|
|
|
|
|
import com.cweb.config.SysConst; |
|
|
|
import com.hai.common.pay.WechatPayUtil; |
|
|
|
import com.hai.common.pay.WechatPayUtil; |
|
|
|
import com.hai.common.pay.util.IOUtil; |
|
|
|
import com.hai.common.pay.util.IOUtil; |
|
|
|
import com.hai.common.pay.util.XmlUtil; |
|
|
|
import com.hai.common.pay.util.XmlUtil; |
|
|
|
import com.hai.common.pay.util.sdk.WXPayConstants; |
|
|
|
import com.hai.common.pay.util.sdk.WXPayConstants; |
|
|
|
import com.hai.common.utils.HttpsUtils; |
|
|
|
import com.hai.common.utils.HttpsUtils; |
|
|
|
|
|
|
|
import com.hai.common.utils.ResponseMsgUtil; |
|
|
|
import com.hai.common.utils.WxUtils; |
|
|
|
import com.hai.common.utils.WxUtils; |
|
|
|
|
|
|
|
import com.hai.entity.BsCompany; |
|
|
|
|
|
|
|
import com.hai.entity.SecRegion; |
|
|
|
|
|
|
|
import com.hai.model.ResponseData; |
|
|
|
import com.hai.model.WxSharingOrderRequestModel; |
|
|
|
import com.hai.model.WxSharingOrderRequestModel; |
|
|
|
import com.hai.model.WxSharingReceiversVO; |
|
|
|
import com.hai.model.WxSharingReceiversVO; |
|
|
|
import com.hai.service.pay.NotifyService; |
|
|
|
import com.hai.service.pay.NotifyService; |
|
|
|
import com.hai.service.pay.PayRecordService; |
|
|
|
import com.hai.service.pay.PayRecordService; |
|
|
|
|
|
|
|
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil; |
|
|
|
import io.swagger.annotations.Api; |
|
|
|
import io.swagger.annotations.Api; |
|
|
|
import io.swagger.annotations.ApiOperation; |
|
|
|
import io.swagger.annotations.ApiOperation; |
|
|
|
import net.sf.cglib.beans.BeanMap; |
|
|
|
import net.sf.cglib.beans.BeanMap; |
|
|
|
|
|
|
|
import org.apache.http.HttpEntity; |
|
|
|
|
|
|
|
import org.apache.http.client.methods.CloseableHttpResponse; |
|
|
|
|
|
|
|
import org.apache.http.client.methods.HttpPost; |
|
|
|
|
|
|
|
import org.apache.http.conn.ssl.SSLConnectionSocketFactory; |
|
|
|
|
|
|
|
import org.apache.http.entity.StringEntity; |
|
|
|
|
|
|
|
import org.apache.http.impl.client.CloseableHttpClient; |
|
|
|
|
|
|
|
import org.apache.http.impl.client.HttpClients; |
|
|
|
|
|
|
|
import org.apache.http.ssl.SSLContexts; |
|
|
|
|
|
|
|
import org.apache.http.util.EntityUtils; |
|
|
|
import org.slf4j.Logger; |
|
|
|
import org.slf4j.Logger; |
|
|
|
import org.slf4j.LoggerFactory; |
|
|
|
import org.slf4j.LoggerFactory; |
|
|
|
import org.springframework.stereotype.Controller; |
|
|
|
import org.springframework.stereotype.Controller; |
|
|
|
import org.springframework.web.bind.annotation.RequestMapping; |
|
|
|
import org.springframework.web.bind.annotation.RequestMapping; |
|
|
|
import org.springframework.web.bind.annotation.RequestMethod; |
|
|
|
import org.springframework.web.bind.annotation.RequestMethod; |
|
|
|
|
|
|
|
import org.springframework.web.bind.annotation.RequestParam; |
|
|
|
|
|
|
|
import org.springframework.web.bind.annotation.ResponseBody; |
|
|
|
|
|
|
|
|
|
|
|
import javax.annotation.Resource; |
|
|
|
import javax.annotation.Resource; |
|
|
|
|
|
|
|
import javax.net.ssl.SSLContext; |
|
|
|
import javax.servlet.http.HttpServletRequest; |
|
|
|
import javax.servlet.http.HttpServletRequest; |
|
|
|
import javax.servlet.http.HttpServletResponse; |
|
|
|
import javax.servlet.http.HttpServletResponse; |
|
|
|
import java.io.BufferedOutputStream; |
|
|
|
import java.io.BufferedOutputStream; |
|
|
|
|
|
|
|
import java.io.FileInputStream; |
|
|
|
|
|
|
|
import java.io.FileNotFoundException; |
|
|
|
|
|
|
|
import java.io.UnsupportedEncodingException; |
|
|
|
|
|
|
|
import java.security.*; |
|
|
|
import java.util.*; |
|
|
|
import java.util.*; |
|
|
|
|
|
|
|
|
|
|
|
@Controller |
|
|
|
@Controller |
|
|
@ -155,15 +177,113 @@ public class WechatPayController { |
|
|
|
return key; |
|
|
|
return key; |
|
|
|
}*/ |
|
|
|
}*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@RequestMapping(value = "/wxProfitsharing", method = RequestMethod.GET) |
|
|
|
|
|
|
|
@ApiOperation(value = "微信分账") |
|
|
|
|
|
|
|
@ResponseBody |
|
|
|
|
|
|
|
public ResponseData wxProfitsharing() { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
Map<String,String> param = new LinkedHashMap<>(); |
|
|
|
|
|
|
|
param.put("appid", "wx637bd6f7314daa46"); |
|
|
|
|
|
|
|
param.put("mch_id", "1289663601"); |
|
|
|
|
|
|
|
param.put("sub_mch_id" , "1609882817"); |
|
|
|
|
|
|
|
param.put("transaction_id" , "4200001152202106091959467542"); |
|
|
|
|
|
|
|
param.put("out_order_no" , "HF2021060901121681200"); |
|
|
|
|
|
|
|
param.put("nonce_str" , WxUtils.makeNonStr()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
List<Map<String,Object>> receiversList = new ArrayList<>(); |
|
|
|
|
|
|
|
Map<String,Object> receiversMap = new LinkedHashMap<>(); |
|
|
|
|
|
|
|
receiversMap.put("type", "MERCHANT_ID"); |
|
|
|
|
|
|
|
receiversMap.put("account", "1603942866"); |
|
|
|
|
|
|
|
receiversMap.put("amount", 1); |
|
|
|
|
|
|
|
receiversMap.put("description", "分给1603942866商户"); |
|
|
|
|
|
|
|
//receiversMap.put("name", "个体户黎杨珍");
|
|
|
|
|
|
|
|
receiversList.add(receiversMap); |
|
|
|
|
|
|
|
param.put("receivers" , JSONObject.toJSONString(receiversList)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String signStr = WxUtils.generateSignature(param, "Skufk5oi85wDFGl888i6wsRSTkdd5df5" , WXPayConstants.SignType.HMACSHA256); |
|
|
|
|
|
|
|
param.put("sign" , signStr); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*String certPath = "/path/to/apiclient_cert.p12"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String post = getToken("POST", "/v3/pay/transactions/h5", JSONObject.toJSONString(param)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Map<String,Object> header = new HashMap<>(); |
|
|
|
|
|
|
|
header.put("Accept","application/json"); |
|
|
|
|
|
|
|
header.put("Authorization", "WECHATPAY2-SHA256-RSA2048 " + post);*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//JSONObject object = HttpsUtils.doWxPost("https://api.mch.weixin.qq.com/secapi/pay/profitsharing", param, header);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//String url = "https://api.mch.weixin.qq.com/secapi/pay/profitsharing";
|
|
|
|
|
|
|
|
String xm = WxUtils.mapToXml(param); |
|
|
|
|
|
|
|
// String rest = String.valueOf(HttpsUtils.postData(url, xm));
|
|
|
|
|
|
|
|
return ResponseMsgUtil.success(this.doRefundRequest(param.get("mch_id"),null, xm)); |
|
|
|
|
|
|
|
// return ResponseMsgUtil.success(null);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
|
|
log.error("CmsContentController --> getCorporateAdvertising() error!", e); |
|
|
|
|
|
|
|
return ResponseMsgUtil.exception(e); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//微信小程序读取双向证书
|
|
|
|
|
|
|
|
private static CloseableHttpClient readCertificate(String mchId) throws Exception{ |
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* 注意PKCS12证书 是从微信商户平台-》账户设置-》 API安全 中下载的 |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
KeyStore keyStore = KeyStore.getInstance("PKCS12"); |
|
|
|
|
|
|
|
//P12文件目录 证书路径,这里需要你自己修改,linux下还是windows下的根路径
|
|
|
|
|
|
|
|
FileInputStream instream = new FileInputStream("G:\\hurui-project/hai-parent/hai-cweb/src/main/resources/privatekey/1289663601_apiclient_cert.p12"); |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
keyStore.load(instream, "1289663601".toCharArray());//这里写密码..默认是你的MCHID
|
|
|
|
|
|
|
|
} finally { |
|
|
|
|
|
|
|
instream.close(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, "1289663601".toCharArray()).build();//这里也是写密码的
|
|
|
|
|
|
|
|
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, SSLConnectionSocketFactory.getDefaultHostnameVerifier()); |
|
|
|
|
|
|
|
// Allow TLSv1 protocol only
|
|
|
|
|
|
|
|
return HttpClients.custom().setSSLSocketFactory(sslsf).build(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public String doRefundRequest(String mchId, String url, String data) throws Exception { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//小程序退款需要调用双向证书的认证
|
|
|
|
|
|
|
|
CloseableHttpClient httpClient = readCertificate(mchId); |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
HttpPost httpost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/profitsharing"); // 设置响应头信息
|
|
|
|
|
|
|
|
httpost.addHeader("Connection", "keep-alive"); |
|
|
|
|
|
|
|
httpost.addHeader("Accept", "*/*"); |
|
|
|
|
|
|
|
httpost.addHeader("Content-Type", "text/xml"); |
|
|
|
|
|
|
|
httpost.addHeader("Host", "api.mch.weixin.qq.com"); |
|
|
|
|
|
|
|
httpost.addHeader("X-Requested-With", "XMLHttpRequest"); |
|
|
|
|
|
|
|
httpost.addHeader("Cache-Control", "max-age=0"); |
|
|
|
|
|
|
|
httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) "); |
|
|
|
|
|
|
|
httpost.setEntity(new StringEntity(data, "UTF-8")); |
|
|
|
|
|
|
|
CloseableHttpResponse response = httpClient.execute(httpost); |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
HttpEntity entity = response.getEntity(); |
|
|
|
|
|
|
|
String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8"); |
|
|
|
|
|
|
|
EntityUtils.consume(entity); |
|
|
|
|
|
|
|
return jsonStr; |
|
|
|
|
|
|
|
} finally { |
|
|
|
|
|
|
|
response.close(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} catch (Exception e){ |
|
|
|
|
|
|
|
throw new RuntimeException(e); |
|
|
|
|
|
|
|
} finally { |
|
|
|
|
|
|
|
httpClient.close(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@RequestMapping(value = "/addLedgerReceiver", method = RequestMethod.POST) |
|
|
|
@RequestMapping(value = "/addLedgerReceiver", method = RequestMethod.POST) |
|
|
|
@ApiOperation(value = "微信支付 -> 添加分账接收方") |
|
|
|
@ApiOperation(value = "微信支付 -> 添加分账接收方") |
|
|
|
public void addLedgerReceiver(HttpServletRequest request, HttpServletResponse response) { |
|
|
|
public void addLedgerReceiver(HttpServletRequest request, HttpServletResponse response) { |
|
|
|
try { |
|
|
|
try { |
|
|
|
|
|
|
|
|
|
|
|
WxSharingReceiversVO receiversVO = new WxSharingReceiversVO(); |
|
|
|
WxSharingReceiversVO receiversVO = new WxSharingReceiversVO(); |
|
|
|
receiversVO.setAccount("1609882817"); |
|
|
|
receiversVO.setAccount("1603942866"); |
|
|
|
receiversVO.setType("MERCHANT_ID"); |
|
|
|
receiversVO.setType("MERCHANT_ID"); |
|
|
|
receiversVO.setName("个体户黎杨珍"); |
|
|
|
receiversVO.setName("重庆惠昕石化有限责任公司"); |
|
|
|
receiversVO.setRelation_type("SERVICE_PROVIDER"); |
|
|
|
receiversVO.setRelation_type("SERVICE_PROVIDER"); |
|
|
|
|
|
|
|
|
|
|
|
Map<String , String> map = new HashMap<>(); |
|
|
|
Map<String , String> map = new HashMap<>(); |
|
|
@ -191,5 +311,37 @@ public class WechatPayController { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String getToken(String method, String url, String body) throws UnsupportedEncodingException, SignatureException, NoSuchAlgorithmException, InvalidKeyException, FileNotFoundException { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
long timeMillis = System.currentTimeMillis(); |
|
|
|
|
|
|
|
String nonceStr = String.valueOf(timeMillis); |
|
|
|
|
|
|
|
long timestamp = System.currentTimeMillis() / 1000; |
|
|
|
|
|
|
|
String message = buildMessage(method, url, timestamp, nonceStr, body); |
|
|
|
|
|
|
|
PrivateKey privateKey = PemUtil.loadPrivateKey(new FileInputStream("G:/hurui-project/hai-parent/hai-cweb/src/main/resources/privatekey/apiclient_key.pem")); |
|
|
|
|
|
|
|
String signature = sign(privateKey,message.getBytes("utf-8")); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return "mchid=\"" + SysConst.getSysConfig().getWxSubMchId() + "\"," |
|
|
|
|
|
|
|
+ "nonce_str=\"" + nonceStr + "\"," |
|
|
|
|
|
|
|
+ "timestamp=\"" + timestamp + "\"," |
|
|
|
|
|
|
|
+ "serial_no=\"" + "1B08DC2A078B0B1F77A65C97C445AAD545B5EAA6" + "\"," |
|
|
|
|
|
|
|
+ "signature=\"" + signature + "\""; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String sign(PrivateKey privateKey,byte[] message) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException { |
|
|
|
|
|
|
|
Signature sign = Signature.getInstance("SHA256withRSA"); |
|
|
|
|
|
|
|
sign.initSign(privateKey); |
|
|
|
|
|
|
|
sign.update(message); |
|
|
|
|
|
|
|
return Base64.getEncoder().encodeToString(sign.sign()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String buildMessage(String method, String url, long timestamp, String nonceStr, String body) { |
|
|
|
|
|
|
|
return method + "\n" |
|
|
|
|
|
|
|
+ url + "\n" |
|
|
|
|
|
|
|
+ timestamp + "\n" |
|
|
|
|
|
|
|
+ nonceStr + "\n" |
|
|
|
|
|
|
|
+ body + "\n"; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|