河南循中网络科技有限公司 - 精心创作,详细分解,按照步骤,均可成功!


文章目录

  • 吐槽!
  • 此文章包含实现了哪些接口?
  • 学习资料
  • 集成微信支付V3
    • 什么是“商户证书”?什么是“平台证书”?
    • 获取商户证书
    • 获取平台证书
    • 添加pom依赖
    • common的pom文件
    • yaml配置
    • 创建WeChatPayUtil工具类
    • 创建WeChatPayController微信回调类
  • 河南循中网络科技有限公司精心创作,若解决了您的问题,欢迎点赞+评论

吐槽!

科技应该以人为本,为人服务为宗旨,API的对接应该是很轻松的,就像支付宝一样,傻瓜式对接,哪怕是腾讯系的腾讯云相关的API接口服务,都非常容易对接,无论是文档还是Demo都非常舒服,哪怕小白也可以对接成功,但微信支付就很奇葩…之前对接v2版本支付系列接口几乎没有一次轻松的,现在的V3接口虽然好很多,但官方Demo写的…啥也不是。

不适合小白入门,网上关于微信支付V3的文章又少之又少,而且坑巨多…尤其是使用了某些工具类,然后少放一些,是让人呕血?搞不懂!!!,在此我推出如下傻瓜式对接,小白也可完成微信支付V3相关API的对接!!!

此文章包含实现了哪些接口?

实现的接口:JSAPI下单、小程序支付、申请退款

其余接口,可通过对应的微信支付API文档,根据不同的请求方式,调用对应的POST或GET请求工具方法,传入JSON对象即可完成,无需担心证书相关问题,证书封装在请求体内,直接调用封装好的POST或GET请求工具方法即可。

学习资料

接入前准备
微信支付API文档

集成微信支付V3

什么是“商户证书”?什么是“平台证书”?

“商户证书”是指由商户申请的,包含商户的商户号、公司名称、公钥信息的证书。
”平台证书”是指由微信支付负责申请的,包含微信支付平台标识、公钥信息的证书。

获取商户证书

通过完成接入前准备,可获得3个API证书:apiclient_cert.p12、apiclient_cert.pem、apiclient_key.pem,但此证书为商户证书,跟平台证书是不一样的。

获取平台证书

大多数人在接入时,由于官方文档写的很…令人无语会忽略此步,博主就是忽略了此步骤,从而在调用API的时候,错误的使用了商户证书,导致报错:“应答的微信支付签名验证失败”。

  1. GitHub下载微信支付平台证书生成工具
  2. CSDN下载微信支付平台证书生成工具
  3. 执行命令生成微信支付平台证书
java -jar CertificateDownloader-1.2.0-jar-with-dependencies.jar -f 商户私钥文件路径 -k 证书解密的密钥 -m 商户号 -o 证书保存路径  -s 商户证书序列号

商户私钥文件:apiclient_key.pem
证书解密的密钥:登陆商户平台【API安全】->【APIv3密钥】
商户证书序列号:登陆商户平台【API安全】->【API证书】->【查看证书】,可查看商户API证书序列号。

实践:

  1. 在D盘中创建D:\wechatPay文件。
  2. 将apiclient_cert.p12、apiclient_cert.pem、apiclient_key.pem放在文件目录下。
  3. CMD命令进入D:\wechatPay,输入java -jar CertificateDownloader-1.2.0-jar-with-dependencies.jar -f 商户私钥文件路径 -k 证书解密的密钥 -m 商户号 -o 证书保存路径 -s 商户证书序列号,则可得到微信支付平台证书。

添加pom依赖

     <!-- 微信支付 --><wechatpay-apache-httpclient.version>0.4.8</wechatpay-apache-httpclient.version><!-- Hutool小而全的Java工具类库 --><hutool-all.version>5.8.5</hutool-all.version><!-- alibaba JSON --><fastjson.version>2.0.11</fastjson.version><!-- apache公共基础类 --><commons-lang3.version>3.12.0</commons-lang3.version>
     <!-- 微信支付 --><dependency><groupId>com.github.wechatpay-apiv3</groupId><artifactId>wechatpay-apache-httpclient</artifactId><version>${wechatpay-apache-httpclient.version}</version></dependency><!-- Hutool小而全的Java工具类库 --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>${hutool-all.version}</version></dependency><!-- alibaba JSON --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>${fastjson.version}</version></dependency><!-- apache公共基础类 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>${commons-lang3.version}</version></dependency>

