admin管理员组文章数量:1558098
接着上一篇: SpringBoot对接微信小程序支付功能开发(二,支付回调功能)
1,申请退款接口调用
/**
* 申请退款url
*/
String V3_REFUNDS = "https://api.mch.weixin.qq/v3/refund/domestic/refunds";
/**
* @Description: 申请退款
* @Param: [transactionId] 支付订单号
* @return: java.lang.String
* @Author: XQD
* @Date:2022/8/25 13:25
*/
@Override
public String refundsOrder(String transactionId) throws Exception {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectMapper objectMapper = new ObjectMapper();
// 计算扣除的钱
ObjectNode rootNode = objectMapper.createObjectNode();
rootNode.put("transaction_id", transactionId)
.put("out_refund_no", System.currentTimeMillis() + "")
.put("funds_account", "AVAILABLE")
.put("notify_url", WechatPayConstant.REFUNDS_URL);
rootNode.putObject("amount")
.put("refund", "退款金额")//必须为整数
.put("total", "原订单金额")//必须为整数
.put("currency", "CNY");
objectMapper.writeValue(bos, rootNode);
CloseableHttpClient httpClient = WxPayUtil.getHttpClient();
HttpPost httpPost = new HttpPost(WechatPayConstant.V3_REFUNDS);
httpPost.addHeader("Accept", "application/json");
httpPost.addHeader("Content-type", "application/json; charset=utf-8");
httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
CloseableHttpResponse response = httpClient.execute(httpPost);
String bodyAsString = EntityUtils.toString(response.getEntity());
log.info("申请退款返回报文信息 = {}", bodyAsString);
JSONObject jsonObject = JSON.parseObject(bodyAsString);
//返回成功的信息是不会有code值,如果能取到说明申请失败
String code = jsonObject.getString("code");
if (StringUtils.isNotBlank(code)) {
return "ERROR-" + jsonObject.getString("message");
}
//退款信息存入数据库...
return bodyAsString;
}
2,退款结果回调功能
package com.office.miniapp.controller;
import cn.hutool.core.date.DateTime;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.office.miniapp.constants.ProjectConstant;
import com.office.miniapp.constants.WechatPayConstant;
import com.office.miniapp.utils.HttpClientUtil;
import com.office.miniapp.utils.WxPayUtil;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
/**
* @ClassName: TdRefundsController
* @Description: TODO
* @Authror: XQD
* @Date: 2022/8/25 11:22
*/
@RestController
@RequestMapping("/refunds")
public class TdRefundsController {
@PostMapping("/callback")
public Object callback(HttpServletRequest request) {
log.info("【退款通知回调】");
System.out.println("Wechatpay-Timestamp:" + request.getHeader("Wechatpay-Timestamp"));
System.out.println("Wechatpay-Nonce:" + request.getHeader("Wechatpay-Nonce"));
System.out.println("Wechatpay-Signature:" + request.getHeader("Wechatpay-Signature"));
System.out.println("Wechatpay-Serial:" + request.getHeader("Wechatpay-Serial"));
Map result = new HashMap();
result.put("code", "FAIL");
try {
StringBuilder signStr = new StringBuilder();
// 应答时间戳\n
signStr.append(request.getHeaders("Wechatpay-Timestamp")).append("\n");
// 应答随机串\n
signStr.append(request.getHeaders("Wechatpay-Nonce")).append("\n");
// 应答报文主体\n
BufferedReader br = request.getReader();
String str = null;
StringBuilder builder = new StringBuilder();
while ((str = br.readLine()) != null) {
builder.append(str);
}
log.info("退款应答报文主体:{}", builder.toString());
signStr.append(builder.toString()).append("\n");
// 第一步:验证签名
if (WxPayUtil.signVerify(request.getHeader("Wechatpay-Serial"), signStr.toString(), request.getHeader("Wechatpay-Signature"))) {
result.put("message", "sign error");
return result;
}
// 第二步:解密密文
String decryptOrder = WxPayUtil.decryptOrder(builder.toString());
log.info("解密后退款信息:{}", decryptOrder);
JSONObject jsonObject = JSON.parseObject(decryptOrder);
String mchid = jsonObject.getString("mchid");
if (!mchid.equals(WechatPayConstant.MCH_ID)) {
log.error("mchid对不上:{}", mchid);
result.put("message", "mchid对不上");
return result;
}
//进行业务逻辑处理,修改申请退款时存入数据库的退款状态,检查退款信息是否正确等...
result.put("code", "SUCCESS");
result.put("message", "成功");
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
3,主动查询退款结果
接口地址
/**
* 查询退款订单url
*/
String V3_OUT_REFUND_NO = "https://api.mch.weixin.qq/v3/refund/domestic/refunds/{out_refund_no}";
/**
* @Description: 查询退款订单
* @Param: [outRefundsNo] 商户订单号
* @return: java.lang.Object
* @Author: XQD
* @Date:2022/8/14 21:44
*/
@Override
public Object queryRefundsOrder(String outRefundsNo) throws Exception {
CloseableHttpClient httpClient = WxPayUtil.getHttpClient();
String v3_out_refund_no = WechatPayConstant.V3_OUT_REFUND_NO.replaceFirst("\\{out_refund_no}", outRefundsNo);
HttpGet httpGet = new HttpGet(v3_out_refund_no);
httpGet.addHeader("Accept", "application/json");
CloseableHttpResponse response = httpClient.execute(httpGet);
String bodyAsString = EntityUtils.toString(response.getEntity());
System.out.println(bodyAsString);
return bodyAsString;
}
退款结果有两种获取方式,一种是让微信回调接口通知,还有一种就是我们主动查询退款结果,根据业务自行选择,也可以都是用,更保险。
以上只做功能开发介绍,不参与业务
退款功能完成!!!
补充:WxPayUtil
package com.office.miniapp.utils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.office.miniapp.constants.WechatPayConstant;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import java.security.Signature;
import java.util.Base64;
/**
* @ClassName: WxPayUtil
* @Description: 微信支付工具类
* @Authror: XQD
* @Date: 2022/8/13 23:04
*/
@Component
public class WxPayUtil {
/**
* @Description: 获取httpClient
* @Param: []
* @return: org.apache.http.impl.client.CloseableHttpClient
* @Author: XQD
* @Date:2022/8/13 23:16
*/
public static CloseableHttpClient getHttpClient() {
CloseableHttpClient httpClient = null;
// 加载商户私钥(privateKey:私钥字符串)
try {
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(
new ByteArrayInputStream(WechatPayConstant.PRIVATE_KEY.getBytes("utf-8")));
//使用自动更新的签名验证器,不需要传入证书
AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
new WechatPay2Credentials(WechatPayConstant.MCH_ID, new PrivateKeySigner(WechatPayConstant.MCH_SERIAL_NO, merchantPrivateKey)),
WechatPayConstant.API_V3KEY.getBytes("utf-8"));
// 初始化httpClient
httpClient = WechatPayHttpClientBuilder.create()
.withMerchant(WechatPayConstant.MCH_ID, WechatPayConstant.MCH_SERIAL_NO, merchantPrivateKey)
.withValidator(new WechatPay2Validator(verifier))
.build();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return httpClient;
}
/**
* @Description: 生成签名
* @Param: [message]
* @return: java.lang.String
* @Author: XQD
* @Date:2022/6/7 16:00
*/
public static String sign(byte[] message) throws Exception {
Signature sign = Signature.getInstance("SHA256withRSA");
PrivateKey privateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(WechatPayConstant.PRIVATE_KEY.getBytes("utf-8")));
sign.initSign(privateKey);
sign.update(message);
return Base64.getEncoder().encodeToString(sign.sign());
}
/**
* @Description: 验证签名
* @Param: [serial, message, signature]请求头中带的序列号, 验签名串, 请求头中的应答签名
* @return: boolean
* @Author: XQD
* @Date:2021/9/14 10:36
*/
public static boolean signVerify(String serial, String message, String signature) {
AutoUpdateCertificatesVerifier verifier = null;
try {
// 加载商户私钥(privateKey:私钥字符串)
PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(
new ByteArrayInputStream(WechatPayConstant.PRIVATE_KEY.getBytes("utf-8")));
//使用自动更新的签名验证器,不需要传入证书
verifier = new AutoUpdateCertificatesVerifier(
new WechatPay2Credentials(WechatPayConstant.MCH_ID, new PrivateKeySigner(WechatPayConstant.MCH_SERIAL_NO, merchantPrivateKey)),
WechatPayConstant.API_V3KEY.getBytes("utf-8"));
return verifier.verify(serial, message.getBytes("utf-8"), signature);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return false;
}
/**
* @Description: 解密订单信息
* @Param: [body] 应答报文主体
* @return: java.lang.String
* @Author: XQD
* @Date:2021/9/14 11:48
*/
public static String decryptOrder(String body) {
try {
AesUtil aesUtil = new AesUtil(WechatPayConstant.API_V3KEY.getBytes("utf-8"));
ObjectMapper objectMapper = new ObjectMapper();
JsonNode node = objectMapper.readTree(body);
JsonNode resource = node.get("resource");
String ciphertext = resource.get("ciphertext").textValue();
String associatedData = resource.get("associated_data").textValue();
String nonce = resource.get("nonce").textValue();
return aesUtil.decryptToString(associatedData.getBytes("utf-8"), nonce.getBytes("utf-8"), ciphertext);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
return "";
}
}
本文标签: 功能程序SpringBoot微信小
版权声明:本文标题:SpringBoot对接微信小程序支付功能开发(三,退款功能) 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/dianzi/1727371504a1111226.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论