springboot集成微信APP支付V3最新版

  • 初识微信支付(不明白微信文档的请看,否则请跳过)
    • 指引文档
    • API字典
    • 接口规则
  • 具体流程+代码
    • 第一步:申请证书并创建应用
    • 第二步:下单支付(熟悉调用流程、封装参数配置类、公用支付方法)
    • 第三步:接收异步通知
  • 结束总结:

初识微信支付(不明白微信文档的请看,否则请跳过)

微信文档地址
众所周知,看别人的文档是个痛苦的事情,尤其是复杂的文档,这里说一下自己总结看文档的经验,先不着急上去就看某一个功能,先把文档的分类搞明白,然后是每个分类下的每个功能列表,切忌直接进去一顿操作跳转,结果自己都晕了,感觉到处都是支付的信息,总结一句话,看文档之前,先搞懂写文档人的套路,然后你会发现,真的是手到擒来,废话不多说,直接进入正题。

第一步,进入文档中心

主要看这几个,最重要的是API字典!

指引文档

这里主要是告诉我们接入微信支付的前置条件以及满足接入条件之后的开发步骤。这里建议大概看一下。

  • 接入前的准备
    主要是准备一些支付所需要的资料,例如:appid,证书等,基本按照文档一步步操作就能轻松搞定。
  • 开发指引
    这里主要是讲开发步骤,以及提供一些各语言的参考代码,建议主看,初看的时候尽量先看一遍流程,先不要点里边的链接跳转过去看,搞明白了之后再回头逐步去研究每个步骤的详细介绍。
    总结一下,简单的流程:
    1、前端请求后端支付接口(一般给个订单号即可)
    2、后端加载证书,配置预支付所需要的参数
    3、请求微信支付下单接口,获取预支付id,也就是所谓的 prepay_id
    4、组装好前端拉起微信支付所需要的参数,返回给前端即可
    5、前端拉起微信支付,支付或取消,微信会以异步通知告知后端,这里需要后端提供一个接口给微信支付官方(文档说是必须用https,我用的http也可以)
    6、接收微信异步通知,获取相关参数,处理对应逻辑
    详细流程及代码逻辑,下边会具体说!!!

API字典

这个比较简单但也是最重要的,后边我们会频繁用到

这个就不多说了,提醒一下,请求接口的时候一定要正确填写接口地址和请求方式!!!

接口规则

这里主要讲签名,验签,敏感信息加解密(例如:异步通知返回的订单信息),证书更新(微信支付证书有时间限制,需要定期更新)的介绍

具体流程+代码

第一步:申请证书并创建应用

准备必要的材料,去微信开放平台-管理中心,创建移动应用(应用没有上线也可以申请,资料填好就行,没有的先不填,基本可以通过审核),之后申请开通微信支付功能,得到所有配置所需要的参数。

注意,这里有个很容易配错的地方:应用签名,创建app应用的时候会让你填写应用签名和应用包名,应用包名是你自己填写的,保持跟安卓包名一致即可,应用签名并不是你keystore文件里的MD5值,而是需要你用微信提供的工具安装到手机上(同时安装你的app),获取你app的签名。

微信开发指引
如果这里的连接下载不了签名生成工具,可以去开放平台安卓资源下载微信资源下载

如果配错应用签名,你会发现app只能首次拉起微信支付,之后支付的时候,微信怎么都拉不起来!!!

第二步:下单支付(熟悉调用流程、封装参数配置类、公用支付方法)

下载证书,配置微信支付。
证书申请参考:证书申请

配置微信支付config类:

