前面我已经做了手机端和电脑端的支付,这两天整了一下退款,万万没想到啊,一样的道理我却走了半天弯路麻蛋啊,MD5和RSA两种方式我全试了,单笔数据集detail_data写对了就好使了。。。,多谢支付宝接入人员的提醒
先看一下 官方文档,技术人员给我的,很有用的:https://docs.open.alipay.com/62/104744
说的已经很明白了,不可为空的你就传参就是了,关于代码方面有不懂的看我 支付宝手机网页唤醒app支付 逻辑代码以及log走的流程和参数都在这,
我只说需要改动的地方,后续会提供demo,还有记得先支付,无支付,不退款
MD5方式:
AlipayConfig中调用的接口名:public static String service = "refund_fastpay_by_platform_pwd";
并且加一个 //退款日期 时间格式 yyyy-MM-dd HH:mm:ss——public static String refund_date = UtilDate.getDateFormatter(); 后续会用到
index 退款界面和支付界面当然不一样
<%
/* *
*功能:支付宝即时到账交易接口调试入口页面
*版本:3.4
*日期:2016-03-08
*说明:
*以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
**********************************************
*/
%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
支付宝即时到账批量退款有密接口
请扫码关注
接收重要信息
即时到账批量退款有密接口(refund_fastpay_by_platform_pwd)
然后也是请求到alipayapi
<%
请求参数//
//批次号,必填,格式:当天日期[8位]+序列号[3至24位],如:201603081000001
String batch_no = new String(request.getParameter("WIDbatch_no").getBytes("ISO-8859-1"),"UTF-8");
//退款笔数,必填,参数detail_data的值中,“#”字符出现的数量加1,最大支持1000笔(即“#”字符出现的数量999个)
String batch_num = new String(request.getParameter("WIDbatch_num").getBytes("ISO-8859-1"),"UTF-8");
//退款详细数据,必填,格式(支付宝交易号^退款金额^备注),多笔请用#隔开
String detail_data = new String(request.getParameter("WIDdetail_data").getBytes("ISO-8859-1"),"UTF-8");
//
//把请求参数打包成数组
Map sParaTemp = new HashMap();
sParaTemp.put("service", AlipayConfig.service);
sParaTemp.put("partner", AlipayConfig.partner);
sParaTemp.put("_input_charset", AlipayConfig.input_charset);
sParaTemp.put("MD5", AlipayConfig.sign_type);
sParaTemp.put("notify_url", AlipayConfig.notify_url);
sParaTemp.put("seller_user_id", AlipayConfig.seller_user_id);
sParaTemp.put("refund_date", AlipayConfig.refund_date);
sParaTemp.put("batch_no", batch_no);
sParaTemp.put("batch_num", batch_num);
sParaTemp.put("detail_data", detail_data);
//建立请求
String sHtmlText = AlipaySubmit.buildRequest(sParaTemp,"get","确认");
out.println(sHtmlText);
%>
话说我走的弯路在哪呢,没找到一个好的文档所以就没有规范,然后我开始用的RSA方式,并且那个detail_data格式不对,大家不要和我犯一样的错误哦,正确的单笔退款方式是:订单号也就是流水号也就是交易号^钱数^退款说明,这个确实挺重要,卡个跟头
RSA方式
这个方式麻烦的地方在于先生成公匙私匙,好吧,说说怎么生成的吧
生成工具,很好使的生成工具,关于这方面的说明也不少了,直接去这看看吧http://blog.csdn.net/zhouhui520w/article/details/49885135,说的挺详细的,注意pkcs8格式的生成并且无空格无回车,将公匙上传到支付宝中,我相信你能上传上去,有一步是私匙验证公匙是否匹配,不用管它,前面做对了就一定是匹配的
AlipayConfig中我贴一下代码:
public class AlipayConfig {
//↓↓↓↓↓↓↓↓↓↓请在这里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
// 合作身份者ID,签约账号,以2088开头由16位纯数字组成的字符串,查看地址:https://b.alipay.com/order/pidAndKey.htm
public static String partner = "";
// 收款支付宝账号,以2088开头由16位纯数字组成的字符串,一般情况下收款账号就是签约账号
public static String seller_user_id = partner;
// 商户的私钥,需要PKCS8格式,RSA公私钥生成:https://doc.open.alipay.com/doc2/detail.htm?spm=a219a.7629140.0.0.nBDxfy&treeId=58&articleId=103242&docType=1
public static String private_key =
"MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAt97DHzJ+6ETQ8AY/k31hrF9L1wZVr/kpiF2gnP/sOAIZqNioR6sZMh54kdBZB8+jWjOhpMHZfqJ3JI2A+5mCs0tUl4rBpWmww8OjEGRoixamCc6Hsr9/Gn4pMUMURtVMEXdHeLNQPr/xNd7dbYKxRYiGoCZAVAgMBAAECgYEArdX6OmhnpxLCBdrNZD0B/icLBU1WqtScpJAIMQZLrzcN+XEzKiN4JKxDyWLN7PIHBoIpIDX9a0OLO3uDfcVqJ1eL1hMPDsvlxV72FWzUlkFZcBdVgm800CjB3F2z414zPNGWbo2/RQOp9JkEnnF0ekdOqdMBufoQk3W9ofv/UMECQQD7KXatki/rB6HxDXY3tjg91zE69hTJKvYLN8Cq/rkrAoT5XU2fcwg2CyRXVGgc+DlS+zKf5Bchcp2i6yQK+A3xAkEA1VAwWCCv6WE+Rrbe4aLkWc6p+57E90LPo3a6u96aCIBeZT0oTp2lXlQ4gmWCH6jFeeQHxOUJ8FvIWL+hLx0QZQI/LSFGMeoSsiis8KN6mogjkvkX34BYO818aIecFx2uKAxL2ILrb7s7vnpCDW8dRhdUNZTtg814Woo9yQh3cYEhAkEAukZyUSMKOtTuWzYqYAOtQTeVfONiwUGYrPhrjM+Q10eyJtpHLo+/7yXAyy31ecwZ1p1oo2oXScv8onOFP+0zeQJBAMGyDyZqBcbzrUVFRbSAMvno8GqEflNuPJv4/uiy5pI0qHn0GA/dmab/lUX7BA4dsXyoBoRHyheeYgo9J0lwUtQ=";
// 支付宝公钥,查看地址:https://b.alipay.com/order/pidAndKey.htm
public static String alipay_public_key =
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRSCwhfuhE0PAGP5N9YaxfS9cGVa/5KYhdoJz/7DgCGajYqEerGTIeeJHQWQfPo1ozoaTB2X6idySNgPuZgrNLVJeKwaVpsMPDoxBkaIsWpgnOh7K/fxp+KTFDFEbVTBF3R3izUD6/8TXe3W2CsUWIhqAmQFQIDAQAB";
// 服务器异步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
public static String notify_url = "http://域名/Refund/jsp/notify_url.jsp";
// 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
public static String return_url = "http://域名/Refund/jsp/return_url.jsp";
// 签名方式
public static String sign_type = "RSA";
// 调试用,创建TXT日志文件夹路径,见AlipayCore.java类中的logResult(String sWord)打印方法。
public static String log_path = "C:\\";
// 字符编码格式 目前支持 gbk 或 utf-8
public static String input_charset = "utf-8";
//退款日期 时间格式 yyyy-MM-dd HH:mm:ss
public static String refund_date = UtilDate.getDateFormatter();
// 调用的接口名,无需修改
public static String service = "refund_fastpay_by_platform_pwd";
//↑↑↑↑↑↑↑↑↑↑请在这里配置您的基本信息↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
}
package com.alipay.sign;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
public class RSA{
public static final String SIGN_ALGORITHMS = "SHA1WithRSA";
/**
* RSA签名
* @param content 待签名数据
* @param privateKey 商户私钥
* @param input_charset 编码格式
* @return 签名值
*/
public static String sign(String content, String privateKey, String input_charset)
{
try
{
PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec( Base64.decode(privateKey) );
KeyFactory keyf = KeyFactory.getInstance("RSA");
PrivateKey priKey = keyf.generatePrivate(priPKCS8);
java.security.Signature signature = java.security.Signature
.getInstance(SIGN_ALGORITHMS);
signature.initSign(priKey);
signature.update( content.getBytes(input_charset) );
byte[] signed = signature.sign();
return Base64.encode(signed);
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
/**
* RSA验签名检查
* @param content 待签名数据
* @param sign 签名值
* @param ali_public_key 支付宝公钥
* @param input_charset 编码格式
* @return 布尔值
*/
public static boolean verify(String content, String sign, String ali_public_key, String input_charset)
{
try
{
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] encodedKey = Base64.decode(ali_public_key);
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
java.security.Signature signature = java.security.Signature
.getInstance(SIGN_ALGORITHMS);
signature.initVerify(pubKey);
signature.update( content.getBytes(input_charset) );
boolean bverify = signature.verify( Base64.decode(sign) );
return bverify;
}
catch (Exception e)
{
e.printStackTrace();
}
return false;
}
/**
* 解密
* @param content 密文
* @param private_key 商户私钥
* @param input_charset 编码格式
* @return 解密后的字符串
*/
public static String decrypt(String content, String private_key, String input_charset) throws Exception {
PrivateKey prikey = getPrivateKey(private_key);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, prikey);
InputStream ins = new ByteArrayInputStream(Base64.decode(content));
ByteArrayOutputStream writer = new ByteArrayOutputStream();
//rsa解密的字节大小最多是128,将需要解密的内容,按128位拆开解密
byte[] buf = new byte[128];
int bufl;
while ((bufl = ins.read(buf)) != -1) {
byte[] block = null;
if (buf.length == bufl) {
block = buf;
} else {
block = new byte[bufl];
for (int i = 0; i < bufl; i++) {
block[i] = buf[i];
}
}
writer.write(cipher.doFinal(block));
}
return new String(writer.toByteArray(), input_charset);
}
/**
* 得到私钥
* @param key 密钥字符串(经过base64编码)
* @throws Exception
*/
public static PrivateKey getPrivateKey(String key) throws Exception {
byte[] keyBytes;
keyBytes = Base64.decode(key);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
return privateKey;
}
}
这就是RSA的加密方式了,需要Base64.java工具类有点长就不贴了,在demo中有,其他的都一样了
退款两种加密方式的demo 对照着看一下就懂了,我相信你可以的
这个demo忘了在哪找的了,就按这个做就行,真是没做过就不会,做过就很简单