微信小程序支付Jsapi下單Java版保姆級教程
前置環(huán)境
- jdk:21
- maven:3.9.9
需要自己去注冊申請微信小程序和微信支付平臺商戶號綁定
注意上述兩張圖片是微信公眾平臺和微信支付平臺,兩個地方的appid和商戶號必須得對的上
支付產(chǎn)品許可申請
需要把這個申請上,這個就 不做贅述了,這個跟著申請內容填資料就行了。
支付參數(shù)申請
這里點擊進去后申請一個證書
然后進入這個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; } } /** * 發(fā)送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 { //統(tǒng)一下單,生成預支付交易單 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()); //構造數(shù)據(jù)給微信小程序,用于調起微信支付 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; } /** * 發(fā)送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); } }
遇到的問題:
- 應答的狀態(tài)碼不為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下單內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
從try-with-resources到ThreadLocal,優(yōu)化你的代碼編寫方式
這篇文章主要為大家介紹了從try-with-resources到ThreadLocal,優(yōu)化代碼的編寫方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-04-04Java基礎開發(fā)之JDBC操作數(shù)據(jù)庫增刪改查,分頁查詢實例詳解
這篇文章主要介紹了Java基礎開發(fā)之JDBC操作數(shù)據(jù)庫增刪改查,分頁查詢實例詳解,需要的朋友可以參考下2020-02-02mybatis中BigDecimal中的0存為null的坑及解決
在使用MyBatis進行數(shù)據(jù)庫操作時,若Java中屬性類型為BigDecimal且值為0,插入數(shù)據(jù)庫時可能會變?yōu)閚ull,而不是0,這個問題可能是由于MyBatis在處理BigDecimal類型時的弱類型判斷導致的,當BigDecimal變量與空字符串進行比較時,MyBatis可能將其視為null2024-10-10spring中的BeanFactory與FactoryBean的講解
今天小編就為大家分享一篇關于spring中的BeanFactory與FactoryBean的講解,小編覺得內容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-01-01MyBatis中使用foreach循環(huán)的坑及解決
這篇文章主要介紹了MyBatis中使用foreach循環(huán)的坑及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01springboot2.x解決運行順序及Bean對象注入順序的問題
這篇文章主要介紹了springboot2.x解決運行順序及Bean對象注入順序的問題,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01SpringBoot優(yōu)化連接數(shù)的方法詳解
SpringBoot開發(fā)最大的好處是簡化配置,內置了Tomcat,下面這篇文章主要給大家介紹了關于SpringBoot優(yōu)化連接數(shù)的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2023-06-06使用maven項目pom.xml文件配置打包功能和靜態(tài)資源文件自帶版本號功能
在Maven項目中,通過pom.xml文件配置打包功能,可以控制構建過程,生成可部署的包,同時,為了緩存控制與版本更新,可以在打包時給靜態(tài)資源文件如JS、CSS添加版本號,這通常通過插件如maven-resources-plugin實現(xiàn)2024-09-09