public class WxPayInfoConfig {public final static String mchId = "********";public final static String appid = "********";public final static String apiV3Key = "********";/*** 退款异步通知地址*/public final static String refund_notify_url = "http://api.wx.com/refundNotify/refunded/wxNotify";/*** 下单异步通知地址,你后端的开放的接口地址,必须能外网访问,确保微信能正常调用,且不要加任何限制* 改成你自己的地址*/public final static String pay_notify_url = "http://api.wx.com/payNotify/payed/wxNotify";/*** 证书相对路径*/public final static String privateKeyPath = "wx/apiclient_key.pem";/*** 下单地址*/public final static String singleUrl = "https://api.mch.weixin.qq.com/v3/pay/transactions/app";/*** 退款地址*/public final static String refundUrl = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";/*** 查询订单地址* transaction_id:微信支付系统生成的订单号 或者 商户订单号* mchid:直连商户的商户号,由微信支付生成并下发* 组合地址:String url = String.format(WxPayInfoConfig.signUrl, transaction_id, WxPayInfoConfig.mchId);*/public final static String queryUrl = "https://api.mch.weixin.qq.com/v3/pay/transactions/id/%s?mchid=%s";/*** 关闭订单地址*/public final static String closeUrl = "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/%s/close";public static String mchSerialNo;public static PrivateKey privateKey;static {// 加载商户私钥(privateKey:私钥字符串)privateKey = WxPayUtil.getPrivateKey(privateKeyPath);// 加载平台证书(mchId:商户号,mchSerialNo:商户证书序列号,apiV3Key:V3密钥)X509Certificate certificate = WxPayUtil.getX509Certificate();// 证书的序列号 也有用mchSerialNo = certificate.getSerialNumber().toString(16).toUpperCase();}
}

提取微信支付工具类:
这里注意,微信证书会过期,所以需要你定期更新证书,可手动更新,也可以自动更新,这里说下自动更新,自动更新,微信提供了java库wechatpay-apache-httpclient(不仅封装了证书相关发放,还封装了下单,加解密的相关方法,可以细细研究一下)
在我们往下看之前,请务必了解微信支付请求流程:
以下单支付流程为例:

<dependency><groupId>com.github.wechatpay-apiv3</groupId><artifactId>wechatpay-apache-httpclient</artifactId><version>0.2.3</version>
</dependency>

详细介绍
工具类配置