common的pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.xz</groupId><artifactId>common</artifactId><version>0.0.1-SNAPSHOT</version><name>common</name><description>河南循中网络科技有限公司 - 通用工具</description><!-- 子模块打包类型必须为jar --><packaging>jar</packaging><!-- parent指明继承关系,给出被继承的父项目的具体信息 --><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.1</version><relativePath/> <!-- lookup parent from repository --></parent><!-- 版本控制 --><properties><java.version>1.8</java.version><!-- 实体类注解 --><lombok.version>1.18.24</lombok.version><!-- swagger --><springfox-boot-starter.version>3.0.0</springfox-boot-starter.version><!-- 腾讯云cos存储 --><cos_api.version>5.6.89</cos_api.version><!-- alibaba JSON --><fastjson.version>2.0.11</fastjson.version><!-- apache公共基础类 --><commons-lang3.version>3.12.0</commons-lang3.version><!-- 微信支付 --><wechatpay-apache-httpclient.version>0.4.8</wechatpay-apache-httpclient.version><!-- Hutool小而全的Java工具类库 --><hutool-all.version>5.8.5</hutool-all.version></properties><!-- 引入的jar包 --><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- 实体类注解 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version></dependency><!-- swagger --><dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>${springfox-boot-starter.version}</version></dependency><!-- spring boot内置redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- 腾讯云cos存储 --><dependency><groupId>com.qcloud</groupId><artifactId>cos_api</artifactId><version>${cos_api.version}</version></dependency><!-- alibaba JSON --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>${fastjson.version}</version></dependency><!-- apache公共基础类 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>${commons-lang3.version}</version></dependency><!-- 微信支付 --><dependency><groupId>com.github.wechatpay-apiv3</groupId><artifactId>wechatpay-apache-httpclient</artifactId><version>${wechatpay-apache-httpclient.version}</version></dependency><!-- Hutool小而全的Java工具类库 --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>${hutool-all.version}</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

yaml配置

weChatPay:# 支付回调地址notifyUrl: 支付回调地址# 退款回调地址refundNotifyUrl: 退款回调地址# 商户号mchId: 商户号# 公众号appIdappid: 公众号appId# 公众号secretsecret: 公众号secret# APIv3密钥apiV3Key: API v3密钥# 小程序appIdminiProgramAppid: 小程序appId# 小程序secretminiProgramSecret: 小程序secret# 商户证书-apiclient_cert.p12路径apiclientCertp12: 商户证书-apiclient_cert.p12路径# 商户证书公钥-apiclient_cert.pem路径apiclientCert: 商户证书公钥-apiclient_cert.pem路径# 商户证书私钥-apiclient_key.pem路径apiclientKey: 商户证书私钥-apiclient_key.pem路径# 微信支付平台证书,有效期五年,xxxx年xx月份之前进行替换wechatPayCert: 微信支付平台证书,有效期五年,xxxx年xx月份之前进行替换# 商户证书序列号wechatPaySerial: 商户证书序列号

创建WeChatPayUtil工具类

