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