ChenJiaHe
2021-05-06 58930c66d39a016c3165e8f15ba2214cb140d050
提交 | 用户 | age
6efc67 1 package com.hx.corp.util;
C 2
3 import com.alibaba.fastjson.JSON;
4 import com.hx.corp.entity.CorpPayRequest;
5 import com.hx.corp.entity.CorpPayResponse;
6 import com.hx.exception.ServiceException;
7 import com.hx.mp.util.*;
8 import com.hx.util.SimpleTool;
9 import com.hx.util.StringUtils;
10 import net.sf.json.JSONObject;
11 import org.apache.http.HttpEntity;
12 import org.apache.http.client.methods.CloseableHttpResponse;
13 import org.apache.http.client.methods.HttpPost;
14 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
15 import org.apache.http.entity.StringEntity;
16 import org.apache.http.impl.client.CloseableHttpClient;
17 import org.apache.http.impl.client.HttpClients;
18 import org.apache.http.ssl.SSLContexts;
19 import org.apache.http.util.EntityUtils;
20 import org.dom4j.Document;
21 import org.dom4j.Element;
22 import org.dom4j.io.SAXReader;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26 import javax.net.ssl.SSLContext;
27 import javax.servlet.http.HttpServletRequest;
28 import java.io.File;
29 import java.io.FileInputStream;
30 import java.security.KeyStore;
31 import java.util.*;
32
33
34 /** 企业微信支付/退款
35  * @author ChenJiaHe
36  */
37 public class WxCorpPayUtil {
38
39     //log4j日志
40     private static Logger logger = LoggerFactory.getLogger(WxCorpPayUtil.class.getName());
41
42     // 退款接口连接
43     private static final String REFUND_URL = "https://api.mch.weixin.qq.com/secapi/pay/refund";
44      /**查询订单链接*/
45     @SuppressWarnings("unused")
46     private static final String QUERY_URL = "https://api.mch.weixin.qq.com/pay/orderquery";
47     /**同意下单链接*/
48     private static final String FIRST_ORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
49
50     // 企业付款
51     private static final String CORP_PAY_URL = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
52
53
54     /** 企业付款
55      * @param corpPayRequest 请求对象
56      * @param mchKey 商户号秘钥
57      * @param certPath 支付证书
58      * @return CorpPayResponse
59      * @throws Exception
60      */
61     public static CorpPayResponse qdCorpPay(CorpPayRequest corpPayRequest, String mchKey, String certPath)
62             throws Exception {
63
64         CorpPayResponse corpPayResponse = new CorpPayResponse();
65
66         SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
67         parameters.put("mch_appid", corpPayRequest.getMch_appid());
68         parameters.put("mchid", corpPayRequest.getMchid());
69         parameters.put("partner_trade_no", corpPayRequest.getPartner_trade_no());
70         //parameters.put("nonce_str", UUID.randomUUID().toString().substring(0, 30));
71         parameters.put("nonce_str", corpPayRequest.getNonce_str());
72         parameters.put("openid", corpPayRequest.getOpenid());
73         parameters.put("check_name", corpPayRequest.getCheck_name());
6cec25 74         parameters.put("amount", corpPayRequest.getAmount().toString());
6efc67 75         parameters.put("spbill_create_ip", corpPayRequest.getSpbill_create_ip());
C 76         parameters.put("desc", corpPayRequest.getDesc());
77
6cec25 78         corpPayRequest.setSign(WXSignUtils.createSign("UTF-8", parameters, mchKey));
C 79         parameters.put("sign", corpPayRequest.getSign());
6efc67 80         String xmlInfo = HttpXmlUtils.transferXml(parameters);
C 81         try {
82             CloseableHttpResponse response = HttpUtil.Post(CORP_PAY_URL, xmlInfo, true, certPath, corpPayRequest.getMchid());
83             String transfersXml = EntityUtils.toString(response.getEntity(), "utf-8");
6cec25 84
C 85            //Map<String, String> transferMap = HttpXmlUtils.parseRefundXml(transfersXml);
86
87             Map<String,Object> transferMap = XMLUtil.doXMLParse(transfersXml);
88
6efc67 89             // 将 Map 转换为 实体类
C 90             corpPayResponse = JSON.parseObject(JSON.toJSONString(transferMap),CorpPayResponse.class);
91         } catch (Exception e) {
92             logger.error("企业付款接口报错",e);
93         }
94         return corpPayResponse;
95     }
96
97
98     /**统一支付
99      * @param request 方法获取
100      * @param appId  小程序号
101      * @param partner  商户号
102      * @param key  秘钥
103      * @param notifyUrl  回调链接
104      * @param out_trade_no  订单号
105      * @param body 商品描述
106      * @param total_fee 支付金额
107      * @param openid 用户openId
108      * @param attach 附带数据包
109      * @param notifyUrl 回调通知地址
110      * @param trade_type 交易类型
111      * @return JSON  status = "SUC"为成功
112      */
113     public static JSONObject unifiedPay(HttpServletRequest request,String appId,String partner,String key,String notifyUrl,String out_trade_no, String body, String total_fee, String openid,
114             String attach,String trade_type) throws Exception {
115
116         if (!SimpleTool.checkNotNull(notifyUrl)) {
117             throw new ServiceException("支付功能故障!");
118         }
119
120         // 创建查询请求对象
121         RequestHandler reqHandler = new RequestHandler(null, null);
122         // 通信对象
123         TenpayHttpClient httpClient = new TenpayHttpClient();
124         // 应答对象
125         ClientResponseHandler resHandler = new ClientResponseHandler();
126
127         // -----------------------------
128         // 设置请求参数
129         // -----------------------------
130         // reqHandler.init();
131         reqHandler.setKey(key);
132         reqHandler.setGateUrl(FIRST_ORDER_URL);// 请求URL
133
134         // -----------------------------
135         // 设置接口参数(sign后台自动生成)
136         // -----------------------------
137         reqHandler.setParameter("appid", appId); // 公众号/小程序
138         reqHandler.setParameter("mch_id", partner); // 商户号
139         reqHandler.setParameter("nonce_str", SimpleTool.getUUIDName().substring(0, 30));// 随机乱码
140         reqHandler.setParameter("body", body);// 商品描述
141         reqHandler.setParameter("out_trade_no", out_trade_no);// 商户订单号
142         reqHandler.setParameter("total_fee", total_fee);// 总金额
143         reqHandler.setParameter("spbill_create_ip", "8.8.8.8");// 终端IP
144         reqHandler.setParameter("notify_url",notifyUrl);// 通知地址
145         reqHandler.setParameter("trade_type", trade_type);// 交易类型
146                                                           // JSAPI,NATIVE,APP
147         reqHandler.setParameter("openid", openid);// openId
148         reqHandler.setParameter("attach", attach);// 附带数据包
149
150         // -----------------------------
151         // 设置通信参数
152         // -----------------------------
153         // 设置请求返回的等待时间
154         httpClient.setTimeOut(5);
155
156         // 设置ca证书
157         // httpClient.setCaInfo(new File(CA_PATH));
158
159         // 设置个人(商户)证书
160         // httpClient.setCertInfo(new File(CERT_PATH), CERT_PWD);
161
162         // 设置发送类型POST
163         httpClient.setMethod("POST");
164
165         // 设置请求内容(生成sign)
166         String requestUrl = reqHandler.getRequestURL();// 组拼https://www.baidu.com?a=x&b=xx
167
168         httpClient.setReqContent(requestUrl);// https://www.baidu.com?a=x&b=xx
169         String rescontent = "null";
170
171         httpClient.setRequestHandler(reqHandler);// 把处理对象,像是参数各种东西都设置进去方便获取(quan)
172
173         // 返回出去的对象(状态,错误原因,该操作相关信息(参数,返回值))
174         JSONObject returnObj = new JSONObject();
175
176         // 后台调用
177         if (httpClient.call()) {
178             System.out.println("统一下单,成功cll了::");
179
180             // 设置结果参数
181             rescontent = httpClient.getResContent();
182             System.out.println("统一下单返回结果:" + rescontent);
183             resHandler.setContent(rescontent);// 解析xml
184             resHandler.setKey(key);
185
186             // 获取返回参数
187             String return_code = resHandler.getParameter("return_code");
188             String return_msg = resHandler.getParameter("return_msg");
189
190             // 判断签名及结果
191             if (resHandler.isTenpaySign() && "SUCCESS".equals(return_code)) {
192                 String prepay_id = resHandler.getParameter("prepay_id");// 预支付交易会话标识
193                 String code_url = resHandler.getParameter("code_url");// 二维码链接
194
195                 String result_code = resHandler.getParameter("result_code");// 业务结果
196                 String appid = resHandler.getParameter("appid");// 公众账号ID
197                 String mch_id = resHandler.getParameter("mch_id");// 商户号
198                 String nonce_str = resHandler.getParameter("nonce_str");// 随机码
199                 String sign = resHandler.getParameter("sign");// 签名
200
201                 if (result_code.equals("SUCCESS")) {
202                     returnObj.put("status", "suc");
203                     returnObj.put("sign", sign);
204                     returnObj.put("nonce_str", nonce_str);
205                     returnObj.put("mch_id", mch_id);
206                     returnObj.put("appid", appid);
207                     returnObj.put("prepay_id", prepay_id);
208                     returnObj.put("code_url", code_url);
209                     returnObj.put("out_trade_no", out_trade_no);
210                 } else {
211                     String errMsg = "[ERROR]result_code:" + resHandler.getParameter("result_code") + " err_code:"
212                             + resHandler.getParameter("err_code") + "err_code_des:"
213                             + resHandler.getParameter("err_code_des");
214
215                     // 错误时,返回结果未签名,记录retcode、retmsg看失败详情。
216                     returnObj.put("status", "ERROR-C");
217                     returnObj.put("errMsg", errMsg);
218                 }
219             } else {
220                 String errMsg = "return_code:" + return_code + "err_code:" + resHandler.getParameter("err_code")
221                         + " return_msg:" + return_msg;
222                 // 错误时,返回结果未签名,记录retcode、retmsg看失败详情。
223                 returnObj.put("status", "ERROR-B");
224                 returnObj.put("errMsg", errMsg);
225             }
226         } else {
227             // 有可能因为网络原因,请求已经处理,但未收到应答。
228             returnObj.put("status", "ERROR-A");
229             returnObj.put("errMsg", httpClient.getResponseCode() + ":" + httpClient.getErrInfo());
230         }
231
232         // 获取debug信息,建议把请求、应答内容、debug信息,通信返回码写入日志,方便定位问题
233         String detail = "http res:" + httpClient.getResponseCode() + "," + httpClient.getErrInfo() + ";" + "req url:"
234                 + requestUrl + ";" + ";" + "req debug:" + reqHandler.getDebugInfo() + ";" + "res content:" + rescontent
235                 + ";" + "res debug:" + resHandler.getDebugInfo() + ";";
236
237         returnObj.put("detail", detail);
238
239         
240         return returnObj;
241     }
242
243     /**统一支付(分账)
244      * @param request 方法获取
245      * @param appId  小程序号
246      * @param partner  商户号
247      * @param key  秘钥
248      * @param notifyUrl  回调链接
249      * @param out_trade_no  订单号
250      * @param body 商品描述
251      * @param total_fee 支付金额
252      * @param openid 用户openId
253      * @param attach 附带数据包
254      * @param notifyUrl 回调通知地址
255      * @param trade_type 交易类型
256      * @param profit_sharing 是否分账:N不,Y是
257      * @return JSON  status = "SUC"为成功
258      */
259     public static JSONObject unifiedPay(HttpServletRequest request,String appId,String partner,String key,String notifyUrl,String out_trade_no, String body, String total_fee, String openid,
260                                         String attach,String trade_type,String profit_sharing) throws Exception {
261
262         if (!SimpleTool.checkNotNull(notifyUrl)) {
263             throw new ServiceException("支付功能故障!");
264         }
265
266         // 创建查询请求对象
267         RequestHandler reqHandler = new RequestHandler(null, null);
268         // 通信对象
269         TenpayHttpClient httpClient = new TenpayHttpClient();
270         // 应答对象
271         ClientResponseHandler resHandler = new ClientResponseHandler();
272
273         // -----------------------------
274         // 设置请求参数
275         // -----------------------------
276         // reqHandler.init();
277         reqHandler.setKey(key);
278         reqHandler.setGateUrl(FIRST_ORDER_URL);// 请求URL
279
280         // -----------------------------
281         // 设置接口参数(sign后台自动生成)
282         // -----------------------------
283
284         reqHandler.setParameter("appid", appId); // 公众号/小程序
285         reqHandler.setParameter("mch_id", partner); // 商户号
286         reqHandler.setParameter("nonce_str", SimpleTool.getUUIDName().substring(0, 30));// 随机乱码
287         reqHandler.setParameter("body", body);// 商品描述
288         reqHandler.setParameter("out_trade_no", out_trade_no);// 商户订单号
289         reqHandler.setParameter("total_fee", total_fee);// 总金额
290         reqHandler.setParameter("spbill_create_ip", "8.8.8.8");// 终端IP
291         reqHandler.setParameter("notify_url",notifyUrl);// 通知地址
292         reqHandler.setParameter("trade_type", trade_type);// 交易类型
293         //JSAPI,NATIVE,APP
294         reqHandler.setParameter("openid", openid);// openId
295         reqHandler.setParameter("attach", attach);// 附带数据包
296         reqHandler.setParameter("profit_sharing", profit_sharing);// 附带数据包
297
298         // -----------------------------
299         // 设置通信参数
300         // -----------------------------
301         // 设置请求返回的等待时间
302         httpClient.setTimeOut(5);
303
304         // 设置ca证书
305         // httpClient.setCaInfo(new File(CA_PATH));
306
307         // 设置个人(商户)证书
308         // httpClient.setCertInfo(new File(CERT_PATH), CERT_PWD);
309
310         // 设置发送类型POST
311         httpClient.setMethod("POST");
312
313         // 设置请求内容(生成sign)
314         String requestUrl = reqHandler.getRequestURL();// 组拼https://www.baidu.com?a=x&b=xx
315
316         httpClient.setReqContent(requestUrl);// https://www.baidu.com?a=x&b=xx
317         String rescontent = "null";
318
319         httpClient.setRequestHandler(reqHandler);// 把处理对象,像是参数各种东西都设置进去方便获取(quan)
320
321         // 返回出去的对象(状态,错误原因,该操作相关信息(参数,返回值))
322         JSONObject returnObj = new JSONObject();
323
324         // 后台调用
325         if (httpClient.call()) {
326             System.out.println("统一下单,成功cll了::");
327
328             // 设置结果参数
329             rescontent = httpClient.getResContent();
330             System.out.println("统一下单返回结果:" + rescontent);
331             resHandler.setContent(rescontent);// 解析xml
332             resHandler.setKey(key);
333
334             // 获取返回参数
335             String return_code = resHandler.getParameter("return_code");
336             String return_msg = resHandler.getParameter("return_msg");
337
338             // 判断签名及结果
339             if (resHandler.isTenpaySign() && "SUCCESS".equals(return_code)) {
340                 String prepay_id = resHandler.getParameter("prepay_id");// 预支付交易会话标识
341                 String code_url = resHandler.getParameter("code_url");// 二维码链接
342
343                 String result_code = resHandler.getParameter("result_code");// 业务结果
344                 String appid = resHandler.getParameter("appid");// 公众账号ID
345                 String mch_id = resHandler.getParameter("mch_id");// 商户号
346                 String nonce_str = resHandler.getParameter("nonce_str");// 随机码
347                 String sign = resHandler.getParameter("sign");// 签名
348
349                 if (result_code.equals("SUCCESS")) {
350                     returnObj.put("status", "suc");
351                     returnObj.put("sign", sign);
352                     returnObj.put("nonce_str", nonce_str);
353                     returnObj.put("mch_id", mch_id);
354                     returnObj.put("appid", appid);
355                     returnObj.put("prepay_id", prepay_id);
356                     returnObj.put("code_url", code_url);
357                     returnObj.put("out_trade_no", out_trade_no);
358                 } else {
359                     String errMsg = "[ERROR]result_code:" + resHandler.getParameter("result_code") + " err_code:"
360                             + resHandler.getParameter("err_code") + "err_code_des:"
361                             + resHandler.getParameter("err_code_des");
362
363                     // 错误时,返回结果未签名,记录retcode、retmsg看失败详情。
364                     returnObj.put("status", "ERROR-C");
365                     returnObj.put("errMsg", errMsg);
366                 }
367             } else {
368                 String errMsg = "return_code:" + return_code + "err_code:" + resHandler.getParameter("err_code")
369                         + " return_msg:" + return_msg;
370                 // 错误时,返回结果未签名,记录retcode、retmsg看失败详情。
371                 returnObj.put("status", "ERROR-B");
372                 returnObj.put("errMsg", errMsg);
373             }
374         } else {
375             // 有可能因为网络原因,请求已经处理,但未收到应答。
376             returnObj.put("status", "ERROR-A");
377             returnObj.put("errMsg", httpClient.getResponseCode() + ":" + httpClient.getErrInfo());
378         }
379
380         // 获取debug信息,建议把请求、应答内容、debug信息,通信返回码写入日志,方便定位问题
381         String detail = "http res:" + httpClient.getResponseCode() + "," + httpClient.getErrInfo() + ";" + "req url:"
382                 + requestUrl + ";" + ";" + "req debug:" + reqHandler.getDebugInfo() + ";" + "res content:" + rescontent
383                 + ";" + "res debug:" + resHandler.getDebugInfo() + ";";
384
385         returnObj.put("detail", detail);
386
387
388         return returnObj;
389     }
390
391     /**处理信息
392      */
393     public static JSONObject paymentData(JSONObject payObj,String key){
394         JSONObject wxObj = new JSONObject();
395         /**统一下单*/
396         String payStatus = payObj.getString("status");
397         if (payStatus.equals("suc")) {
398             // JSONObject payObj = po.getJSONObject("inf");
399             String appId = payObj.getString("appid");
400             String nonceStr = payObj.getString("nonce_str");
401             String prepay_id = payObj.getString("prepay_id");
402             // JSAPI调用支付返回的数据
403             String timeStamp = SimpleTool.getTenTime(new Date()).toString();
404             String signType = "MD5";
405             String packagef = "prepay_id=" + prepay_id;
406             RequestHandler reqHandler = new RequestHandler(null, null);
407             reqHandler.setParameter("appId", appId);
408             reqHandler.setParameter("nonceStr", nonceStr);
409             reqHandler.setParameter("timeStamp", timeStamp);
410             reqHandler.setParameter("package", packagef);
411             reqHandler.setParameter("signType", signType);
412             reqHandler.setKey(key);
413             String paySign = reqHandler.createSign();// 生成签名
414             wxObj.put("orderNo", payObj.getString("out_trade_no"));
415             wxObj.put("paySign", paySign);
416             wxObj.put("appId", appId);
417             wxObj.put("nonceStr", nonceStr);
418             wxObj.put("package", packagef);
419             wxObj.put("timeStamp", timeStamp);
420         } else {
421             throw new RuntimeException(payObj.toString());
422         }
423         return wxObj;
424     }
425
426     /**
427      * 退款
428      * @param appId 小程序/公众号 appId
429      * @param partner 商户号
430      * @param key 商户号秘钥
431      * @param certPath 个人商户证书
432      * @param out_trade_no 商户订单号
433      * @param transaction_id 财付通订单号(微信订单号)
434      * @param out_refund_no 商户退单号
435      * @param total_fee 订单总额(单位:分)
436      * @param refund_fee 退款金额(单位:分)
437      * @return JSON status="SUCCESS"(成功) (状态,错误原因,该操作相关信息(参数,返回值))
438      */
439     public static JSONObject refund(String appId,String partner,String key,String certPath,String out_trade_no, String transaction_id, String out_refund_no, String total_fee,
440             String refund_fee) {
441          try{  
442              KeyStore keyStore = KeyStore.getInstance("PKCS12");
443              FileInputStream instream = new FileInputStream(new File(certPath));
444              try {  
445                  keyStore.load(instream,partner.toCharArray());
446              }finally {  
447                  instream.close();  
448              }  
449              // Trust own CA and all self-signed certs  
450              SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore,partner.toCharArray()).build();
451              // Allow TLSv1 protocol only  
452              SSLConnectionSocketFactory sslsf;
453             sslsf = new SSLConnectionSocketFactory(
454                     sslcontext, new String[] { "TLSv1" }, null,
455                     SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
456             CloseableHttpClient httpclient = HttpClients.custom()
457                      .setSSLSocketFactory(sslsf).build();  
458              HttpPost httppost = new HttpPost(REFUND_URL);
459              String xml = wxPayRefundData(appId, partner, key, out_trade_no, transaction_id, out_refund_no, total_fee, refund_fee);
460              try {
461                  StringEntity se = new StringEntity(xml);
462                  httppost.setEntity(se);  
463
464                  CloseableHttpResponse responseEntry = httpclient.execute(httppost);
465                  try {  
466                      HttpEntity entity = responseEntry.getEntity();
467                      if (entity != null) {
468
469                          SAXReader saxReader = new SAXReader();
470                          Document document = saxReader.read(entity.getContent());
471                          Element rootElt = document.getRootElement();
472                          String returnCode = rootElt.elementText("return_code");
473                          JSONObject result = new JSONObject();
474
475                          if(returnCode.equals("SUCCESS")){
476                              String resultCode = rootElt.elementText("result_code");
477                              if(resultCode.equals("SUCCESS")) {
478                                  result.put("weixinPayUrl", rootElt.elementText("code_url"));
479                                  result.put("prepayId", rootElt.elementText("prepay_id"));
480                                  result.put("msg", "success");
481
482                                  String refund_id = rootElt.elementText("refund_id");//微信退款单号
483                                  String r_out_refund_no = rootElt.elementText("out_refund_no");
484                                  String errMsg = "商户号" + r_out_refund_no + "的退款流水号是:" + refund_id;
485                                  result.put("status", "SUCCESS");
486                                  result.put("errMsg", errMsg);
487                                  result.put("refund_id", refund_id);
488                              }else{
489                                  String errMsg = "[ERROR]result_code:" + rootElt.elementText("result_code")+
490                                          " err_code:" + rootElt.elementText("err_code");
491
492                                  //错误时,返回结果未签名,记录retcode、retmsg看失败详情。
493                                  result.put("errMsg", errMsg);
494                                  result.put("status","false");
495                                  result.put("msg",rootElt.elementText("err_code_des"));
496                              }
497                          }else{  
498                              String errMsg = "[ERROR]return_code:" + rootElt.elementText("return_code");
499                              
500                              //错误时,返回结果未签名,记录retcode、retmsg看失败详情。
501                              result.put("errMsg", errMsg);
502                              result.put("status","false");
503                              result.put("msg",rootElt.elementText("return_msg"));
504                          }  
505                          return result;  
506                      }  
507                      EntityUtils.consume(entity);
508                  }  
509                  finally {  
510                      responseEntry.close();  
511                  }  
512              }  
513              finally {  
514                  httpclient.close();  
515              }  
516              return null;  
517          }catch(Exception e){  
518              e.printStackTrace();  
519              JSONObject result = new JSONObject();  
520              result.put("status","error");  
521              result.put("msg",e.getMessage());  
522              return result;  
523          }  
524     }
525
526     /** 封装参数数据
527      * @param appId 小程序/公众号 appId
528      * @param partner 商户号
529      * @param key 商户号秘钥
530      * @param out_trade_no 商户订单号
531      * @param transaction_id 财付通订单号(微信订单号)
532      * @param out_refund_no 商户退单号
533      * @param total_fee 订单总额(单位:分)
534      * @param refund_fee 退款金额(单位:分)
535      * @return
536      */
537     public static String wxPayRefundData(String appId,String partner,String key,String out_trade_no, String transaction_id,String out_refund_no,String total_fee,String refund_fee) {
538         StringBuffer xml = new StringBuffer();
539         String data = null;
540         try {
541             String nonceStr = SimpleTool.getUUIDName().substring(0,30);
542             xml.append("</xml>");
543             SortedMap<String,String> parameters = new TreeMap<String,String>();
544             parameters.put("appid",appId);
545             parameters.put("mch_id",partner);
546             parameters.put("nonce_str", nonceStr);
547             if(!StringUtils.isEmpty(out_trade_no)) {
548                 parameters.put("out_trade_no", out_trade_no);
549             }
550             if(!StringUtils.isEmpty(transaction_id)) {
551                 parameters.put("transaction_id", transaction_id);
552             }
553             parameters.put("out_refund_no", out_refund_no);
554             parameters.put("fee_type", "CNY");
555             parameters.put("total_fee", total_fee);//总金额
556             parameters.put("refund_fee", refund_fee);//退款金额
557             parameters.put("op_user_id",partner);
558             parameters.put("sign", createSign(parameters,key));
559             
560             data =SortedMaptoXml(parameters);
561         } catch (Exception e) {
562             System.err.println(e.getMessage());
563             return null;
564         }
565         return data;
566     }
567     
568     /**
569      * 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
570      */
571     public static String createSign(SortedMap<String, String> packageParams, String AppKey) {
572         StringBuffer sb;
573         sb = new StringBuffer();
574         Set es = packageParams.entrySet();
575         Iterator it = es.iterator();
576         while (it.hasNext()) {
577             Map.Entry entry = (Map.Entry) it.next();
578             String k = (String) entry.getKey();
579             String v = (String) entry.getValue();
580             if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
581                 sb.append(k + "=" + v + "&");
582             }
583         }
584         sb.append("key=" + AppKey);
585         String sign = MD5Util.MD5Encode(sb.toString(), "UTF-8").toUpperCase();
586         return sign;
587     }
588     
589     /**
590      * @Author: HONGLINCHEN
591      * @Description:请求值转换为xml格式 SortedMap转xml
592      * @param params
593      * @Date: 2017-9-7 17:18
594      */
595     private static String SortedMaptoXml(SortedMap<String,String> params) {
596         StringBuilder sb = new StringBuilder();
597         Set es = params.entrySet();
598         Iterator it = es.iterator();
599         sb.append("<xml>\n");
600         while(it.hasNext()) {
601             Map.Entry entry = (Map.Entry)it.next();
602             String k = (String)entry.getKey();
603             Object v = entry.getValue();
604             sb.append("<"+k+">");
605             sb.append(v);
606             sb.append("</"+k+">\n");
607         }
608         sb.append("</xml>");
609         return sb.toString();
610     }
611 }