diff --git a/util_wechat/src/main/java/com/ccsens/wechatutil/bean/vo/WxNativePay.java b/util_wechat/src/main/java/com/ccsens/wechatutil/bean/vo/WxPayOrders.java similarity index 91% rename from util_wechat/src/main/java/com/ccsens/wechatutil/bean/vo/WxNativePay.java rename to util_wechat/src/main/java/com/ccsens/wechatutil/bean/vo/WxPayOrders.java index 610a304..5bb7a7b 100644 --- a/util_wechat/src/main/java/com/ccsens/wechatutil/bean/vo/WxNativePay.java +++ b/util_wechat/src/main/java/com/ccsens/wechatutil/bean/vo/WxPayOrders.java @@ -8,7 +8,7 @@ import java.util.List; * @author 逗 */ @Data -public class WxNativePay { +public class WxPayOrders { /** * 应用ID 是 */ @@ -56,7 +56,11 @@ public class WxNativePay { /** * 结算信息 */ - private SceneInfo settle_info; + private SettleInfo settle_info; + /** + * 支付者 + */ + private Payer payer; @Data public static class Amount{ @@ -117,4 +121,10 @@ public class WxNativePay { //是否指定分账 private boolean profit_sharing; } + + @Data + public static class Payer{ + //是否指定分账 + private String openid; + } } diff --git a/util_wechat/src/main/java/com/ccsens/wechatutil/payutil/wxjsapi/JsApiPay.java b/util_wechat/src/main/java/com/ccsens/wechatutil/payutil/wxjsapi/JsApiPay.java new file mode 100644 index 0000000..fdc3e71 --- /dev/null +++ b/util_wechat/src/main/java/com/ccsens/wechatutil/payutil/wxjsapi/JsApiPay.java @@ -0,0 +1,73 @@ +package com.ccsens.wechatutil.payutil.wxjsapi; + +import com.alibaba.fastjson.JSONObject; +import com.ccsens.wechatutil.bean.vo.WxPayOrders; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.util.EntityUtils; + +/** + * @author 逗 + */ +@Slf4j +public class JsApiPay { + + + /** + * 生成订单 返回预支付交易会话标识 + * @return 返回二维码访问路径(不包含前缀) + */ + public static JSONObject transactions(WxPayOrders wxPayOrders,String serialNo,String keyFilePath,String v3Key) throws Exception { + HttpPost httpPost = new HttpPost(JsApiUtils.URL_TRANSACTIONS); + httpPost.addHeader("Accept", "application/json"); + httpPost.addHeader("Content-type", "application/json; charset=utf-8"); + + JSONObject params = new JSONObject(); + JSONObject amount = new JSONObject(); + JSONObject payer = new JSONObject(); + payer.put("openid", wxPayOrders.getPayer().getOpenid()); + + amount.put("total", wxPayOrders.getAmount().getTotal()); + amount.put("currency", "CNY"); + + params.put("appid", wxPayOrders.getAppid()); + params.put("mchid", wxPayOrders.getMchid()); + params.put("out_trade_no", wxPayOrders.getOut_trade_no()); + params.put("description", wxPayOrders.getDescription()); + params.put("notify_url", wxPayOrders.getNotify_url()); + params.put("amount", amount); + params.put("payer", payer); + + httpPost.setEntity(new StringEntity(params.toJSONString(), "UTF-8")); + CloseableHttpResponse response = (CloseableHttpResponse) JsApiUtils.getWechatPayHttpClient(wxPayOrders.getMchid(),serialNo,keyFilePath, v3Key).execute(httpPost); + String bodyAsString = EntityUtils.toString(response.getEntity()); + JSONObject respJson = JSONObject.parseObject(bodyAsString); + + Object prepayId = respJson.get("prepay_id"); + Object code = respJson.get("code"); + + if (code != null) { + throw new Exception(respJson.get("message").toString()); + } + JSONObject result = new JSONObject(); + //根据返回的prepay_id生成发起支付需要的参数签名返回前端 + + result.put("appId", wxPayOrders.getAppid()); + result.put("timeStamp", System.currentTimeMillis() / 1000); + result.put("nonceStr", JsApiUtils.createNonceStr()); + result.put("package", "prepay_id=" + prepayId); + result.put("signType", "RSA"); + + String message = wxPayOrders.getAppid() + "\n" + + result.get("timeStamp") + "\n" + + result.get("nonceStr") + "\n" + + result.get("package") + "\n"; + String sign = JsApiUtils.wxPayReqSign(keyFilePath,message.getBytes("utf-8")); + result.put("paySign", sign); + return result; + } + + +} diff --git a/util_wechat/src/main/java/com/ccsens/wechatutil/payutil/wxjsapi/JsApiUtils.java b/util_wechat/src/main/java/com/ccsens/wechatutil/payutil/wxjsapi/JsApiUtils.java new file mode 100644 index 0000000..2c73d9c --- /dev/null +++ b/util_wechat/src/main/java/com/ccsens/wechatutil/payutil/wxjsapi/JsApiUtils.java @@ -0,0 +1,76 @@ +package com.ccsens.wechatutil.payutil.wxjsapi; + +import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder; +import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier; +import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner; +import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials; +import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator; +import com.wechat.pay.contrib.apache.httpclient.util.PemUtil; +import org.apache.http.client.HttpClient; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.security.*; +import java.util.Base64; +import java.util.UUID; + + +/** + * @author 逗 + */ +public class JsApiUtils { + + /** + * 请求地址 + */ + public static final String URL_TRANSACTIONS = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi"; + + /** + * 根据微信平台证书获取httpclient + */ + public static HttpClient getWechatPayHttpClient(String mchId,String serialNo,String keyFilePath,String v3Key) throws FileNotFoundException { + HttpClient httpClient; + //构造WechatPayHttpClientBuilder + WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create() + .withMerchant(mchId, serialNo, getPrivateKey(keyFilePath)) + .withValidator(new WechatPay2Validator(getVerifier(mchId,serialNo,keyFilePath,v3Key))); + // 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新 + httpClient = builder.build(); + return httpClient; + } + + /** + * 根据商户证书,获取私钥 + */ + public static PrivateKey getPrivateKey(String keyFilePath) throws FileNotFoundException { + return PemUtil.loadPrivateKey( + new FileInputStream(keyFilePath)); + } + + /** + * 自动获取微信平台证书 + */ + public static AutoUpdateCertificatesVerifier getVerifier(String mchId,String serialNo,String keyFilePath,String v3Key) throws FileNotFoundException { + //不需要传入微信支付证书了 + return new AutoUpdateCertificatesVerifier( + new WechatPay2Credentials(mchId, new PrivateKeySigner(serialNo, getPrivateKey(keyFilePath))), + v3Key.getBytes(StandardCharsets.UTF_8)); + } + + /** + * 生成随机字符串 + */ + public static String createNonceStr() { + return UUID.randomUUID().toString().replace("-", ""); + } + + /** + * 依据商户证书私钥进行签名 + */ + public static String wxPayReqSign(String keyFilePath,byte[] message) throws Exception { + Signature sign = Signature.getInstance("SHA256withRSA"); + sign.initSign(getPrivateKey(keyFilePath)); + sign.update(message); + return Base64.getEncoder().encodeToString(sign.sign()); + } +} diff --git a/util_wechat/src/main/java/com/ccsens/wechatutil/payutil/wxnative/NativePay.java b/util_wechat/src/main/java/com/ccsens/wechatutil/payutil/wxnative/NativePay.java index 0261d04..c8f4f21 100644 --- a/util_wechat/src/main/java/com/ccsens/wechatutil/payutil/wxnative/NativePay.java +++ b/util_wechat/src/main/java/com/ccsens/wechatutil/payutil/wxnative/NativePay.java @@ -4,7 +4,7 @@ import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.ccsens.util.QrCodeUtil; -import com.ccsens.wechatutil.bean.vo.WxNativePay; +import com.ccsens.wechatutil.bean.vo.WxPayOrders; import lombok.extern.slf4j.Slf4j; import okhttp3.HttpUrl; @@ -22,7 +22,7 @@ public class NativePay { * @param filePath 二维码存放地址(前缀路径) * @return 返回二维码访问路径(不包含前缀) */ - public static String generateOrder( String serialNo, String pathPem, WxNativePay wxNativePay, String filePath){ + public static String generateOrder(String serialNo, String pathPem, WxPayOrders wxNativePay, String filePath){ String path = ""; try { HttpUrl httpurl = HttpUrl.parse(NativeUtils.NATIVE_URL);