package com.xz.weChat;import cn.hutool.core.io.resource.ClassPathResource;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
import com.wechat.pay.contrib.apache.httpclient.notification.Notification;
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationHandler;
import com.wechat.pay.contrib.apache.httpclient.notification.NotificationRequest;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import com.xz.redis.RedisUtil;
import com.xz.util.NumberUtil;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;import static org.apache.http.HttpHeaders.ACCEPT;
import static org.apache.http.HttpHeaders.CONTENT_TYPE;
import static org.apache.http.entity.ContentType.APPLICATION_JSON;/*** 微信V3工具类*/
@Component
public class WeChatPayUtil {private Logger logger = LoggerFactory.getLogger(this.getClass());@Value("${weChatPay.notifyUrl}")private String notifyUrl;@Value("${weChatPay.refundNotifyUrl}")private String refundNotifyUrl;@Value("${weChatPay.mchId}")private String mchId;@Value("${weChatPay.apiV3Key}")private String apiV3Key;@Value("${weChatPay.miniProgramAppid}")private String miniProgramAppid;@Value("${weChatPay.miniProgramSecret}")private String miniProgramSecret;@Value("${weChatPay.apiclientKey}")private String apiclientKey;@Value("${weChatPay.wechatPayCert}")private String wechatPayCert;@Value("${weChatPay.wechatPaySerial}")private String wechatPaySerial;@Resourceprivate RedisUtil redisUtil;/*** 普通get请求* @param url* @return*/public String doGet(String url){BufferedReader read = null;try {URL URL = new URL(url);read = new BufferedReader(new InputStreamReader(URL.openStream(),"utf-8"));StringBuffer str = new StringBuffer();String buf = "";buf = read.readLine();while (buf != null && !buf.equals("")) {str.append(buf);buf = read.readLine();}return str.toString();} catch (Exception e) {e.printStackTrace();} finally{try{if(read!=null) read.close();} catch(IOException ex){ex.printStackTrace();}}return null;}/*** 普通post请求* @param url* @param param* @return* @throws Exception*/public String doPost(String url, String param)throws Exception {PrintWriter out = null;BufferedReader read = null;String result = "";try {URL URL = new URL(url);HttpURLConnection conn = (HttpURLConnection)URL.openConnection();conn.setRequestProperty("Accept","application/json");conn.setRequestProperty("Content-type","application/json");conn.setDoOutput(true);conn.setDoInput(true);conn.setUseCaches(false);// 忽略缓存conn.setRequestMethod("POST");conn.setConnectTimeout(20000);conn.setReadTimeout(300000);out = new PrintWriter(conn.getOutputStream());out.print(param);out.flush();// 获得响应状态int responseCode = conn.getResponseCode();if (HttpURLConnection.HTTP_OK == responseCode) {// 连接成功read = new BufferedReader(new InputStreamReader(conn.getInputStream()));String line;while ((line = read.readLine()) != null) {result += line;}}else{throw new Exception("请求链接失败");}} catch (IOException e) {throw e;} finally{try{if(out!=null) out.close();if(read!=null) read.close();} catch(IOException ex){ex.printStackTrace();}}return result;}/*** 微信v3 post请求* @param url* @param body* @return* @throws Exception*/public String v3Post(String url,String body) throws Exception {logger.info("微信v3 post请求参数:" + body);CloseableHttpClient httpClient = getClient();HttpPost httpPost = new HttpPost(url);httpPost.addHeader(ACCEPT, APPLICATION_JSON.toString());httpPost.addHeader(CONTENT_TYPE, APPLICATION_JSON.toString());httpPost.addHeader("Wechatpay-Serial", wechatPaySerial);httpPost.setEntity(new StringEntity(body, "UTF-8"));CloseableHttpResponse response = httpClient.execute(httpPost);try {String bodyAsString = EntityUtils.toString(response.getEntity());logger.info("微信v3 post请求返回信息:"+bodyAsString);return bodyAsString;} finally {httpClient.close();response.close();}}/*** 微信v3 get请求* @param url* @return* @throws Exception*/public String v3Get(String url) throws Exception {logger.info("微信v3 get请求URL:" + url);CloseableHttpClient httpClient = getClient();HttpGet httpGet = new HttpGet(url);httpGet.addHeader(ACCEPT, APPLICATION_JSON.toString());httpGet.addHeader(CONTENT_TYPE, APPLICATION_JSON.toString());httpGet.addHeader("Wechatpay-Serial", wechatPaySerial);CloseableHttpResponse response = httpClient.execute(httpGet);try {String bodyAsString = EntityUtils.toString(response.getEntity());logger.info("微信v3 get请求返回信息:"+bodyAsString);return bodyAsString;} finally {httpClient.close();response.close();}}/*** 小程序快捷登录* @param jsCode* @return* @throws Exception*/public String miniJscode2session(String jsCode) throws Exception {String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + miniProgramAppid + "&secret=" + miniProgramSecret + "&js_code=" + jsCode + "&grant_type=authorization_code";return doGet(url);}/*** 小程序获取手机号* @param code* @return* @throws Exception*/public JSONObject miniGetuserphonenumber(String code) throws Exception {String accessToken = getAccessTokenMini();String Url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token="+accessToken;String getPhoneNumber = doPost(Url,"{\"code\": \""+code+"\"}");JSONObject getPhoneNumberJSON = JSON.parseObject(getPhoneNumber);return getPhoneNumberJSON;}/*** 微信通讯client* @return CloseableHttpClient*/public CloseableHttpClient getClient() {/**商户证书私钥文件*/ClassPathResource apiclientKeyFile = new ClassPathResource(apiclientKey);InputStream apiclientKeyInputStream = apiclientKeyFile.getStream();/**微信支付平台证书文件*/ClassPathResource wechatPayCertFile = new ClassPathResource(wechatPayCert);InputStream wechatPayCertInputStream = wechatPayCertFile.getStream();PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(apiclientKeyInputStream);WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create().withMerchant(mchId, wechatPaySerial, merchantPrivateKey).withWechatPay(Arrays.asList(PemUtil.loadCertificate(wechatPayCertInputStream)));CloseableHttpClient httpClient = builder.build();return httpClient;}/*** 微信敏感数据加密公钥* 使用方法:* X509Certificate x509Certificate = getSaveCertificates();* RsaCryptoUtil.encryptOAEP(要加密的数据, x509Certificate)* @return*/public X509Certificate getSaveCertificates() {ClassPathResource wechatPayCertFile = new ClassPathResource(wechatPayCert);InputStream platformCertInputStream = wechatPayCertFile.getStream();return PemUtil.loadCertificate(platformCertInputStream);}/*** 转换为分数,money小数长度不允许超过2位,如果超过2位小数,自动直接舍弃* @param money* @return*/public int conversionFraction(BigDecimal money){int fractionMonery = 0;if(money!=null){fractionMonery = money.multiply(new BigDecimal(100)).intValue();}return fractionMonery;}/*** 获取时间戳* @return*/private String getTimeStamp() {return String.valueOf(System.currentTimeMillis() / 1000);}/*** 生成签名* @param message* @return* @throws Exception*/public String sign(byte[] message) throws Exception {Signature sign = Signature.getInstance("SHA256withRSA");// 商户证书私钥sign.initSign(getPrivateKey());sign.update(message);return Base64.getEncoder().encodeToString(sign.sign());}/*** 获取商户证书私钥* @return 私钥对象*/public PrivateKey getPrivateKey() throws IOException {ClassPathResource apiclientKeyFile = new ClassPathResource(apiclientKey);PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(apiclientKeyFile.getStream());return merchantPrivateKey;}/*** 构造签名串* @param signMessage 待签名的参数* @return 构造后带待签名串*/public String buildSignMessage(ArrayList<String> signMessage) {if (signMessage == null || signMessage.size() <= 0) {return null;}StringBuilder sbf = new StringBuilder();for (String str : signMessage) {sbf.append(str).append("\n");}return sbf.toString();}/*** 获取微信回调结果* @param request* @return* @throws Exception*/public JSONObject getCallback(HttpServletRequest request) throws Exception {//获取报文String body = getRequestBody(request);//随机串String nonce = request.getHeader("Wechatpay-Nonce");//微信传递过来的签名String signature = request.getHeader("Wechatpay-Signature");//证书序列号(微信平台)String wechatPaySerial = request.getHeader("Wechatpay-Serial");//时间戳String timestamp = request.getHeader("Wechatpay-Timestamp");// 验签NotificationRequest notificationRequest = new NotificationRequest.Builder().withSerialNumber(wechatPaySerial).withNonce(nonce).withTimestamp(timestamp).withSignature(signature).withBody(body).build();NotificationHandler handler = new NotificationHandler(verifier(), apiV3Key.getBytes(StandardCharsets.UTF_8));// 验签和解析请求体Notification notification = handler.parse(notificationRequest);return JSON.parseObject(notification.getDecryptData());}/*** 获取报文* @param request* @return* @throws Exception*/private String getRequestBody(HttpServletRequest request) throws Exception {StringBuffer stringBuffer = new StringBuffer();ServletInputStream inputStream = request.getInputStream();BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));String line;while ((line = reader.readLine()) != null) {stringBuffer.append(line);}return stringBuffer.toString();}/*** 获得验签器* @return* @throws Exception*/public Verifier verifier() throws Exception {//获取证书管理器实例CertificatesManager certificatesManager = CertificatesManager.getInstance();certificatesManager.putMerchant(mchId, new WechatPay2Credentials(mchId,new PrivateKeySigner(wechatPaySerial, getPrivateKey())), apiV3Key.getBytes(StandardCharsets.UTF_8));// 从证书管理器中获取verifierVerifier verifier = certificatesManager.getVerifier(mchId);return verifier;}/*** JSAPI下单* @param appid 对应openid的应用ID* @param description 商品描述* @param orderNum 商户订单号* @param total 总金额* @param openid 个人用户openId* @throws Exception*/public String transactionsJsapi(String appid, String description, String orderNum, BigDecimal total, String openid) throws Exception {JSONObject transactionsJsapiJSON = new JSONObject();transactionsJsapiJSON.put("appid", appid);transactionsJsapiJSON.put("mchid", mchId);transactionsJsapiJSON.put("description", description);transactionsJsapiJSON.put("out_trade_no", orderNum);transactionsJsapiJSON.put("notify_url",notifyUrl);JSONObject amount = new JSONObject();amount.put("total",conversionFraction(total));amount.put("currency","CNY");transactionsJsapiJSON.put("amount",amount);JSONObject payer = new JSONObject();payer.put("openid",openid);transactionsJsapiJSON.put("payer",payer);String body = transactionsJsapiJSON.toJSONString();return v3Post("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi",body);}/*** 小程序支付* @param orderNum 商户订单号* @param total 总金额* @param openid 个人用户openId* @throws Exception*/public JSONObject payMini(String orderNum,BigDecimal total,String openid) throws Exception {String transactionsJsapiBody = transactionsJsapi(miniProgramAppid,"么丢",orderNum,total,openid);JSONObject transactionsJsapiBodyJSON = JSON.parseObject(transactionsJsapiBody);String prepayId = transactionsJsapiBodyJSON.getString("prepay_id");if(StringUtils.isNotBlank(prepayId)){String timeStamp = getTimeStamp();String nonceStr = RandomStringUtils.randomNumeric(32);ArrayList<String> list = new ArrayList<>();list.add(miniProgramAppid);list.add(timeStamp);list.add(nonceStr);list.add("prepay_id=" + prepayId);//二次签名,调起支付需要重新签名,注意这个是buildSignMessage()String packageSign = sign(buildSignMessage(list).getBytes());JSONObject jsonObject = new JSONObject();jsonObject.put("timeStamp", timeStamp);jsonObject.put("nonceStr", nonceStr);jsonObject.put("package", "prepay_id=" + prepayId);jsonObject.put("signType", "RSA");jsonObject.put("paySign", packageSign);return jsonObject;}else{return transactionsJsapiBodyJSON;}}/*** 申请退款* @param transactionId 微信支付订单号* @param outRefundNo 商户退款单号* @param refund 退款金额* @param total 原订单金额* @return* @throws Exception*/public String domesticRefunds(String transactionId,String outRefundNo,BigDecimal refund,BigDecimal total) throws Exception {JSONObject domesticRefundsJSON = new JSONObject();domesticRefundsJSON.put("transaction_id", transactionId);domesticRefundsJSON.put("out_refund_no", outRefundNo);JSONObject amount = new JSONObject();amount.put("refund",conversionFraction(refund));amount.put("total",conversionFraction(total));amount.put("currency","CNY");domesticRefundsJSON.put("amount",amount);domesticRefundsJSON.put("notify_url", refundNotifyUrl);String body = domesticRefundsJSON.toJSONString();String domesticRefundsBody = v3Post("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds",body);JSONObject domesticRefundsBodyJSON = JSON.parseObject(domesticRefundsBody);if(StringUtils.isNotBlank(domesticRefundsBodyJSON.getString("status")) && (domesticRefundsBodyJSON.getString("status").equals("SUCCESS") || domesticRefundsBodyJSON.getString("status").equals("PROCESSING"))){return "200";}else{return "code="+domesticRefundsBodyJSON.getString("code")+",message="+domesticRefundsBodyJSON.getString("message");}}/*** 发起商家转账* @param appid 对应openid的应用ID* @param outBatchNo 转账单号* @param batchName 转账的名称* @param batchRemark 转账说明* @param totalAmount 转账金额* @param openid 个人用户openId* @return* @throws Exception*/public String transferBatches(String appid,String outBatchNo,String batchName,String batchRemark,BigDecimal totalAmount,String openid) throws Exception {JSONObject transactionsJsapiJSON = new JSONObject();transactionsJsapiJSON.put("appid", appid);transactionsJsapiJSON.put("out_batch_no", outBatchNo);transactionsJsapiJSON.put("batch_name", batchName);transactionsJsapiJSON.put("batch_remark", batchRemark);transactionsJsapiJSON.put("total_amount", NumberUtil.conversionFraction(totalAmount));transactionsJsapiJSON.put("total_num", 1);JSONArray transferDetailList = new JSONArray();JSONObject transferDetail = new JSONObject();transferDetail.put("out_detail_no", outBatchNo);transferDetail.put("transfer_amount", NumberUtil.conversionFraction(totalAmount));transferDetail.put("transfer_remark", batchRemark);transferDetail.put("openid", openid);transferDetailList.add(transferDetail);transactionsJsapiJSON.put("transfer_detail_list", transferDetailList);String body = transactionsJsapiJSON.toJSONString();return v3Post("https://api.mch.weixin.qq.com/v3/transfer/batches",body);}/*** 小程序发起商家转账* @param outBatchNo 转账单号* @param batchName 转账的名称* @param batchRemark 转账说明* @param totalAmount 转账金额* @param openid 个人用户openId* @return* @throws Exception*/public String miniTransferBatches(String outBatchNo,String batchName,String batchRemark,BigDecimal totalAmount,String openid) throws Exception {String transferBatchesStr = transferBatches(miniProgramAppid,outBatchNo,batchName,batchRemark,totalAmount,openid);JSONObject transferBatchesJSON = JSON.parseObject(transferBatchesStr);if(StringUtils.isNotBlank(transferBatchesJSON.getString("out_batch_no")) && StringUtils.isNotBlank(transferBatchesJSON.getString("batch_id")) && StringUtils.isNotBlank(transferBatchesJSON.getString("create_time"))){return "200";}else{return transferBatchesStr;}}/*** 获取基础access_token* @param appid 对应openid的应用ID* @param secret 对应openid的secret* @return* @throws Exception*/public JSONObject getAccessToken(String appid,String secret) throws Exception {// 获取accres_tokenString Url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret;String doGet = doGet(Url);// 结果转为json对象if(StringUtils.isNotBlank(doGet)){JSONObject json = JSONObject.parseObject(doGet);if(json!=null){return json;}else{return null;}}else{return null;}}/*** 获取小程序基础access_token* @return* @throws Exception*/public String getAccessTokenMini() throws Exception {String accessToken = null;if(redisUtil.get("accessToken")!=null){accessToken = redisUtil.get("accessToken").toString();}if(StringUtils.isBlank(accessToken)){JSONObject accessTokenJSON = getAccessToken(miniProgramAppid,miniProgramSecret);if(StringUtils.isBlank(accessTokenJSON.getString("errcode"))){accessToken = accessTokenJSON.getString("access_token");redisUtil.set("accessToken",accessToken);int expires_in = accessTokenJSON.getInteger("expires_in")-120;//基础token的时间减去2分钟redisUtil.expire("accessToken",expires_in);//将基础token存入redisreturn accessToken;}else{logger.info(accessTokenJSON.getString("errmsg"));return null;}}else{return accessToken;}}/*** 检测内容安全方法* 文档:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/sec-check/security.msgSecCheck.html* @param openid 用户的openid(用户需在近两小时访问过小程序)* @param scene 场景枚举值(1 资料;2 评论;3 论坛;4 社交日志)* @param content 需检测的文本内容,文本字数的上限为2500字,需使用UTF-8编码* @param accessToken 接口调用凭证* @return*/public String msgSecCheck(String openid,Integer scene,String content, String accessToken) throws Exception {JSONObject msgSecCheckJSON = new JSONObject();msgSecCheckJSON.put("version", "2");msgSecCheckJSON.put("openid", openid);msgSecCheckJSON.put("scene", scene);msgSecCheckJSON.put("content", content);return v3Post("https://api.weixin.qq.com/wxa/msg_sec_check?access_token="+accessToken, msgSecCheckJSON.toJSONString());}/*** 小程序检测内容安全方法* 文档:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/sec-check/security.msgSecCheck.html* @param openid 用户的openid(用户需在近两小时访问过小程序)* @param scene 场景枚举值(1 资料;2 评论;3 论坛;4 社交日志)* @param content 需检测的文本内容,文本字数的上限为2500字,需使用UTF-8编码* @return*/public JSONObject msgSecCheckMini(String openid,Integer scene,String content) throws Exception {JSONObject data = new JSONObject();String returnData = msgSecCheck(openid, scene, content, getAccessTokenMini());JSONObject returnDataJSON = JSON.parseObject(returnData);if(returnDataJSON!=null && returnDataJSON.getString("errcode").equals("0")){JSONObject resultJSON = returnDataJSON.getJSONObject("result");if(resultJSON!=null && resultJSON.getString("suggest").equals("pass")){data.put("code", 200);data.put("msg", "正常");return data;}else{data.put("code", 400);switch (resultJSON.getString("label")){case "100":data.put("msg", "正常");break;case "10001":data.put("msg", "广告");break;case "20001":data.put("msg", "时政");break;case "20002":data.put("msg", "色情");break;case "20003":data.put("msg", "辱骂");break;case "20006":data.put("msg", "违法犯罪");break;case "20008":data.put("msg", "欺诈");break;case "20012":data.put("msg", "低俗");break;case "20013":data.put("msg", "版权");break;case "21000":data.put("msg", "其他");break;default:data.put("msg", "其他");break;}return data;}}else{data.put("code", 400);data.put("msg", "接口请求异常"+returnDataJSON.toJSONString());return data;}}
}

创建WeChatPayController微信回调类

package com.xz.controller.pay;import com.alibaba.fastjson.JSONObject;
import com.xz.weChat.WeChatPayUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** 微信支付回调*/
@RestController
public class WeChatPayController {private Logger logger = LoggerFactory.getLogger(this.getClass());@Resourceprivate WeChatPayUtil weChatPayUtil;/*** v3处理微信支付异步回调* @param request* @param response*/@RequestMapping("/clientWeChatNotify")public void clientWeChatNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {try{//获取微信回调结果JSONObject dataJSON = weChatPayUtil.getCallback(request);logger.info("v3处理微信支付异步回调=============================================================="+dataJSON);String out_trade_no = dataJSON.getString("out_trade_no");//商户平台订单号String transaction_id = dataJSON.getString("transaction_id");//微信支付交易号//处理业务逻辑//返回给微信response.setStatus(200);}catch (Exception e){e.printStackTrace();logger.error("v3处理微信支付异步回调:错误-"+e.getMessage());}}/*** v3处理微信退款异步回调* @param request* @param response*/@RequestMapping("/refundWeChatNotify")public void refundWeChatNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {try{//获取微信回调结果JSONObject dataJSON = weChatPayUtil.getCallback(request);logger.info("v3处理微信退款异步回调=============================================================="+dataJSON);String outRefundNo = dataJSON.getString("out_refund_no");//商户退款单号String refundStatus = dataJSON.getString("refund_status");//退款状态,枚举值:SUCCESS:退款成功、CLOSED:退款关闭、ABNORMAL:退款异常,退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往【商户平台—>交易中心】,手动处理此笔退款//处理业务逻辑//返回给微信response.setStatus(200);}catch (Exception e){e.printStackTrace();logger.error("v3处理微信退款异步回调:错误-"+e.getMessage());}}
}

河南循中网络科技有限公司精心创作,若解决了您的问题,欢迎点赞+评论

SpringBoot集成微信支付V3相关推荐

