Java接入微信支付詳細(xì)實(shí)現(xiàn)步驟
一:主要流程
(1)前期準(zhǔn)備工作
①注冊認(rèn)證微信公眾號/小程序
②申請微信商戶號
③配置API安全
(2)環(huán)境搭建和主要流程理解
①引入依賴
②確定支付方式,分析其流程
(3)核心代碼開發(fā)
①配置參數(shù)
②向微信發(fā)送請求
二:注意事項(xiàng)
(1)個人類型賬號無法開通微信支付
(2)切勿泄露APIV3秘鑰
三:步驟實(shí)現(xiàn)
官方文檔(以Native為例):產(chǎn)品介紹_Native支付|微信支付商戶文檔中心

先查看具體流程
(1)先注冊對應(yīng)的公眾號/小程序
官網(wǎng)鏈接:https://mp.weixin.qq.com/
(2)認(rèn)證對應(yīng)的公眾號/小程序
①方法一:

②方法二:

(3)注冊商戶號,開通對應(yīng)的Native支付權(quán)限
官網(wǎng)鏈接:https://pay.weixin.qq.com/
開通步驟指引鏈接:申請Native支付權(quán)限指引_Native支付|微信支付商戶文檔中心
(4)綁定商戶號與APPID
對應(yīng)指引鏈接:管理商戶號綁定的APPID賬號_Native支付|微信支付商戶文檔中心
(5)獲取對應(yīng)參數(shù)開發(fā)
對應(yīng)指引鏈接:開發(fā)必要參數(shù)說明_通用規(guī)則|微信支付商戶文檔中心


(6)核心代碼開發(fā)
①推薦使用官方SDK:https://github.com/wechatpay-apiv3/wechatpay-java
②引入依賴
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-java</artifactId>
<version>0.4.13</version> <!-- 注意檢查最新版本 -->
</dependency>③代碼實(shí)現(xiàn)
配置類:
@Configuration
public class WeChatPayConfig {
@Value("${wechat.pay.mchid}")
private String mchId;
@Value("${wechat.pay.mchSerialNo}") // 你的商戶API證書序列號
private String mchSerialNo;
@Value("${wechat.pay.privateKeyPath}") // 你的.p12證書中的私鑰文件路徑 (.pem格式更佳)
private String privateKeyPath;
@Value("${wechat.pay.apiV3Key}")
private String apiV3Key;
@Value("${wechat.pay.certPath}") // 下載的微信平臺證書路徑
private String certPath;
/**
* 創(chuàng)建私鑰簽名對象
*/
@Bean
public PrivateKey getPrivateKey() throws Exception {
return PemUtil.loadPrivateKey(
new FileInputStream(privateKeyPath));
}
/**
* 創(chuàng)建自動更新的Verifier (驗(yàn)證微信響應(yīng)簽名)
*/
@Bean
public Verifier getVerifier() throws Exception {
// 方式1: 使用本地已下載的平臺證書 (簡單,需手動更新)
// X509Certificate certificate = PemUtil.loadCertificate(new FileInputStream(certPath));
// return new StaticVerifier(mchId, mchSerialNo, certificate);
// 方式2: 使用自動更新機(jī)制 (推薦)
ScheduledUpdateCertificatesVerifier verifier =
new ScheduledUpdateCertificatesVerifier(
new WechatPay2Credentials(mchId, new PrivateKeySigner(mchSerialNo, getPrivateKey())),
apiV3Key.getBytes(StandardCharsets.UTF_8));
return verifier;
}
/**
* 創(chuàng)建HttpClient (用于調(diào)用微信API)
*/
@Bean
public CloseableHttpClient getWxPayClient() throws Exception {
return WechatPayHttpClientBuilder.create()
.withMerchant(mchId, mchSerialNo, getPrivateKey())
.withValidator(new WechatPay2Validator(getVerifier()))
.build();
}
}服務(wù)層(統(tǒng)一下單)示例與代碼(需調(diào)整)

