微信公众号-JSAPI支付
微信公众号-JSAPI支付
1、微信公众号配置
https://mp.weixin.qq.com/cgi-bin/home
① 开通网页授权域名(前置条件:需开通网页授权接口权限)
②暴露网络授权域名
③获取基本配置中的AppID、AppSecret
④微信支付关联商户号
2、微信支付配置
https://pay.weixin.qq.com/
① 配置API证书 获取证书序列号
②获取正式序列号
③设置APIV3秘钥
④ 产品中心—开通JSAPI支付
⑤添加支付域名配置
⑥暴露域名
⑦AppId账号设置-商户关联公众号
程序配置
必要配置信息:
公众号appId
公众号appSecret
商户id
证书序列号
商户API秘钥
①配置yml文件
② 微信支付平台下载的秘钥证书放入项目resources目录下
主要流程及代码实现
①前端通过url获取code
(url参数配置)
Appid:公众号的appid
Redirect_uri:重定向至微信支付调用接口
Scope:snsapi_base(授权方式 无需弹窗静默授权)
https://open.weixin.qq.com/connect/oauth2/authorize?appid=xx&redirect_uri=xxx&response_type=code&scope=snsapi_base&state=STATE&connect_redirect=1#wechat_redirect
②通过前端获取的code,传入指定支付接口(Redirect_uri),获取openId
1)通过appID、appSecret、code构建请求URL,解析返回结果获取openId
public static String getOpenId(String code) throws Exception {
// 构建请求URL
String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + APP_ID
+ "&secret=" + APP_SECRET
+ "&code=" + code
+ "&grant_type=authorization_code";
// 发送HTTP GET请求
URL url = new URL(requestUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) { // 请求成功
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder response = new StringBuilder();
String line;
while ((line = in.readLine()) != null) {
response.append(line);
}
in.close();
// 解析JSON响应,获取openid
String jsonResponse = response.toString();
JsonObject jsonObject = new Gson().fromJson(jsonResponse, JsonObject.class);
String openid = jsonObject.get("openid").getAsString();
return openid;
} else {
throw new Exception("HTTP GET请求失败:" + responseCode);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
②获取到openId后,构建请求参数
log.info("code:{}", code);
String openId = WXGetOpenIdUtil.getOpenId(code);
//请求URL
HttpPost httpPost = new HttpPost(WxPayJsApiConstant.JS_API_URL);
// 请求body参数
WxPayJsApiAmountBO amount = new WxPayJsApiAmountBO();
amount.setTotal(1);//总金额
amount.setCurrency("CNY");//货币类型
WxPayPayerBO payer = new WxPayPayerBO();
payer.setOpenid(openId);//openId
WxPayJsApiOrderBO request = new WxPayJsApiOrderBO();
request.setMchid(mchId);//商户号
String out_trade_no = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_MS_PATTERN);
request.setOut_trade_no(out_trade_no);//生成的订单号
request.setAttach("--非必填数据--");//附加信息
request.setAppid(appId);//appId
request.setDescription("停车费用");//描述
request.setNotify_url(notifyUrl);//异步接收微信支付结果通知的回调地址
request.setAmount(amount);//订单金额信息:总金额 货币类型
request.setPayer(payer);//openId如何获取
StringEntity entity = new StringEntity(JSONUtil.toJsonStr(request), "utf-8");
entity.setContentType("application/json");
httpPost.setEntity(entity);
httpPost.setHeader(WxPayJsApiHeaderConstant.HTTP_HEADER_ACCEPT, WxPayJsApiHeaderConstant.HTTP_HEADER_ACCEPT_VAL);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
其中initCloseableHttpClientV3方法为:读取resources下的apiclient_key.pem密钥文件 获取秘钥 构建请求信息
/**
* 构造 - 通用CloseableHttpClient(定时更新平台证书功能)
**/
protected CloseableHttpClient initCloseableHttpClientV3() throws IOException, HttpCodeException, GeneralSecurityException, NotFoundException {
// 获取 - 秘钥证书信息
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new FileInputStream(WxPayJsApiHttpUtil.getResourcesPath() + "apiclient_key.pem"));
// 获取 - 证书管理器实例
CertificatesManager certificatesManager = CertificatesManager.getInstance();
// 操作 - 向证书管理器增加需要自动更新平台证书的商户信息
certificatesManager.putMerchant(mchId, new WechatPay2Credentials(mchId,
new PrivateKeySigner(mchSerialNo, merchantPrivateKey)), apiV3Key.getBytes(StandardCharsets.UTF_8));
// ... 若有多个商户号,可继续调用putMerchant添加商户信息
// 操作 - 从证书管理器中获取verifier
Verifier verifier = certificatesManager.getVerifier(mchId);
WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
.withMerchant(mchId, mchSerialNo, merchantPrivateKey)
.withValidator(new WechatPay2Validator(verifier));
// 构造通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新
return builder.build();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
构建完成后,调用微信JSAPI下单地址httpPost: https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi
// 构建 - 请求信息
CloseableHttpClient closeableHttpClient = initCloseableHttpClientV3();
// 操作 - 完成请求
CloseableHttpResponse response = closeableHttpClient.execute(httpPost);
String bodyAsString = EntityUtils.toString(response.getEntity());
System.out.println(bodyAsString);
try {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) {
JsonObject jsonObject = new Gson().fromJson(bodyAsString, JsonObject.class);
//获取微信支付中的预支付id
String prepayId = jsonObject.get("prepay_id").getAsString();
System.out.println("success,return body = " + EntityUtils.toString(response.getEntity())
+ "prepay_id = " + prepayId);
} else if (statusCode == 204) {
System.out.println("success");
} else {
System.out.println("failed,resp code = " + statusCode + ",return body = " + EntityUtils.toString(response.getEntity()));
throw new IOException("request failed");
}
} finally {
response.close();
closeableHttpClient.close();
}
// 构造 - 响应信息 prepay_id
WxPayJsApiPreVO result = convertWxPayJsApiPreInfo((String) JSONUtil.parseObj(bodyAsString).get(WxPayJsApiOtherConstant.HTTP_OTHER_PREPAY_ID));
System.out.println("result -> " + JSONUtil.toJsonStr(result));
return result;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
其中convertWxPayJsApiPreInfo方法获取JSAPI加密串,构造响应信息result
protected WxPayJsApiPreVO convertWxPayJsApiPreInfo(String prepayId) throws Exception {
logger.info("[开始]预支付信息-prepayId : {}", prepayId);
// 构建 - 相关参数
String time = String.valueOf(System.currentTimeMillis() / 1000);
String nonceStr = UUID.randomUUID().toString().replace("-", "");
String packageStr = StrUtil.format(WxPayJsApiConstant.SIGN_PACKAGE_STR, prepayId);
// 构建 - 签名信息
ArrayList<String> list = new ArrayList<>();
list.add(appId);
list.add(time);
list.add(nonceStr);
list.add(packageStr);
// 操作 - 签名
String packageSign = wxPayJsApiSignUtil.signV3(WxPayJsApiSignUtil.buildSignMessage(list).getBytes());
// 构建 - 响应信息
WxPayJsApiPreVO result = new WxPayJsApiPreVO();
result.setWxAppId(appId);
result.setWxTimeStamp(time);
result.setWxNonceStr(nonceStr);
result.setWxPackage(packageStr);
result.setWxSignType(WxPayJsApiConstant.SIGN_TYPE);
result.setWxPaySign(packageSign);
logger.info("[结束]预支付信息-WxPayJsApiPreVO : {}", JSONUtil.toJsonStr(result));
return result;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
返回预支付相关信息 Result示例参数:
{“status”:200,“msg”:“OK”,“data”:{“wxAppId”:“xxx”,“wxTimeStamp”:“xxx”,“wxNonceStr”:“xxxx”,“wxPackage”:"prepay_id=“xxxx”,“wxSignType”:“RSA”,“wxPaySign”:“xxxx”}}
③Result返回给前端,前端调用WeixinJSBridge方法,完成微信支付
1. function onBridgeReady() {
2. WeixinJSBridge.invoke('getBrandWCPayRequest', {
3. "appId": "xxx", //公众号ID,由商户传入
4. "timeStamp": "xxx", //时间戳,自1970年以来的秒数
5. "nonceStr": "xxx", //随机串
6. "package": "prepay_id=xxx",
7. "signType": "RSA", //微信签名方式:
8. "paySign": "xxx" //微信签名
9. },
10. function(res) {
11. if (res.err_msg == "get_brand_wcpay_request:ok") {
12. // 使用以上方式判断前端返回,微信团队郑重提示:
13. //res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
14. }
15. });
16. }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
④微信回调 支付后微信向改地址发送支付结果通知
1. //读取微信回调的内容
2. InputStream inStream = request.getInputStream();
3. ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
4. byte[] buffer = new byte[1024];
5. int len;
6. while ((len = inStream.read(buffer)) != -1) {
7. outSteam.write(buffer, 0, len);
8. }
9. String resultXml = new String(outSteam.toByteArray(), "utf-8");
10. outSteam.close();
11. inStream.close();
12. //xml转成map
13. Map<String, String> params = WXPayUtil.xmlToMap(resultXml);
14. Map<String, String> return_data = new HashMap<>(); //返回给微信信息
15. if ("SUCCESS".equals(params.get("return_code"))) { //返回成功 付款成功
16. String outTradeNo = params.get("out_trade_no"); //返回的商户订单号
17. Integer totalFee = Integer.parseInt(params.get("total_fee")); //总金额
18. ParkingBasicInfo parkingBasicInfo = parkingBasicInfoService.lambdaQuery().eq(ParkingBasicInfo::getOutTradeNo, outTradeNo).one();
19. if (ObjectUtil.isNotEmpty(parkingBasicInfo)) {
20. if (totalFee.equals(parkingBasicInfo.getPayMoney())) {
21. String paymentTime = params.get("time_end"); //支付完成时间
22. //发票表添加支付时间
23. String transactionId = params.get("transaction_id"); //微信支付订单号
24. //支付成功后修改订单信息 paymentTime transactionId微信支付订单号
25. }
26. }
27. //正确返回给微信
28. return_data.put("return_code", "SUCCESS");
29. return_data.put("return_msg", "OK");
30. return WXPayUtil.mapToXml(return_data);
31. }
32. // 支付失败
33. return_data.put("return_code", "FAIL");
34. return_data.put("return_msg", "return_code不正确");
35. return WXPayUtil.mapToXml(return_data);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_43890604/article/details/136938311
<以上资讯仅供参考,如果您需解决具体问题,建议您关注作者;如果有软件产品开发需求,可在线咨询加速度产品经理获取方案和报价>
****更多行业产品开发方案,请关注jsudo加速度 https://www.jsudo.com***
【加速度jsudo(www.jsudo.com)】是国内知名企业数字化建设提供商,为企业提供电商平台搭建(多种模式电商平台搭建:B2B/B2B2C/B2C/O2O/新零售等)、智慧园区建设、数字化营销、人才外包等服务,点击这里查看了解更多行业解决方案。
评论 (0)