  1. springboot集成微信支付V3 SDK

    微信支付开通支付方法在这里可以参考一下:申请开通微信支付教程_个人怎么申请微信支付_郑鹏川的博客-CSDN博客 因为微信支付回调需要一个外网可访问的地址,我本地调试是采用的内网穿透的方式进行调试的. ...

  2. SpringBoot集成微信支付微信退款

    微信支付 备注:本次支付接入的是微信支付v2.0版本,其中所有的请求格式均为XML. 如有需求可直接参阅官方文档 https://pay.weixin.qq.com/wiki/doc/api/inde ...

  3. springboot集成微信支付

    一.先去微信申请相应的appid等,然后在yml文件增加相应配置 pay:   wxpay:     appID: ******     mchID: *****     key: *****     ...

  4. springboot利用官方SDK(wechatpay-apache-httpclient)接入微信支付V3

    利用微信官方提供的SDK wechatpay-apache-httpclient 实现.以微信小程序支付为例,其他支付也是一样的,就是参数和接口地址不同. 微信支付V3文档 首先要在微信商户平台设置好 ...

  5. 小程序微信支付V3版本Java集成

    一.简介 1.关于API v3 相较于之前的微信支付API,主要区别是: 遵循统一的REST的设计风格 使用JSON作为数据交互的格式,不再使用XML 使用基于非对称密钥的SHA256-RSA的数字签 ...

