当前位置:   article > 正文

java微信小程序支付-回调(Jsapi-APIv3)_java 微信支付通知回调

java 微信支付通知回调

一、接入前准备,按照这个文档准备

       准备: 接入前准备-小程序支付 | 微信支付商户平台文档中心

准备好了就可以获得(第二点里需要的参数):
        参数1 商户号 merchantId:xxxxxx(全是数字)

        参数2 商户APIV3密钥 apiV3key:xxxxxxx(32位字母数字大小写串,开发自己准备的)

        参数3 商户证书序列号 merchantSerialNumber:xxxxx

            查看方式:微信支付证书序列号在哪里看(v3商户证书序列号在哪里查找)-李飞SEO

        参数4 商户API私钥路径 privateKeyPath:apiclient_key.pem的文件路径

---------------------Native (二维码)支付下单,前四个就够了,5是用于Jsapi支付----------------
        参数5 国密的微信支付平台证书路径(X509文件) wechatPayCertificatePath:wechatpay_xxxx.pem()

                这个文件找了好久,最后试用下边这个工具下下来可以用GitHub - wechatpay-apiv3/CertificateDownloader: Java 微信支付 APIv3 平台证书的命令行下载工具
 

二、支付代码接入

支付-官网文档:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7

微信给apiv3做了个maven包,终于像个样子了,结果我发现里边native支付例子虽然完整,但是第一大点里的1-5个参数完全不知道怎么给,jsapi参数同理,我是的东拼西凑凑齐了。maven包文档

-

贴一个jsapi的调用例子,小程序端唤起支付用它就够了,这是在官方的例子基础上补全了:

  1. import com.alibaba.fastjson.JSONObject;
  2. import com.wechat.pay.java.core.Config;
  3. import com.wechat.pay.java.core.RSAConfig;
  4. import com.wechat.pay.java.core.exception.HttpException;
  5. import com.wechat.pay.java.core.exception.MalformedMessageException;
  6. import com.wechat.pay.java.core.exception.ServiceException;
  7. import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
  8. import com.wechat.pay.java.service.payments.jsapi.model.CloseOrderRequest;
  9. import com.wechat.pay.java.service.payments.jsapi.model.Payer;
  10. import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
  11. import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
  12. import com.wechat.pay.java.service.payments.jsapi.model.QueryOrderByIdRequest;
  13. import com.wechat.pay.java.service.payments.jsapi.model.QueryOrderByOutTradeNoRequest;
  14. import com.wechat.pay.java.service.payments.model.Transaction;
  15. import com.wechat.pay.java.service.payments.jsapi.model.Amount;
  16. import lombok.extern.slf4j.Slf4j;
  17. @Slf4j
  18. public class JsapiDemoService {
  19. public static String merchantId = "1xxxx";
  20. // public static String privateKeyPath = "";
  21. public static String merchantSerialNumber = "xxxx";
  22. public static String wechatPayCertificatePath = "";
  23. public static com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension service;
  24. public static PrepayWithRequestPaymentResponse createWxJsapOrder(String certificatePath, String keyPath, JsapiReq cliReq) {
  25. String method = Thread.currentThread().getStackTrace()[1].getMethodName();
  26. // 使用自动更新平台证书的RSA配置
  27. // 一个商户号只能初始化一个配置,否则会因为重复的下载任务报错
  28. Config config =
  29. new RSAConfig.Builder()
  30. .merchantId(merchantId)
  31. // 使用 com.wechat.pay.java.core.util 中的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名
  32. .privateKeyFromPath(keyPath)
  33. .merchantSerialNumber(merchantSerialNumber)
  34. .wechatPayCertificatesFromPath(certificatePath)
  35. .build();
  36. // 构建service
  37. JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
  38. // request.setXxx(val)设置所需参数,具体参数可见Request定义
  39. PrepayRequest request = new PrepayRequest();
  40. Payer payer = new Payer();
  41. payer.setOpenid(cliReq.getOpenid());
  42. request.setPayer(payer);
  43. Amount amount = new Amount();
  44. amount.setTotal(10);//订单总金额,单位为分
  45. request.setAmount(amount);
  46. request.setAppid("wxddddxxxxxx");
  47. request.setMchid("1xxxx");
  48. request.setDescription("ms");
  49. request.setNotifyUrl("https://xxx.net/callBackr");
  50. //request.setOutTradeNo("out_trade_no_1");
  51. request.setOutTradeNo(cliReq.getOutTradeNo());
  52. // 调用下单方法,得到应答
  53. try {
  54. // ... 调用接口
  55. PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
  56. // 使用微信扫描 code_url 对应的二维码,即可体验Native支付
  57. System.out.println(JSONObject.toJSON(response));
  58. return response;
  59. } catch (HttpException e) { // 发送HTTP请求失败
  60. // 调用e.getHttpRequest()获取请求打印日志或上报监控,更多方法见HttpException定义
  61. log.error(method, e);
  62. } catch (ServiceException e) { // 服务返回状态小于200或大于等于300,例如500
  63. // 调用e.getResponseBody()获取返回体打印日志或上报监控,更多方法见ServiceException定义
  64. log.error(method, e);
  65. } catch (MalformedMessageException e) { // 服务返回成功,返回体类型不合法,或者解析返回体失败
  66. // 调用e.getMessage()获取信息打印日志或上报监控,更多方法见MalformedMessageException定义
  67. log.error(method, e);
  68. } catch (Exception e) { // 服务返回成功,返回体类型不合法,或者解析返回体失败
  69. // 调用e.getMessage()获取信息打印日志或上报监控,更多方法见MalformedMessageException定义
  70. log.error(method, e);
  71. }
  72. return new PrepayWithRequestPaymentResponse();
  73. }
  74. /** 关闭订单 */
  75. public static void closeOrder() {
  76. CloseOrderRequest request = new CloseOrderRequest();
  77. // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
  78. // 调用接口
  79. service.closeOrder(request);
  80. }
  81. /** JSAPI支付下单,并返回JSAPI调起支付数据 */
  82. public static PrepayWithRequestPaymentResponse prepayWithRequestPayment() {
  83. PrepayRequest request = new PrepayRequest();
  84. // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
  85. // 调用接口
  86. return service.prepayWithRequestPayment(request);
  87. }
  88. /** 微信支付订单号查询订单 */
  89. public static Transaction queryOrderById() {
  90. QueryOrderByIdRequest request = new QueryOrderByIdRequest();
  91. // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
  92. // 调用接口
  93. return service.queryOrderById(request);
  94. }
  95. /** 商户订单号查询订单 */
  96. public static Transaction queryOrderByOutTradeNo() {
  97. QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
  98. // 调用request.setXxx(val)设置所需参数,具体参数可见Request定义
  99. // 调用接口
  100. return service.queryOrderByOutTradeNo(request);
  101. }
  102. }

