因项目集成新项目,app嵌套业务板块实现对接后台新项目,新项目对接的是V2版本微信支付APP使用的sdk是V3版本,和后台对接微信V2版本不适配,app调用微信APP支付sdk提示签名错误,升级后台对接微信支付V3版本后解决微信SDK适配问题。
微信支付V3-github:
https://github.com/wechatpay-apiv3/wechatpay-java
微信支付使用示例:
https://github.com/wechatpay-apiv3/wechatpay-java/tree/main/service/src/example/java/com/wechat/pay/java/service
com.github.wxpay wxpay-sdk 0.0.3 com.github.wechatpay-apiv3 wechatpay-java 0.2.17 com.github.binarywang weixin-java-pay ${binarywang.weixin.java.version}
import com.github.binarywang.wxpay.v3.util.PemUtils;
import com.github.binarywang.wxpay.v3.util.SignUtils;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.service.payments.app.AppService;
import com.wechat.pay.java.service.payments.app.model.Amount;
import com.wechat.pay.java.service.payments.app.model.PrepayRequest;
import com.wechat.pay.java.service.payments.app.model.PrepayResponse;
public Map createPay(){
Map returnMap = new HashMap<>();
try {
// 初始化微信支付配置工具类
WXConfigUtil config = new WXConfigUtil();
//更新证书配置,这里用官方sdk,不需要考虑时效性问题
Config wxConfig = new RSAAutoCertificateConfig.Builder()
.merchantId(config.getMchID())
.privateKeyFromPath(config.getPrivateKeyFromPath())//微信v3-私钥路径 例:/app/www/cert/apiclient_key.pem
.merchantSerialNumber(config.getCertSerialNum())//微信v3证书序列号
.apiV3Key(config.getApiV3Key())//微信v3-apiV3Key
.build();
AppService service = new AppService.Builder().config(wxConfig).build();
PrepayRequest wxRequest = new PrepayRequest();
wxRequest.setAppid(config.getAppID());//appId
wxRequest.setMchid(config.getMchID());//商户id
wxRequest.setDescription(goodsName);//备注
wxRequest.setOutTradeNo(outTradeNo);//订单号
wxRequest.setNotifyUrl(config.NOTIFY_URL_APP);//回调地址
Amount amount = new Amount();
amount.setTotal(totalPrice.multiply(BigDecimal.valueOf(100)).intValueExact());//支付金额
wxRequest.setAmount(amount);
//调用预支付接口
PrepayResponse prepay = service.prepay(wxRequest);
log.info("预支付:{}",prepay.toString());
//主要返回以下5个参数(必须按照顺序,否则APP报错:-1)
returnMap.put("appid", config.getAppID());
returnMap.put("noncestr", this.create_nonce_str());
returnMap.put("package","Sign=WXPay");
returnMap.put("partnerid", config.getMchID());
returnMap.put("prepayid", prepay.getPrepayId());
//单位为秒
returnMap.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
//签名
// 此map用于客户端与微信服务器交互
String beforeSign = String.format("%s\n%s\n%s\n%s\n", returnMap.get("appid"), returnMap.get("timestamp"), returnMap.get("noncestr"), returnMap.get("prepayid"));
returnMap.put("sign",SignUtils.sign(beforeSign, PemUtils.loadPrivateKey(new FileInputStream(config.getPrivateKeyFromPath()))));
return returnMap;
} catch (Exception e) {
e.printStackTrace();
log.error("微信app支付v3异常:{}",e.getMessage());
}
return returnMap;
}
// 生成随机数
public String create_nonce_str() {
String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
String res = "";
for (int i = 0; i < 16; i++) {
Random rd = new Random();
res += chars.charAt(rd.nextInt(chars.length() - 1));
}
return res;
}
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.StringReader;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
@Override
@GlobalTransactional(rollbackFor = Exception.class)
public String notifyWeiXinPay(HttpServletRequest request, HttpServletResponse response) {
log.info("------支付成功,进入回调notifyWeiXinPay------");
try {
Map return_data = new HashMap();
WxPayAppNotifyDTO wxPayAppNotifyDTO = new WxPayAppNotifyDTO();
if (request.getHeader("Wechatpay-Signature") != null) {//V3版本
wxPayAppNotifyDTO.setPayVersionType(23);
// 请求头Wechatpay-Signature
String signature = request.getHeader("Wechatpay-Signature");
// 请求头Wechatpay-nonce
String nonce = request.getHeader("Wechatpay-Nonce");
// 请求头Wechatpay-Timestamp
String timestamp = request.getHeader("Wechatpay-Timestamp");
// 微信支付证书序列号
String serial = request.getHeader("Wechatpay-Serial");
// 签名方式
String signType = request.getHeader("Wechatpay-Signature-Type");
//请求body
BufferedReader br = request.getReader();
String str = null;
StringBuilder sb = new StringBuilder();
while ((str = br.readLine()) != null) {
sb.append(str);
}
br.close();
// 初始化微信支付配置工具类
WXConfigUtil config = new WXConfigUtil();
// 构造 RequestParam
RequestParam requestParam = new RequestParam.Builder()
.serialNumber(serial)
.nonce(nonce)
.signature(signature)
.timestamp(timestamp)
.signType(signType)
.body(String.valueOf(sb))
.build();
// 2. 如果你仍在使用微信支付平台证书,则使用 RSAAutoCertificateConfig
NotificationConfig wxConfig = new RSAAutoCertificateConfig.Builder()
.merchantId(config.getMchID())
.privateKeyFromPath(config.getPrivateKeyFromPath())
.merchantSerialNumber(config.getCertSerialNum())
.apiV3Key(config.getApiV3Key())
.build();
// 初始化 NotificationParser
NotificationParser parser = new NotificationParser(wxConfig);
// 以支付通知回调为例,验签、解密并转换成 Transaction
log.info("验签参数:{}", requestParam);
Transaction transaction = parser.parse(requestParam, Transaction.class);
log.info("验签成功!-支付回调结果:{}", transaction.toString());
wxPayAppNotifyDTO.setOutTradeNo(transaction.getOutTradeNo());
wxPayAppNotifyDTO.setMchId(transaction.getMchid());
wxPayAppNotifyDTO.setTotalFee(transaction.getAmount().getTotal().toString());
wxPayAppNotifyDTO.setTransactionId(transaction.getTransactionId());
}
} catch (Exception e) {
e.printStackTrace();
}
return "success";
}
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.http.*;
import com.wechat.pay.java.core.http.HttpClient;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
/**
* 退款申请
*
* @param request 请求参数
* @return Refund
* @throws HttpException 发送HTTP请求失败。例如构建请求参数失败、发送请求失败、I/O错误等。包含请求信息。
* @throws ValidationException 发送HTTP请求成功,验证微信支付返回签名失败。
* @throws ServiceException 发送HTTP请求成功,服务返回异常。例如返回状态码小于200或大于等于300。
* @throws MalformedMessageException 服务返回成功,content-type不为application/json、解析返回体失败。
*/
public Boolean create(CreateRequest request) {
try{
String requestPath = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";
// 初始化微信支付配置工具类
WXConfigUtil config = new WXConfigUtil();
//更新证书配置,这里用官方sdk,不需要考虑时效性问题
Config wxConfig = new RSAAutoCertificateConfig.Builder()
.merchantId(config.getMchID())
.privateKeyFromPath(config.getPrivateKeyFromPath())
.merchantSerialNumber(config.getCertSerialNum())
.apiV3Key(config.getApiV3Key())
.build();
HttpHeaders headers = new HttpHeaders();
headers.addHeader(com.wechat.pay.java.core.http.Constant.ACCEPT, MediaType.APPLICATION_JSON.getValue());
headers.addHeader(com.wechat.pay.java.core.http.Constant.CONTENT_TYPE, MediaType.APPLICATION_JSON.getValue());
HttpRequest httpRequest =
new HttpRequest.Builder()
.httpMethod(HttpMethod.POST)
.url(requestPath)
.headers(headers)
.body(new JsonRequestBody.Builder().body(com.wechat.pay.java.core.util.GsonUtil.toJson(request)).build())
.build();
HttpClient httpClient = new DefaultHttpClientBuilder().config(wxConfig).build();
HttpResponse httpResponse = httpClient.execute(httpRequest, Refund.class);
httpResponse.getServiceResponse();
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
//填写参数调用退款
public Boolean weChatRefund(){
CreateRequest request = new CreateRequest();
AmountReq amountReq = new AmountReq();
amountReq.setTotal(Long.parseLong(PayToolUtil.getMoney(allMoney.toString())));
amountReq.setRefund(Long.parseLong(PayToolUtil.getMoney(money.toString())));
amountReq.setCurrency("CNY");
request.setAmount(amountReq);
request.setOutRefundNo(refundOrderId);
request.setTransactionId(paymentOtherNumber);
return create(request);
}