这个是微信退款api 可以直接复制去测试。如果没有问题可以直接封装自己的方法
package com.huanuan.zl.order.weixin;
import java.io.InputStream;
import java.security.KeyStore;
import java.util.Map;
import javax.net.ssl.SSLContext;
import org.apache.commons.collections4.map.HashedMap;
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.springframework.core.io.ClassPathResource;
import com.github.wxpay.sdk.WXPayUtil;
import com.huanuan.zl.order.weixin.util.WeiXinUtil;
public class weixin {
public static void main(String[] args) {
try {
//构建参数
Map<String, String> dataMap = new HashedMap<String, String>();
dataMap.put("appid","");
dataMap.put("mch_id","");
//自行实现该随机串
dataMap.put("nonce_str","");
dataMap.put("out_trade_no","P190808170038402889c5318502");
dataMap.put("out_refund_no","P190808170038402889c5318502");
dataMap.put("total_fee","1");
dataMap.put("refund_fee","1");
dataMap.put("refund_desc","退款");
//生成签名
String sign = WXPayUtil.generateSignature(dataMap,"65b20e102f369c75c169aef14d2fb9f6");
dataMap.put("sign", sign);
//map数据转xml
String xmlString = WeiXinUtil.MapToXml(dataMap);
//发起退款
String doRefund = doRefund("mch_id(你的商户id)", "https://api.mch.weixin.qq.com/secapi/pay/refund", xmlString);
System.out.println("=================="+doRefund);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*
* @param mchId 商户ID
* @param url 请求URL
* @param data 退款参数
* @return
* @throws Exception
*/
public static String doRefund(String mchId, String url, String data) throws Exception {
/**
* 注意PKCS12证书 是从微信商户平台-》账户设置-》 API安全 中下载的
*/
KeyStore keyStore = KeyStore.getInstance("PKCS12");
// this.getClass().getClassLoader().getResource("apiclient_cert.p12").getFile()
//File file = new File("classpath:WX_FILE/apiclient_cert.p12");
ClassPathResource classPathResource = new ClassPathResource("cert/apiclient_cert.p12");
InputStream fileInputStream = classPathResource.getInputStream();
//FileInputStream fileInputStream = new FileInputStream(file);1578564831
char[] password = "你的商户id".toCharArray();
//这里自行实现我是使用数据库配置将证书上传到了服务器可以使用 FileInputStream读取本地文件
// ByteArrayInputStream inputStream = FileUtil.getInputStream("https://############################.p12");
try {
//这里写密码..默认是你的MCHID
keyStore.load(fileInputStream, password);
} finally {
fileInputStream.close();
}
SSLContext sslcontext = SSLContexts.custom()
//这里也是写密码的
.loadKeyMaterial(keyStore, mchId.toCharArray())
.build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpclient = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
try {
HttpPost httpost = new HttpPost(url);
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();
}
}
}
使用的工具类
里面有生成签名和解析Map
组装Map的方法,验签。。。。
package com.huanuan.zl.order.weixin.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.apache.commons.codec.digest.DigestUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.xml.sax.InputSource;
public class WeiXinUtil {
private static int number = 10;
private static Random random = new Random();
@Value("${huanuan.pay.key}")
private String key;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
/**
* 组装xml
* @param dataMap
* @return
*/
public static String MapToXml(Map<String, String> dataMap) {
StringBuilder newxml = new StringBuilder();
newxml.append("<xml>");
for(String s : dataMap.keySet()){
newxml.append("<").append(s).append(">");
newxml.append(dataMap.get(s));
newxml.append("</").append(s).append(">");
}
newxml.append("</xml>");
System.out.println(newxml);
return newxml.toString();
}
/**
* POST请求,字符串形式数据
* @param url 请求地址
* @param param 请求数据
* @param
*/
public static String sendPostUrl(String url, String param) {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
out = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(),"UTF-8"));
// 发送请求参数
out.print(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(
conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!" + e);
e.printStackTrace();
}
// 使用finally块来关闭输出流、输入流
finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result;
}
/**
* 验证签名
* @param
* @return
*/
public static boolean checkSign(LinkedHashMap<String, Object> map) {
String signFromAPIResponse = map.get("sign").toString();
if (signFromAPIResponse == "" || signFromAPIResponse == null) {
System.out.println("API返回的数据签名数据不存在,有可能被第三方篡改!!!");
return false;
}
System.out.println("服务器回包里面的签名是:" + signFromAPIResponse);
//清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名
map.put("sign", "");
//将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较
String signForAPIResponse = new WeiXinUtil().creatsign(map);
if (!signForAPIResponse.equals(signFromAPIResponse)) {
//签名验不过,表示这个API返回的数据有可能已经被篡改了
System.out.println("API返回的数据签名验证不通过,有可能被第三方篡改!!! signForAPIResponse生成的签名为" + signForAPIResponse);
return false;
}
System.out.println("恭喜,API返回的数据签名验证通过!!!");
return true;
}
/**
* 把数组装换map
* @param result
* @return
*/
public static LinkedHashMap<String, Object> XmlToMap(String result) throws DocumentException {
LinkedHashMap<String, Object> map = new LinkedHashMap<String, Object>();
InputSource in = new InputSource (new StringReader(result));
in.setEncoding("utf-8");
SAXReader sax = new SAXReader();
Document document = sax.read(in);
Element el = document.getRootElement();
List<Element> list = el.elements();
for(Element element:list) {
map.put(element.getName(), element.getTextTrim());
System.out.println(element.getName()+"============"+element.getTextTrim());
}
return map;
}
/**
* 签名生成
* @return
*/
public String creatsign(LinkedHashMap<String, Object> linkedHashMap){
StringBuilder xml = new StringBuilder();
for(String s : linkedHashMap.keySet()){
xml.append(s).append("=").append(linkedHashMap.get(s)).append("&");
}
xml.append("key="+key);
String sign = DigestUtils.md5Hex(xml.toString()).toString().toUpperCase();
System.out.println("你的签名为==="+sign);
return sign;
}
/**
* 随机生成数
* @return
*/
public static String strcode(){
StringBuilder code = new StringBuilder();
for(int i = 0 ; i < 10 ; i++){
code.append(random.nextInt(10));
}
code.append(System.currentTimeMillis());
return code.toString();
}
public static void main(String[] args) throws IOException {
ClassPathResource classPathResource = new ClassPathResource("p12/apiclient_cert.p12");
//InputStream inputStream = classPathResource.getInputStream();
System.out.println(classPathResource.contentLength());
}
}