微信小程序支付Jsapi下單Java版保姆級教程
前置環(huán)境
- jdk:21
- maven:3.9.9

需要自己去注冊申請微信小程序和微信支付平臺商戶號綁定


注意上述兩張圖片是微信公眾平臺和微信支付平臺,兩個地方的appid和商戶號必須得對的上
支付產(chǎn)品許可申請

需要把這個申請上,這個就 不做贅述了,這個跟著申請內(nèi)容填資料就行了。
支付參數(shù)申請

這里點擊進去后申請一個證書

然后進入這個API安全,這里比較關(guān)鍵,注意操作步驟。


這里的密鑰記清楚,最好新建一個文件做一個備注。


點擊這個下載,按照這個下載證書文檔,操作,這里注意的是這個outputFilePath以及apiclinet_key.pem地址

apiclinet_key.pem地址
這個地址需要在解密回調(diào)里面去申請,同樣里面的密鑰也需要記住。

然后按照這個工具里面的操作進行來回復(fù)制就會得到一個文件,這個文件里面的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
# 解密回調(diào)的密鑰
apiV3Key: Cwxpay435434323FFDuv3
# 這個是解密回調(diào)也就是生成的(微信支付商戶平臺證書工具)
privateKeyFilePath: E:\code\AI\乞討\1622408443_20250307_cert\apiclient_cert.pem
# 這個是通cmd生成的
weChatPayCertFilePath: E:\www\code\wechatpay_54D388B975FD231C6CA45BE67F78D0E4181AC0C2.pem
# 支付成功回調(diào)地址
notifyUrl: https://taluop.top/cant/notify導(dǎo)入依賴
<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; //支付成功的回調(diào)地址
private String refundNotifyUrl; //退款成功的回調(diào)地址
}
工具類
/**
* 微信支付工具類
*/
@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;
/**
* 獲取調(diào)用微信接口的客戶端工具對象
*
* @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構(gòu)造的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)一下單,生成預(yù)支付交易單
String bodyAsString = jsapi(orderNum, total, description, openid);
//解析返回結(jié)果
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);
//二次簽名,調(diào)起支付需要重新簽名
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());
//構(gòu)造數(shù)據(jù)給微信小程序,用于調(diào)起微信支付
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();
//調(diào)用申請退款接口
return post(REFUNDS, body);
}
}
遇到的問題:
- 應(yīng)答的狀態(tài)碼不為200-299,商戶證書序列號有誤。

你需要找到最近操作的證書序列號
- 找不到證書序列號對應(yīng)的證書

這個地址對應(yīng)的看一下是否是最新的
- 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文件加序列號生成的文件。
總結(jié)
到此這篇關(guān)于微信小程序支付Jsapi下單Java版的文章就介紹到這了,更多相關(guān)Java微信小程序支付Jsapi下單內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Boot整合Spring Data Jpa代碼實例
這篇文章主要介紹了Spring Boot整合Spring Data Jpa代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-11-11
分布式醫(yī)療掛號系統(tǒng)EasyExcel導(dǎo)入導(dǎo)出數(shù)據(jù)字典的使用
這篇文章主要為大家介紹了分布式醫(yī)療掛號系統(tǒng)EasyExcel導(dǎo)入導(dǎo)出數(shù)據(jù)字典的使用,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-04-04
java CompletableFuture實現(xiàn)異步編排詳解
這篇文章主要為大家介紹了java CompletableFuture實現(xiàn)異步編排詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-01-01
使用stream的Collectors.toMap()方法常見的問題及解決
這篇文章主要介紹了使用stream的Collectors.toMap()方法常見的問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-03-03
淺試仿?mapstruct實現(xiàn)微服務(wù)編排框架詳解
這篇文章主要為大家介紹了淺試仿?mapstruct實現(xiàn)微服務(wù)編排框架詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08
Java toString方法重寫工具之ToStringBuilder案例詳解
這篇文章主要介紹了Java toString方法重寫工具之ToStringBuilder案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下2021-08-08