补下JsapiReq 的定义

  1. public class JsapiReq implements Serializable {
  2. private static final long serialVersionUID = 1L;
  3. private String openid;
  4. private String outTradeNo;
  5. }

 另外记一下java/spring/srpingboot里resource文件读取路径的方法

  1. String userDir = System.getProperty("user.dir");
  2. String certificatePath = userDir + "/src/main/resources/cert/wechatpay_xxx.pem";
  3. String keyPath = userDir + "/src/main/resources/cert/apiclient_xxxxkey.pem";

三、支付回调

支付回调-官网文档:微信支付-开发者文档

代码

  1. @PostMapping(value = "/callBack")
  2. public Map<String, String> callBack(@RequestBody JSONObject jsonObject) {
  3. String method = Thread.currentThread().getStackTrace()[1].getMethodName();
  4. try {
  5. String key = WxNativePayProxy.getWxV3Key();
  6. String json = jsonObject.toString();
  7. String associated_data = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.associated_data");
  8. String ciphertext = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.ciphertext");
  9. String nonce = (String) JSONUtil.getByPath(JSONUtil.parse(json), "resource.nonce");
  10. String decryptData = new AesUtil(key.getBytes(StandardCharsets.UTF_8)).decryptToString(associated_data.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);
  11. //验签成功
  12. JSONObject decryptDataObj = JSONObject.parseObject(decryptData, JSONObject.class);
  13. //decryptDataObj 为解码后的obj,其内容如下。之后便是验签成功后的业务处理
  14. //{
  15. // "sp_appid": "wx8888888888888888",
  16. // "sp_mchid": "1230000109",
  17. // "sub_appid": "wxd678efh567hg6999",
  18. // "sub_mchid": "1900000109",
  19. // "out_trade_no": "1217752501201407033233368018",
  20. // "trade_state_desc": "支付成功",
  21. // "trade_type": "MICROPAY",
  22. // "attach": "自定义数据",
  23. // "transaction_id": "1217752501201407033233368018",
  24. // "trade_state": "SUCCESS",
  25. // "bank_type": "CMC",
  26. // "success_time": "2018-06-08T10:34:56+08:00",
  27. // ...
  28. // "payer": {
  29. // "openid": "oUpF8uMuAJO_M2pxb1Q9zNjWeS6o"
  30. // },
  31. // "scene_info": {
  32. // "device_id": "013467007045764"
  33. // }
  34. //}
  35. }catch (Exception e){
  36. log.info("{} ,parms{}, 异常:", method, jsonObject.toJSONString(), e);
  37. }
  38. Map<String, String> res = new HashMap<>();
  39. res.put("code", "SUCCESS");
  40. res.put("message", "成功");
  41. return res;
  42. }

其中有用到微信解码工具类:AesUtil

  1. import java.io.IOException;
  2. import java.security.GeneralSecurityException;
  3. import java.security.InvalidAlgorithmParameterException;
  4. import java.security.InvalidKeyException;
  5. import java.security.NoSuchAlgorithmException;
  6. import java.util.Base64;
  7. import javax.crypto.Cipher;
  8. import javax.crypto.NoSuchPaddingException;
  9. import javax.crypto.spec.GCMParameterSpec;
  10. import javax.crypto.spec.SecretKeySpec;
  11. public class AesUtil{
  12. static final int KEY_LENGTH_BYTE = 32;
  13. static final int TAG_LENGTH_BIT = 128;
  14. private final byte[] aesKey;
  15. public AesUtil(byte[] key) {
  16. if (key.length != KEY_LENGTH_BYTE) {
  17. throw new IllegalArgumentException("无效的ApiV3Key,长度必须为32个字节");
  18. }
  19. this.aesKey = key;
  20. }
  21. public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext)
  22. throws GeneralSecurityException, IOException {
  23. try {
  24. Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
  25. SecretKeySpec key = new SecretKeySpec(aesKey, "AES");
  26. GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce);
  27. cipher.init(Cipher.DECRYPT_MODE, key, spec);
  28. cipher.updateAAD(associatedData);
  29. return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8");
  30. } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
  31. throw new IllegalStateException(e);
  32. } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
  33. throw new IllegalArgumentException(e);
  34. }
  35. }
  36. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/408730
推荐阅读
相关标签
  

闽ICP备14008679号