java對接微信支付SDK接口簡單圖文教程
1.對接準(zhǔn)備
需要的參數(shù)包括開發(fā)者ID(appid)、商戶號、商戶api私鑰、商戶證書序列號、商戶APIV3密鑰、回調(diào)地址。
在微信公眾平臺https://mp.weixin.qq.com/ 注冊應(yīng)用,類型只選擇“公眾號/小程序/企業(yè)微信”,注冊完成后需完成”微信認(rèn)證“(微信收取300元),在基礎(chǔ)配置中拿到開發(fā)者ID(APPID)。

在微信支付商戶平臺https://pay.weixin.qq.com注冊商戶,在賬戶中心-api安全中設(shè)置APIv3密鑰,微信支付 APIv3 使用由 證書授權(quán)機(jī)構(gòu)(Certificate Authority,簡稱CA)簽發(fā)的證書,商戶申請證書時,證書工具會生成商戶私鑰,并保存在本地證書文件夾的件 apiclient_key.pem 中。開發(fā)和部署,需要區(qū)分環(huán)境,加載 apiclient_key.pem 文件。

在賬戶中心-商戶信息中拿到微信支付商戶號,即商戶ID (收錢的商家ID);

在產(chǎn)品中心-appid賬號管理中,將申請的下來的APPID綁定到商戶號下。

Certificate Downloader 是 Java 微信支付 APIv3 平臺證書的命令行下載工具。該工具可從https://api.mch.weixin.qq.com/v3/certificates 接口獲取商戶可用證書。
2.maven引入jar包
<!-- 微信支付SDK -->
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-java</artifactId>
<version>0.2.9</version>
</dependency>3.yml文件配置微信參數(shù),工具類讀取