public class WxPayUtil {/*** 保存微信平台证书*/private static final ConcurrentHashMap<String, AutoUpdateCertificatesVerifier> verifierMap = new ConcurrentHashMap<>();/*** 功能描述:获取平台证书,自动更新* 注意:这个方法内置了平台证书的获取和返回值解密* @return com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier* @author zhouwenjie* @date 2021/6/13 20:29*/static AutoUpdateCertificatesVerifier getVerifier(String serialNumber) {AutoUpdateCertificatesVerifier verifier = null;if (verifierMap.isEmpty() || !verifierMap.containsKey(serialNumber)) {verifierMap.clear();try {//刷新PrivateKeySigner signer = new PrivateKeySigner(WxPayInfoConfig.mchSerialNo, WxPayInfoConfig.privateKey);WechatPay2Credentials credentials = new WechatPay2Credentials(WxPayInfoConfig.mchId, signer);verifier = new AutoUpdateCertificatesVerifier(credentials, WxPayInfoConfig.apiV3Key.getBytes("utf-8"));verifierMap.put(verifier.getValidCertificate().getSerialNumber()+"", verifier);} catch (UnsupportedEncodingException e) {e.printStackTrace();}} else {verifier = verifierMap.get(serialNumber);}return verifier;}/*** 获取httpClient,用于之后请求微信接口* 用这个工具类的好处就是不用你自己去拼接签名参数了,每次请求会自动帮你创建签名* 详情可以点击进去看源码*/static CloseableHttpClient getHttpClient(String serialNumber) {//获取平台证书AutoUpdateCertificatesVerifier verifier = getVerifier(serialNumber);if (verifier == null) {ExceptionCast.cast(CommonCode.OPERATION_ERROR);}// 初始化httpClient  httpClient会在发送请求之前拦截并且自动根据请求信息创建签名CloseableHttpClient httpClient = WechatPayHttpClientBuilder.create().withMerchant(WxPayInfoConfig.mchId, WxPayInfoConfig.mchSerialNo, WxPayInfoConfig.privateKey).withValidator(new WechatPay2Validator(verifier)).build();return httpClient;}/*** 获取私钥。** @return 私钥对象*/public static PrivateKey getPrivateKey(String fileName) {try {ClassPathResource resource = new ClassPathResource(fileName);String content = IOUtils.toString(resource.getInputStream(), "utf-8");String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "").replaceAll("\\s+", "");KeyFactory kf = KeyFactory.getInstance("RSA");PrivateKey key = kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));return key;} catch (NoSuchAlgorithmException e) {throw new RuntimeException("当前Java环境不支持RSA", e);} catch (InvalidKeySpecException e) {throw new RuntimeException("无效的密钥格式");} catch (UnsupportedEncodingException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return null;}/*** 功能描述: 移动端支付请求签名** @param prepayid* @param nonceStr* @return java.lang.String* @author zhouwenjie* @date 2021/6/10 9:09*/@SneakyThrowspublic static String appPaySign(String prepayid, String nonceStr, String timestamp) {String signatureStr = Stream.of(WxPayInfoConfig.appid, timestamp, nonceStr, prepayid).collect(Collectors.joining("\n", "", "\n"));Signature sign = Signature.getInstance("SHA256withRSA");sign.initSign(WxPayInfoConfig.privateKey);sign.update(signatureStr.getBytes(StandardCharsets.UTF_8));return Base64Utils.encodeToString(sign.sign());}/*** 功能描述: 验证签名* 注意:使用微信支付平台公钥验签* Wechatpay-Signature 微信返签名* Wechatpay-Serial 微信平台证书序列号** @return java.lang.String* @author zhouwenjie* @date 2021/6/10 9:09*/@SneakyThrowspublic static boolean verifySign(HttpServletRequest request,String body) {boolean verify = false;try {String wechatPaySignature = request.getHeader("Wechatpay-Signature");String wechatPayTimestamp = request.getHeader("Wechatpay-Timestamp");String wechatPayNonce = request.getHeader("Wechatpay-Nonce");String wechatPaySerial = request.getHeader("Wechatpay-Serial");//组装签名串String signStr = Stream.of(wechatPayTimestamp, wechatPayNonce, body).collect(Collectors.joining("\n", "", "\n"));//获取平台证书AutoUpdateCertificatesVerifier verifier = getVerifier(wechatPaySerial);//获取失败 验证失败if (verifier != null) {Signature signature = Signature.getInstance("SHA256withRSA");signature.initVerify(verifier.getValidCertificate());//放入签名串signature.update(signStr.getBytes(StandardCharsets.UTF_8));verify = signature.verify(Base64.getDecoder().decode(wechatPaySignature.getBytes()));}} catch (InvalidKeyException e) {e.printStackTrace();} catch (NoSuchAlgorithmException e) {e.printStackTrace();}return verify;}/*** 功能描述: 获取X509Certificate** @param* @return java.security.cert.X509Certificate* @author zhouwenjie* @date 2021/6/15 11:49*/public static X509Certificate getX509Certificate() {ClassPathResource resource = new ClassPathResource("wx/apiclient_cert.p12");KeyStore keyStore;X509Certificate certificate = null;try {keyStore = KeyStore.getInstance("PKCS12");keyStore.load(resource.getInputStream(), WxPayInfoConfig.mchId.toCharArray());certificate = (X509Certificate) keyStore.getCertificate("Tenpay Certificate");certificate.checkValidity();} catch (KeyStoreException | IOException e) {e.printStackTrace();} catch (CertificateNotYetValidException e) {e.printStackTrace();} catch (CertificateExpiredException e) {e.printStackTrace();} catch (CertificateException e) {e.printStackTrace();} catch (NoSuchAlgorithmException e) {e.printStackTrace();}return certificate;}/*** 证书和回调报文解密** @param associatedData response.body.data[i].encrypt_certificate.associated_data 附加数据包(可能为空)* @param nonce          response.body.data[i].encrypt_certificate.nonce 加密使用的随机串初始化向量* @param ciphertext     response.body.data[i].encrypt_certificate.ciphertext Base64编码后的密文* @return the string* @throws GeneralSecurityException the general security exception*/public static String decryptToString(String associatedData, String nonce, String ciphertext) {String cert = null;try {//简化AesUtil aesUtil = new AesUtil(WxPayInfoConfig.apiV3Key.getBytes(StandardCharsets.UTF_8));cert = aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);} catch (GeneralSecurityException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return cert;}/*** 敏感信息加解密-解密.* 使用商户私钥解密* <p>* `为了保证通信过程中敏感信息字段(如用户的住址、银行卡号、手机号码等)的机密性,* `微信支付API v3要求商户对上送的敏感信息字段进行加密。* `与之相对应,微信支付会对下行的敏感信息字段进行加密,商户需解密后方能得到原文** @param ciphertext 密文*/public static String rsaDecryptOAEP(String ciphertext) {// 使用商户私钥解密String text = null;try {text = RsaCryptoUtil.decryptOAEP(ciphertext, WxPayInfoConfig.privateKey);} catch (BadPaddingException e) {e.printStackTrace();}return text;}/*** 敏感信息加解密-加密.* 使用微信支付平台证书中的公钥加密* 使用封装的RsaCryptoUtil* https://github.com/wechatpay-apiv3/wechatpay-apache-httpclient** @param message 需要加密的信息*                certificate 证书*/public static String rsaEncryptOAEP(String message) {String ciphertext = null;try {AutoUpdateCertificatesVerifier verifier = getVerifier(null);X509Certificate certificate = verifier.getValidCertificate();ciphertext = RsaCryptoUtil.encryptOAEP(message, certificate);} catch (IllegalBlockSizeException e) {e.printStackTrace();}return ciphertext;}/*** 功能描述: 发起get请求* 动态返回自定义的实体类型** @param method 请求方式 GET POST* @param url* @param t      泛型* @return T 实体类class* @author zhouwenjie* @date 2021/6/15 14:49*/public static <T> T wxHttpRequest(String method, String url, String reqdata, Class<T> t) {T resultBean = null;T instance = null;CloseableHttpResponse response;CloseableHttpClient httpClient = null;try {if (!verifierMap.isEmpty()) {String bigInteger = verifierMap.keys().nextElement();//httpClient 内置有签名信息httpClient = getHttpClient(bigInteger);} else {httpClient = getHttpClient("1");}//创建实体,相当于new对象instance = t.newInstance();if ("get".equalsIgnoreCase(method)) {HttpGet httpGet = new HttpGet(url);httpGet.setHeader("Accept", "application/json");//完成签名并执行请求response = httpClient.execute(httpGet);} else {StringEntity entity = new StringEntity(reqdata, StandardCharsets.UTF_8);entity.setContentType("application/json");HttpPost httpPost = new HttpPost(url);httpPost.setEntity(entity);httpPost.setHeader("Accept", "application/json");//完成签名并执行请求response = httpClient.execute(httpPost);}//如果状态码为200,就是正常返回int statusCode = response.getStatusLine().getStatusCode();if (statusCode == 200) {String result = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);JSONObject jsonObject = JSON.parseObject(result);if (instance instanceof JSONObject) {resultBean = (T) jsonObject;} else {resultBean = JSONObject.parseObject(jsonObject.toString(), t);}} else if (statusCode == 204) {log.info("关单成功");String code = "204";resultBean = (T) code;} else {log.error("错误状态码 = " + statusCode + ",返回的错误信息 = " + EntityUtils.toString(response.getEntity()));ExceptionCast.cast(CommonCode.WX_ORDER_REAUEST_FAIL);}} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (ClientProtocolException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {if (httpClient != null) {httpClient.close();}} catch (IOException e) {e.printStackTrace();}}return resultBean;}/*** 功能描述:生成单个订单预付单** @param totalPrice* @param out_trade_no* @param description* @return java.util.Map<java.lang.String, java.lang.String>* @author zhouwenjie* @date 2021/6/10 10:16*/public static Map<String, String> createOrder(Integer totalPrice, String out_trade_no, Stringdescription) {WxOnePayVo wxOnePayVo = new WxOnePayVo(totalPrice);wxOnePayVo.setAppid(WxPayInfoConfig.appid);wxOnePayVo.setMchid(WxPayInfoConfig.mchId);wxOnePayVo.setNotify_url(WxPayInfoConfig.pay_notify_url);wxOnePayVo.setDescription(description);wxOnePayVo.setAttach(CommonConstant.pay_order);wxOnePayVo.setOut_trade_no(out_trade_no);//计算失效时间  15分钟订单关闭wxOnePayVo.setTime_expire(CommonUtil.getTimeExpire());String reqdata = JSON.toJSONString(wxOnePayVo);Map<String, String> returnMap = getPayReturnMap("POST", reqdata, WxPayInfoConfig.singleUrl);return returnMap;}public static Map<String, String> getPayReturnMap(String method, String reqdata, String url) {HashMap<String, String> returnMap = new HashMap<String, String>();JSONObject jsonObject = wxHttpRequest(method, url, reqdata, JSONObject.class);//处理成功String prepay_id = (String) jsonObject.get("prepay_id");//生成代签名的支付信息String nonceStr = UUID.randomUUID().toString(true);String timestamp = String.valueOf(System.currentTimeMillis() / 1000);String signature = appPaySign(prepay_id, nonceStr, timestamp);returnMap.put("appid", WxPayInfoConfig.appid);returnMap.put("partnerid", WxPayInfoConfig.mchId);returnMap.put("prepayid", prepay_id);returnMap.put("package", "Sign=WXPay");returnMap.put("noncestr", nonceStr);returnMap.put("timestamp", timestamp);returnMap.put("sign", signature);return returnMap;}/*** 功能描述:退款操作* 注意:* 1、交易时间超过一年的订单无法提交退款* <p>* 2、微信支付退款支持单笔交易分多次退款(不超50次),多次退款需要提交原支付订单的商户订单号和设置不同的退款单号。申请退款总金额不能超过订单金额。 一笔退款失败后重新提交,请不要更换退款单号,请使用原商户退款单号* <p>* 3、错误或无效请求频率限制:6qps,即每秒钟异常或错误的退款申请请求不超过6次* <p>* 4、每个支付订单的部分退款次数不能超过50次* <p>* 5、如果同一个用户有多笔退款,建议分不同批次进行退款,避免并发退款导致退款失败* <p>* 6、申请退款接口的返回仅代表业务的受理情况,具体退款是否成功,需要通过退款查询接口获取结果* <p>* 7、一个月之前的订单申请退款频率限制为:5000/min*/public static WxRefundReturnInfoVo refundOrder(WxRefundInfoVo wxRefundInfoVo) {wxRefundInfoVo.setNotify_url(WxPayInfoConfig.refund_notify_url);String reqdata = JSON.toJSONString(wxRefundInfoVo);WxRefundReturnInfoVo wxRefundReturnInfoVo = wxHttpRequest("POST", WxPayInfoConfig.refundUrl, reqdata, WxRefundReturnInfoVo.class);return wxRefundReturnInfoVo;}/*** 功能描述: 查询订单* 查询订单可通过微信支付订单号和商户订单号两种方式查询,两种查询方式返回结果相同** @param transaction_id* @return void* @author zhouwenjie* @date 2021/6/15 16:08*/public static NotifyResourceVO QueryOrder(String transaction_id) {String url = String.format(WxPayInfoConfig.queryUrl, transaction_id, WxPayInfoConfig.mchId);NotifyResourceVO notifyResourceVO = wxHttpRequest("GET", url, null, NotifyResourceVO.class);return notifyResourceVO;}/*** 功能描述: 关闭订单* POST  接口响应204,无内容  即成功** @param out_trade_no 商户系统内部订单号* @return void* @author zhouwenjie* @date 2021/6/15 16:08*/public static String CloseOrder(String out_trade_no) {String url = String.format(WxPayInfoConfig.closeUrl, out_trade_no);//请求body参数String reqdata = "{\"mchid\": \"" + WxPayInfoConfig.mchId + "\"}";String code = wxHttpRequest("POST", url, reqdata, String.class);return code;}}

实体类:
WxOnePayVo:请求预付单标识的关键参数

@Data
public class WxOnePayVo {/*** 商户订单号 只能是数字、大小写字母_-*且在同一个商户号下唯一* 示例值:1217752501201407033233368018*/private String out_trade_no;/*** 商户订单号 直连商户的商户号,由微信支付生成并下发。* 示例值:1230000109*/private String mchid;/*** 应用ID* 示例值:wxd678efh567hg6787*/private String appid;/***  附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用*/private String attach;/*** 商品描述* 示例值:Image形象店-深圳腾大-QQ公仔*/private String description;/*** 通知地址 通知URL必须为直接可访问的URL,不允许携带查询串* 示例值:https://www.weixin.qq.com/wxpay/pay.php*/private String notify_url;/*** 订单失效时间* 格式为YYYY-MM-DDTHH:mm:ss+TIMEZONE* 例如:2015-05-20T13:29:35+08:00表示,北京时间2015年5月20日 13点29分35秒。* 示例值:2018-06-08T10:34:56+08:00*/private String time_expire;/*** amount 订单金额信息* 示例值:* "amount": {* "total": 1,  [订单总金额,单位为分]* "currency": "CNY" [CNY:人民币,境内商户号仅支持人民币]* }*/private Amount amount;/*** 订单金额*/@Dataclass Amount {/*** 总金额*/@ApiModelProperty("总金额")private Integer total;@ApiModelProperty("CNY")private String currency = "CNY";}public WxOnePayVo(Integer total){Amount amount = new Amount();amount.setTotal(total);this.amount = amount;}
}

代码里都有对应的方法,顺序可能有些乱,不过参照上边的流程图看,应该没问题,代码里的加解密敏感信息,我暂时我用到,只用了解密报文(decryptToString)。

第三步:接收异步通知

接收异步通知(按照第二步完成支付信息的封装并返回给前端之后,接下来就是默默等待异步通知了,所有支付的后续工作都在这里完成)
流程:定义异步通知接口-接收通知并解析处理
关键代码:

