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