@Component
public class WechatPayConfig {
/**
* 應(yīng)用ID
*/
public static String appid;
/**
* 商戶號
*/
public static String merchantId;
/**
* 商戶API私鑰路徑
*/
public static String privateKeyPath;
/**
* 商戶證書序列號
*/
public static String merchantSerialNumber;
/**
* 商戶APIV3密鑰
*/
public static String apiV3Key;
/**
* 通知地址(有效性:1. HTTPS;2. 不允許攜帶查詢串。)
*/
public static String notifyUrl;
/**
* 微信支付配置
*/
public static Config config;
/**
* 訂單支付超時時間/分鐘
*/
public static final Integer ORDER_PAY_TIME_OUT = 1440;
private WechatPayConfig() {}
@Value("${wechat.pay.appid}")
public void setAppid(String appid) {
WechatPayConfig.appid = appid;
}
@Value("${wechat.pay.merchantId}")
public void setMerchantId(String merchantId) {
WechatPayConfig.merchantId = merchantId;
}
@Value("${wechat.pay.privateKeyPath}")
public void setPrivateKeyPath(String privateKeyPath) {
String classPath = System.getProperty("java.class.path");
// 是否運(yùn)行在開發(fā)環(huán)境
boolean isRunningFromIde = classPath.toLowerCase().contains("eclipse") || classPath.toLowerCase().contains("idea");
// 開發(fā)環(huán)境與部署jar包環(huán)境 不同獲取私鑰路徑
if (isRunningFromIde){
WechatPayConfig.privateKeyPath = getClass().getClassLoader().getResource("apiclient_key.pem").getPath();
}else {
WechatPayConfig.privateKeyPath = privateKeyPath;
}
}
@Value("${wechat.pay.merchantSerialNumber}")
public void setMerchantSerialNumber(String merchantSerialNumber) {
WechatPayConfig.merchantSerialNumber = merchantSerialNumber;
}
@Value("${wechat.pay.apiV3Key}")
public void setApiV3Key(String apiV3Key) {
WechatPayConfig.apiV3Key = apiV3Key;
}
@Value("${wechat.pay.notifyUrl}")
public void setNotifyUrl(String notifyUrl) {
WechatPayConfig.notifyUrl = notifyUrl;
}
@PostConstruct
public void initializeConfig() {
// 初始化微信配置
config = new RSAAutoCertificateConfig.Builder()
.merchantId(merchantId)
.privateKeyFromPath(privateKeyPath)
.merchantSerialNumber(merchantSerialNumber)
.apiV3Key(apiV3Key)
.build();
}
}
4.對接支付接口
/**
* 微信 Native 支付下單
*
* @param amt 金額
* @param orderNumber 訂單號
* @param description 描述
* @return 二維碼鏈接
*/
public static AjaxResult nativePay(BigDecimal amt, String orderNumber, String description) {
// 當(dāng)前時間
Date currentDate = new Date();
// 將金額轉(zhuǎn)換為分
int total = amt.multiply(new BigDecimal("100")).intValue();
try {
// 構(gòu)建service
NativePayService service = new NativePayService.Builder().config(WechatPayConfig.config).build();
// 構(gòu)建請求對象
PrepayRequest request = new PrepayRequest();
request.setAppid(WechatPayConfig.appid);
request.setMchid(WechatPayConfig.merchantId);
request.setNotifyUrl(WechatPayConfig.notifyUrl);
// 設(shè)置金額
Amount amount = new Amount();
amount.setTotal(total);
request.setAmount(amount);
request.setDescription(description);
request.setOutTradeNo(orderNumber);
// 計算訂單失效時間
Calendar calendar = DateUtils.toCalendar(currentDate);
calendar.add(Calendar.MINUTE, WechatPayConfig.ORDER_PAY_TIME_OUT);
request.setTimeExpire(DateUtils.parseDateToStr("yyyy-MM-dd'T'HH:mm:ss+08:00", calendar.getTime()));
return AjaxResult.success(service.prepay(request).getCodeUrl());
} catch (Exception e){
log.error(e.getMessage(),e);
return AjaxResult.error("支付訂單創(chuàng)建失敗");
}
}5.回調(diào)地址
/**
* 微信支付回調(diào)
*
* @return 回調(diào)結(jié)果
*/
@PostMapping("/wechat")
public ResponseEntity.BodyBuilder wechat(@RequestBody String body, HttpServletRequest request) {
try {
// 構(gòu)造 RequestParam
RequestParam requestParam = new RequestParam.Builder()
// 序列號
.serialNumber(request.getHeader("Wechatpay-Serial"))
// 隨機(jī)數(shù)
.nonce(request.getHeader("Wechatpay-Nonce"))
// 簽名
.signature(request.getHeader("Wechatpay-Signature"))
// 時間戳
.timestamp(request.getHeader("Wechatpay-Timestamp"))
.body(body)
.build();
// 初始化解析器
NotificationParser parser = new NotificationParser((NotificationConfig) WechatPayConfig.config);
// 驗(yàn)簽、解密并轉(zhuǎn)換成 Transaction
Transaction transaction = parser.parse(requestParam, Transaction.class);
// 校驗(yàn)交易狀態(tài)
if (Transaction.TradeStateEnum.SUCCESS.equals(transaction.getTradeState())) {
// 支付成功,根據(jù)訂單編號查詢訂單信息
// 1.查詢訂單信息
Order orderOld = orderService.selectForUpdateByOrderNumber(transaction.getOutTradeNo());
// 校驗(yàn)金額
if (orderOld != null && orderOld.getPayAmount().equals(transaction.getAmount().getTotal())) {
// 金額相等 完成支付 更新訂單狀態(tài)
WechatPayUtil.success(orderOld,transaction);
} else {
// 金額異常 執(zhí)行退款
WechatPayUtil.refunded(new WechatPayRedis(transaction.getOutTradeNo(), transaction.getAmount().getTotal(), null));
}
}
} catch (ValidationException e) {
// 簽名驗(yàn)證失敗,返回 401 UNAUTHORIZED 狀態(tài)碼
return ResponseEntity.status(HttpStatus.UNAUTHORIZED);
}
// 處理成功,返回 200 OK 狀態(tài)碼
return ResponseEntity.status(HttpStatus.OK);
}
/**
* 支付成功
*/
public static void success( Order orderOld,Transaction transaction) {
try {
// 支付完成時間
Date payTime = DateUtils.parseDate(transaction.getSuccessTime(), "yyyy-MM-dd'T'HH:mm:ss+08:00");
// 校驗(yàn)訂單信息 & 支付結(jié)果 & 訂單有效期止日期
if (orderOld != null && orderOld.getPayResult() == 0 && payTime.compareTo(orderOld.getExpirationDate()) < 1) {
// 構(gòu)建修改對象
Order updateOrder = new Order();
updateOrder.setId(orderOld.getId());
updateOrder.setPayMethod(PayMethodEnum.W.name());
updateOrder.setPayChannel(PayChannelEnum.P.name());
updateOrder.setPayDate(payTime);
updateOrder.setPayResult(PayResultEnum.PAID.getCode());
updateOrder.setPayType(PayTypeEnum.U.name());
updateOrder.setSerialNumber(transaction.getTransactionId());
if (orderService.editPayResult(updateOrder,orderOld) == 1) {
// 刪除Redis訂單支付信息
SpringUtils.getBean(RedisCache.class).deleteObject(WechatPayConfig.ORDER_PAY_REDIS_PREFIX + transaction.getOutTradeNo());
}
} else {
// 訂單信息不存在 執(zhí)行退款
WechatPayUtil.refunded(new WechatPayRedis(transaction.getOutTradeNo(), transaction.getAmount().getTotal(), null));
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
/**
* 執(zhí)行退款
*/
public static void refunded(WechatPayRedis wechatPay) {
try {
// 構(gòu)建退款Service
RefundService service = new RefundService.Builder().config(WechatPayConfig.config).build();
// 構(gòu)建請求對象
CreateRequest request = new CreateRequest();
request.setOutTradeNo(wechatPay.getOrderNumber());
request.setOutRefundNo(wechatPay.getOrderNumber());
// 支付總金額(分)
long total = wechatPay.getTotal();
// 設(shè)置退款金額
AmountReq amount = new AmountReq();
amount.setRefund(total);
amount.setTotal(total);
amount.setCurrency("CNY");
request.setAmount(amount);
// 請求API申請退款
Refund refund = service.create(request);
// 校驗(yàn)退款結(jié)果
if (refund != null && Status.SUCCESS.equals(refund.getStatus())) {
// 退款成功
log.info("微信退款成功:{}", wechatPay);
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}總結(jié)
到此這篇關(guān)于java對接微信支付SDK接口的文章就介紹到這了,更多相關(guān)java對接微信支付SDK接口內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot工程jar包部署到云服務(wù)器的方法
這篇文章主要介紹了springboot工程jar包部署到云服務(wù)器的方法,本文通過實(shí)例介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友參考下吧2018-05-05
Java實(shí)現(xiàn)中文字符串與unicode互轉(zhuǎn)工具類
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)中文字符串與unicode互轉(zhuǎn)的工具類,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-04-04
java數(shù)據(jù)結(jié)構(gòu)之希爾排序
這篇文章主要為大家詳細(xì)介紹了java數(shù)據(jù)結(jié)構(gòu)之希爾排序的相關(guān)代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-11-11
基于SpringBoot實(shí)現(xiàn)大文件分塊上傳功能
這篇文章主要介紹了基于SpringBoot實(shí)現(xiàn)大文件分塊上傳功能,實(shí)現(xiàn)原理其實(shí)很簡單,核心就是客戶端把大文件按照一定規(guī)則進(jìn)行拆分,比如20MB為一個小塊,分解成一個一個的文件塊,然后把這些文件塊單獨(dú)上傳到服務(wù)端,需要的朋友可以參考下2024-09-09
Java數(shù)據(jù)結(jié)構(gòu)之圖(動力節(jié)點(diǎn)Java學(xué)院整理)
本文章主要講解學(xué)習(xí)如何使用JAVA語言以鄰接表的方式實(shí)現(xiàn)了數(shù)據(jù)結(jié)構(gòu)---圖(Graph)。對java數(shù)據(jù)結(jié)構(gòu)之圖相關(guān)知識感興趣的朋友一起學(xué)習(xí)吧2017-04-04
Java 如何實(shí)現(xiàn)POST(x-www-form-urlencoded)請求
這篇文章主要介紹了Java 實(shí)現(xiàn)POST(x-www-form-urlencoded)請求,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10
關(guān)于cron表達(dá)式每天整點(diǎn)執(zhí)行一次的問題
這篇文章主要介紹了關(guān)于cron表達(dá)式每天整點(diǎn)執(zhí)行一次的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-12-12