 @ApiOperation(value = "微信异步通知", notes = "微信异步通知")@PostMapping(value = "/wxNotify")public Map<String, String> getTenPayNotify(HttpServletRequest request) throws IOException {HashMap<String, String> returnMap = new HashMap<>(2);String body = request.getReader().lines().collect(Collectors.joining());WxPayAsyncVo wxPayAsyncVo = JSONObject.parseObject(body, WxPayAsyncVo.class);//验证签名boolean verifySign = WxPayUtil.verifySign(request, body);if (verifySign) {//https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_2_5.shtml//获得加密数据,得到的资源对象com.ls.modules.common.vo.wx.pay.Resource resource = wxPayAsyncVo.getResource();//解密后资源数据String notifyResourceStr = WxPayUtil.decryptToString(resource.getAssociated_data(), resource.getNonce(), resource.getCiphertext());//通知资源数据对象NotifyResourceVO notifyResourceVO = JSONObject.parseObject(notifyResourceStr, NotifyResourceVO.class);}}

封装的实体类对象:
WxPayAsyncVo:通知结果大对象

@ToString
@Data
public class WxPayAsyncVo {/*** 通知的唯一ID* 示例值:EV-2018022511223320873*/private String id;/*** 通知创建的时间* 示例值:2015-05-20T13:29:35+08:00*/private String create_time;/*** 通知的类型* 示例值:REFUND.SUCCESS*/private String event_type;/*** 通知的资源数据类型,支付成功通知为encrypt-resource* 示例值:encrypt-resource*/private String resource_type;/*** 回调摘要* 示例值:支付成功*/private String summary;/*** 通知资源数据*/private Resource resource;
}

NotifyResourceVO:大对象中包含的资源对象

@Data
public class NotifyResourceVO {/*** 公众号ID*/private String appid;/*** 直连商户号*/private String mchid;/*** 商户订单号*/private String out_trade_no;/*** 微信支付订单号*/private String transaction_id;/*** 交易类型*/private String trade_type;/*** 交易状态*/private String trade_state;/*** 交易状态描述*/private String trade_state_desc;/*** 付款银行*/private String bank_type;/*** 支付完成时间*/private String success_time;/*** 附加数据 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用*/private String attach;/*** 支付者*/private Payer payer;/*** 订单金额*/private NotifyAmount amount;/*** 支付者*/@Datapublic class Payer {/*** 用户标识*/private String openid;}
}

结束总结:

了解清楚app下单,那么其他的功能,比如:关单、查单、退款等等操作都基本相同,直接在公共类中增加对应的方法即可。
配置证书和各种id,key的时候一定要仔细,最容易出错的就是路径问题,id或者密钥等配反了、错了。
增加新功能的时候多查看微信提供的示例代码,另外注意的是,微信的示例代码有些是V2的或者自己手写实现的,最好看完示例代码,去这里java类库看看,里边封装了很多方法,能够节省很多工作量。

springboot集成微信APP支付V3最新版相关推荐

  1. php-laravel对接微信app支付V3接口的流程以及坑(应答的微信支付签名验证失败)

    最近在做app当我对接到微信支付的app支付时,居然有那么多文档没说明白的坑,我相信很多人也会遇到所以再次记录一下帮帮有缘人吧. 首先我用的是laravel框架,然后用到了微信官方提供的sdk htt ...

  2. 微信App支付总结(返回-1什么的最e心)

    微信支付总结 简介 微信支付商户平台官网:https://pay.weixin.qq.com 版权声明:本文为原创文章,未经允许不得转载 更新时间:2016/6/27 本文说明 现在很多项目都会集成微 ...

  3. 基于spring-boot+uni-app实现app支付功能(微信/支付宝)服务端

    基于spring-boot+uni-app实现app支付功能(微信/支付宝)服务端 支付宝支付 1 准备工作 申请支付能力 接口加签方式 2代码 依赖 支付宝支付配置类 支付宝控制层 异步通知 微信支 ...

  4. 实现微信app支付的springboot项目

    1.1请先完成微信APP支付接入商户服务中心 1.2详情请参考微信官方文档:https://open.weixin.qq.com/ 2.application.yml文件的配置如下 #微信支付配置 t ...

  5. SpringBoot 集成第三方聚合支付 微信、支付宝

    SpringBoot 集成第三方聚合支付 1. 创建Spring Boot项目 2. 添加依赖 3. 配置支付宝.微信 4. 实现支付接口 5. 实现支付服务 6. 实现支付回调接口 7. 测试支付 ...

  6. Java对接微信支付实现微信APP支付

    Java对接微信实现微信APP支付 之前对接过第三方的支付方式,也有接入微信jsapi的支付方式,这次项目需求要求对接微信APP支付,找了很多,几乎都没有最新版的微信支付v3的对接相关的详细博客,真的 ...

  7. java后端实现集成支付宝APP支付(沙箱环境)

    沙箱环境集成支付宝APP支付后端实现 前言 获取支付宝相关信息 整体开发流程 1.获取核心参数 2.将支付宝SDK集成到项目中 3.后台使用支付宝SDK与支付宝进行交互逻辑 1.将支付宝公共信息参数写 ...

  8. java后台 apiV3 对接微信app支付

    因为项目中需要用到微信支付,这里对自己对接的流程做一个记录 一.接入前准备 1.申请应用appId与商户号,配置apiV3秘钥 2.生成商户证书 首先登录微信商家平台,进入"账户中心–> ...

  9. Android安卓原生接入微信app支付PHP服务端

    Android安卓接入微信app支付PHP服务端 1.进入微信商户平台查看统一下单接口文档. 在查看完统一下单文档后,能够看到需要传递给微信"统一下单接口"地址的参数有哪些 统一下 ...

  10. JAVA微信扫码支付及微信App支付开发(模式二)完整功能实现

    一,准备工作 事前申请一个商家版的微信公众号(目前微信支付只有商家版公众号可开通),然后开通微信支付功能,并做相应的配置. 申请开通微信公众号和开通微信支付需要等待审核,一般都5个工作日左右.开通成功 ...

最新文章

  1. JavaScript异步流程控制的前世今生
  2. 豆瓣评分9.1榜首图书:这本经典编程教材,第2版全面升级!
  3. MySQL索引效率对比_mysql下普通索引和唯一索引的效率对比
  4. LeetCode 1680. 连接连续二进制数字(位运算)
  5. 数据库高级知识——查询截取分析(一)
  6. 规培手册填写模板_9年老资料员经验分享,181套资料员模板+302页工作手册,成为优秀资料员还能提高工作效率,限时分享...
  7. Qt::WindowFlags
  8. 日志收集十大技术细节
  9. K8S架构设计及工作流程分析
  10. 桶排序JAVA软件测试_111-堆排序的速度测试和小结
  11. 【CentOS后遗症】刚毕业的运维小姐姐 Linux用不了!你的也用不了了~
  12. NTP漏洞可致Windows系统触发DoS
  13. 那些相见恨晚的 JavaScript 技巧
  14. (转)注意力机制(Attention Mechanism)在自然语言处理中的应用
  15. eclipse设置代码自动提示
  16. Java自动化测试系列[v1.0.1][ZTestReport测试报告]
  17. word分节符设置与不同页眉页脚页码设置
  18. 矩阵运算-克罗内克积⨂ Hadamard乘积 2022年3月24日
  19. 51单片机项目设计:基于51单片机时钟万年历
  20. 2021年制冷与空调设备运行操作最新解析及制冷与空调设备运行操作模拟考试题库

热门文章

  1. 北大中文核心期刊目录(2004年版)全文
  2. nginx报错502:connect() to unix:/var/run/php5-fpm.sock failed (2: No such file or directory)
  3. web逻辑思维题目_逻辑思维训练500题
  4. 软考计算机评职称,软考通过后如何评职称?
  5. 【ManageEngine】局域网监控软件是什么,有什么作用
  6. 图像处理软件-Adobe Illustrator 2020-位图转化为矢量图
  7. P6800 - 刷入CWM
  8. Windows Server 2012 R2 安装IIS
  9. 信息安全原理与技术第七次实验:木马攻击与防范
  10. 中国卫生健康统计年鉴(2006-2021年)