@Override
public String createNativeOrder(String outTradeNo, int totalFee, String body) {
// ... 構(gòu)建請求參數(shù) (類似JSAPI,但去掉payer,增加scene_info等)
json.put("appid", appid); // Native也需要appid
json.put("mchid", mchId);
json.put("description", body);
json.put("out_trade_no", outTradeNo);
json.put("notify_url", "https://yourdomain.com/api/wxpay/notify");
JSONObject amount = new JSONObject();
amount.put("total", totalFee);
amount.put("currency", "CNY");
json.put("amount", amount);
// 場景信息 (可選)
JSONObject sceneInfo = new JSONObject();
sceneInfo.put("payer_client_ip", "用戶IP"); // 必須傳真實(shí)IP
json.put("scene_info", sceneInfo);
// 發(fā)送請求到 Native 接口
try {
HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/native");
// ... 同上設(shè)置請求頭和實(shí)體
// 解析響應(yīng),獲取 code_url
JSONObject result = JSON.parseObject(responseString);
return result.getString("code_url"); // 返回二維碼鏈接
} catch (Exception e) {
throw new RuntimeException("創(chuàng)建Native訂單失敗", e);
}
}④回調(diào)處理
注意:此路徑必須是公網(wǎng)能訪問的路徑
@RestController
@RequestMapping("/api/wxpay")
public class WeChatPayController {
@Autowired
private WeChatPayService weChatPayService;
@PostMapping("/create-jsapi-order")
public ResponseEntity<Map<String, String>> createJsapiOrder(@RequestBody PayRequest request) {
// 獲取用戶openid (通常由前端通過登錄態(tài)傳遞或后端通過code換取)
String openid = getUserOpenidFromSessionOrToken(request.getToken());
Map<String, String> result = weChatPayService.createJsapiOrder(
openid, request.getOutTradeNo(), request.getTotalFee(), request.getBody());
return ResponseEntity.ok(result);
}
@PostMapping("/notify")
public ResponseEntity<String> handleNotify(@RequestBody String notifyData,
HttpServletRequest request) {
try {
// 1. 驗(yàn)證通知的簽名和有效性 (SDK提供了工具類)
// 這里需要解析請求頭中的 Wechatpay-Signature, Wechatpay-Nonce, Wechatpay-Timestamp
String signature = request.getHeader("Wechatpay-Signature");
String nonce = request.getHeader("Wechatpay-Nonce");
String timestamp = request.getHeader("Wechatpay-Timestamp");
String body = notifyData; // 請求體
// 使用之前配置的Verifier來驗(yàn)證
// boolean isValid = verifier.verify(timestamp, nonce, body, signature);
// if (!isValid) {
// return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("簽名驗(yàn)證失敗");
// }
// 2. 解密通知數(shù)據(jù) (APIv3通知體是加密的)
AesUtil aesUtil = new AesUtil(apiV3Key.getBytes(StandardCharsets.UTF_8));
String plainText = aesUtil.decryptToString(
nonce.getBytes(StandardCharsets.UTF_8),
associatedData.getBytes(StandardCharsets.UTF_8), // 關(guān)聯(lián)數(shù)據(jù)
ciphertext.getBytes(StandardCharsets.UTF_8)); // 密文
// 3. 解析解密后的JSON數(shù)據(jù)
JSONObject notifyDataObj = JSON.parseObject(plainText);
String eventType = notifyDataObj.getString("event_type");
JSONObject resource = notifyDataObj.getJSONObject("resource");
String ciphertext = resource.getString("ciphertext"); // 加密的數(shù)據(jù)包
String associatedData = resource.getString("associated_data");
String nonce = resource.getString("nonce");
// 再次解密ciphertext得到最終的訂單信息
String orderInfo = aesUtil.decryptToString(nonce.getBytes(),
associatedData.getBytes(), ciphertext.getBytes());
JSONObject orderData = JSON.parseObject(orderInfo);
String outTradeNo = orderData.getString("out_trade_no");
String transactionId = orderData.getString("transaction_id");
String tradeState = orderData.getString("trade_state"); // SUCCESS為支付成功
// 4. 業(yè)務(wù)處理
if ("SUCCESS".equals(tradeState)) {
// TODO: 更新你的數(shù)據(jù)庫訂單狀態(tài)為"已支付"
// TODO: 執(zhí)行發(fā)貨、積分發(fā)放等后續(xù)業(yè)務(wù)邏輯
// TODO: 記錄日志
} else if ("CLOSED".equals(tradeState) || "REVOKED".equals(tradeState)) {
// 支付失敗或關(guān)閉
}
// 5. 返回成功響應(yīng) (必須是200且內(nèi)容為"success")
return ResponseEntity.ok().body("{\"code\":\"SUCCESS\",\"message\":\"成功\"}");
} catch (Exception e) {
// 記錄詳細(xì)的錯誤日志
log.error("處理微信支付通知失敗", e);
// 返回失敗,微信會在一段時間后重試
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("");
}
}
}工具類
public class WeChatPayUtil {
// 生成JSAPI調(diào)用所需參數(shù)的簽名 (注意:這是RSA-SHA256,不是APIv3的HMAC-SHA256)
public static String sign(Map<String, String> params, String apiKey) {
// 1. 參數(shù)按key ASCII排序
List<String> keys = new ArrayList<>(params.keySet());
Collections.sort(keys);
StringBuilder sb = new StringBuilder();
for (String key : keys) {
String value = params.get(key);
if (value != null && !value.trim().isEmpty() && !"sign".equals(key)) {
sb.append(key).append("=").append(value).append("&");
}
}
sb.append("key=").append(apiKey);
// 2. 計(jì)算MD5 (舊版) 或 HMAC-SHA256 (新版推薦,但JSAPI仍多用MD5?實(shí)際看文檔)
// 注意:微信JSAPI目前主流仍是MD5,但請查閱最新官方文檔確認(rèn)!
String stringA = sb.toString();
String sign = DigestUtils.md5Hex(stringA).toUpperCase();
return sign;
}
}四:總結(jié)
對接微信支付主要繁瑣的是前期商戶號、證書、配置,需仔細(xì)閱讀文檔,后續(xù)對接SDK非常簡單,注意處理冪等性
到此這篇關(guān)于Java接入微信支付的文章就介紹到這了,更多相關(guān)Java接入微信支付內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Guava?Retryer實(shí)現(xiàn)接口重試的示例
本文主要介紹了Guava?Retryer實(shí)現(xiàn)接口重試的示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-12-12
Java Mail與Apache Mail發(fā)送郵件示例
這篇文章主要介紹了Java Mail與Apache Mail發(fā)送郵件示例的相關(guān)資料,需要的朋友可以參考下2014-10-10
SpringMVC基于注解方式實(shí)現(xiàn)上傳下載
本文主要介紹了SpringMVC基于注解方式實(shí)現(xiàn)上傳下載,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04