  6. SpringBoot整合微信支付(Native最详细)

    一.微信支付产品介绍 1.付款码支付 用户展示微信钱包内的 " 付款码 " 给商家,商家扫描后直接完成支付,适用于线下面对面收银的场景. 2.JSAPI支付 线下场所:商户展示一个 ...

  7. springboot集成支付宝支付2.0

    springboot集成微信APP支付V3最新版 流程详解 创建应用 添加支付能力 接口加签 获取证书 集成支付到springboot项目 流程详解 相对于集成微信支付来说,支付宝相对简单些,支付宝对 ...

  8. springboot整合微信支付

    讲解微信支付V3接口真实开发代码,非demo 使用微信支付需要开通微信支付商户号:微信支付 - 中国领先的第三方支付平台 | 微信支付提供安全快捷的支付方式 微信支付提供多种支付功能,包括[JSAPI ...

  9. java微信支付v3系列——1.微信支付准备工作

    目录 java微信支付v3系列--1.微信支付准备工作 java微信支付v3系列--2.微信支付基本配置 java微信支付v3系列--3.订单创建准备操作 java微信支付v3系列--4.创建订单的封 ...

最新文章

  1. 华为今年不会发布鸿蒙系统的手机,华为:今年不会推出鸿蒙系统手机 将坚守安卓生态...
  2. 「NLP-语义匹配」详解深度语义匹配模型DSSM
  3. tts代表_Text-to-Speech (TTS) Synthesis语音合成----控制语言合成
  4. sql 分组求和_从零学会SQL:汇总分析 D3
  5. 应届生求职产品经理系列【三】:0岁产品经理的八大困惑(上)
  6. 《计算机科学概论》—第3章3.3节文本表示法
  7. 产业数字化升级进入深化期,腾讯智慧出行释放“数字底座”核心能力
  8. mybatis xml 参数 使用
  9. 旅游景点人流量代码php,用 PHP 爬虫做旅游数据分析
  10. 银行工作中有哪些需要注意的事?
  11. 十五、K8s helm包管理与应用
  12. Windows下安装和配置Java JDK
  13. 浅谈系统如何对接社交登录之微博登录功能
  14. java反编译jar包
  15. Eclipse安装WindowsBuilder失败解决方法
  16. 各厂商服务器存储默认管理口登录信息(默认IP、用户名、密码)
  17. 唐宇迪学习笔记9:逻辑回归与梯度下降策略
  18. php制作单位换算,在线单位换算器
  19. ietest 如何在多种浏览器上面测试JS页面效果
  20. 笃行杂记之Zookeeper SessionTimeOut分析

热门文章

  1. 番茄时间管理——规则
  2. 永磁同步电机的标么值系统
  3. 自定义ImageView实现播放帧动画
  4. 基于HDP使用Flume实时采集MySQL中数据传到Kafka+HDFS或Hive
  5. MD 风格的 Dialog ---- MaterialDialog
  6. Win10中安装Oracle11g
  7. 邮箱自动化(smtplib模块)--以邮件正文HTML表格形式
  8. 转载的一篇嵌入式大佬经验博文
  9. 计算机二级C语言学习笔记(十八)
  10. 2款免费的安卓后台游戏