前言
上一篇文章,我们介绍了微信云支付的扫码支付实现的大体流程,这篇文章我们将介绍的是退款。
一、 计算签名
我们查看API说明的时候,发现退款的时候,需要传递签名和签名算法,如下图
签名生成算法:RSASSA-PSS-2048-SHA256,私钥为服务商在云支付录入商户时,在网页上生成的签名私钥(该私钥只有服务商知道,云支付不知道,请妥善保存
)
使用java实现计算签名功能(官方API上是C++实现)
/**
* 计算SHA256WithRSA签名
*
* @param data
* @param
* @return
* @throws Exception
*/
public static String caculateSignature(String key, String data) throws Exception {
PrivateKey privateKey = null;
try {
byte[] buffer = Base64.getDecoder().decode(key);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
privateKey = (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
} catch (NoSuchAlgorithmException e) {
throw new Exception("无此算法");
} catch (InvalidKeySpecException e) {
throw new Exception("私钥非法");
} catch (NullPointerException e) {
throw new Exception("私钥数据为空");
}
Signature signature = Signature.getInstance("SHA256withRSA/PSS", "BC"); //安装bcprov-ext-jdk15on-158.jar
signature.initSign(privateKey);
signature.update(data.getBytes(ENCODING));
return encodeBase64(signature.sign());
}
/***
* encode by Base64
*/
public static String encodeBase64(byte[] input) throws Exception {
Class clazz = Class.forName("com.sun.org.apache.xerces.internal.impl.dv.util.Base64");
Method mainMethod = clazz.getMethod("encode", byte[].class);
mainMethod.setAccessible(true);
Object retObj = mainMethod.invoke(null, new Object[]{input});
return (String) retObj;
}
拼接请求数据
申请退款API
相关代码如下(其中,代码中传递的订单号,一定是之前付款成功的订单号)
private static void initRefund() {
RefundRequestContent requestContent = new RefundRequestContent();
refundAuthenInfo = new SignatureInfo();
PayMchKey payMchKey = new PayMchKey();
payMchKey.setPayPlatform(2);
payMchKey.setOut_mch_id("云支付分配给服务商的帐号");//
payMchKey.setOut_sub_mch_id("云支付分配给子商户的帐号");
payMchKey.setOut_shop_id("门店账号"); //在请求门店接口的返回信息中找
OrderClient orderClient = new OrderClient();
orderClient.setDevice_id("设备id");//在请求门店接口的返回信息中找
orderClient.setStaff_id("店员id");//在请求门店接口的返回信息中找
orderClient.setTerminal_type(2);在请求门店接口的返回信息中找
orderClient.setSdk_version("SDK");
orderClient.setSpbill_create_ip("ip地址");
RefundContent refundContent = new RefundContent();
refundContent.setOut_trade_no("订单号"); //由客户端生成的订单号,需要退款的订单号,前缀必须是云支付订单前缀
refundContent.setOut_refund_no("退款单号");//由客户端生成的退款单号,前缀必须是云支付订单前缀
refundContent.setTotal_fee(Long.parseLong(AmountUtils.changeY2F(0.01 + "")));//单位:分,总金额,当前是举例0.01元
refundContent.setRefund_fee(Long.parseLong(AmountUtils.changeY2F(0.01 + "")));//单位:分,此次退款金额,当前是举例0.01元
refundContent.setRefund_fee_type("CNY");
requestContent.setPay_mch_key(payMchKey);
requestContent.setPay_content(refundContent);
requestContent.setOrder_client(orderClient);
requestContent.setNonce_str("17f827a751761f6f");
/**
* 退款的requestContent
*/
requestContentJson = requestContent.getJson();
System.out.println("request=="+requestContentJson);
/**
* 计算签名
*/
String str ="您的签名私钥";
try {
hashScanCode = CaculateUtil.caculateSignature(str, requestContentJson);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("hashScanCode:"+ hashScanCode);
/**
* 认证信息
*/
Signature signature = new Signature();
signature.setSign_type(1);
signature.setSign(hashScanCode);
refundAuthenInfo.setS(signature);
}
使用上一节介绍的方法请求微信云支付后台
如果退款成功,得到数据大体如下
退款成功后,如果之前是余额支付的,基本上实时到账,如果是银行卡付款,应该是7个工作日到账。