JAVA实现微信小程序支付退款功能
BigDecimal payMoney = new BigDecimal(BigDecimal.valueOf(Double.parseDouble(BigDecimalUtil.mulBig(money, new BigDecimal(100)).toString())).stripTrailingZeros().toPlainString());
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import javax.net.ssl.SSLContext;
import java.io.*;
import java.security.KeyStore;
import java.util.*;
public class PayUtil {
private static String APPID = "";
private static String MCH_ID = "";
private static String KEY = "";
private byte [] certData;
private String getRandomStringByLength(int length) {
String base = "abcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
private static String mapToXml(Map<String, String> param) {
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
for (Map.Entry<String, String> entry : param.entrySet()) {
sb.append("<" + entry.getKey() + ">");
sb.append(entry.getValue());
sb.append("</" + entry.getKey() + ">");
}
sb.append("</xml>");
return sb.toString();
}
private static Map xmlToMap(String strxml) throws Exception {
Map<String, String> map = new HashMap<>();
if (null == strxml || "".equals(strxml)) {
return null;
}
InputStream in = String2Inputstream(strxml);
SAXReader read = new SAXReader();
Document doc = read.read(in);
Element root = doc.getRootElement();
@SuppressWarnings("unchecked")
List<Element> list = root.elements();
for (Element element : list) {
map.put(element.getName(), element.getText());
}
in.close();
return map;
}
private static InputStream String2Inputstream(String strxml) throws IOException {
return new ByteArrayInputStream(strxml.getBytes("UTF-8"));
}
private static String createLinkString(Map<String, String> params) {
List<String> keys = new ArrayList<>(params.keySet());
Collections.sort(keys);
String preStr = "";
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
if (i == keys.size() - 1) {
preStr = preStr + key + "=" + value;
} else {
preStr = preStr + key + "=" + value + "&";
}
}
return preStr;
}
public static String sign(String text, String key, String input_charset) {
text = text + "&key=" + key;
return DigestUtils.md5Hex(getContentBytes(text, input_charset));
}
private static byte[] getContentBytes(String content, String charset) {
if (charset == null || "".equals(charset)) {
return content.getBytes();
}
try {
return content.getBytes(charset);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
}
}
private String doRefund(String url, String data) throws Exception {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
try {
InputStream certStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("apiclient_cert.p12");
this.certData = IOUtils.toByteArray(certStream);
certStream.close();
} catch (Exception e) {
e.printStackTrace();
}
ByteArrayInputStream is = new ByteArrayInputStream(this.certData);
try {
keyStore.load(is, PayUtil.MCH_ID.toCharArray());
} finally {
is.close();
}
SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(
keyStore,
PayUtil.MCH_ID.toCharArray())
.build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext,
new String[]{"TLSv1"},
null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
);
CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
try {
HttpPost httpost = new HttpPost(url);
httpost.addHeader("Connection", "keep-alive");
httpost.addHeader("Accept", "*/*");
httpost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
httpost.addHeader("Host", "api.mch.weixin.qq.com");
httpost.addHeader("X-Requested-With", "XMLHttpRequest");
httpost.addHeader("Cache-Control", "max-age=0");
httpost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
httpost.setEntity(new StringEntity(data, "UTF-8"));
CloseableHttpResponse response = httpclient.execute(httpost);
try {
HttpEntity entity = response.getEntity();
String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");
EntityUtils.consume(entity);
return jsonStr;
} finally {
response.close();
}
} finally {
httpclient.close();
}
}
public Map<String, String> refund(String orderId, String refundId, String totalFee,
String refundFee, String refundAccount) {
Map<String, String> params = new HashMap<>();
params.put("appid", PayUtil.APPID);
params.put("mch_id", PayUtil.MCH_ID);
params.put("nonce_str", getRandomStringByLength(32));
params.put("out_trade_no", orderId);
params.put("out_refund_no", refundId);
params.put("total_fee", totalFee);
params.put("refund_fee", refundFee);
params.put("refund_account", refundAccount);
params.put("sign_type", "MD5");
String preStr = PayUtil.createLinkString(params);
String sign = (sign(preStr, PayUtil.KEY, "utf-8")).toUpperCase();
params.put("sign", sign);
Map<String, String> map = new HashMap<>();
try {
String xml = mapToXml(params);
String xmlStr = doRefund("https://api.mch.weixin.qq.com/secapi/pay/refund", xml);
map = xmlToMap(xmlStr);
if ("SUCCESS".equals(status)){
}else {
return Result.fail("退款失败");
}
} catch (Exception e) {
}
return map;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?