前言:之前接APP支付,微信遇到了一点点坑,为了方便以后copy,把之前写的代码粘贴出来。需要的同学可以参考一下,具体参数说明还请详细查看官方文档:
支付宝回调参数说明:https://doc.open.alipay.com/docs/doc.htm?treeId=193&articleId=105301&docType=1
微信支付回调参数:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_7&index=3
1.微信支付
1.0 导入xml支持
<!--XML支持-->
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.7</version>
</dependency>
<dependency>
<groupId>org.jdom</groupId>
<artifactId>jdom2</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
1.1 微信统一下单
/**
* 统一下单
*
* @param orderSn
* @param totalFee
* @param spBillCreateIP
* @return
*/
public static Map<Object, Object> sendWxPayRequest(String orderSn, String totalFee, String spBillCreateIP) {
//签名
SortedMap<Object, Object> parameters = new TreeMap<>();
parameters.put("appid", Constant.APPID);
parameters.put("body", Constant.ORDER_NAME);
parameters.put("mch_id", Constant.MCH_ID);
parameters.put("nonce_str", String.valueOf(new Date().getTime()));
parameters.put("notify_url", Constant.CONFIGMAP.get("weixin.asynchronousNotifyUrl"));
parameters.put("out_trade_no", orderSn);
parameters.put("spbill_create_ip", spBillCreateIP);
parameters.put("total_fee", totalFee);
parameters.put("trade_type", "APP");
String sign = createSign("utf-8", parameters);
//请求xml参数
StringBuffer requestStr = new StringBuffer("<xml>");
requestStr.append("<appid><![CDATA[");
requestStr.append(parameters.get("appid"));
requestStr.append("]]></appid>");
requestStr.append("<body><![CDATA[");
requestStr.append(parameters.get("body"));
requestStr.append("]]></body>");
requestStr.append("<mch_id><![CDATA[");
requestStr.append(parameters.get("mch_id"));
requestStr.append("]]></mch_id>");
requestStr.append("<nonce_str><![CDATA[");
requestStr.append(parameters.get("nonce_str"));
requestStr.append("]]></nonce_str>");
requestStr.append("<notify_url><![CDATA[");
requestStr.append(parameters.get("notify_url"));
requestStr.append("]]></notify_url>");
requestStr.append("<out_trade_no><![CDATA[");
requestStr.append(parameters.get("out_trade_no"));
requestStr.append("]]></out_trade_no>");
requestStr.append("<spbill_create_ip><![CDATA[");
requestStr.append(parameters.get("spbill_create_ip"));
requestStr.append("]]></spbill_create_ip>");
requestStr.append("<total_fee><![CDATA[");
requestStr.append(parameters.get("total_fee"));
requestStr.append("]]></total_fee>");
requestStr.append("<trade_type><![CDATA[");
requestStr.append(parameters.get("trade_type"));
requestStr.append("]]></trade_type>");
requestStr.append("<sign><![CDATA[");
requestStr.append(sign);
requestStr.append("]]></sign>");
requestStr.append("</xml>");
try {
String body = HttpUtil.post(Constant.ORDER_URL, requestStr.toString());
String resultStr = new String(body.getBytes("ISO-8859-1"), "utf-8");
SortedMap<Object, Object> resultMap = XMLUtil.doXMLParse(resultStr);
logger.info("微信统一下单响应参数= {}", JSON.toJSON(resultMap));
if (Constant.SUCCESS.equals(resultMap.get("result_code"))) {
String package1 = "Sign=WXPay";
SortedMap<Object, Object> payParameters = new TreeMap<>();
payParameters.put("appid", Constant.APPID);
payParameters.put("partnerid", Constant.MCH_ID);
payParameters.put("prepayid", resultMap.get("prepay_id"));
payParameters.put("package", package1);
payParameters.put("noncestr", String.valueOf(new Date().getTime()));
payParameters.put("timestamp", new Date().getTime() / 1000);
String paySign = SignUtil.createSign("utf-8", payParameters);
payParameters.put("sign", paySign.toUpperCase());
return payParameters;
} else {
logger.warn("微信统一下单错误:{}", JSON.toJSON(resultMap));
}
return null;
} catch (Exception ex) {
logger.warn("微信统一下单异常 ex:", ex);
}
return null;
}
1.2 XmlUtil代码
package com.wangnian.util.wechat.pay;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
public class XmlUtil {
/**
* 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
*
* @param strxml
* @return
* @throws JDOMException
* @throws IOException
*/
public static SortedMap<Object, Object> doXMLParse(String strxml) throws JDOMException, IOException {
if (null == strxml || "".equals(strxml)) {
return null;
}
SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
InputStream in = String2Inputstream(strxml);
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(in);
Element root = doc.getRootElement();
List list = root.getChildren();
Iterator it = list.iterator();
while (it.hasNext()) {
Element e = (Element) it.next();
String k = e.getName();
String v = "";
List children = e.getChildren();
if (children.isEmpty()) {
v = e.getTextNormalize();
} else {
v = XMLUtil.getChildrenText(children);
}
parameters.put(k, v);
}
//关闭流
in.close();
return parameters;
}
/**
* 获取子结点的xml
*
* @param children
* @return String
*/
public static String getChildrenText(List children) {
StringBuffer sb = new StringBuffer();
if (!children.isEmpty()) {
Iterator it = children.iterator();
while (it.hasNext()) {
Element e = (Element) it.next();
String name = e.getName();
String value = e.getTextNormalize();
List list = e.getChildren();
sb.append("<" + name + ">");
if (!list.isEmpty()) {
sb.append(XMLUtil.getChildrenText(list));
}
sb.append(value);
sb.append("</" + name + ">");
}
}
return sb.toString();
}
/**
* 获取xml编码字符集
*
* @param strxml
* @return
* @throws IOException
* @throws JDOMException
*/
public static String getXMLEncoding(String strxml) throws JDOMException, IOException {
InputStream in = String2Inputstream(strxml);
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(in);
in.close();
return (String) doc.getProperty("encoding");
}
public static InputStream String2Inputstream(String str) {
return new ByteArrayInputStream(str.getBytes());
}
}
1.3 SignUtil代码
package com.wangnian.util.wechat.pay;
import com.wangnian.api.config.Constant;
import java.security.MessageDigest;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.logging.Logger;
/**
* Created by http://my.oschina.net/wangnian on 2016/7/27.
*/
public class SignUtil {
/**
* 微信支付签名算法sign
*
* @param characterEncoding
* @param parameters
* @return
*/
public static String createSign(String characterEncoding, SortedMap<Object, Object> parameters) {
StringBuffer sb = new StringBuffer();
Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序(升序)
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
Object v = entry.getValue();
if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}
sb.append("key=" + Constant.WEIXIN_KEY);
String sign = MD5Encode(sb.toString(), characterEncoding).toUpperCase();
return sign;
}
private static String byteArrayToHexString(byte b[]) {
StringBuffer resultSb = new StringBuffer();
for (int i = 0; i < b.length; i++)
resultSb.append(byteToHexString(b[i]));
return resultSb.toString();
}
private static String byteToHexString(byte b) {
int n = b;
if (n < 0)
n += 256;
int d1 = n / 16;
int d2 = n % 16;
return hexDigits[d1] + hexDigits[d2];
}
public static String MD5Encode(String origin, String charsetname) {
String resultString = null;
try {
resultString = new String(origin);
MessageDigest md = MessageDigest.getInstance("MD5");
if (charsetname == null || "".equals(charsetname))
resultString = byteArrayToHexString(md.digest(resultString
.getBytes()));
else
resultString = byteArrayToHexString(md.digest(resultString
.getBytes(charsetname)));
} catch (Exception exception) {
}
return resultString;
}
private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
public static String resultSuccess() {
return "<xml>\n" +
" <return_code><![CDATA[SUCCESS]]></return_code>\n" +
" <return_msg><![CDATA[OK]]></return_msg>\n" +
"</xml>";
}
}
1.4 微信通知回调
/**
* 微信回调地址
*
* @param request
* @return
*/
@RequestMapping(value = "/weixin/asynchronousNotify", method = RequestMethod.POST)
public String wexinNotify(HttpServletRequest request) {
try {
InputStream inStream = request.getInputStream();
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outSteam.write(buffer, 0, len);
}
outSteam.close();
inStream.close();
String resultStr = new String(outSteam.toByteArray(), "utf-8");
SortedMap<String, String> resultMap = XmlUtil.doXMLParse(resultStr);//将xml转成排序之后的map
logger.info("微信支付回调地址请求参数=requst:{}", JSON.toJSON(resultMap));
String result_code = resultMap.get("result_code");//业务结果
String is_subscribe = resultMap.get("is_subscribe");//是否关注了微信公众号
String out_trade_no = resultMap.get("out_trade_no");//订单号
String transaction_id = resultMap.get("transaction_id");//微信支付订单号 类似于支付宝的交易号
String sign = resultMap.get("sign");//签名
String total_fee = resultMap.get("total_fee");//订单总金额 单位为 分
String openid = resultMap.get("openid");//用户在商户appid下的唯一标识
String time_end = resultMap.get("time_end");
String bank_type = resultMap.get("bank_type");
//签名验证
String signStr = SignUtil.createSign("UTF-8", resultMap);
logger.warn("验证= signStr:{},sign:{}", signStr, sign);
if (!signStr.equals(sign)) {
logger.warn("微信支付回调地址请求参数签名验证失败= signStr:{},sign:{}", signStr, sign);
mailTools.SendMail("微信支付回调地址请求参数签名验证失败", "signStr:" + signStr + ",sign:" + sign, null);
return "error";
}
if (result_code.equals("SUCCESS")) {
logger.info("支付成功= 订单号:{},交易号:{}", out_trade_no, transaction_id);
BigDecimal bigDecimal_total_fee = new BigDecimal(total_fee);
BigDecimal bigDecimal = bigDecimal_total_fee.divide(new BigDecimal(100));
//TODO
支付成功处理业务逻辑
}
//通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
return WeixinUtil.resultSuccess();
} catch (Exception ex) {
logger.warn("微信支付回调地址处理异常:{}", ex);
mailTools.SendMail("环境异常,微信支付回调地址处理异常", "异常", ex);
ex.printStackTrace();
}
return "success";
}
1.5 httpUtil代码
package com.wangnian.util.net;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Http工具类
* Created by wangnian on 2016/6/2.
*/
public class HttpUtil {
private static Logger logger = LoggerFactory.getLogger(HttpUtil.class);
/**
* get请求
*
* @param url
* @return
*/
public static String get(String url) {
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet httpget = new HttpGet(url);
try {
CloseableHttpResponse response = httpClient.execute(httpget);
HttpEntity httpEntity = response.getEntity();
String strResult = EntityUtils.toString(httpEntity);
logger.debug("url:{},response:{}", url, strResult);
return strResult;
} catch (Exception ex) {
logger.warn("excption:{}", ex);
} finally {
httpget.releaseConnection();
try {
httpClient.close();
} catch (IOException e) {
logger.error("httpclient.close() Failure :{} " + e);
}
}
return null;
}
/**
* 带参数的get请求
*
* @param url
* @param parMap
* @return
*/
public static String get(String url, Map<String, String> parMap) {
String body = null;
HttpClientBuilder httpclientBuilder = HttpClientBuilder.create();
CloseableHttpClient httpclient = httpclientBuilder.build();
HttpGet httpget = new HttpGet(url);
List<NameValuePair> nvps = new ArrayList<>();
Set<Map.Entry<String, String>> paramsEntry = parMap.entrySet();
for (Map.Entry<String, String> paramEntry : paramsEntry) {
nvps.add(new BasicNameValuePair(paramEntry.getKey(), paramEntry.getValue()));
}
try {
String str = EntityUtils.toString(new UrlEncodedFormEntity(nvps, "UTF-8"));
httpget.setURI(new URI(httpget.getURI().toString() + "?" + str));
CloseableHttpResponse response = httpclient.execute(httpget);
try {
logger.debug("http get status is : {}", response.getStatusLine());//状态码,一般状态码为200时,为正常状态
HttpEntity entity = response.getEntity();
body = EntityUtils.toString(entity, "UTF-8");
EntityUtils.consume(entity);
} finally {
response.close();
}
} catch (Exception e) {
logger.info("Http Get Method Failure : {}", e);
} finally {
httpget.releaseConnection();
try {
httpclient.close();
} catch (IOException e) {
logger.error("httpclient.close() Failure :{} " + e);
}
}
logger.info("response body : {}", body);
return body;
}
/**
* 带参数post请求
*
* @param url
* @return
*/
public static String post(String url, Map<String, String> map) {
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost httpost = new HttpPost(url);
if (map != null) {
List<NameValuePair> nvps = new ArrayList<>();
for (String key : map.keySet()) {
nvps.add(new BasicNameValuePair(key, map.get(key)));
}
httpost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8));
}
try {
CloseableHttpResponse response = httpClient.execute(httpost);
String strResult = EntityUtils.toString(response.getEntity());
logger.debug("url:{} ,map:{},response:{}", url, map, strResult);
return strResult;
} catch (Exception ex) {
logger.warn("excption:{}", ex);
} finally {
httpost.releaseConnection();
try {
httpClient.close();
} catch (IOException e) {
logger.error("httpclient.close() Failure :{} " + e);
}
}
return null;
}
/**
* RAW Post请求
*
* @param url
* @param Body
* @return
* @throws UnsupportedEncodingException
*/
public static String post(String url, String Body) {
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost httpost = new HttpPost(url);
httpost.setEntity(new StringEntity(Body, Consts.UTF_8));
try {
CloseableHttpResponse response = httpClient.execute(httpost);
String strResult = EntityUtils.toString(response.getEntity());
logger.debug("url:{} ,Body:{},response:{}", url, Body, strResult);
return strResult;
} catch (Exception ex) {
logger.warn("excption:{}", ex);
} finally {
httpost.releaseConnection();
try {
httpClient.close();
} catch (IOException e) {
logger.error("httpclient.close() Failure :{} " + e);
}
}
return null;
}
/**
* 微信API请求 (带证书)
*
* @param url
* @param Body
* @return
* @throws UnsupportedEncodingException
*/
public static String weixinApipost(String url, String Body) {
HttpPost httpost = null;
CloseableHttpClient httpClient = null;
try {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
FileInputStream instream = new FileInputStream(new File("C:/Users/Administrator/Desktop/apiclient_cert.p12"));
try {
keyStore.load(instream, "1370249302".toCharArray());
} finally {
instream.close();
}
SSLContext sslcontext = SSLContexts.custom()
.loadKeyMaterial(keyStore, "1370249302".toCharArray())
.build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext,
new String[]{"TLSv1"},
null,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
httpClient = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
httpost = new HttpPost(url);
httpost.setEntity(new StringEntity(Body, Consts.UTF_8));
CloseableHttpResponse response = httpClient.execute(httpost);
String strResult = EntityUtils.toString(response.getEntity());
logger.debug("url:{} ,Body:{},response:{}", url, Body, strResult);
return strResult;
} catch (Exception ex) {
logger.warn("excption:{}", ex);
} finally {
httpost.releaseConnection();
try {
httpClient.close();
} catch (IOException e) {
logger.error("httpclient.close() Failure :{} " + e);
}
}
return null;
}
}
2.支付宝支付
2.0 导入支付宝的jar包
<!--阿里支付-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>alipay</artifactId>
<version>20160828220058</version>
</dependency>
注意公共的maven里是没有这个jar包的,需要自己导入到自己的私服maven里,或者直接依赖jar包
2.1生成支付宝请求签名
Map<String, String> map = new HashMap<>();
//实例化客户端
AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", alipay_app_id, APP_PRIVATE_KEY, "json", CHARSET_UTF8, ALIPAY_PUBLIC_KEY, "RSA2");
//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
//SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setBody("");
model.setSubject("");
model.setOutTradeNo(orderNo);
model.setTimeoutExpress("30m");
model.setTotalAmount(orderPrice);
model.setProductCode("QUICK_MSECURITY_PAY");
request.setBizModel(model);
request.setNotifyUrl(alipayNotifyUrl);
try {
//这里和普通的接口调用不同,使用的是sdkExecute
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
map.put("orderString", response.getBody());//就是orderString 可以直接给客户端请求,无需再做处理。
} catch (AlipayApiException e) {
throw new BusinessException("获取支付宝参数错误");
}
return map;
2.2 支付宝通知回调
/**
* 支付宝异步的通知
*/
@RequestMapping(value = "/alipay/asynchronousNotify", method = RequestMethod.POST)
public String alipayNotify(HttpServletRequest request) throws UnsupportedEncodingException, AlipayApiException {
logger.info("支付宝回调地址请求参数=requst:{}", JSON.toJSON(request.getParameterMap()));
//获取支付宝POST过来反馈信息)
Map requestParams = request.getParameterMap();
Map<String, String> params = MapConverter.requestParameterMapToHashMap(requestParams);
//获取支付宝POST过来反馈信息)
boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.ali_public_key, AlipayConfig.input_charset) //调用SDK验证签名
if (signVerified) {
//按照支付结果异步通知中的描述,对支付结果中的业务内容进行1\2\3\4二次校验,校验成功后在response中返回success,校验失败返回failure
//商户订单号
String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");
//支付宝交易号
String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");
//交易状态
String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"), "UTF-8");
//支付账号
String buyer_email = new String(request.getParameter("buyer_email").getBytes("ISO-8859-1"), "UTF-8");
//支付的金额
BigDecimal total_fee = new BigDecimal(request.getParameter("total_fee"));//支付宝原样返回 1.00
String refund_status = request.getParameter("refund_status");//支付宝退款字段
//获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表(以上仅供参考)//
if (trade_status.equals("TRADE_FINISHED")) {
logger.info("支付失败= 订单号:{},支付宝交易号:{}", out_trade_no, trade_no);
} else if (trade_status.equals("TRADE_SUCCESS")) {
if (refund_status != null) {
logger.info("退款成功= 订单号:{},支付宝交易号:{}", out_trade_no, trade_no);
return "success";
}
logger.info("支付成功= 订单号:{},支付宝交易号:{}", out_trade_no, trade_no);
//TODO 支付成功处理业务逻辑,需要注意避免重复处理
}
} else {
// TODO 验签失败则记录异常日志,并在response中返回failure.
}
return "success";
}
3 支付宝退款
需要导入jar包
package com.wangnian;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeRefundResponse;
import static com.fengchao.api.config.Constant.RSA_PRIVATE;
public class Test {
public static void main(String[] args) throws AlipayApiException {
// 支付宝的公钥,调用接口
String ali_public_key = "WIGfMA0GCSqGSIb3DQECAQUAA4GNADCBiQKBGQDDI6d306Q8fIfCOaTXyiUeJHkrIvYISRcc73s3vF1ZT7XN8RNPwJxo8pWaJMmvyTn9N4HQ632qJBVHf8sxHi/fEsraprwCtzvzQETrNRwVxLO5jVmRGi60j8Ue1efIlzPXV9je9mkjzOmdssymZkh2QhUrCmZYI/FCEa3/cNMW0QIDAQAB";
AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do",
"2016062701558376",
RSA_PRIVATE,
"json",
"GBK",
ali_public_key);
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
request.setBizContent("{" +
" \"out_trade_no\":\"147254841304887\"," + //订单号
" \"trade_no\":\"2016083021001004360293292481\"," +//交易号
" \"refund_amount\":0.01," +//推荐金额
" \"refund_reason\":\"正常退款\"," +//退款备注
" \"out_request_no\":\"HZ01RF0023\"" +//标识一次退款请求,同一笔交易多次退款需要保证唯一,如需部分退款,则此参数必传。
" }");
AlipayTradeRefundResponse response = alipayClient.execute(request);
if ("10000".equals(response.getCode())) {//退款成功
@TODO 处理业务
} else {
//失败
response.getCode();
response.getSubCode();
response.getSubMsg();
}
}
}
4.微信退款
package com.wangnian;
import com.wangnian.api.config.Constant;
import com.wangnian.util.net.HttpUtil;
import com.wangnian.util.wechat.pay.XmlUtil;
import java.util.Date;
import java.util.SortedMap;
import java.util.TreeMap;
import static com.fengchao.util.wechat.pay.SignUtil.createSign;
/**
* Created by http://my.oschina.net/wangnian on 2016/8/30.
*/
public class Test1 {
public static void main(String[] args) {
//签名
SortedMap<Object, Object> parameters = new TreeMap<>();
parameters.put("appid", Constant.APPID);
parameters.put("mch_id", Constant.MCH_ID);
parameters.put("nonce_str", String.valueOf(new Date().getTime()));
parameters.put("out_trade_no", "147201368144688");//订单号
parameters.put("out_refund_no", "1");//退款ID
parameters.put("total_fee", "1");//订单总金额
parameters.put("refund_fee", "1");//订单退款金额
parameters.put("op_user_id", Constant.MCH_ID);//操作员帐号, 默认为商户号
String sign = createSign("utf-8", parameters);
//请求xml参数
StringBuffer requestStr = new StringBuffer("<xml>");
requestStr.append("<appid><![CDATA[");
requestStr.append(parameters.get("appid"));
requestStr.append("]]></appid>");
requestStr.append("<mch_id><![CDATA[");
requestStr.append(parameters.get("mch_id"));
requestStr.append("]]></mch_id>");
requestStr.append("<nonce_str><![CDATA[");
requestStr.append(parameters.get("nonce_str"));
requestStr.append("]]></nonce_str>");
requestStr.append("<out_trade_no><![CDATA[");
requestStr.append(parameters.get("out_trade_no"));
requestStr.append("]]></out_trade_no>");
requestStr.append("<out_refund_no><![CDATA[");
requestStr.append(parameters.get("out_refund_no"));
requestStr.append("]]></out_refund_no>");
requestStr.append("<total_fee><![CDATA[");
requestStr.append(parameters.get("total_fee"));
requestStr.append("]]></total_fee>");
requestStr.append("<refund_fee><![CDATA[");
requestStr.append(parameters.get("refund_fee"));
requestStr.append("]]></refund_fee>");
requestStr.append("<op_user_id><![CDATA[");
requestStr.append(parameters.get("op_user_id"));
requestStr.append("]]></op_user_id>");
requestStr.append("<sign><![CDATA[");
requestStr.append(sign);
requestStr.append("]]></sign>");
requestStr.append("</xml>");
try {
String body = HttpUtil.weixinApipost(Constant.REFUND_URL, requestStr.toString());
String resultStr = new String(body.getBytes("ISO-8859-1"), "utf-8");
SortedMap<Object, Object> resultMap = XmlUtil.doXMLParse(resultStr);
if ("SUCCESS".equals(resultMap.get("return_code")) && "SUCCESS".equals(resultMap.get("result_code"))) {
@TODO 处理业务逻辑
} else {
resultMap.get("return_msg");
resultMap.get("err_code_des");
}
} catch (Exception ex) {
}
}
}
博客地址:https://my.oschina.net/wangnian