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