|
@@ -0,0 +1,292 @@
|
|
|
+package com.kmall.common.utils.wechat.wxglobal;
|
|
|
+
|
|
|
+import com.alibaba.druid.support.logging.Log;
|
|
|
+import com.alibaba.druid.support.logging.LogFactory;
|
|
|
+import com.kmall.common.service.pay.wxpay.CommonWxPayPropertiesBuilder;
|
|
|
+import com.kmall.common.utils.*;
|
|
|
+import com.kmall.common.utils.wechat.*;
|
|
|
+import com.kmall.common.utils.wechat.wxglobal.dto.WechatGlobalQueryApiResult;
|
|
|
+import com.kmall.common.utils.wechat.wxglobal.dto.WechatGlobalQueryRateResult;
|
|
|
+import com.kmall.common.utils.wechat.wxglobal.dto.WechatGlobalRefundApiResult;
|
|
|
+import com.kmall.common.utils.wechat.wxglobal.dto.WechatGlobalRefundQueryResult;
|
|
|
+import org.apache.http.HttpEntity;
|
|
|
+import org.apache.http.HttpResponse;
|
|
|
+import org.apache.http.client.HttpClient;
|
|
|
+import org.apache.http.client.config.RequestConfig;
|
|
|
+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.config.RegistryBuilder;
|
|
|
+import org.apache.http.conn.socket.ConnectionSocketFactory;
|
|
|
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
|
|
|
+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.HttpClientBuilder;
|
|
|
+import org.apache.http.impl.client.HttpClients;
|
|
|
+import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
|
|
|
+import org.apache.http.util.EntityUtils;
|
|
|
+
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.UnsupportedEncodingException;
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.math.MathContext;
|
|
|
+import java.net.URLEncoder;
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+/**
|
|
|
+ * <p>Title: 微信退款工具类</p>
|
|
|
+ * <p>Description: 微信退款工具类,通过充值客户端的不同初始化不同的工具类,得到相应微信退款相关的appid和muchid</p>
|
|
|
+ *
|
|
|
+ * @author xubo
|
|
|
+ * @date 2017年6月6日 下午5:05:03
|
|
|
+ */
|
|
|
+public class WechatGlobalUtil {
|
|
|
+ private static Log logger = LogFactory.getLog(WechatGlobalUtil.class);
|
|
|
+ private static final String EMPTY = "";
|
|
|
+ private static final String URL_PARAM_CONNECT_FLAG = "&";
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 菜单类型
|
|
|
+ *
|
|
|
+ * @author Scott
|
|
|
+ * @email
|
|
|
+ * @date 2016年11月15日 下午1:24:29
|
|
|
+ */
|
|
|
+ public enum WXTradeState {
|
|
|
+ /**
|
|
|
+ * 支付成功
|
|
|
+ */
|
|
|
+ SUCCESS("SUCCESS", "支付成功"),
|
|
|
+ /**
|
|
|
+ * 转入退款
|
|
|
+ */
|
|
|
+ REFUND("REFUND", "转入退款"),
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 未支付
|
|
|
+ */
|
|
|
+ NOTPAY("NOTPAY", "未支付"),
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 已关闭
|
|
|
+ */
|
|
|
+ CLOSED("CLOSED", "已关闭"),
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 已撤销(付款码支付)
|
|
|
+ */
|
|
|
+ REVOKED("REVOKED", "已撤销"),
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 用户支付中(付款码支付)
|
|
|
+ */
|
|
|
+ USERPAYING("USERPAYING", "用户支付中"),
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 支付失败(付款码支付)
|
|
|
+ */
|
|
|
+ PAYERROR("PAYERROR", "支付失败");
|
|
|
+
|
|
|
+ private String code;
|
|
|
+ private String codeZn;
|
|
|
+
|
|
|
+ private WXTradeState(String code, String codeZn) {
|
|
|
+ this.code = code;
|
|
|
+ this.codeZn = codeZn;
|
|
|
+ }
|
|
|
+
|
|
|
+ public String getCode() {
|
|
|
+ return code;
|
|
|
+ }
|
|
|
+
|
|
|
+ public String getCodeZn() {
|
|
|
+ return codeZn;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 微信境外查询订单
|
|
|
+ * @param
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static WechatGlobalQueryApiResult wxOrderQuery(String out_trade_no) {
|
|
|
+ //初始化请求微信服务器的配置信息包括appid密钥等
|
|
|
+ //构建请求参数
|
|
|
+ Map<Object, Object> params = new HashMap<Object, Object>();
|
|
|
+ params.put("appid", CommonWxPayPropertiesBuilder.instance().getAppId());//微信分配的公众账号ID(企业号corpid即为此appId)
|
|
|
+ params.put("mch_id", CommonWxPayPropertiesBuilder.instance().getMchId());//微信支付分配的商户号
|
|
|
+ params.put("out_trade_no", out_trade_no);//商户传给微信的订单号
|
|
|
+ params.put("nonce_str", CharUtil.getRandomString(16));//随机字符串,不长于32位。推荐随机数生成算法
|
|
|
+ //签名前必须要参数全部写在前面
|
|
|
+ params.put("sign", WechatUtil.arraySign(params, CommonWxPayPropertiesBuilder.instance().getPaySignKey()));//签名
|
|
|
+ String mapToXml = MapUtils.convertMap2Xml(params);
|
|
|
+ //请求微信
|
|
|
+ String reponseXml = sendQuerySSLPostToWx(mapToXml, WechatConfig.getSslcsf());
|
|
|
+ WechatGlobalQueryApiResult result =
|
|
|
+ (WechatGlobalQueryApiResult) XmlUtil.xmlStrToBean(reponseXml, WechatGlobalQueryApiResult.class);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 请求查询订单微信
|
|
|
+ **/
|
|
|
+ private static String sendQuerySSLPostToWx(String mapToXml, SSLConnectionSocketFactory sslcsf) {
|
|
|
+ logger.info("*******查询订单(WX Request:" + mapToXml);
|
|
|
+ String xmlStr = sendSSLPostToWx(mapToXml, sslcsf, CommonWxPayPropertiesBuilder.instance().getOrderquery());
|
|
|
+ logger.info("*******查询订单(WX Response:" + xmlStr);
|
|
|
+ return xmlStr;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 微信查询汇率
|
|
|
+ * @param out_trade_no
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static WechatGlobalQueryRateResult wxQueryexchagerate(String out_trade_no) {
|
|
|
+ //初始化请求微信服务器的配置信息包括appid密钥等
|
|
|
+ //构建请求参数
|
|
|
+ Map<Object, Object> params = new HashMap<Object, Object>();
|
|
|
+ params.put("appid", CommonWxPayPropertiesBuilder.instance().getAppId());//微信分配的公众账号ID(企业号corpid即为此appId)
|
|
|
+ params.put("mch_id", CommonWxPayPropertiesBuilder.instance().getMchId());//微信支付分配的商户号
|
|
|
+ params.put("fee_type", "HKD");//外币币种
|
|
|
+ params.put("date", DateUtils.format(new Date(),DateUtils.DATE_TIME_PATTERN_YYYY_MM_DD));//格式为yyyyMMdd
|
|
|
+ //签名前必须要参数全部写在前面
|
|
|
+ params.put("sign", WechatUtil.arraySign(params, CommonWxPayPropertiesBuilder.instance().getPaySignKey()));//签名
|
|
|
+ String mapToXml = MapUtils.convertMap2Xml(params);
|
|
|
+ //请求微信
|
|
|
+ String reponseXml = sendSSLPostToWx(mapToXml, WechatConfig.getSslcsf(), "https://api.mch.weixin.qq.com/pay/queryexchagerate");
|
|
|
+
|
|
|
+ WechatGlobalQueryRateResult result =
|
|
|
+ (WechatGlobalQueryRateResult) XmlUtil.xmlStrToBean(reponseXml, WechatGlobalQueryRateResult.class);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 微信境外申请退款
|
|
|
+ * @param
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static WechatGlobalRefundApiResult wxRefund(String out_trade_no, Double orderMoney, Double refundMoney) {
|
|
|
+ //初始化请求微信服务器的配置信息包括appid密钥等
|
|
|
+ //转换金钱格式
|
|
|
+ BigDecimal bdOrderMoney = new BigDecimal(orderMoney, MathContext.DECIMAL32);
|
|
|
+ BigDecimal bdRefundMoney = new BigDecimal(refundMoney, MathContext.DECIMAL32);
|
|
|
+ //构建请求参数
|
|
|
+ Map<Object, Object> params = new HashMap<Object, Object>();
|
|
|
+ params.put("appid", CommonWxPayPropertiesBuilder.instance().getAppId());//微信分配的公众账号ID(企业号corpid即为此appId)
|
|
|
+ params.put("mch_id", CommonWxPayPropertiesBuilder.instance().getMchId());//微信支付分配的商户号
|
|
|
+ params.put("nonce_str", CharUtil.getRandomString(16));//随机字符串,不长于32位。推荐随机数生成算法
|
|
|
+ params.put("out_trade_no", out_trade_no);//商户传给微信的订单号
|
|
|
+ params.put("out_refund_no", System.currentTimeMillis() + "");//商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔
|
|
|
+ params.put("total_fee", bdOrderMoney.multiply(Constant.ONE_HUNDRED).intValue());//订单总金额,单位为分,只能为整数
|
|
|
+ params.put("refund_fee", bdRefundMoney.multiply(Constant.ONE_HUNDRED).intValue());//退款总金额,订单总金额,单位为分,只能为整数
|
|
|
+ params.put("op_user_id", CommonWxPayPropertiesBuilder.instance().getMchId());//操作员帐号, 默认为商户号
|
|
|
+ params.put("notify_url", CommonWxPayPropertiesBuilder.instance().getRefundNotifyUrl());
|
|
|
+ //签名前必须要参数全部写在前面
|
|
|
+ params.put("sign", WechatUtil.arraySign(params, CommonWxPayPropertiesBuilder.instance().getPaySignKey()));//签名
|
|
|
+ String mapToXml = MapUtils.convertMap2Xml(params);
|
|
|
+
|
|
|
+ //请求微信
|
|
|
+ String reponseXml = sendRefundSSLPostToWx(mapToXml, WechatConfig.getSslcsf());
|
|
|
+ WechatGlobalRefundApiResult result =
|
|
|
+ (WechatGlobalRefundApiResult) XmlUtil.xmlStrToBean(reponseXml, WechatGlobalRefundApiResult.class);
|
|
|
+ result.setOut_refund_no((String) params.get("out_refund_no"));
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 请求退款微信
|
|
|
+ **/
|
|
|
+ public static String sendRefundSSLPostToWx(String mapToXml, SSLConnectionSocketFactory sslcsf) {
|
|
|
+ logger.info("*******退款(WX Request:" + mapToXml);
|
|
|
+ String xmlStr = sendSSLPostToWx(mapToXml, sslcsf, CommonWxPayPropertiesBuilder.instance().getRefundUrl());
|
|
|
+ logger.info("*******退款(WX Response:" + xmlStr);
|
|
|
+ return xmlStr;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 微信境外查询退款
|
|
|
+ * @param
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public static WechatGlobalRefundQueryResult wxRefundquery(String out_trade_no) {
|
|
|
+ Map<Object, Object> params = new HashMap<Object, Object>();
|
|
|
+ params.put("appid", CommonWxPayPropertiesBuilder.instance().getAppId());//微信分配的公众账号ID(企业号corpid即为此appId)
|
|
|
+ params.put("mch_id", CommonWxPayPropertiesBuilder.instance().getMchId());//微信支付分配的商户号
|
|
|
+ params.put("nonce_str", CharUtil.getRandomString(16));//随机字符串,不长于32位。推荐随机数生成算法
|
|
|
+ params.put("out_trade_no", out_trade_no);//商户侧传给微信的订单号
|
|
|
+ //签名前必须要参数全部写在前面
|
|
|
+ params.put("sign", WechatUtil.arraySign(params, CommonWxPayPropertiesBuilder.instance().getPaySignKey()));//签名
|
|
|
+ String mapToXml = MapUtils.convertMap2Xml(params);
|
|
|
+ String reponseXml = sendRefundQerutySSLPostToWx(mapToXml, WechatConfig.getSslcsf());
|
|
|
+ System.out.println(reponseXml);
|
|
|
+ WechatGlobalRefundQueryResult result =
|
|
|
+ (WechatGlobalRefundQueryResult) XmlUtil.xmlStrToBean(reponseXml, WechatGlobalRefundQueryResult.class);
|
|
|
+ result.setXmlStr(reponseXml);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ public static String sendRefundQerutySSLPostToWx(String mapToXml, SSLConnectionSocketFactory sslcsf) {
|
|
|
+ logger.info("*******退款查询(WX Request:" + mapToXml);
|
|
|
+ String xmlStr = sendSSLPostToWx(mapToXml, sslcsf, CommonWxPayPropertiesBuilder.instance().getRefundqueryUrl());
|
|
|
+ logger.info("*******退款查询(WX Response:" + xmlStr);
|
|
|
+ return xmlStr;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 请求微信https
|
|
|
+ **/
|
|
|
+ private static String sendSSLPostToWx(String mapToXml, SSLConnectionSocketFactory sslcsf, String requestUrl) {
|
|
|
+
|
|
|
+ HttpPost httPost = new HttpPost(requestUrl);
|
|
|
+ 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(mapToXml, "UTF-8"));
|
|
|
+ CloseableHttpClient httpClient = null;
|
|
|
+ if (sslcsf != null) {
|
|
|
+ httpClient = HttpClients.custom().setSSLSocketFactory(sslcsf).build();
|
|
|
+ } else {
|
|
|
+ httpClient = HttpClients.createDefault();
|
|
|
+ }
|
|
|
+
|
|
|
+ CloseableHttpResponse response = null;
|
|
|
+ try {
|
|
|
+ response = httpClient.execute(httPost);
|
|
|
+ HttpEntity entity = response.getEntity();
|
|
|
+ String xmlStr = EntityUtils.toString(entity, "UTF-8");
|
|
|
+ return xmlStr;
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error(e.getMessage(), e);
|
|
|
+ return null;
|
|
|
+ } finally {
|
|
|
+ try {
|
|
|
+ if (response != null) {
|
|
|
+ response.close();
|
|
|
+ }
|
|
|
+ } catch (IOException e) {
|
|
|
+ logger.error(e.getMessage(), e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void main(String[] args) throws Exception {
|
|
|
+ Map<Object, Object> parame = new TreeMap<Object, Object>();
|
|
|
+ parame.put("mch_id", "");//
|
|
|
+ String randomStr = CharUtil.getRandomNum(18).toUpperCase();
|
|
|
+ parame.put("nonce_str", randomStr);//
|
|
|
+ String sign = WechatUtil.arraySign(parame, "");
|
|
|
+ parame.put("sign", sign);// 数字签证
|
|
|
+
|
|
|
+ String xml = MapUtils.convertMap2Xml(parame);
|
|
|
+ logger.info("xml:" + xml);
|
|
|
+ Map<String, Object> resultUn = XmlUtil.xmlStrToMap(
|
|
|
+ WechatUtil.requestOnce("https://apitest.mch.weixin.qq.com/sandboxnew/pay/getsignkey", xml));
|
|
|
+ System.out.print(resultUn);
|
|
|
+ }
|
|
|
+}
|