微信小程序支付Jsapi下单Java版保姆级教程
作者:小江-
微信支付作为国内领先的第三方支付平台,为商户提供了多样化的支付解决方案,包括JSAPI支付、APP支付、H5支付、Native支付以及小程序支付,这篇文章主要介绍了微信小程序支付Jsapi下单Java版的相关资料,需要的朋友可以参考下
前置环境
- jdk:21
- maven:3.9.9
需要自己去注册申请微信小程序和微信支付平台商户号绑定
注意上述两张图片是微信公众平台和微信支付平台,两个地方的appid和商户号必须得对的上
支付产品许可申请
需要把这个申请上,这个就 不做赘述了,这个跟着申请内容填资料就行了。
支付参数申请
这里点击进去后申请一个证书
然后进入这个API安全,这里比较关键,注意操作步骤。
这里的密钥记清楚,最好新建一个文件做一个备注。
点击这个下载,按照这个下载证书文档,操作,这里注意的是这个outputFilePath以及apiclinet_key.pem地址
apiclinet_key.pem地址
这个地址需要在解密回调里面去申请,同样里面的密钥也需要记住。
然后按照这个工具里面的操作进行来回复制就会得到一个文件,这个文件里面的apiclinet_key.pem存放的地址。
这样操作下来我们就得到一个
java -jar CertificateDownloader.jar -k CZBK5123643FFDuv3 -m 1622408443 -f E:\code\AI\乞讨\1622408443_20250305_cert\apiclient_key.pem -s 495F550990E8FF3FC72C7 -o E:\www\code
运行后
得到密钥文件。至此我们所需要的文件已全部收集齐全。
代码:
application.yaml
cant: wechat: # 微信公众平台里面的小程序appid appid: wx8b8656de482b # 商户号 mchid: 1622408443 # 商户API证书里面的序列号 mchSerialNo: 405172E0770000864CE6A4136411 # 解密回调的密钥 apiV3Key: Cwxpay435434323FFDuv3 # 这个是解密回调也就是生成的(微信支付商户平台证书工具) privateKeyFilePath: E:\code\AI\乞讨\1622408443_20250307_cert\apiclient_cert.pem # 这个是通cmd生成的 weChatPayCertFilePath: E:\www\code\wechatpay_54D388B975FD231C6CA45BE67F78D0E4181AC0C2.pem # 支付成功回调地址 notifyUrl: https://taluop.top/cant/notify
导入依赖
<dependency> <groupId>com.github.wechatpay-apiv3</groupId> <artifactId>wechatpay-java</artifactId> <version>0.2.10</version> </dependency>
配置类
@Component @ConfigurationProperties(prefix = "cant.wechat") @Data @EnableConfigurationProperties public class WeChatProperties { private String appid; //小程序的appid private String secret; //小程序的秘钥 private String mchid; //商户号 private String mchSerialNo; //商户API证书的证书序列号 private String privateKeyFilePath; //商户私钥文件 private String apiV3Key; //证书解密的密钥 private String weChatPayCertFilePath; //平台证书 private String notifyUrl; //支付成功的回调地址 private String refundNotifyUrl; //退款成功的回调地址 }
工具类
/** * 微信支付工具类 */ @Component public class WeChatPayUtil { //微信支付下单接口地址 public static final String JSAPI = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi"; //申请退款接口地址 public static final String REFUNDS = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds"; @Autowired private WeChatProperties weChatProperties; /** * 获取调用微信接口的客户端工具对象 * * @return */ private CloseableHttpClient getClient() { PrivateKey merchantPrivateKey = null; try { // merchantPrivateKey商户API私钥,如何加载商户API私钥请看常见问题 merchantPrivateKey = PemUtil.loadPrivateKey(new FileInputStream(new File(weChatProperties.getPrivateKeyFilePath()))); // 加载平台证书文件 X509Certificate x509Certificate = PemUtil.loadCertificate(new FileInputStream(new File(weChatProperties.getWeChatPayCertFilePath()))); // wechatPayCertificates微信支付平台证书列表。你也可以使用“定时更新平台证书功能” List<X509Certificate> wechatPayCertificates = Arrays.asList(x509Certificate); WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create() .withMerchant(weChatProperties.getMchid(), weChatProperties.getMchSerialNo(), merchantPrivateKey) .withWechatPay(wechatPayCertificates); // 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签 CloseableHttpClient httpClient = builder.build(); return httpClient; } catch (FileNotFoundException e) { e.printStackTrace(); return null; } } /** * 发送post方式请求 * * @param url * @param body * @return */ private String post(String url, String body) throws Exception { CloseableHttpClient httpClient = getClient(); HttpPost httpPost = new HttpPost(url); httpPost.addHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.toString()); httpPost.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()); httpPost.addHeader("Wechatpay-Serial", weChatProperties.getMchSerialNo()); httpPost.setEntity(new StringEntity(body, "UTF-8")); CloseableHttpResponse response = httpClient.execute(httpPost); try { String bodyAsString = EntityUtils.toString(response.getEntity()); return bodyAsString; } finally { httpClient.close(); response.close(); } } /** * jsapi下单 * * @param orderNum 商户订单号 * @param total 总金额 * @param description 商品描述 * @param openid 微信用户的openid * @return */ private String jsapi(String orderNum, BigDecimal total, String description, String openid) throws Exception { JSONObject jsonObject = new JSONObject(); jsonObject.put("appid", weChatProperties.getAppid()); jsonObject.put("mchid", weChatProperties.getMchid()); jsonObject.put("description", description); jsonObject.put("out_trade_no", orderNum); jsonObject.put("notify_url", weChatProperties.getNotifyUrl()); JSONObject amount = new JSONObject(); amount.put("total", total.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).intValue()); amount.put("currency", "CNY"); jsonObject.put("amount", amount); JSONObject payer = new JSONObject(); payer.put("openid", openid); jsonObject.put("payer", payer); String body = jsonObject.toJSONString(); return post(JSAPI, body); } /** * 小程序支付 * * @param orderNum 商户订单号 * @param total 金额,单位 元 * @param description 商品描述 * @param openid 微信用户的openid * @return */ public JSONObject pay(String orderNum, BigDecimal total, String description, String openid) throws Exception { //统一下单,生成预支付交易单 String bodyAsString = jsapi(orderNum, total, description, openid); //解析返回结果 JSONObject jsonObject = JSON.parseObject(bodyAsString); System.out.println(jsonObject); String prepayId = jsonObject.getString("prepay_id"); if (prepayId != null) { String timeStamp = String.valueOf(System.currentTimeMillis() / 1000); String nonceStr = RandomStringUtils.randomNumeric(32); ArrayList<Object> list = new ArrayList<>(); list.add(weChatProperties.getAppid()); list.add(timeStamp); list.add(nonceStr); list.add("prepay_id=" + prepayId); //二次签名,调起支付需要重新签名 StringBuilder stringBuilder = new StringBuilder(); for (Object o : list) { stringBuilder.append(o).append("\n"); } String signMessage = stringBuilder.toString(); byte[] message = signMessage.getBytes(); Signature signature = Signature.getInstance("SHA256WithRSA"); signature.initSign(PemUtil.loadPrivateKey(new FileInputStream(new File(weChatProperties.getPrivateKeyFilePath())))); signature.update(message); String packageSign = Base64.getEncoder().encodeToString(signature.sign()); //构造数据给微信小程序,用于调起微信支付 JSONObject jo = new JSONObject(); jo.put("timeStamp", timeStamp); jo.put("nonceStr", nonceStr); jo.put("package", "prepay_id=" + prepayId); jo.put("signType", "RSA"); jo.put("paySign", packageSign); return jo; } return jsonObject; } /** * 发送get方式请求 * * @param url * @return */ private String get(String url) throws Exception { CloseableHttpClient httpClient = getClient(); HttpGet httpGet = new HttpGet(url); httpGet.addHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.toString()); httpGet.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()); httpGet.addHeader("Wechatpay-Serial", weChatProperties.getMchSerialNo()); CloseableHttpResponse response = httpClient.execute(httpGet); try { String bodyAsString = EntityUtils.toString(response.getEntity()); return bodyAsString; } finally { httpClient.close(); response.close(); } } /** * 申请退款 * * @param outTradeNo 商户订单号 * @param outRefundNo 商户退款单号 * @param refund 退款金额 * @param total 原订单金额 * @return */ public String refund(String outTradeNo, String outRefundNo, BigDecimal refund, BigDecimal total) throws Exception { JSONObject jsonObject = new JSONObject(); jsonObject.put("out_trade_no", outTradeNo); jsonObject.put("out_refund_no", outRefundNo); JSONObject amount = new JSONObject(); amount.put("refund", refund.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).intValue()); amount.put("total", total.multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_HALF_UP).intValue()); amount.put("currency", "CNY"); jsonObject.put("amount", amount); jsonObject.put("notify_url", weChatProperties.getRefundNotifyUrl()); String body = jsonObject.toJSONString(); //调用申请退款接口 return post(REFUNDS, body); } }
遇到的问题:
- 应答的状态码不为200-299,商户证书序列号有误。
你需要找到最近操作的证书序列号
- 找不到证书序列号对应的证书
这个地址对应的看一下是否是最新的
- Java HotSpot(TM) 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appendedranh
这个需要的是apiclient_key.pem文件,这个是由apiclient_cert.pem文件加序列号生成的文件。
总结
到此这篇关于微信小程序支付Jsapi下单Java版的文章就介绍到这了,更多相关Java微信小程序支付Jsapi下单内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!