微信公众号-JSAPI支付(保姆级教程)

分类: 3658官方网 📅 2025-07-21 12:43:32 👤 admin 👁️ 1763 ❤️ 168
微信公众号-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);

}

②获取到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);

其中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();

}

构建完成后,调用微信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;

其中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 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;

}

返回预支付相关信息 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. 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 params = WXPayUtil.xmlToMap(resultXml);

14. Map 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);

相关文章