SpringBoot整合weixin-java-pay實現(xiàn)微信小程序支付的示例代碼
準備工作
依賴引入
<dependency> <groupId>com.github.binarywang</groupId> <artifactId>weinxin-java-pay</artifactId> <version>對應的版本號</version> </dependency>
證書申請和下載
官方文檔: 直達

擼起袖子使勁干
配置類
參數(shù)配置類
/**
* @author: Eden4J
* @Description: 微信支付商戶信息配置類
*/
@Data
@Component
@RefreshScope
@ConfigurationProperties(prefix = "wechat.pay")
public class WeChatPayProperties {
/**
* 微信小程序或者微信公眾號appId
*/
private String appid;
/**
* 商戶號
*/
private String mchId;
/**
* 商戶密鑰
*/
private String mchKey;
/**
* 商戶證書序列號
*/
private String serialNo;
/**
* apiV3Key
*/
private String apiV3Key;
/**
* 證書
*/
private String keyPath;
/**
* 商戶私鑰文件
*/
private String privateKeyPath;
/**
* apiclient_cert.pem證書文件
*/
private String privateCertPath;
/**
* 交易類型
* JSAPI--公眾號支付
* NATIVE--原生掃碼支付
* APP--app支付
*/
private String tradeType;
/**
* 支付結果異步通知回調(diào)地址
*/
private String notifyUrl;
}
微信支付配置類
/**
* @author: Eden4J
* @Description: 微信支付配置類
*/
@Component
@ConditionalOnClass(WxPayService.class)
@RequiredArgsConstructor
public class WeChatPayConfig {
private final WeChatPayProperties properties;
@Bean
@ConditionalOnMissingBean
public WxPayConfig payConfig() {
WxPayConfig payConfig = new WxPayConfig();
payConfig.setAppId(StringUtils.trimToNull(this.properties.getAppid()));
payConfig.setMchId(StringUtils.trimToNull(this.properties.getMchId()));
payConfig.setMchKey(StringUtils.trimToNull(this.properties.getMchKey()));
payConfig.setCertSerialNo(StringUtils.trimToNull(this.properties.getSerialNo()));
payConfig.setApiV3Key(StringUtils.trimToNull(this.properties.getApiV3Key()));
payConfig.setKeyPath(StringUtils.trimToNull(this.properties.getKeyPath()));
payConfig.setPrivateKeyPath(StringUtils.trimToNull(this.properties.getPrivateKeyPath()));
payConfig.setPrivateCertPath(StringUtils.trimToNull(this.properties.getPrivateCertPath()));
payConfig.setTradeType(StringUtils.trimToNull(this.properties.getTradeType()));
return payConfig;
}
@Bean
public WxPayService wxPayService(WxPayConfig payConfig) {
WxPayService wxPayService = new WxPayServiceImpl();
wxPayService.setConfig(payConfig);
return wxPayService;
}
}
自定義的微信預支付返回信息類
@Data
public class WxPayInfoVO implements Serializable {
private String appId;
private String timeStamp;
private String nonceStr;
private String packageValue;
private String signType;
private String paySign;
}
工具類
/**
* @author: Eden4J
* @Description: 微信支付相關工具類
*/
public class WxPayUtil {
public static String sign(String signStr, PrivateKey privateKey) {
Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, privateKey.getEncoded(), null);
return Base64.encode(sign.sign(signStr.getBytes()));
}
public static String buildMessage(String appId, String timeStamp, String nonceStr, String body) {
return appId + "\n" + timeStamp + "\n" + nonceStr + "\n" + body + "\n";
}
public static AutoUpdateCertificatesVerifier getVerifier(WxPayConfig wxPayConfig) throws IOException {
PrivateKey privateKey = PemUtils.loadPrivateKey(new ClassPathResource("apiclient_key.pem").getInputStream());
AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
new WxPayCredentials(wxPayConfig.getMchId(), new PrivateKeySigner(wxPayConfig.getCertSerialNo(), privateKey))
, wxPayConfig.getApiV3Key().getBytes("utf-8")
);
return verifier;
}
/**
* 驗證簽名
*
* @param certificate
* @param message
* @param signature
* @return
*/
public static boolean verify(AutoUpdateCertificatesVerifier certificate, byte[] message, String signature) {
try {
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initVerify(certificate.getValidCertificate());
sign.update(message);
return sign.verify(java.util.Base64.getDecoder().decode(signature));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("當前Java環(huán)境不支持SHA256withRSA", e);
} catch (SignatureException e) {
throw new RuntimeException("簽名驗證過程發(fā)生了錯誤", e);
} catch (InvalidKeyException e) {
throw new RuntimeException("無效的證書", e);
}
}
}
接口層和服務處理層代碼
重點注意:微信支付回調(diào)結果通知不要使用JSONObject去做接收
接口層
@RestController
@RequestMapping("/請求路徑")
@RequiredArgsConstructor
public class AppCustomerUserRechargeOrderController {
private final IAppCustomerUserRechargeOrderService rechargeOrderService;
@PostMapping("/preOrder")
public Result<WxPayInfoVO> preOrder(@RequestParam("goodId") String goodId) {
return Result.success(rechargeOrderService.preOrder(goodId));
}
// 支付回調(diào)
@PostMapping("/back")
public Map<String,String> back(@RequestBody Map body,HttpServletRequest request) {
return rechargeOrderService.formalOrder(body, request);
}
}
處理層
@Override
public WxPayInfoVO preRecharge(String goodId) {
try {
//看看是否有其他的業(yè)務邏輯
// 調(diào)用微信的統(tǒng)一下單接口獲取預支付單返回前端 createOrderV3(TradeTypeEnum tradeType, WxPayUnifiedOrderV3Request request)
WxPayUnifiedOrderV3Request payRequest = new WxPayUnifiedOrderV3Request();
payRequest.setOutTradeNo(rechargeNo);//系統(tǒng)充值訂單號
payRequest.setDescription(goodsPackage.getPackageName());
//訂單失效時間
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
payRequest.setTimeExpire(dateFormat.format(DateUtil.offset(new Date(), DateField.HOUR_OF_DAY, 1)));
WxPayUnifiedOrderV3Request.Payer payer = new WxPayUnifiedOrderV3Request.Payer();
payer.setOpenid(userAccount.getOpenId());
payRequest.setPayer(payer);
WxPayUnifiedOrderV3Request.Amount amount = new WxPayUnifiedOrderV3Request.Amount();
amount.setTotal(rechargeOrder.getTotalAmount().multiply(BigDecimal.valueOf(100)).intValue());
amount.setCurrency("CNY");
payRequest.setAmount(amount);
payRequest.setNotifyUrl(weChatPayProperties.getNotifyUrl());
WxPayUnifiedOrderV3Result.JsapiResult jsapiResult = wxPayService.createOrderV3(TradeTypeEnum.JSAPI, payRequest);
String encode = WxPayUtil.sign(WxPayUtil.buildMessage(weChatPayProperties.getAppid(), jsapiResult.getTimeStamp(), jsapiResult.getNonceStr(), jsapiResult.getPackageValue())
, PemUtils.loadPrivateKey(new ClassPathResource("apiclient_key.pem").getInputStream()));
WxPayInfoVO payInfoVO = PojoUtil.exchangePojo(jsapiResult, WxPayInfoVO.class);
payInfoVO.setPaySign(encode);
return payInfoVO;
} catch (WxPayException e) {
e.printStackTrace();
throw new BizException("微信支付失敗", e);
} catch (IOException e) {
e.printStackTrace();
throw new BizException("微信支付失敗", e);
}
}
@Override
public Map<String, String> createFormalOrder(Map body, HttpServletRequest request) {
try {
Map<String, String> resultMap = new HashMap<>();
resultMap.put("code", "FAIL");
ObjectMapper objectMapper = new ObjectMapper();
try {
//官方文檔中有說明切記不要改變原始報文主體,如果使用JSONObject接收的話,不能使用JSON轉換出來的字符串,會出現(xiàn)驗簽錯誤的情況,請注意
String data = objectMapper.writeValueAsString(body);
SignatureHeader header = new SignatureHeader();
header.setTimeStamp(request.getHeader("Wechatpay-Timestamp"));
header.setNonce(request.getHeader("Wechatpay-Nonce"));
header.setSignature(request.getHeader("Wechatpay-Signature"));
header.setSerial(request.getHeader("Wechatpay-Serial"));
WxPayNotifyV3Result notifyV3Result =wxPayService.parseOrderNotifyV3Result(data, header);
WxPayNotifyV3Result.DecryptNotifyResult decryptNotifyResult = notifyV3Result.getResult();//解密后的數(shù)據(jù)
if ("SUCCESS".equalsIgnoreCase(decryptNotifyResult.getTradeState())) {
resultMap.put("code", "SUCCESS");
}
} catch (Exception e) {
e.printStackTrace();
}
return resultMap;
} catch (Exception e) {
e.printStackTrace();
throw new BizException("微信支付成功回調(diào)失敗", e);
}
}
到此這篇關于SpringBoot整合weixin-java-pay實現(xiàn)微信小程序支付的示例代碼的文章就介紹到這了,更多相關SpringBoot weixin-java-pay微信小程序支付內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java中的FileInputStream是否需要close問題
這篇文章主要介紹了Java中的FileInputStream是否需要close問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-12-12
SpringBoot整合RocketMq實現(xiàn)分布式事務
這篇文章主要為大家詳細介紹了SpringBoot整合RocketMq實現(xiàn)分布式事務的相關知識,文中的示例代碼講解詳細,有需要的小伙伴可以參考一下2024-11-11
SpringBoot+React實現(xiàn)計算個人所得稅
本文將以個人所得稅的計算為例,使用React+SpringBoot+GcExcel來實現(xiàn)這一功能,文中的示例代碼講解詳細,具有一定的學習價值,感興趣的小伙伴可以了解下2023-09-09
Java實現(xiàn)ThreadLocal數(shù)據(jù)在線程池間傳遞的解決方案
隨著業(yè)務的發(fā)展,系統(tǒng)新增了一個需求:需要根據(jù)接口請求頭中的特定信息動態(tài)選擇數(shù)據(jù)庫實例進行查詢,這個上下文信息在請求進入后被存儲在ThreadLocal中,本文給大家介紹了Java實現(xiàn)ThreadLocal數(shù)據(jù)在線程池間傳遞的解決方案,需要的朋友可以參考下2025-07-07

