java集成微信支付接口(微信V3版)

吐槽下:

经常有人问我,你不是在某软件公司么?我听说大公司都是Java,对吗?

我只想回答,那是网上流传的骗人的传说,据我所知公司开发组大部分都是C#,少部分用JAVA。

这不,官方提供那个Demo就是个例证,JAVA版本完全是V1版本,难以使用,反而C#是V3版本,拿来就用。


最近几天我们公司需要做类似的开发,我作为先锋,率先解决Java集成支付宝支付和微信支付接口工作。


  我们的工作环境:目前工作的支付宝接口为20160912,微信为V3版本,如遇到版本升级,请联系相关机构的客户服务人员升级。


  本文介绍JAVA+微信V3,刚刚已经说过,官方提供那个Demo完全是V1版本,下面是本人原创Java V3版本SDK,

本文的WxPayApi接口完全兼容官方提供C# SDK DEMO WxPayApi类,可以把C# 代码拿来转转就能用。


  新手注意:

 1、配置有个证书路径,是新版httpclient 连接HTTPS需要目标网站证书,不清楚的话,自己看注释做证书或者度娘一下。

 2、用到的Jar:

commons-logging-1.2.jar
fastjson-1.2.7.jar
FastWeixin.jar
httpclient-4.5.2.jar
httpcore-4.4.4.jar
httpmime-4.5.2.jar
xstream-1.4.9.jar

3、使用到UtilDate类,请参考上一篇文章,或者支付宝支付Demo。

4、示例函数:WXPay.weixin_pay(),新手要注意,每种支付所用到参数不尽相同,多看看文档确定使用到哪几个参数,不要想当然。

5、部分通用函数,使用了FastWeixin里面Util 自己根据需要选择替换。

[java] view plain copy
print ?
  1. “2067985” snippet_file_name=“blog_20161222_1_5457278” name=“code” class=“java”>package com.luozhuang;  
  2.   
  3. import java.text.SimpleDateFormat;  
  4. import java.util.Calendar;  
  5. import java.util.Date;  
  6. import java.util.Map;  
  7. import java.util.SortedMap;  
  8. import java.util.TreeMap;  
  9.   
  10. import javax.servlet.http.HttpServletRequest;  
  11.   
  12. import com.luozhuang.util.Configure;  
  13. import com.luozhuang.util.HttpsRequest;  
  14. import com.luozhuang.util.PayCommonUtil;  
  15. import com.luozhuang.util.XMLParser;  
  16.   
  17. /** 
  18.  * SDK总入口 
  19.  */  
  20. public class WXPay {  
  21.     public String getRemortIP(HttpServletRequest request) {  
  22.         if (request.getHeader(“x-forwarded-for”) == null) {  
  23.         return request.getRemoteAddr();  
  24.         }  
  25.         return request.getHeader(“x-forwarded-for”);  
  26.         }  
  27.     /** 
  28.      * 初始化SDK依赖的几个关键配置 
  29.      *  
  30.      * @param key 
  31.      *            签名算法需要用到的秘钥 
  32.      * @param appID 
  33.      *            公众账号ID 
  34.      * @param mchID 
  35.      *            商户ID 
  36.      * @param sdbMchID 
  37.      *            子商户ID,受理模式必填 
  38.      * @param certLocalPath 
  39.      *            HTTP证书在服务器中的路径,用来加载证书用 
  40.      * @param certPassword 
  41.      *            HTTP证书的密码,默认等于MCHID 
  42.      */  
  43.     public static void initSDKConfiguration(String key, String appID, String mchID, String sdbMchID,  
  44.             String certLocalPath, String certPassword) {  
  45.         Configure.setKey(key);  
  46.         Configure.setAppID(appID);  
  47.         Configure.setMchID(mchID);  
  48.         Configure.setSubMchID(sdbMchID);  
  49.         Configure.setCertLocalPath(certLocalPath);  
  50.         Configure.setCertPassword(certPassword);  
  51.     }  
  52.   
  53.     /** 
  54.      *  
  55.      *  
  56.      * @param out_trade_no 
  57.      * @return 
  58.      * @throws Exception 
  59.      */  
  60.     public static String weixin_pay(String out_trade_no) throws Exception {  
  61.         HttpsRequest httpRequest = new HttpsRequest();  
  62.         // 账号信息  
  63.         String appid = Configure.getAppid(); // appid  
  64.         // String appsecret = PayConfigUtil.APP_SECRET; // appsecret  
  65.         // 商业号  
  66.         String mch_id = Configure.getMchid();  
  67.         // key  
  68.         String key = Configure.getKey();  
  69.   
  70.         String currTime = PayCommonUtil.getCurrTime();  
  71.         String strTime = currTime.substring(8, currTime.length());  
  72.         String strRandom = PayCommonUtil.buildRandom(4) + “”;  
  73.         // 随机字符串  
  74.         String nonce_str = strTime + strRandom;  
  75.         // 价格 注意:价格的单位是分  
  76.          String order_price = ”1”;  
  77.         // 商品名称  
  78.         // String body = “luozhuang”;  
  79.   
  80.         // 获取发起电脑 ip  
  81.         String spbill_create_ip = Configure.getIP();  
  82.         // 回调接口  
  83.         String notify_url = Configure.NOTIFY_URL;  
  84.         String product_id=”luozhuang”;  
  85.         String trade_type = ”NATIVE”;//JSAPI–公众号支付、NATIVE–原生扫码支付、APP–app支付  
  86.         String time_start = new SimpleDateFormat(“yyyyMMddHHmmss”).format(new Date());  
  87.         Calendar ca = Calendar.getInstance();  
  88.         ca.setTime(new Date());  
  89.         ca.add(Calendar.DATE, 1);  
  90.         String time_expire = new SimpleDateFormat(“yyyyMMddHHmmss”).format(ca.getTime());  
  91.         WxPayData packageParams = new WxPayData();  
  92.         packageParams.put(”appid”, appid);  
  93.         packageParams.put(”mch_id”, mch_id);  
  94.         packageParams.put(”nonce_str”, nonce_str);  
  95.         packageParams.put(”body”“luozhuang-服务费”);  
  96.         packageParams.put(”out_trade_no”, out_trade_no);  
  97.         packageParams.put(”product_id”,product_id);  
  98.         packageParams.put(”total_fee”, order_price);  
  99.         packageParams.put(”spbill_create_ip”, spbill_create_ip);  
  100.         packageParams.put(”notify_url”, notify_url);  
  101.         packageParams.put(”trade_type”, trade_type);  
  102.         packageParams.put(”time_start”, time_start);  
  103.         packageParams.put(”time_expire”, time_expire);  
  104.         String sign = packageParams.MakeSign();  
  105.         packageParams.put(”sign”, sign);  
  106.         WxPayData resXml=WxPayApi.UnifiedOrder(packageParams, 20);  
  107.         String requestXML = packageParams.ToXml();  
  108.         System.out.println(”请求xml::::” + requestXML);  
  109.         System.out.println(”得到xml::::” + resXml.toString());  
  110.         // String return_code = (String) map.get(“return_code”);  
  111.         // String prepay_id = (String) map.get(“prepay_id”);  
  112.         String urlCode = (String) resXml.GetValue(”code_url”);  
  113.         System.out.println(”打印调用统一下单接口生成二维码url:::::” + urlCode);  
  114.         return urlCode;  
  115.     }  
  116.   
  117. }  

  118.   
  119.   
  120.   

  121.   

  122.   
  123.   
  124. ”2067985”
     snippet_file_name=“blog_20161222_2_3079537” name=“code” class=“java”>package com.luozhuang;  
  125.   
  126. import java.io.IOException;  
  127. import java.security.KeyManagementException;  
  128. import java.security.KeyStoreException;  
  129. import java.security.NoSuchAlgorithmException;  
  130. import java.security.UnrecoverableKeyException;  
  131. import java.util.Calendar;  
  132. import java.util.Date;  
  133. import java.util.Random;  
  134.   
  135. import javax.xml.parsers.ParserConfigurationException;  
  136.   
  137. import org.xml.sax.SAXException;  
  138.   
  139. import com.fastwixinextend.CommonClass;  
  140. import com.luozhuang.util.Configure;  
  141. import com.luozhuang.util.HttpsRequest;  
  142.   
  143. public class WxPayApi  
  144. {  
  145.     private static final int REPORT_LEVENL = 0;  
  146.   
  147.     /** 
  148.     * 提交被扫支付API 
  149.     * 收银员使用扫码设备读取微信用户刷卡授权码以后,二维码或条码信息传送至商户收银台, 
  150.     * 由商户收银台或者商户后台调用该接口发起支付。 
  151.     * @param WxPayData inputObj 提交给被扫支付API的参数 
  152.     * @param int timeOut 超时时间 
  153.     * @throws WxPayException 
  154.     * @return 成功时返回调用结果,其他抛异常 
  155.      * @throws IOException  
  156.      * @throws KeyStoreException  
  157.      * @throws NoSuchAlgorithmException  
  158.      * @throws KeyManagementException  
  159.      * @throws UnrecoverableKeyException  
  160.      * @throws SAXException  
  161.      * @throws ParserConfigurationException  
  162.     */  
  163.     public static WxPayData Micropay(WxPayData inputObj, int timeOut) throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, WxPayException, ParserConfigurationException, SAXException  
  164.     {  
  165.         String url =Configure.PAY_API;  
  166.         //检测必填参数  
  167.         if (!inputObj.IsSet(“body”))  
  168.         {  
  169.             throw new WxPayException(“提交被扫支付API接口中,缺少必填参数body!”);  
  170.         }  
  171.         else if (!inputObj.IsSet(“out_trade_no”))  
  172.         {  
  173.             throw new WxPayException(“提交被扫支付API接口中,缺少必填参数out_trade_no!”);  
  174.         }  
  175.         else if (!inputObj.IsSet(“total_fee”))  
  176.         {  
  177.             throw new WxPayException(“提交被扫支付API接口中,缺少必填参数total_fee!”);  
  178.         }  
  179.         else if (!inputObj.IsSet(“auth_code”))  
  180.         {  
  181.             throw new WxPayException(“提交被扫支付API接口中,缺少必填参数auth_code!”);  
  182.         }  
  183.      
  184.         inputObj.SetValue(”spbill_create_ip”, Configure.getIP());//终端ip  
  185.         inputObj.SetValue(”appid”, Configure.getAppid());//公众账号ID  
  186.         inputObj.SetValue(”mch_id”, Configure.getMchid());//商户号  
  187.         inputObj.SetValue(”nonce_str”, UUIDGenerator.getUUID().toString().replace(“-““”));//随机字符串  
  188.         inputObj.SetValue(”sign”, inputObj.MakeSign());//签名  
  189.         String xml = inputObj.ToXml();  
  190.   
  191.         HttpsRequest https=new HttpsRequest();  
  192.         https.setSocketTimeout(timeOut);  
  193.         String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API  
  194.         WxPayData result = new WxPayData();  
  195.         result.FromXml(response);  
  196.   
  197.   
  198.   
  199.         return result;  
  200.     }  
  201.   
  202.       
  203.     /** 
  204.     *     
  205.     * 查询订单 
  206.     * @param WxPayData inputObj 提交给查询订单API的参数 
  207.     * @param int timeOut 超时时间 
  208.     * @throws WxPayException 
  209.     * @return 成功时返回订单查询结果,其他抛异常 
  210.      * @throws IOException  
  211.      * @throws KeyStoreException  
  212.      * @throws NoSuchAlgorithmException  
  213.      * @throws KeyManagementException  
  214.      * @throws UnrecoverableKeyException  
  215.      * @throws SAXException  
  216.      * @throws ParserConfigurationException  
  217.     */  
  218.     public static WxPayData OrderQuery(WxPayData inputObj, int timeOut) throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, WxPayException, ParserConfigurationException, SAXException  
  219.     {  
  220.         String url = Configure.PAY_QUERY_API;  
  221.         //检测必填参数  
  222.         if (!inputObj.IsSet(“out_trade_no”) && !inputObj.IsSet(“transaction_id”))  
  223.         {  
  224.             throw new WxPayException(“订单查询接口中,out_trade_no、transaction_id至少填一个!”);  
  225.         }  
  226.   
  227.         inputObj.SetValue(”appid”, Configure.getAppid());//公众账号ID  
  228.         inputObj.SetValue(”mch_id”, Configure.getMchid());//商户号  
  229.         inputObj.SetValue(”nonce_str”, WxPayApi.GenerateNonceStr());//随机字符串  
  230.         inputObj.SetValue(”sign”, inputObj.MakeSign());//签名  
  231.   
  232.         String xml = inputObj.ToXml();  
  233.   
  234.         HttpsRequest https=new HttpsRequest();  
  235.         https.setSocketTimeout(timeOut);  
  236.         String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API  
  237.         WxPayData result = new WxPayData();  
  238.         result.FromXml(response);  
  239.   
  240.         return result;  
  241.     }  
  242.   
  243.   
  244.     /** 
  245.     *  
  246.     * 撤销订单API接口 
  247.     * @param WxPayData inputObj 提交给撤销订单API接口的参数,out_trade_no和transaction_id必填一个 
  248.     * @param int timeOut 接口超时时间 
  249.     * @throws WxPayException 
  250.     * @return 成功时返回API调用结果,其他抛异常 
  251.      * @throws IOException  
  252.      * @throws KeyStoreException  
  253.      * @throws NoSuchAlgorithmException  
  254.      * @throws KeyManagementException  
  255.      * @throws UnrecoverableKeyException  
  256.      * @throws SAXException  
  257.      * @throws ParserConfigurationException  
  258.     */  
  259.     public static WxPayData Reverse(WxPayData inputObj, int timeOut) throws WxPayException, UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, ParserConfigurationException, SAXException  
  260.     {  
  261.         String url =Configure.REVERSE_API;  
  262.         //检测必填参数  
  263.         if (!inputObj.IsSet(“out_trade_no”) && !inputObj.IsSet(“transaction_id”))  
  264.         {  
  265.             throw new WxPayException(“撤销订单API接口中,参数out_trade_no和transaction_id必须填写一个!”);  
  266.         }  
  267.   
  268.         inputObj.SetValue(”appid”, Configure.getAppid());//公众账号ID  
  269.         inputObj.SetValue(”mch_id”, Configure.getMchid());//商户号  
  270.         inputObj.SetValue(”nonce_str”, GenerateNonceStr());//随机字符串  
  271.         inputObj.SetValue(”sign”, inputObj.MakeSign());//签名  
  272.         String xml = inputObj.ToXml();  
  273.   
  274.   
  275.         HttpsRequest https=new HttpsRequest();  
  276.         https.setSocketTimeout(timeOut);  
  277.         String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API  
  278.         WxPayData result = new WxPayData();  
  279.         result.FromXml(response);  
  280.   
  281.         return result;  
  282.     }  
  283.   
  284.   
  285.     /** 
  286.     *  
  287.     * 申请退款 
  288.     * @param WxPayData inputObj 提交给申请退款API的参数 
  289.     * @param int timeOut 超时时间 
  290.     * @throws WxPayException 
  291.     * @return 成功时返回接口调用结果,其他抛异常 
  292.      * @throws IOException  
  293.      * @throws KeyStoreException  
  294.      * @throws NoSuchAlgorithmException  
  295.      * @throws KeyManagementException  
  296.      * @throws UnrecoverableKeyException  
  297.      * @throws SAXException  
  298.      * @throws ParserConfigurationException  
  299.     */  
  300.     public static WxPayData Refund(WxPayData inputObj, int timeOut) throws WxPayException, UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, ParserConfigurationException, SAXException  
  301.     {  
  302.         String url = Configure.REFUND_API;  
  303.         //检测必填参数  
  304.         if (!inputObj.IsSet(“out_trade_no”) && !inputObj.IsSet(“transaction_id”))  
  305.         {  
  306.             throw new WxPayException(“退款申请接口中,out_trade_no、transaction_id至少填一个!”);  
  307.         }  
  308.         else if (!inputObj.IsSet(“out_refund_no”))  
  309.         {  
  310.             throw new WxPayException(“退款申请接口中,缺少必填参数out_refund_no!”);  
  311.         }  
  312.         else if (!inputObj.IsSet(“total_fee”))  
  313.         {  
  314.             throw new WxPayException(“退款申请接口中,缺少必填参数total_fee!”);  
  315.         }  
  316.         else if (!inputObj.IsSet(“refund_fee”))  
  317.         {  
  318.             throw new WxPayException(“退款申请接口中,缺少必填参数refund_fee!”);  
  319.         }  
  320.         else if (!inputObj.IsSet(“op_user_id”))  
  321.         {  
  322.             throw new WxPayException(“退款申请接口中,缺少必填参数op_user_id!”);  
  323.         }  
  324.   
  325.         inputObj.SetValue(”appid”, Configure.getAppid());//公众账号ID  
  326.         inputObj.SetValue(”mch_id”, Configure.getMchid());//商户号  
  327.         inputObj.SetValue(”nonce_str”, UUIDGenerator.getUUID().toString().replace(“-““”));//随机字符串  
  328.         inputObj.SetValue(”sign”, inputObj.MakeSign());//签名  
  329.           
  330.         String xml = inputObj.ToXml();  
  331.     
  332.         HttpsRequest https=new HttpsRequest();  
  333.         https.setSocketTimeout(timeOut);  
  334.         String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API  
  335.         WxPayData result = new WxPayData();  
  336.         result.FromXml(response);  
  337.   
  338.         return result;  
  339.     }  
  340.   
  341.   
  342.     /** 
  343.     *  
  344.     * 查询退款 
  345.     * 提交退款申请后,通过该接口查询退款状态。退款有一定延时, 
  346.     * 用零钱支付的退款20分钟内到账,银行卡支付的退款3个工作日后重新查询退款状态。 
  347.     * out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个 
  348.     * @param WxPayData inputObj 提交给查询退款API的参数 
  349.     * @param int timeOut 接口超时时间 
  350.     * @throws WxPayException 
  351.     * @return 成功时返回,其他抛异常 
  352.      * @throws IOException  
  353.      * @throws KeyStoreException  
  354.      * @throws NoSuchAlgorithmException  
  355.      * @throws KeyManagementException  
  356.      * @throws UnrecoverableKeyException  
  357.      * @throws SAXException  
  358.      * @throws ParserConfigurationException  
  359.     */  
  360.     public static WxPayData RefundQuery(WxPayData inputObj, int timeOut) throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, WxPayException, ParserConfigurationException, SAXException  
  361.     {  
  362.         String url = Configure.REFUND_QUERY_API;  
  363.         //检测必填参数  
  364.         if(!inputObj.IsSet(“out_refund_no”) && !inputObj.IsSet(“out_trade_no”) &&  
  365.             !inputObj.IsSet(”transaction_id”) && !inputObj.IsSet(“refund_id”))  
  366.         {  
  367.             throw new WxPayException(“退款查询接口中,out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个!”);  
  368.         }  
  369.   
  370.         inputObj.SetValue(”appid”,Configure.getAppid());//公众账号ID  
  371.         inputObj.SetValue(”mch_id”,Configure.getMchid());//商户号  
  372.         inputObj.SetValue(”nonce_str”,GenerateNonceStr());//随机字符串  
  373.         inputObj.SetValue(”sign”,inputObj.MakeSign());//签名  
  374.   
  375.         String xml = inputObj.ToXml();  
  376.       
  377.         
  378.         HttpsRequest https=new HttpsRequest();  
  379.         https.setSocketTimeout(timeOut);  
  380.         String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API  
  381.         WxPayData result = new WxPayData();  
  382.         result.FromXml(response);  
  383.   
  384.         return result;  
  385.     }  
  386.   
  387.   
  388.     /** 
  389.     * 下载对账单 
  390.     * @param WxPayData inputObj 提交给下载对账单API的参数 
  391.     * @param int timeOut 接口超时时间 
  392.     * @throws WxPayException 
  393.     * @return 成功时返回,其他抛异常 
  394.      * @throws IOException  
  395.      * @throws NoSuchAlgorithmException  
  396.      * @throws KeyStoreException  
  397.      * @throws KeyManagementException  
  398.      * @throws UnrecoverableKeyException  
  399.      * @throws SAXException  
  400.      * @throws ParserConfigurationException  
  401.     */  
  402.     public static WxPayData DownloadBill(WxPayData inputObj, int timeOut) throws UnrecoverableKeyException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, IOException, WxPayException, ParserConfigurationException, SAXException  
  403.     {  
  404.         String url = Configure.DOWNLOAD_BILL_API;  
  405.         //检测必填参数  
  406.         if (!inputObj.IsSet(“bill_date”))  
  407.         {  
  408.             throw new WxPayException(“对账单接口中,缺少必填参数bill_date!”);  
  409.         }  
  410.   
  411.         inputObj.SetValue(”appid”, Configure.getAppid());//公众账号ID  
  412.         inputObj.SetValue(”mch_id”, Configure.getMchid());//商户号  
  413.         inputObj.SetValue(”nonce_str”, GenerateNonceStr());//随机字符串  
  414.         inputObj.SetValue(”sign”, inputObj.MakeSign());//签名  
  415.   
  416.         String xml = inputObj.ToXml();  
  417.   
  418.         HttpsRequest https=new HttpsRequest();  
  419.         https.setSocketTimeout(timeOut);  
  420.         String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API  
  421.        
  422.         WxPayData result = new WxPayData();  
  423.         //若接口调用失败会返回xml格式的结果  
  424.         if (response.startsWith())  
  425.         {  
  426.           
  427.                result.FromXml(response);  
  428.         }  
  429.         //接口调用成功则返回非xml格式的数据  
  430.         else  
  431.             result.SetValue(”result”, response);  
  432.   
  433.         return result;  
  434.     }  
  435.   
  436.   
  437.     /** 
  438.     *  
  439.     * 转换短链接 
  440.     * 该接口主要用于扫码原生支付模式一中的二维码链接转成短链接(weixin://wxpay/s/XXXXXX), 
  441.     * 减小二维码数据量,提升扫描速度和精确度。 
  442.     * @param WxPayData inputObj 提交给转换短连接API的参数 
  443.     * @param int timeOut 接口超时时间 
  444.     * @throws WxPayException 
  445.     * @return 成功时返回,其他抛异常 
  446.      * @throws IOException  
  447.      * @throws KeyStoreException  
  448.      * @throws NoSuchAlgorithmException  
  449.      * @throws KeyManagementException  
  450.      * @throws UnrecoverableKeyException  
  451.      * @throws SAXException  
  452.      * @throws ParserConfigurationException  
  453.     */  
  454.     public static WxPayData ShortUrl(WxPayData inputObj, int timeOut) throws WxPayException, UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, ParserConfigurationException, SAXException  
  455.     {  
  456.         String url = Configure.Shorturl_API;  
  457.         //检测必填参数  
  458.         if(!inputObj.IsSet(“long_url”))  
  459.         {  
  460.             throw new WxPayException(“需要转换的URL,签名用原串,传输需URL encode!”);  
  461.         }  
  462.   
  463.         inputObj.SetValue(”appid”,Configure.getAppid());//公众账号ID  
  464.         inputObj.SetValue(”mch_id”,Configure.getMchid());//商户号  
  465.         inputObj.SetValue(”nonce_str”,GenerateNonceStr());//随机字符串     
  466.         inputObj.SetValue(”sign”,inputObj.MakeSign());//签名  
  467.         String xml = inputObj.ToXml();  
  468.       
  469.         HttpsRequest https=new HttpsRequest();  
  470.         https.setSocketTimeout(timeOut);  
  471.         String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API  
  472.         WxPayData result = new WxPayData();  
  473.         result.FromXml(response);  
  474.   
  475.   
  476.   
  477.       
  478.         return result;  
  479.     }  
  480.   
  481.   
  482.     /** 
  483.     *  
  484.     * 统一下单 
  485.     * @param WxPaydata inputObj 提交给统一下单API的参数 
  486.     * @param int timeOut 超时时间 
  487.     * @throws WxPayException 
  488.     * @return 成功时返回,其他抛异常 
  489.      * @throws IOException  
  490.      * @throws KeyStoreException  
  491.      * @throws NoSuchAlgorithmException  
  492.      * @throws KeyManagementException  
  493.      * @throws UnrecoverableKeyException  
  494.      * @throws SAXException  
  495.      * @throws ParserConfigurationException  
  496.     */  
  497.     public static WxPayData UnifiedOrder(WxPayData inputObj, int timeOut) throws WxPayException, UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, ParserConfigurationException, SAXException  
  498.     {  
  499.         String url =Configure.UnifiedOrder_API;  
  500.         //检测必填参数  
  501.         if (!inputObj.IsSet(“out_trade_no”))  
  502.         {  
  503.             throw new WxPayException(“缺少统一支付接口必填参数out_trade_no!”);  
  504.         }  
  505.         else if (!inputObj.IsSet(“body”))  
  506.         {  
  507.             throw new WxPayException(“缺少统一支付接口必填参数body!”);  
  508.         }  
  509.         else if (!inputObj.IsSet(“total_fee”))  
  510.         {  
  511.             throw new WxPayException(“缺少统一支付接口必填参数total_fee!”);  
  512.         }  
  513.         else if (!inputObj.IsSet(“trade_type”))  
  514.         {  
  515.             throw new WxPayException(“缺少统一支付接口必填参数trade_type!”);  
  516.         }  
  517.   
  518.         //关联参数  
  519.         if (inputObj.GetValue(“trade_type”).toString() == “JSAPI” && !inputObj.IsSet(“openid”))  
  520.         {  
  521.             throw new WxPayException(“统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!”);  
  522.         }  
  523.         if (inputObj.GetValue(“trade_type”).toString() == “NATIVE” && !inputObj.IsSet(“product_id”))  
  524.         {  
  525.             throw new WxPayException(“统一支付接口中,缺少必填参数product_id!trade_type为JSAPI时,product_id为必填参数!”);  
  526.         }  
  527.   
  528.         //异步通知url未设置,则使用配置文件中的url  
  529.         if (!inputObj.IsSet(“notify_url”))  
  530.         {  
  531.             inputObj.SetValue(”notify_url”, Configure.NOTIFY_URL);//异步通知url  
  532.         }  
  533.   
  534.         inputObj.SetValue(”appid”, Configure.getAppid());//公众账号ID  
  535.         inputObj.SetValue(”mch_id”, Configure.getMchid());//商户号  
  536.         inputObj.SetValue(”spbill_create_ip”, Configure.getIP());//终端ip           
  537.         inputObj.SetValue(”nonce_str”, GenerateNonceStr());//随机字符串  
  538.   
  539.         //签名  
  540.         inputObj.SetValue(”sign”, inputObj.MakeSign());  
  541.         String xml = inputObj.ToXml();  
  542.   
  543.      
  544.         HttpsRequest https=new HttpsRequest();  
  545.         https.setSocketTimeout(timeOut);  
  546.         String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API  
  547.         WxPayData result = new WxPayData();  
  548.         result.FromXml(response);  
  549.   
  550.   
  551.   
  552.         return result;  
  553.     }  
  554.   
  555.   
  556.     /** 
  557.     *  
  558.     * 关闭订单 
  559.     * @param WxPayData inputObj 提交给关闭订单API的参数 
  560.     * @param int timeOut 接口超时时间 
  561.     * @throws WxPayException 
  562.     * @return 成功时返回,其他抛异常 
  563.      * @throws IOException  
  564.      * @throws KeyStoreException  
  565.      * @throws NoSuchAlgorithmException  
  566.      * @throws KeyManagementException  
  567.      * @throws UnrecoverableKeyException  
  568.      * @throws SAXException  
  569.      * @throws ParserConfigurationException  
  570.     */  
  571.     public static WxPayData CloseOrder(WxPayData inputObj, int timeOut) throws WxPayException, UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, ParserConfigurationException, SAXException  
  572.     {  
  573.           
  574.         String url =Configure.CloseOrder_API;  
  575.         //检测必填参数  
  576.         if(!inputObj.IsSet(“out_trade_no”))  
  577.         {  
  578.             throw new WxPayException(“关闭订单接口中,out_trade_no必填!”);  
  579.         }  
  580.   
  581.         inputObj.SetValue(”appid”,Configure.getAppid());//公众账号ID  
  582.         inputObj.SetValue(”mch_id”,Configure.getMchid());//商户号  
  583.         inputObj.SetValue(”nonce_str”,GenerateNonceStr());//随机字符串         
  584.         inputObj.SetValue(”sign”,inputObj.MakeSign());//签名  
  585.         String xml = inputObj.ToXml();  
  586.       
  587.         HttpsRequest https=new HttpsRequest();  
  588.         https.setSocketTimeout(timeOut);  
  589.         String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API  
  590.         WxPayData result = new WxPayData();  
  591.         result.FromXml(response);  
  592.   
  593.       
  594.         return result;  
  595.     }  
  596.   
  597.   
  598.     /** 
  599.     *  
  600.     * 测速上报 
  601.     * @param String interface_url 接口URL 
  602.     * @param int timeCost 接口耗时 
  603.     * @param WxPayData inputObj参数数组 
  604.     */  
  605.     private static void ReportCostTime(String interface_url, int timeCost, WxPayData inputObj)  
  606.     {  
  607.         //如果不需要进行上报  
  608.         if(REPORT_LEVENL == 0)  
  609.         {  
  610.             return;  
  611.         }   
  612.   
  613.         //如果仅失败上报  
  614.         if(REPORT_LEVENL == 1 && inputObj.IsSet(“return_code”) && inputObj.GetValue(“return_code”).toString() == “SUCCESS” &&  
  615.          inputObj.IsSet(”result_code”) && inputObj.GetValue(“result_code”).toString() == “SUCCESS”)  
  616.         {  
  617.             return;  
  618.         }  
  619.        
  620.         //上报逻辑  
  621.         WxPayData data = new WxPayData();  
  622.         data.SetValue(”interface_url”,interface_url);  
  623.         data.SetValue(”execute_time_”,timeCost);  
  624.         //返回状态码  
  625.         if(inputObj.IsSet(“return_code”))  
  626.         {  
  627.             data.SetValue(”return_code”,inputObj.GetValue(“return_code”));  
  628.         }  
  629.         //返回信息  
  630.         if(inputObj.IsSet(“return_msg”))  
  631.         {  
  632.             data.SetValue(”return_msg”,inputObj.GetValue(“return_msg”));  
  633.         }  
  634.         //业务结果  
  635.         if(inputObj.IsSet(“result_code”))  
  636.         {  
  637.             data.SetValue(”result_code”,inputObj.GetValue(“result_code”));  
  638.         }  
  639.         //错误代码  
  640.         if(inputObj.IsSet(“err_code”))  
  641.         {  
  642.             data.SetValue(”err_code”,inputObj.GetValue(“err_code”));  
  643.         }  
  644.         //错误代码描述  
  645.         if(inputObj.IsSet(“err_code_des”))  
  646.         {  
  647.             data.SetValue(”err_code_des”,inputObj.GetValue(“err_code_des”));  
  648.         }  
  649.         //商户订单号  
  650.         if(inputObj.IsSet(“out_trade_no”))  
  651.         {  
  652.             data.SetValue(”out_trade_no”,inputObj.GetValue(“out_trade_no”));  
  653.         }  
  654.         //设备号  
  655.         if(inputObj.IsSet(“device_info”))  
  656.         {  
  657.             data.SetValue(”device_info”,inputObj.GetValue(“device_info”));  
  658.         }  
  659.       
  660.     }  
  661.   
  662.   
  663.     /** 
  664.     *  
  665.     * 测速上报接口实现 
  666.     * @param WxPayData inputObj 提交给测速上报接口的参数 
  667.     * @param int timeOut 测速上报接口超时时间 
  668.     * @throws WxPayException 
  669.     * @return 成功时返回测速上报接口返回的结果,其他抛异常 
  670.      * @throws IOException  
  671.      * @throws KeyStoreException  
  672.      * @throws NoSuchAlgorithmException  
  673.      * @throws KeyManagementException  
  674.      * @throws UnrecoverableKeyException  
  675.      * @throws SAXException  
  676.      * @throws ParserConfigurationException  
  677.     */  
  678.     public static WxPayData Report(WxPayData inputObj, int timeOut) throws WxPayException, UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, ParserConfigurationException, SAXException  
  679.     {  
  680.         String url = Configure.REPORT_API;  
  681.         //检测必填参数  
  682.         if(!inputObj.IsSet(“interface_url”))  
  683.         {  
  684.             throw new WxPayException(“接口URL,缺少必填参数interface_url!”);  
  685.         }   
  686.         if(!inputObj.IsSet(“return_code”))  
  687.         {  
  688.             throw new WxPayException(“返回状态码,缺少必填参数return_code!”);  
  689.         }   
  690.         if(!inputObj.IsSet(“result_code”))  
  691.         {  
  692.             throw new WxPayException(“业务结果,缺少必填参数result_code!”);  
  693.         }   
  694.         if(!inputObj.IsSet(“user_ip”))  
  695.         {  
  696.             throw new WxPayException(“访问接口IP,缺少必填参数user_ip!”);  
  697.         }   
  698.         if(!inputObj.IsSet(“execute_time_”))  
  699.         {  
  700.             throw new WxPayException(“接口耗时,缺少必填参数execute_time_!”);  
  701.         }  
  702.   
  703.         inputObj.SetValue(”appid”,Configure.getAppid());//公众账号ID  
  704.         inputObj.SetValue(”mch_id”,Configure.getMchid());//商户号  
  705.         inputObj.SetValue(”user_ip”,Configure.getIP());//终端ip  
  706.         inputObj.SetValue(”time”,CommonClass.GetCurrentDateTimeTextNosplit());//商户上报时间     
  707.         inputObj.SetValue(”nonce_str”,GenerateNonceStr());//随机字符串  
  708.         inputObj.SetValue(”sign”,inputObj.MakeSign());//签名  
  709.         String xml = inputObj.ToXml();  
  710.   
  711.         HttpsRequest https=new HttpsRequest();  
  712.         https.setSocketTimeout(timeOut);  
  713.         String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API  
  714.         WxPayData result = new WxPayData();  
  715.         result.FromXml(response);  
  716.   
  717.         return result;  
  718.     }  
  719.   
  720.     /** 
  721.     * 根据当前系统时间加随机序列来生成订单号 
  722.      * @return 订单号 
  723.     */  
  724.     public static String GenerateOutTradeNo()  
  725.     {  
  726.         Random ran = new Random();  
  727.         return String.format(“{0}{1}{2}”, Configure.getMchid(),CommonClass.GetCurrentDateTimeTextNosplit(), ran.nextInt(999));  
  728.     }  
  729.   
  730.     /** 
  731.     * 生成时间戳,标准北京时间,时区为东八区,自1970年1月1日 0点0分0秒以来的秒数 
  732.      * @return 时间戳 
  733.     */  
  734.     public static String GenerateTimeStamp()  
  735.     {  
  736.         //Java中的getTime方法默认的是从1970 1 1 算起所以可以直接调用  
  737.         //date.getTime获得的是毫秒数,不是秒,所以最后的结果day应当再除以1000才对。  
  738.         return String.valueOf(Calendar.getInstance().getTimeInMillis()/1000);  
  739.     }  
  740.   
  741.     /** 
  742.     * 生成随机串,随机串包含字母或数字 
  743.     * @return 随机串 
  744.     */  
  745.     public static String GenerateNonceStr()  
  746.     {  
  747.         return UUIDGenerator.getUUID().toString().replace(“-““”);  
  748.     }  
  749. }  

  750.   
  751. ”2067985” snippet_file_name=“blog_20161222_3_3558714” name=“code” class=“java”>package com.luozhuang;  
  752.   
  753. import java.io.IOException;  
  754. import java.util.Map;  
  755. import java.util.SortedMap;  
  756. import java.util.TreeMap;  
  757. import java.util.regex.Matcher;  
  758. import java.util.regex.Pattern;  
  759.   
  760. import javax.xml.parsers.ParserConfigurationException;  
  761.   
  762. import org.slf4j.Logger;  
  763. import org.xml.sax.SAXException;  
  764.   
  765. import com.alibaba.fastjson.JSON;  
  766. import com.luozhuang.util.Configure;  
  767. import com.luozhuang.util.MD5;  
  768. import com.luozhuang.util.PayCommonUtil;  
  769. import com.luozhuang.util.XMLParser;  
  770.   
  771. ///   
  772. /// 微信支付协议接口数据类,所有的API接口通信都依赖这个数据结构,  
  773. /// 在调用接口之前先填充各个字段的值,然后进行接口通信,  
  774. /// 这样设计的好处是可扩展性强,用户可随意对协议进行更改而不用重新设计数据结构,  
  775. /// 还可以随意组合出不同的协议数据包,不用为每个协议设计一个数据包结构  
  776. ///   
  777. public class WxPayData {  
  778.   
  779.     private static Logger Log = new Logger();  
  780.   
  781.     public WxPayData() {  
  782.   
  783.     }  
  784.   
  785.     // 采用排序的Dictionary的好处是方便对数据包进行签名,不用再签名之前再做一次排序  
  786.     private SortedMap m_values = new TreeMap();  
  787.   
  788.       
  789.     public void put(String key, String value) {  
  790.         SetValue(key, value);  
  791.           
  792.     }  
  793.     /** 
  794.      * 设置某个字段的值 
  795.      *  
  796.      * @param key 
  797.      *            字段名 
  798.      * @param value 
  799.      *            字段值 
  800.      */  
  801.     public void SetValue(String key, Object value) {  
  802.         m_values.put(key, value);  
  803.     }  
  804.   
  805.     /** 
  806.      * 根据字段名获取某个字段的值 
  807.      *  
  808.      * @param key 
  809.      *            字段名 
  810.      * @return key对应的字段值 
  811.      */  
  812.     public Object GetValue(String key) {  
  813.         Object o = m_values.get(key);  
  814.         return o;  
  815.     }  
  816.   
  817.     /** 
  818.      * 判断某个字段是否已设置 
  819.      *  
  820.      * @param key 
  821.      *            字段名 
  822.      * @return 若字段key已被设置,则返回true,否则返回false 
  823.      */  
  824.     public boolean IsSet(String key) {  
  825.   
  826.         Object o = m_values.get(key);  
  827.         if (null != o)  
  828.             return true;  
  829.         else  
  830.             return false;  
  831.     }  
  832.   
  833.     /** 
  834.      * @将Dictionary转成xml 
  835.      * @return 经转换得到的xml串 
  836.      * @throws WxPayException 
  837.      **/  
  838.     public String ToXml() throws WxPayException {  
  839.         // 数据为空时不能转化为xml格式  
  840.         if (0 == m_values.size()) {  
  841.   
  842.             throw new WxPayException(“WxPayData数据为空!”);  
  843.         }  
  844.   
  845.         /* 
  846.          * String xml = ””; for (Map.Entry pair : 
  847.          * m_values.entrySet()) 
  848.          *  
  849.          * { // 字段值不能为null,会影响后续流程 if (pair.getValue() == null) { 
  850.          *  
  851.          * throw new WxPayException(“WxPayData内部含有值为null的字段!”); } 
  852.          *  
  853.          * if (pair.getValue() instanceof Integer) { xml += ”<” + pair.getKey() 
  854.          * + ”>” + pair.getValue() + ””; } else if 
  855.          * (pair.getValue() instanceof String) { xml += ”<” + pair.getKey() + 
  856.          * ”>” + ””; 
  857.          * } else// 除了String和int类型不能含有其他数据类型 { 
  858.          *  
  859.          * throw new WxPayException(“WxPayData字段数据类型错误!”); } } xml += ””; 
  860.          */  
  861.         return PayCommonUtil.getRequestXml(m_values);  
  862.     }  
  863.   
  864.     /** 
  865.      * @将xml转为WxPayData对象并返回对象内部的数据 
  866.      * @param String 
  867.      *            待转换的xml串 
  868.      * @return 经转换得到的Dictionary 
  869.      * @throws WxPayException 
  870.      * @throws SAXException 
  871.      * @throws IOException 
  872.      * @throws ParserConfigurationException 
  873.      */  
  874.     public SortedMap FromXml(String xml)  
  875.             throws WxPayException, ParserConfigurationException, IOException, SAXException {  
  876.         if (xml == null) {  
  877.   
  878.             throw new WxPayException(“将空的xml串转换为WxPayData不合法!”);  
  879.         }  
  880.   
  881.         m_values = XMLParser.getMapFromXML(xml);  
  882.   
  883.         // 2015-06-29 错误是没有签名  
  884.         if (m_values.get(“return_code”) != “SUCCESS”) {  
  885.             return m_values;  
  886.         }  
  887.         CheckSign();// 验证签名,不通过会抛异常  
  888.   
  889.         return m_values;  
  890.     }  
  891.   
  892.     /** 
  893.      * @throws WxPayException  
  894.      * @Dictionary格式转化成url参数格式 @ return url格式串, 该串不包含sign字段值 
  895.      */  
  896.     public String ToUrl() throws WxPayException {  
  897.         String buff = ”“;  
  898.         for (Map.Entry pair : m_values.entrySet()) {  
  899.             if (pair.getValue() == null) {  
  900.                 throw new WxPayException(“WxPayData内部含有值为null的字段!”);  
  901.             }  
  902.   
  903.             if (pair.getKey() != “sign” && pair.getValue().toString() != “”) {  
  904.                 buff += pair.getKey() + ”=” + pair.getValue() + “&”;  
  905.             }  
  906.         }  
  907.         buff = sideTrim(buff, ”&”);  
  908.         return buff;  
  909.     }  
  910.   
  911.     /** 
  912.      * 
  913.      *  
  914.      * 去掉指定字符串的开头和结尾的指定字符 
  915.      *  
  916.      * 
  917.      *  
  918.      * @param stream 
  919.      *            要处理的字符串 
  920.      * @param trimstr 
  921.      *            要去掉的字符串 
  922.      * @return 处理后的字符串 
  923.      */  
  924.     public static String sideTrim(String stream, String trimstr) {  
  925.         // null或者空字符串的时候不处理  
  926.         if (stream == null || stream.length() == 0 || trimstr == null || trimstr.length() == 0) {  
  927.             return stream;  
  928.         }  
  929.   
  930.         // 结束位置  
  931.         int epos = 0;  
  932.   
  933.         // 正规表达式  
  934.         String regpattern = ”[“ + trimstr + “]*+”;  
  935.         Pattern pattern = Pattern.compile(regpattern, Pattern.CASE_INSENSITIVE);  
  936.   
  937.         // 去掉结尾的指定字符  
  938.         StringBuffer buffer = new StringBuffer(stream).reverse();  
  939.         Matcher matcher = pattern.matcher(buffer);  
  940.         if (matcher.lookingAt()) {  
  941.             epos = matcher.end();  
  942.             stream = new StringBuffer(buffer.substring(epos)).reverse().toString();  
  943.         }  
  944.   
  945.         // 去掉开头的指定字符  
  946.         matcher = pattern.matcher(stream);  
  947.         if (matcher.lookingAt()) {  
  948.             epos = matcher.end();  
  949.             stream = stream.substring(epos);  
  950.         }  
  951.   
  952.         // 返回处理后的字符串  
  953.         return stream;  
  954.     }  
  955.   
  956.     /** 
  957.      * @Dictionary格式化成Json 
  958.      * @return json串数据 
  959.      */  
  960.     public String ToJson() {  
  961.         String jsonStr = JSON.toJSONString(m_values);  
  962.         return jsonStr;  
  963.     }  
  964.   
  965.     /** 
  966.      * @throws WxPayException 
  967.      * @values格式化成能在Web页面上显示的结果(因为web页面上不能直接输出xml格式的字符串) 
  968.      */  
  969.     public String ToPrintStr() throws WxPayException {  
  970.         String str = ”“;  
  971.         for (Map.Entry pair : m_values.entrySet()) {  
  972.             if (pair.getValue() == null) {  
  973.   
  974.                 throw new WxPayException(“WxPayData内部含有值为null的字段!”);  
  975.             }  
  976.   
  977.             str += String.format(”{0}={1}
    , pair.getKey(), pair.getValue().toString());  
  978.         }  
  979.   
  980.         return str;  
  981.     }  
  982.   
  983.     /** 
  984.      * @生成签名,详见签名生成算法 
  985.      * @return 签名, sign字段不参加签名 
  986.      * @throws WxPayException  
  987.      */  
  988.     public String MakeSign() throws WxPayException {  
  989.         // 转url格式  
  990.         String str = ToUrl();  
  991.         // 在String后加入API KEY  
  992.         str += ”&key=” + Configure.getKey();  
  993.         // MD5加密  
  994. //PayCommonUtil.createSign(“UTF-8”, packageParams,key)  
  995.         // 所有字符转为大写  
  996.         return MD5.MD5Encode(str, “UTF-8”).toUpperCase();  
  997.     }  
  998.   
  999.     /** 
  1000.      *  
  1001.      * 检测签名是否正确 正确返回true,错误抛异常 
  1002.      *  
  1003.      * @throws WxPayException 
  1004.      */  
  1005.     public boolean CheckSign() throws WxPayException {  
  1006.         // 如果没有设置签名,则跳过检测  
  1007.         if (!IsSet(“sign”)) {  
  1008.   
  1009.             throw new WxPayException(“WxPayData签名存在但不合法!”);  
  1010.         }  
  1011.         // 如果设置了签名但是签名为空,则抛异常  
  1012.         else if (GetValue(“sign”) == null || GetValue(“sign”).toString() == “”) {  
  1013.   
  1014.             throw new WxPayException(“WxPayData签名存在但不合法!”);  
  1015.         }  
  1016.   
  1017.         // 获取接收到的签名  
  1018.         String return_sign = GetValue(”sign”).toString();  
  1019.   
  1020.         // 在本地计算新的签名  
  1021.         String cal_sign = MakeSign();  
  1022.   
  1023.         if (cal_sign == return_sign) {  
  1024.             return true;  
  1025.         }  
  1026.   
  1027.         throw new WxPayException(“WxPayData签名验证错误!”);  
  1028.     }  
  1029.   
  1030.     /** 
  1031.      * @获取Dictionary 
  1032.      */  
  1033.     public SortedMap GetValues() {  
  1034.         return m_values;  
  1035.     }  
  1036.   
  1037.       
  1038. }
      
  1039. ”2067985” snippet_file_name=“blog_20161222_4_9512532” name=“code” class=“java”>package com.luozhuang;  
  1040.   
  1041. public class WxPayException extends Exception {  
  1042.   
  1043.     public WxPayException(String string) {  
  1044.         super(string);  
  1045.     }  
  1046.    
  1047. }  

  1048.   
  1049. ”2067985” snippet_file_name=“blog_20161222_5_4386556” name=“code” class=“java”>package com.luozhuang.util;  
  1050.   
  1051. /** 
  1052.  * luozhuang 这里放置各种配置数据 
  1053.  */  
  1054. public class Configure {  
  1055.   
  1056.     // 回调地址  
  1057.   
  1058.     public static final String NOTIFY_URL = “http://www.weixin.qq.com/wxpay/pay.php”;  
  1059.   
  1060.     /** 
  1061.      * 这个就是自己要保管好的私有Key了(切记只能放在自己的后台代码里,不能放在任何可能被看到源代码的客户端程序中) 
  1062.      *  
  1063.      * 每次自己Post数据给API的时候都要用这个key来对所有字段进行签名,生成的签名会放在Sign这个字段,API收到Post数据的时候也会用同样的签名算法对Post过来的数据进行签名和验证 
  1064.      * 收到API的返回的时候也要用这个key来对返回的数据算下签名,跟API的Sign数据进行比较,如果值不一致,有可能数据被第三方给篡改 
  1065.      */  
  1066.     private static String key = “luozhuang”;  
  1067.   
  1068.     /** 
  1069.      * 微信分配的公众号ID(开通公众号之后可以获取到) 
  1070.      *  
  1071.      */  
  1072.     private static String appID = “luozhuang”;  
  1073.   
  1074.     /** 
  1075.      * 微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到) 
  1076.      *  
  1077.      */  
  1078.     private static String mchID = “luozhuang”;  
  1079.   
  1080.     /** 
  1081.      * 受理模式下给子商户分配的子商户号 
  1082.      *  
  1083.      */  
  1084.     private static String subMchID = “luozhuang”;  
  1085.   
  1086.     /** 
  1087.      * HTTPS证书的本地路径 
  1088.      *  
  1089.      */  
  1090.     private static String certLocalPath = “C:\\Users\\luozhuang\\my.store”;  
  1091.   
  1092.     /** 
  1093.      * HTTPS证书密码,默认密码等于商户号MCHID 
  1094.      *  
  1095.      */  
  1096.     private static String certPassword = “luozhuang”;  
  1097.   
  1098.     /** 
  1099.      * 是否使用异步线程的方式来上报API测速,默认为异步模式 
  1100.      *  
  1101.      */  
  1102.     private static boolean useThreadToDoReport = true;  
  1103.   
  1104.     /** 
  1105.      * 机器IP 
  1106.      *  
  1107.      */  
  1108.     private static String ip = “luozhuang”;  
  1109.   
  1110.     // 以下是几个API的路径:  
  1111.     /** 
  1112.      * 1)被扫支付API 
  1113.      *  
  1114.      */  
  1115.     public static String PAY_API = “https://api.mch.weixin.qq.com/pay/micropay”;  
  1116.   
  1117.     /** 
  1118.      * 2)被扫支付查询API 
  1119.      *  
  1120.      */  
  1121.     public static String PAY_QUERY_API = “https://api.mch.weixin.qq.com/pay/orderquery”;  
  1122.   
  1123.     /** 
  1124.      * 3)退款API 
  1125.      *  
  1126.      */  
  1127.     public static String REFUND_API = “https://api.mch.weixin.qq.com/secapi/pay/refund”;  
  1128.   
  1129.     /** 
  1130.      * 4)退款查询API 
  1131.      *  
  1132.      */  
  1133.     public static String REFUND_QUERY_API = “https://api.mch.weixin.qq.com/pay/refundquery”;  
  1134.   
  1135.     /** 
  1136.      * 5)撤销API 
  1137.      *  
  1138.      */  
  1139.     public static String REVERSE_API = “https://api.mch.weixin.qq.com/secapi/pay/reverse”;  
  1140.   
  1141.     /** 
  1142.      * 6)下载对账单API 
  1143.      *  
  1144.      */  
  1145.     public static String DOWNLOAD_BILL_API = “https://api.mch.weixin.qq.com/pay/downloadbill”;  
  1146.   
  1147.     /** 
  1148.      * 7) 统计上报API 
  1149.      *  
  1150.      */  
  1151.     public static String REPORT_API = “https://api.mch.weixin.qq.com/payitil/report”;  
  1152.   
  1153.     /** 
  1154.      * 转换短链接 
  1155.      */  
  1156.     public static String Shorturl_API = “https://api.mch.weixin.qq.com/tools/shorturl”;  
  1157.   
  1158.     /** 
  1159.      * 统一下单 
  1160.      */  
  1161.     public static String UnifiedOrder_API = “https://api.mch.weixin.qq.com/pay/unifiedorder”;  
  1162.   
  1163.     /** 
  1164.      * 关闭订单 
  1165.      */  
  1166.     public static String CloseOrder_API = “https://api.mch.weixin.qq.com/pay/closeorder”;  
  1167.   
  1168.     public static boolean isUseThreadToDoReport() {  
  1169.         return useThreadToDoReport;  
  1170.     }  
  1171.   
  1172.     public static void setUseThreadToDoReport(boolean useThreadToDoReport) {  
  1173.         Configure.useThreadToDoReport = useThreadToDoReport;  
  1174.     }  
  1175.   
  1176.     public static String HttpsRequestClassName = “com.tencent.common.HttpsRequest”;  
  1177.   
  1178.     public static void setKey(String key) {  
  1179.         Configure.key = key;  
  1180.     }  
  1181.   
  1182.     public static void setAppID(String appID) {  
  1183.         Configure.appID = appID;  
  1184.     }  
  1185.   
  1186.     public static void setMchID(String mchID) {  
  1187.         Configure.mchID = mchID;  
  1188.     }  
  1189.   
  1190.     public static void setSubMchID(String subMchID) {  
  1191.         Configure.subMchID = subMchID;  
  1192.     }  
  1193.   
  1194.     public static void setCertLocalPath(String certLocalPath) {  
  1195.         Configure.certLocalPath = certLocalPath;  
  1196.     }  
  1197.   
  1198.     public static void setCertPassword(String certPassword) {  
  1199.         Configure.certPassword = certPassword;  
  1200.     }  
  1201.   
  1202.     public static void setIp(String ip) {  
  1203.         Configure.ip = ip;  
  1204.     }  
  1205.   
  1206.     public static String getKey() {  
  1207.         return key;  
  1208.     }  
  1209.   
  1210.     public static String getAppid() {  
  1211.         return appID;  
  1212.     }  
  1213.   
  1214.     public static String getMchid() {  
  1215.         return mchID;  
  1216.     }  
  1217.   
  1218.     public static String getSubMchid() {  
  1219.         return subMchID;  
  1220.     }  
  1221.   
  1222.     public static String getCertLocalPath() {  
  1223.         return certLocalPath;  
  1224.     }  
  1225.   
  1226.     public static String getCertPassword() {  
  1227.         return certPassword;  
  1228.     }  
  1229.   
  1230.     public static String getIP() {  
  1231.         return ip;  
  1232.     }  
  1233.   
  1234.     public static void setHttpsRequestClassName(String name) {  
  1235.         HttpsRequestClassName = name;  
  1236.     }  
  1237.   
  1238. }  

  1239.   
  1240. ”2067985” snippet_file_name=“blog_20161222_6_9293599” name=“code” class=“java”>package com.luozhuang.util;  
  1241.   
  1242. import com.thoughtworks.xstream.XStream;  
  1243. import com.thoughtworks.xstream.io.xml.DomDriver;  
  1244. import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;  
  1245. import org.apache.http.HttpEntity;  
  1246. import org.apache.http.HttpResponse;  
  1247. import org.apache.http.client.config.RequestConfig;  
  1248. import org.apache.http.client.methods.HttpPost;  
  1249. import org.apache.http.conn.ConnectTimeoutException;  
  1250. import org.apache.http.conn.ConnectionPoolTimeoutException;  
  1251. import org.apache.http.conn.ssl.SSLConnectionSocketFactory;  
  1252. import org.apache.http.conn.ssl.SSLContexts;  
  1253. import org.apache.http.entity.StringEntity;  
  1254. import org.apache.http.impl.client.CloseableHttpClient;  
  1255. import org.apache.http.impl.client.HttpClients;  
  1256. import org.apache.http.util.EntityUtils;  
  1257. import org.slf4j.Logger;  
  1258. import org.slf4j.LoggerFactory;  
  1259.   
  1260. import javax.net.ssl.SSLContext;  
  1261. import java.io.File;  
  1262. import java.io.FileInputStream;  
  1263. import java.io.IOException;  
  1264. import java.io.InputStream;  
  1265. import java.net.SocketTimeoutException;  
  1266. import java.security.*;  
  1267. import java.security.cert.CertificateException;  
  1268.   
  1269. /** 
  1270.  * luozhuang 
  1271.  */  
  1272. public class HttpsRequest {  
  1273.   
  1274.     public interface ResultListener {  
  1275.   
  1276.         public void onConnectionPoolTimeoutError();  
  1277.   
  1278.     }  
  1279.   
  1280.     private static Logger log = new Logger();  
  1281.   
  1282.     // 表示请求器是否已经做了初始化工作  
  1283.     private boolean hasInit = false;  
  1284.   
  1285.     // 连接超时时间,默认10秒  
  1286.     private int socketTimeout = 10000;  
  1287.   
  1288.     // 传输超时时间,默认30秒  
  1289.     private int connectTimeout = 30000;  
  1290.   
  1291.     // 请求器的配置  
  1292.     private RequestConfig requestConfig;  
  1293.   
  1294.     // HTTP请求器  
  1295.     private CloseableHttpClient httpClient;  
  1296.   
  1297.     public HttpsRequest() throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException,  
  1298.             KeyStoreException, IOException {  
  1299.         init();  
  1300.     }  
  1301.   
  1302.     /** 
  1303.      * 对安全性有要求的网站一般使用https来加密传输的请求和响应。https离不开证书,关于证书不在多说。Apache的HttpClient支持https, 
  1304.      * 面是官方的样例程序,程序中使用了my.store这个文件, 
  1305.      * 这个文件不是网站的证书,而是一份包含自己密码的自己的证书库。这个文件是需要自己生成的,使用jdk中的keytool命令可以很方便的生成my.store文件。步骤如下(以支付宝为例): 
  1306.      * 浏览器(以chrome为例)访问https://www.alipay.com/,点击域名左侧的小锁,可以查看支付宝的证书信息 
  1307.      *  
  1308.      *  
  1309.      * 将支付包的证书信息导出,证书格式有很多中,der、cer等。随便选择即可。 命令行或者shell执行 keytool -import -alias 
  1310.      * “my alipay cert” -file www.alipay.com.cert -keystore my.store, 
  1311.      * 如果keytool命令不识别,去检查一下jdk的环境变量是否设置正确。”my alipay 
  1312.      * cert”是个别名,随便取。“www.alipay.com.cert”这个文件就是从浏览器中导出的支付宝的证书。 
  1313.      *  
  1314.      * @throws IOException 
  1315.      * @throws KeyStoreException 
  1316.      * @throws UnrecoverableKeyException 
  1317.      * @throws NoSuchAlgorithmException 
  1318.      * @throws KeyManagementException 
  1319.      */  
  1320.     private void init() throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException,  
  1321.             KeyManagementException {  
  1322.         if (Configure.getCertLocalPath() == null || Configure.getCertLocalPath().length() < 1) {  
  1323.   
  1324.         }  
  1325.          KeyStore keyStore  = KeyStore.getInstance(KeyStore.getDefaultType());  
  1326.         FileInputStream instream = new FileInputStream(new File(Configure.getCertLocalPath()));// 加载本地的证书进行https加密传输  
  1327.         try {  
  1328.             keyStore.load(instream, Configure.getCertPassword().toCharArray());// 设置证书密码  
  1329.         } catch (CertificateException e) {  
  1330.             e.printStackTrace();  
  1331.         } catch (NoSuchAlgorithmException e) {  
  1332.             e.printStackTrace();  
  1333.         } finally {  
  1334.             instream.close();  
  1335.         }  
  1336.   
  1337.         // Trust own CA and all self-signed certs  
  1338.         SSLContext sslcontext = SSLContexts.custom()  
  1339.                 .loadKeyMaterial(keyStore, Configure.getCertPassword().toCharArray()).build();  
  1340.         // Allow TLSv1 protocol only  
  1341.         SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { “TLSv1” }, null,  
  1342.                 SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);  
  1343.   
  1344.         httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();  
  1345.   
  1346.         // 根据默认超时限制初始化requestConfig  
  1347.         requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout)  
  1348.                 .build();  
  1349.   
  1350.         hasInit = true;  
  1351.     }  
  1352.   
  1353.     /** 
  1354.      * 通过Https往API post xml数据 
  1355.      * 
  1356.      * @param url 
  1357.      *            API地址 
  1358.      * @param xmlObj 
  1359.      *            要提交的XML数据对象 
  1360.      * @return API回包的实际数据 
  1361.      * @throws IOException 
  1362.      * @throws KeyStoreException 
  1363.      * @throws UnrecoverableKeyException 
  1364.      * @throws NoSuchAlgorithmException 
  1365.      * @throws KeyManagementException 
  1366.      */  
  1367.   
  1368.     public String sendPost(String url, String postDataXML) throws IOException, KeyStoreException,  
  1369.             UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException {  
  1370.   
  1371.         if (!hasInit) {  
  1372.             init();  
  1373.         }  
  1374.   
  1375.         String result = null;  
  1376.   
  1377.         HttpPost httpPost = new HttpPost(url);  
  1378.   
  1379.         Util.log(”API,POST过去的数据是:”);  
  1380.         Util.log(postDataXML);  
  1381.   
  1382.         // 得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别  
  1383.         StringEntity postEntity = new StringEntity(postDataXML, “UTF-8”);  
  1384.         httpPost.addHeader(”Content-Type”“text/xml”);  
  1385.         httpPost.setEntity(postEntity);  
  1386.   
  1387.         // 设置请求器的配置  
  1388.         httpPost.setConfig(requestConfig);  
  1389.   
  1390.         Util.log(”executing request” + httpPost.getRequestLine());  
  1391.   
  1392.         try {  
  1393.             HttpResponse response = httpClient.execute(httpPost);  
  1394.   
  1395.             HttpEntity entity = response.getEntity();  
  1396.   
  1397.             result = EntityUtils.toString(entity, ”UTF-8”);  
  1398.   
  1399.         } catch (ConnectionPoolTimeoutException e) {  
  1400.             log.error(”http get throw ConnectionPoolTimeoutException(wait time out)”, e);  
  1401.   
  1402.         } catch (ConnectTimeoutException e) {  
  1403.             log.error(”http get throw ConnectTimeoutException”, e);  
  1404.   
  1405.         } catch (SocketTimeoutException e) {  
  1406.             log.error(”http get throw SocketTimeoutException”, e);  
  1407.   
  1408.         } catch (Exception e) {  
  1409.             log.error(”http get throw Exception”, e);  
  1410.   
  1411.         } finally {  
  1412.             httpPost.abort();  
  1413.         }  
  1414.   
  1415.         return result;  
  1416.     }  
  1417.   
  1418.     /** 
  1419.      * 设置连接超时时间 
  1420.      * 
  1421.      * @param socketTimeout 
  1422.      *            连接时长,默认10秒 
  1423.      */  
  1424.     public void setSocketTimeout(int socketTimeout) {  
  1425.         socketTimeout = socketTimeout;  
  1426.         resetRequestConfig();  
  1427.     }  
  1428.   
  1429.     /** 
  1430.      * 设置传输超时时间 
  1431.      * 
  1432.      * @param connectTimeout 
  1433.      *            传输时长,默认30秒 
  1434.      */  
  1435.     public void setConnectTimeout(int connectTimeout) {  
  1436.         connectTimeout = connectTimeout;  
  1437.         resetRequestConfig();  
  1438.     }  
  1439.   
  1440.     private void resetRequestConfig() {  
  1441.         requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout)  
  1442.                 .build();  
  1443.     }  
  1444.   
  1445.     /** 
  1446.      * 允许商户自己做更高级更复杂的请求器配置 
  1447.      * 
  1448.      * @param requestConfig 
  1449.      *            设置HttpsRequest的请求器配置 
  1450.      */  
  1451.     public void setRequestConfig(RequestConfig requestConfig) {  
  1452.         requestConfig = requestConfig;  
  1453.     }  
  1454.   
  1455. }  

  1456.   
  1457. ”2067985” snippet_file_name=“blog_20161222_7_5629101” name=“code” class=“java”>package com.luozhuang.util;  
  1458.   
  1459. import java.security.MessageDigest;  
  1460.   
  1461. /** 
  1462.  * luozhuang 
  1463.  */  
  1464. public class MD5 {  
  1465.     private final static String[] hexDigits = {“0”“1”“2”“3”“4”“5”“6”“7”,  
  1466.             ”8”“9”“a”“b”“c”“d”“e”“f”};  
  1467.   
  1468.     /** 
  1469.      * 转换字节数组为16进制字串 
  1470.      * @param b 字节数组 
  1471.      * @return 16进制字串 
  1472.      */  
  1473.     public static String byteArrayToHexString(byte[] b) {  
  1474.         StringBuilder resultSb = new StringBuilder();  
  1475.         for (byte aB : b) {  
  1476.             resultSb.append(byteToHexString(aB));  
  1477.         }  
  1478.         return resultSb.toString();  
  1479.     }  
  1480.   
  1481.     /** 
  1482.      * 转换byte到16进制 
  1483.      * @param b 要转换的byte 
  1484.      * @return 16进制格式 
  1485.      */  
  1486.     private static String byteToHexString(byte b) {  
  1487.         int n = b;  
  1488.         if (n < 0) {  
  1489.             n = 256 + n;  
  1490.         }  
  1491.         int d1 = n / 16;  
  1492.         int d2 = n % 16;  
  1493.         return hexDigits[d1] + hexDigits[d2];  
  1494.     }  
  1495.   
  1496.     /** 
  1497.      * MD5编码 
  1498.      * @param origin 原始字符串 
  1499.      * @param characterEncoding  
  1500.      * @return 经过MD5加密之后的结果 
  1501.      */  
  1502.     public static String MD5Encode(String origin, String charsetname) {  
  1503.         String resultString = null;  
  1504.         try {  
  1505.             resultString = origin;  
  1506.             MessageDigest md = MessageDigest.getInstance(”MD5”);  
  1507.             if (charsetname == null || “”.equals(charsetname))    
  1508.                 resultString = byteArrayToHexString(md.digest(resultString    
  1509.                         .getBytes()));    
  1510.             else    
  1511.                 resultString = byteArrayToHexString(md.digest(resultString    
  1512.                         .getBytes(charsetname)));    
  1513.         } catch (Exception e) {  
  1514.             e.printStackTrace();  
  1515.         }  
  1516.         return resultString;  
  1517.     }  
  1518.   
  1519. }  

  1520.   
  1521. ”2067985” snippet_file_name=“blog_20161222_8_7471482” name=“code” class=“java”>package com.luozhuang.util;  
  1522.   
  1523. import java.text.SimpleDateFormat;  
  1524. import java.util.Date;  
  1525. import java.util.Iterator;  
  1526. import java.util.Map;  
  1527. import java.util.Set;  
  1528. import java.util.SortedMap;  
  1529.   
  1530. import com.luozhuang.WxPayException;  
  1531.   
  1532. public class PayCommonUtil {  
  1533.   
  1534.     /** 
  1535.      * 是否签名正确,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。 
  1536.      *  
  1537.      * @return boolean 
  1538.      */  
  1539.     public static boolean isTenpaySign(String characterEncoding, SortedMap packageParams,  
  1540.             String API_KEY) {  
  1541.         StringBuffer sb = new StringBuffer();  
  1542.         Set es = packageParams.entrySet();  
  1543.         Iterator it = es.iterator();  
  1544.         while (it.hasNext()) {  
  1545.             Map.Entry entry = (Map.Entry) it.next();  
  1546.             String k = (String) entry.getKey();  
  1547.             String v = (String) entry.getValue();  
  1548.             if (!“sign”.equals(k) && null != v && !“”.equals(v)) {  
  1549.                 sb.append(k + ”=” + v + “&”);  
  1550.             }  
  1551.         }  
  1552.   
  1553.         sb.append(”key=” + API_KEY);  
  1554.   
  1555.         // 算出摘要  
  1556.         String mysign = MD5.MD5Encode(sb.toString(), characterEncoding).toLowerCase();  
  1557.         String tenpaySign = ((String) packageParams.get(”sign”)).toLowerCase();  
  1558.   
  1559.         return tenpaySign.equals(mysign);  
  1560.     }  
  1561.   
  1562.     /** 
  1563.      * @author 
  1564.      * @date 2016-4-22 
  1565.      * @Description:sign签名 
  1566.      * @param characterEncoding 
  1567.      *            编码格式 
  1568.      * @param parameters 
  1569.      *            请求参数 
  1570.      * @return 
  1571.      */  
  1572.     public static String createSign(String characterEncoding, SortedMap packageParams, String API_KEY) {  
  1573.         StringBuffer sb = new StringBuffer();  
  1574.         Set es = packageParams.entrySet();  
  1575.         Iterator it = es.iterator();  
  1576.         while (it.hasNext()) {  
  1577.             Map.Entry entry = (Map.Entry) it.next();  
  1578.             String k = (String) entry.getKey();  
  1579.             String v = (String) entry.getValue();  
  1580.             if (null != v && !“”.equals(v) && !“sign”.equals(k) && !“key”.equals(k)) {  
  1581.                 sb.append(k + ”=” + v + “&”);  
  1582.             }  
  1583.         }  
  1584.         sb.append(”key=” + API_KEY);  
  1585.         String sign = MD5.MD5Encode(sb.toString(), characterEncoding).toUpperCase();  
  1586.         return sign;  
  1587.     }  
  1588.   
  1589.     /** 
  1590.      * @author 
  1591.      * @date 2016-4-22 
  1592.      * @Description:将请求参数转换为xml格式的string 
  1593.      * @param parameters 
  1594.      *            请求参数 
  1595.      * @return 
  1596.      * @throws WxPayException 
  1597.      */  
  1598.     public static String getRequestXml(SortedMap parameters) throws WxPayException {  
  1599.         StringBuffer sb = new StringBuffer();  
  1600.         sb.append();  
  1601.         Set> es = parameters.entrySet();  
  1602.         Iterator> it = es.iterator();  
  1603.         while (it.hasNext()) {  
  1604.             Map.Entry entry = (Map.Entry) it.next();  
  1605.             String k = entry.getKey();  
  1606.             String v = (String) entry.getValue();  
  1607.   
  1608.             // 字段值不能为null,会影响后续流程  
  1609.             if (v == null) {  
  1610.   
  1611.                 throw new WxPayException(“WxPayData内部含有值为null的字段!”);  
  1612.             }  
  1613.   
  1614.             if (“attach”.equalsIgnoreCase(k) || “body”.equalsIgnoreCase(k) || “sign”.equalsIgnoreCase(k)) {  
  1615.                 sb.append(”<” + k + “>” +  + v + “]]> + k + “>”);  
  1616.             } else {  
  1617.                 sb.append(”<” + k + “>” + v +  + k + “>”);  
  1618.             }  
  1619.         }  
  1620.         sb.append(””);  
  1621.         return sb.toString();  
  1622.     }  
  1623.   
  1624.     /** 
  1625.      * 取出一个指定长度大小的随机正整数. 
  1626.      *  
  1627.      * @param length 
  1628.      *            int 设定所取出随机数的长度。length小于11 
  1629.      * @return int 返回生成的随机数。 
  1630.      */  
  1631.     public static int buildRandom(int length) {  
  1632.         int num = 1;  
  1633.         double random = Math.random();  
  1634.         if (random < 0.1) {  
  1635.             random = random + 0.1;  
  1636.         }  
  1637.         for (int i = 0; i < length; i++) {  
  1638.             num = num * 10;  
  1639.         }  
  1640.         return (int) ((random * num));  
  1641.     }  
  1642.   
  1643.     /** 
  1644.      * 获取当前时间 yyyyMMddHHmmss 
  1645.      *  
  1646.      * @return String 
  1647.      */  
  1648.     public static String getCurrTime() {  
  1649.         Date now = new Date();  
  1650.         SimpleDateFormat outFormat = new SimpleDateFormat(“yyyyMMddHHmmss”);  
  1651.         String s = outFormat.format(now);  
  1652.         return s;  
  1653.     }  
  1654.   
  1655. }  

  1656.   
  1657. ”2067985” snippet_file_name=“blog_20161222_9_7046370” name=“code” class=“java”>package com.luozhuang.util;  
  1658.   
  1659. import java.util.Random;  
  1660.   
  1661. /** 
  1662.  * luozhuang 
  1663.  */  
  1664. public class RandomStringGenerator {  
  1665.   
  1666.     /** 
  1667.      * 获取一定长度的随机字符串 
  1668.      * @param length 指定字符串长度 
  1669.      * @return 一定长度的字符串 
  1670.      */  
  1671.     public static String getRandomStringByLength(int length) {  
  1672.         String base = ”abcdefghijklmnopqrstuvwxyz0123456789”;  
  1673.         Random random = new Random();  
  1674.         StringBuffer sb = new StringBuffer();  
  1675.         for (int i = 0; i < length; i++) {  
  1676.             int number = random.nextInt(base.length());  
  1677.             sb.append(base.charAt(number));  
  1678.         }  
  1679.         return sb.toString();  
  1680.     }  
  1681.   
  1682. }  

  1683.   
  1684. ”2067985” snippet_file_name=“blog_20161222_10_9968546” name=“code” class=“java”>package com.luozhuang.util;  
  1685.   
  1686. import org.xml.sax.SAXException;  
  1687.   
  1688. import javax.xml.parsers.ParserConfigurationException;  
  1689. import java.io.IOException;  
  1690. import java.lang.reflect.Field;  
  1691. import java.util.ArrayList;  
  1692. import java.util.Arrays;  
  1693. import java.util.Map;  
  1694.   
  1695. /** 
  1696.  * luozhuang 
  1697.  */  
  1698. public class Signature {  
  1699.     /** 
  1700.      * 签名算法 
  1701.      * @param o 要参与签名的数据对象 
  1702.      * @return 签名 
  1703.      * @throws IllegalAccessException 
  1704.      */  
  1705.     public static String getSign(Object o) throws IllegalAccessException {  
  1706.         ArrayList list = new ArrayList();  
  1707.         Class cls = o.getClass();  
  1708.         Field[] fields = cls.getDeclaredFields();  
  1709.         for (Field f : fields) {  
  1710.             f.setAccessible(true);  
  1711.             if (f.get(o) != null && f.get(o) != “”) {  
  1712.                 list.add(f.getName() + ”=” + f.get(o) + “&”);  
  1713.             }  
  1714.         }  
  1715.         int size = list.size();  
  1716.         String [] arrayToSort = list.toArray(new String[size]);  
  1717.         Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);  
  1718.         StringBuilder sb = new StringBuilder();  
  1719.         for(int i = 0; i < size; i ++) {  
  1720.             sb.append(arrayToSort[i]);  
  1721.         }  
  1722.         String result = sb.toString();  
  1723.         result += ”key=” + Configure.getKey();  
  1724.         Util.log(”Sign Before MD5:” + result);  
  1725.         result = MD5.MD5Encode(result,null).toUpperCase();  
  1726.         Util.log(”Sign Result:” + result);  
  1727.         return result;  
  1728.     }  
  1729.   
  1730.     public static String getSign(Map map){  
  1731.         ArrayList list = new ArrayList();  
  1732.         for(Map.Entry entry:map.entrySet()){  
  1733.             if(entry.getValue()!=“”){  
  1734.                 list.add(entry.getKey() + ”=” + entry.getValue() + “&”);  
  1735.             }  
  1736.         }  
  1737.         int size = list.size();  
  1738.         String [] arrayToSort = list.toArray(new String[size]);  
  1739.         Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);  
  1740.         StringBuilder sb = new StringBuilder();  
  1741.         for(int i = 0; i < size; i ++) {  
  1742.             sb.append(arrayToSort[i]);  
  1743.         }  
  1744.         String result = sb.toString();  
  1745.         result += ”key=” + Configure.getKey();  
  1746.         //Util.log(“Sign Before MD5:” + result);  
  1747.         result = MD5.MD5Encode(result,null).toUpperCase();  
  1748.         //Util.log(“Sign Result:” + result);  
  1749.         return result;  
  1750.     }  
  1751.   
  1752.     /** 
  1753.      * 从API返回的XML数据里面重新计算一次签名 
  1754.      * @param responseString API返回的XML数据 
  1755.      * @return 新鲜出炉的签名 
  1756.      * @throws ParserConfigurationException 
  1757.      * @throws IOException 
  1758.      * @throws SAXException 
  1759.      */  
  1760.     public static String getSignFromResponseString(String responseString) throws IOException, SAXException, ParserConfigurationException {  
  1761.         Map map = XMLParser.getMapFromXML(responseString);  
  1762.         //清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名  
  1763.         map.put(”sign”,“”);  
  1764.         //将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较  
  1765.         return Signature.getSign(map);  
  1766.     }  
  1767.   
  1768.     /** 
  1769.      * 检验API返回的数据里面的签名是否合法,避免数据在传输的过程中被第三方篡改 
  1770.      * @param responseString API返回的XML数据字符串 
  1771.      * @return API签名是否合法 
  1772.      * @throws ParserConfigurationException 
  1773.      * @throws IOException 
  1774.      * @throws SAXException 
  1775.      */  
  1776.     public static boolean checkIsSignValidFromResponseString(String responseString) throws ParserConfigurationException, IOException, SAXException {  
  1777.   
  1778.         Map map = XMLParser.getMapFromXML(responseString);  
  1779.         Util.log(map.toString());  
  1780.   
  1781.         String signFromAPIResponse = map.get(”sign”).toString();  
  1782.         if(signFromAPIResponse==“” || signFromAPIResponse == null){  
  1783.             Util.log(”API返回的数据签名数据不存在,有可能被第三方篡改!!!”);  
  1784.             return false;  
  1785.         }  
  1786.         Util.log(”服务器回包里面的签名是:” + signFromAPIResponse);  
  1787.         //清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名  
  1788.         map.put(”sign”,“”);  
  1789.         //将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较  
  1790.         String signForAPIResponse = Signature.getSign(map);  
  1791.   
  1792.         if(!signForAPIResponse.equals(signFromAPIResponse)){  
  1793.             //签名验不过,表示这个API返回的数据有可能已经被篡改了  
  1794.             Util.log(”API返回的数据签名验证不通过,有可能被第三方篡改!!!”);  
  1795.             return false;  
  1796.         }  
  1797.         Util.log(”恭喜,API返回的数据签名验证通过!!!”);  
  1798.         return true;  
  1799.     }  
  1800.   
  1801. }  

  1802.   
  1803. ”2067985” snippet_file_name=“blog_20161222_11_2367335” name=“code” class=“java”>package com.luozhuang.util;  
  1804.   
  1805.   
  1806. import com.thoughtworks.xstream.XStream;  
  1807.   
  1808. import org.slf4j.Logger;  
  1809. import org.slf4j.LoggerFactory;  
  1810.   
  1811. import java.io.*;  
  1812. import java.lang.reflect.Field;  
  1813. import java.text.SimpleDateFormat;  
  1814. import java.util.Date;  
  1815. import java.util.Map;  
  1816.   
  1817. /** 
  1818.  * luozhuang 
  1819.  */  
  1820. public class Util {  
  1821.   
  1822.     //打log用  
  1823.     private static Logger logger = new Logger();  
  1824.   
  1825.     /** 
  1826.      * 通过反射的方式遍历对象的属性和属性值,方便调试 
  1827.      * 
  1828.      * @param o 要遍历的对象 
  1829.      * @throws Exception 
  1830.      */  
  1831.     public static void reflect(Object o) throws Exception {  
  1832.         Class cls = o.getClass();  
  1833.         Field[] fields = cls.getDeclaredFields();  
  1834.         for (int i = 0; i < fields.length; i++) {  
  1835.             Field f = fields[i];  
  1836.             f.setAccessible(true);  
  1837.             Util.log(f.getName() + ” -> ” + f.get(o));  
  1838.         }  
  1839.     }  
  1840.   
  1841.     public static byte[] readInput(InputStream in) throws IOException {  
  1842.         ByteArrayOutputStream out = new ByteArrayOutputStream();  
  1843.         int len = 0;  
  1844.         byte[] buffer = new byte[1024];  
  1845.         while ((len = in.read(buffer)) > 0) {  
  1846.             out.write(buffer, 0, len);  
  1847.         }  
  1848.         out.close();  
  1849.         in.close();  
  1850.         return out.toByteArray();  
  1851.     }  
  1852.   
  1853.     public static String inputStreamToString(InputStream is) throws IOException {  
  1854.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  1855.         int i;  
  1856.         while ((i = is.read()) != -1) {  
  1857.             baos.write(i);  
  1858.         }  
  1859.         return baos.toString();  
  1860.     }  
  1861.   
  1862.   
  1863.     public static InputStream getStringStream(String sInputString) throws UnsupportedEncodingException {  
  1864.         ByteArrayInputStream tInputStringStream = null;  
  1865.         if (sInputString != null && !sInputString.trim().equals(“”)) {  
  1866.             tInputStringStream = new ByteArrayInputStream(sInputString.getBytes(“UTF-8”));  
  1867.         }  
  1868.         return tInputStringStream;  
  1869.     }  
  1870.   
  1871.     public static Object getObjectFromXML(String xml, Class tClass) {  
  1872.         //将从API返回的XML数据映射到Java对象  
  1873.         XStream xStreamForResponseData = new XStream();  
  1874.         xStreamForResponseData.alias(”xml”, tClass);  
  1875.         xStreamForResponseData.ignoreUnknownElements();//暂时忽略掉一些新增的字段  
  1876.         return xStreamForResponseData.fromXML(xml);  
  1877.     }  
  1878.   
  1879.     public static String getStringFromMap(Map map, String key, String defaultValue) {  
  1880.         if (key == “” || key == null) {  
  1881.             return defaultValue;  
  1882.         }  
  1883.         String result = (String) map.get(key);  
  1884.         if (result == null) {  
  1885.             return defaultValue;  
  1886.         } else {  
  1887.             return result;  
  1888.         }  
  1889.     }  
  1890.   
  1891.     public static int getIntFromMap(Map map, String key) {  
  1892.         if (key == “” || key == null) {  
  1893.             return 0;  
  1894.         }  
  1895.         if (map.get(key) == null) {  
  1896.             return 0;  
  1897.         }  
  1898.         return Integer.parseInt((String) map.get(key));  
  1899.     }  
  1900.   
  1901.     /** 
  1902.      * 打log接口 
  1903.      * @param log 要打印的log字符串 
  1904.      * @return 返回log 
  1905.      */  
  1906.     public static String log(Object log){  
  1907.         logger.info(log.toString());  
  1908.         //System.out.println(log);  
  1909.         return log.toString();  
  1910.     }  
  1911.   
  1912.     /** 
  1913.      * 读取本地的xml数据,一般用来自测用 
  1914.      * @param localPath 本地xml文件路径 
  1915.      * @return 读到的xml字符串 
  1916.      */  
  1917.     public static String getLocalXMLString(String localPath) throws IOException {  
  1918.         return Util.inputStreamToString(Util.class.getResourceAsStream(localPath));  
  1919.     }  
  1920.   
  1921. }  

  1922.   
  1923. ”2067985” snippet_file_name=“blog_20161222_12_1178072” name=“code” class=“java”>package com.luozhuang.util;  
  1924.   
  1925.   
  1926. import org.w3c.dom.Document;  
  1927. import org.w3c.dom.Element;  
  1928. import org.w3c.dom.Node;  
  1929. import org.w3c.dom.NodeList;  
  1930. import org.xml.sax.SAXException;  
  1931.   
  1932. import javax.xml.parsers.DocumentBuilder;  
  1933. import javax.xml.parsers.DocumentBuilderFactory;  
  1934. import javax.xml.parsers.ParserConfigurationException;  
  1935. import java.io.IOException;  
  1936. import java.io.InputStream;  
  1937. import java.util.ArrayList;  
  1938. import java.util.HashMap;  
  1939. import java.util.List;  
  1940. import java.util.Map;  
  1941. import java.util.SortedMap;  
  1942. import java.util.TreeMap;  
  1943.   
  1944. /** 
  1945.  * luozhuang 
  1946.  */  
  1947. public class XMLParser {  
  1948.   
  1949.      
  1950.   
  1951.     public static SortedMap getMapFromXML(String xmlString) throws ParserConfigurationException, IOException, SAXException {  
  1952.   
  1953.         //这里用Dom的方式解析回包的最主要目的是防止API新增回包字段  
  1954.         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();  
  1955.         DocumentBuilder builder = factory.newDocumentBuilder();  
  1956.         InputStream is =  Util.getStringStream(xmlString);  
  1957.         Document document = builder.parse(is);  
  1958.   
  1959.         //获取到document里面的全部结点  
  1960.         NodeList allNodes = document.getFirstChild().getChildNodes();  
  1961.         Node node;  
  1962.         SortedMap map = new TreeMap();  
  1963.         int i=0;  
  1964.         while (i < allNodes.getLength()) {  
  1965.             node = allNodes.item(i);  
  1966.             if(node instanceof Element){  
  1967.                 map.put(node.getNodeName(),node.getTextContent());  
  1968.             }  
  1969.             i++;  
  1970.         }  
  1971.         return map;  
  1972.   
  1973.     }  
  1974.   
  1975.   
  1976. }  

  1977.   

  1978.   
  1979.   
  1980.      

     
     
     
     
[java] view plain copy
print ?
  1. package com.luozhuang;  
  2.   
  3. import java.text.SimpleDateFormat;  
  4. import java.util.Calendar;  
  5. import java.util.Date;  
  6. import java.util.Map;  
  7. import java.util.SortedMap;  
  8. import java.util.TreeMap;  
  9.   
  10. import javax.servlet.http.HttpServletRequest;  
  11.   
  12. import com.luozhuang.util.Configure;  
  13. import com.luozhuang.util.HttpsRequest;  
  14. import com.luozhuang.util.PayCommonUtil;  
  15. import com.luozhuang.util.XMLParser;  
  16.   
  17. /** 
  18.  * SDK总入口 
  19.  */  
  20. public class WXPay {  
  21.     public String getRemortIP(HttpServletRequest request) {  
  22.         if (request.getHeader("x-forwarded-for") == null) {  
  23.         return request.getRemoteAddr();  
  24.         }  
  25.         return request.getHeader("x-forwarded-for");  
  26.         }  
  27.     /** 
  28.      * 初始化SDK依赖的几个关键配置 
  29.      *  
  30.      * @param key 
  31.      *            签名算法需要用到的秘钥 
  32.      * @param appID 
  33.      *            公众账号ID 
  34.      * @param mchID 
  35.      *            商户ID 
  36.      * @param sdbMchID 
  37.      *            子商户ID,受理模式必填 
  38.      * @param certLocalPath 
  39.      *            HTTP证书在服务器中的路径,用来加载证书用 
  40.      * @param certPassword 
  41.      *            HTTP证书的密码,默认等于MCHID 
  42.      */  
  43.     public static void initSDKConfiguration(String key, String appID, String mchID, String sdbMchID,  
  44.             String certLocalPath, String certPassword) {  
  45.         Configure.setKey(key);  
  46.         Configure.setAppID(appID);  
  47.         Configure.setMchID(mchID);  
  48.         Configure.setSubMchID(sdbMchID);  
  49.         Configure.setCertLocalPath(certLocalPath);  
  50.         Configure.setCertPassword(certPassword);  
  51.     }  
  52.   
  53.     /** 
  54.      *  
  55.      *  
  56.      * @param out_trade_no 
  57.      * @return 
  58.      * @throws Exception 
  59.      */  
  60.     public static String weixin_pay(String out_trade_no) throws Exception {  
  61.         HttpsRequest httpRequest = new HttpsRequest();  
  62.         // 账号信息  
  63.         String appid = Configure.getAppid(); // appid  
  64.         // String appsecret = PayConfigUtil.APP_SECRET; // appsecret  
  65.         // 商业号  
  66.         String mch_id = Configure.getMchid();  
  67.         // key  
  68.         String key = Configure.getKey();  
  69.   
  70.         String currTime = PayCommonUtil.getCurrTime();  
  71.         String strTime = currTime.substring(8, currTime.length());  
  72.         String strRandom = PayCommonUtil.buildRandom(4) + "";  
  73.         // 随机字符串  
  74.         String nonce_str = strTime + strRandom;  
  75.         // 价格 注意:价格的单位是分  
  76.          String order_price = "1";  
  77.         // 商品名称  
  78.         // String body = "luozhuang";  
  79.   
  80.         // 获取发起电脑 ip  
  81.         String spbill_create_ip = Configure.getIP();  
  82.         // 回调接口  
  83.         String notify_url = Configure.NOTIFY_URL;  
  84.         String product_id="luozhuang";  
  85.         String trade_type = "NATIVE";//JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付  
  86.         String time_start = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());  
  87.         Calendar ca = Calendar.getInstance();  
  88.         ca.setTime(new Date());  
  89.         ca.add(Calendar.DATE, 1);  
  90.         String time_expire = new SimpleDateFormat("yyyyMMddHHmmss").format(ca.getTime());  
  91.         WxPayData packageParams = new WxPayData();  
  92.         packageParams.put("appid", appid);  
  93.         packageParams.put("mch_id", mch_id);  
  94.         packageParams.put("nonce_str", nonce_str);  
  95.         packageParams.put("body""luozhuang-服务费");  
  96.         packageParams.put("out_trade_no", out_trade_no);  
  97.         packageParams.put("product_id",product_id);  
  98.         packageParams.put("total_fee", order_price);  
  99.         packageParams.put("spbill_create_ip", spbill_create_ip);  
  100.         packageParams.put("notify_url", notify_url);  
  101.         packageParams.put("trade_type", trade_type);  
  102.         packageParams.put("time_start", time_start);  
  103.         packageParams.put("time_expire", time_expire);  
  104.         String sign = packageParams.MakeSign();  
  105.         packageParams.put("sign", sign);  
  106.         WxPayData resXml=WxPayApi.UnifiedOrder(packageParams, 20);  
  107.         String requestXML = packageParams.ToXml();  
  108.         System.out.println("请求xml::::" + requestXML);  
  109.         System.out.println("得到xml::::" + resXml.toString());  
  110.         // String return_code = (String) map.get("return_code");  
  111.         // String prepay_id = (String) map.get("prepay_id");  
  112.         String urlCode = (String) resXml.GetValue("code_url");  
  113.         System.out.println("打印调用统一下单接口生成二维码url:::::" + urlCode);  
  114.         return urlCode;  
  115.     }  
  116.   
  117. }  
package com.luozhuang;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.servlet.http.HttpServletRequest;

import com.luozhuang.util.Configure;
import com.luozhuang.util.HttpsRequest;
import com.luozhuang.util.PayCommonUtil;
import com.luozhuang.util.XMLParser;

/**
 * SDK总入口
 */
public class WXPay {
    public String getRemortIP(HttpServletRequest request) {
        if (request.getHeader("x-forwarded-for") == null) {
        return request.getRemoteAddr();
        }
        return request.getHeader("x-forwarded-for");
        }
    /**
     * 初始化SDK依赖的几个关键配置
     * 
     * @param key
     *            签名算法需要用到的秘钥
     * @param appID
     *            公众账号ID
     * @param mchID
     *            商户ID
     * @param sdbMchID
     *            子商户ID,受理模式必填
     * @param certLocalPath
     *            HTTP证书在服务器中的路径,用来加载证书用
     * @param certPassword
     *            HTTP证书的密码,默认等于MCHID
     */
    public static void initSDKConfiguration(String key, String appID, String mchID, String sdbMchID,
            String certLocalPath, String certPassword) {
        Configure.setKey(key);
        Configure.setAppID(appID);
        Configure.setMchID(mchID);
        Configure.setSubMchID(sdbMchID);
        Configure.setCertLocalPath(certLocalPath);
        Configure.setCertPassword(certPassword);
    }

    /**
     * 
     * 
     * @param out_trade_no
     * @return
     * @throws Exception
     */
    public static String weixin_pay(String out_trade_no) throws Exception {
        HttpsRequest httpRequest = new HttpsRequest();
        // 账号信息
        String appid = Configure.getAppid(); // appid
        // String appsecret = PayConfigUtil.APP_SECRET; // appsecret
        // 商业号
        String mch_id = Configure.getMchid();
        // key
        String key = Configure.getKey();

        String currTime = PayCommonUtil.getCurrTime();
        String strTime = currTime.substring(8, currTime.length());
        String strRandom = PayCommonUtil.buildRandom(4) + "";
        // 随机字符串
        String nonce_str = strTime + strRandom;
        // 价格 注意:价格的单位是分
         String order_price = "1";
        // 商品名称
        // String body = "luozhuang";

        // 获取发起电脑 ip
        String spbill_create_ip = Configure.getIP();
        // 回调接口
        String notify_url = Configure.NOTIFY_URL;
        String product_id="luozhuang";
        String trade_type = "NATIVE";//JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付
        String time_start = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        Calendar ca = Calendar.getInstance();
        ca.setTime(new Date());
        ca.add(Calendar.DATE, 1);
        String time_expire = new SimpleDateFormat("yyyyMMddHHmmss").format(ca.getTime());
        WxPayData packageParams = new WxPayData();
        packageParams.put("appid", appid);
        packageParams.put("mch_id", mch_id);
        packageParams.put("nonce_str", nonce_str);
        packageParams.put("body", "luozhuang-服务费");
        packageParams.put("out_trade_no", out_trade_no);
        packageParams.put("product_id",product_id);
        packageParams.put("total_fee", order_price);
        packageParams.put("spbill_create_ip", spbill_create_ip);
        packageParams.put("notify_url", notify_url);
        packageParams.put("trade_type", trade_type);
        packageParams.put("time_start", time_start);
        packageParams.put("time_expire", time_expire);
        String sign = packageParams.MakeSign();
        packageParams.put("sign", sign);
        WxPayData resXml=WxPayApi.UnifiedOrder(packageParams, 20);
        String requestXML = packageParams.ToXml();
        System.out.println("请求xml::::" + requestXML);
        System.out.println("得到xml::::" + resXml.toString());
        // String return_code = (String) map.get("return_code");
        // String prepay_id = (String) map.get("prepay_id");
        String urlCode = (String) resXml.GetValue("code_url");
        System.out.println("打印调用统一下单接口生成二维码url:::::" + urlCode);
        return urlCode;
    }

}




[java] view plain copy
print ?
  1. package com.luozhuang;  
  2.   
  3. import java.io.IOException;  
  4. import java.security.KeyManagementException;  
  5. import java.security.KeyStoreException;  
  6. import java.security.NoSuchAlgorithmException;  
  7. import java.security.UnrecoverableKeyException;  
  8. import java.util.Calendar;  
  9. import java.util.Date;  
  10. import java.util.Random;  
  11.   
  12. import javax.xml.parsers.ParserConfigurationException;  
  13.   
  14. import org.xml.sax.SAXException;  
  15.   
  16. import com.fastwixinextend.CommonClass;  
  17. import com.luozhuang.util.Configure;  
  18. import com.luozhuang.util.HttpsRequest;  
  19.   
  20. public class WxPayApi  
  21. {  
  22.     private static final int REPORT_LEVENL = 0;  
  23.   
  24.     /** 
  25.     * 提交被扫支付API 
  26.     * 收银员使用扫码设备读取微信用户刷卡授权码以后,二维码或条码信息传送至商户收银台, 
  27.     * 由商户收银台或者商户后台调用该接口发起支付。 
  28.     * @param WxPayData inputObj 提交给被扫支付API的参数 
  29.     * @param int timeOut 超时时间 
  30.     * @throws WxPayException 
  31.     * @return 成功时返回调用结果,其他抛异常 
  32.      * @throws IOException  
  33.      * @throws KeyStoreException  
  34.      * @throws NoSuchAlgorithmException  
  35.      * @throws KeyManagementException  
  36.      * @throws UnrecoverableKeyException  
  37.      * @throws SAXException  
  38.      * @throws ParserConfigurationException  
  39.     */  
  40.     public static WxPayData Micropay(WxPayData inputObj, int timeOut) throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, WxPayException, ParserConfigurationException, SAXException  
  41.     {  
  42.         String url =Configure.PAY_API;  
  43.         //检测必填参数  
  44.         if (!inputObj.IsSet(“body”))  
  45.         {  
  46.             throw new WxPayException(“提交被扫支付API接口中,缺少必填参数body!”);  
  47.         }  
  48.         else if (!inputObj.IsSet(“out_trade_no”))  
  49.         {  
  50.             throw new WxPayException(“提交被扫支付API接口中,缺少必填参数out_trade_no!”);  
  51.         }  
  52.         else if (!inputObj.IsSet(“total_fee”))  
  53.         {  
  54.             throw new WxPayException(“提交被扫支付API接口中,缺少必填参数total_fee!”);  
  55.         }  
  56.         else if (!inputObj.IsSet(“auth_code”))  
  57.         {  
  58.             throw new WxPayException(“提交被扫支付API接口中,缺少必填参数auth_code!”);  
  59.         }  
  60.      
  61.         inputObj.SetValue(”spbill_create_ip”, Configure.getIP());//终端ip  
  62.         inputObj.SetValue(”appid”, Configure.getAppid());//公众账号ID  
  63.         inputObj.SetValue(”mch_id”, Configure.getMchid());//商户号  
  64.         inputObj.SetValue(”nonce_str”, UUIDGenerator.getUUID().toString().replace(“-““”));//随机字符串  
  65.         inputObj.SetValue(”sign”, inputObj.MakeSign());//签名  
  66.         String xml = inputObj.ToXml();  
  67.   
  68.         HttpsRequest https=new HttpsRequest();  
  69.         https.setSocketTimeout(timeOut);  
  70.         String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API  
  71.         WxPayData result = new WxPayData();  
  72.         result.FromXml(response);  
  73.   
  74.   
  75.   
  76.         return result;  
  77.     }  
  78.   
  79.       
  80.     /** 
  81.     *     
  82.     * 查询订单 
  83.     * @param WxPayData inputObj 提交给查询订单API的参数 
  84.     * @param int timeOut 超时时间 
  85.     * @throws WxPayException 
  86.     * @return 成功时返回订单查询结果,其他抛异常 
  87.      * @throws IOException  
  88.      * @throws KeyStoreException  
  89.      * @throws NoSuchAlgorithmException  
  90.      * @throws KeyManagementException  
  91.      * @throws UnrecoverableKeyException  
  92.      * @throws SAXException  
  93.      * @throws ParserConfigurationException  
  94.     */  
  95.     public static WxPayData OrderQuery(WxPayData inputObj, int timeOut) throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, WxPayException, ParserConfigurationException, SAXException  
  96.     {  
  97.         String url = Configure.PAY_QUERY_API;  
  98.         //检测必填参数  
  99.         if (!inputObj.IsSet(“out_trade_no”) && !inputObj.IsSet(“transaction_id”))  
  100.         {  
  101.             throw new WxPayException(“订单查询接口中,out_trade_no、transaction_id至少填一个!”);  
  102.         }  
  103.   
  104.         inputObj.SetValue(”appid”, Configure.getAppid());//公众账号ID  
  105.         inputObj.SetValue(”mch_id”, Configure.getMchid());//商户号  
  106.         inputObj.SetValue(”nonce_str”, WxPayApi.GenerateNonceStr());//随机字符串  
  107.         inputObj.SetValue(”sign”, inputObj.MakeSign());//签名  
  108.   
  109.         String xml = inputObj.ToXml();  
  110.   
  111.         HttpsRequest https=new HttpsRequest();  
  112.         https.setSocketTimeout(timeOut);  
  113.         String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API  
  114.         WxPayData result = new WxPayData();  
  115.         result.FromXml(response);  
  116.   
  117.         return result;  
  118.     }  
  119.   
  120.   
  121.     /** 
  122.     *  
  123.     * 撤销订单API接口 
  124.     * @param WxPayData inputObj 提交给撤销订单API接口的参数,out_trade_no和transaction_id必填一个 
  125.     * @param int timeOut 接口超时时间 
  126.     * @throws WxPayException 
  127.     * @return 成功时返回API调用结果,其他抛异常 
  128.      * @throws IOException  
  129.      * @throws KeyStoreException  
  130.      * @throws NoSuchAlgorithmException  
  131.      * @throws KeyManagementException  
  132.      * @throws UnrecoverableKeyException  
  133.      * @throws SAXException  
  134.      * @throws ParserConfigurationException  
  135.     */  
  136.     public static WxPayData Reverse(WxPayData inputObj, int timeOut) throws WxPayException, UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, ParserConfigurationException, SAXException  
  137.     {  
  138.         String url =Configure.REVERSE_API;  
  139.         //检测必填参数  
  140.         if (!inputObj.IsSet(“out_trade_no”) && !inputObj.IsSet(“transaction_id”))  
  141.         {  
  142.             throw new WxPayException(“撤销订单API接口中,参数out_trade_no和transaction_id必须填写一个!”);  
  143.         }  
  144.   
  145.         inputObj.SetValue(”appid”, Configure.getAppid());//公众账号ID  
  146.         inputObj.SetValue(”mch_id”, Configure.getMchid());//商户号  
  147.         inputObj.SetValue(”nonce_str”, GenerateNonceStr());//随机字符串  
  148.         inputObj.SetValue(”sign”, inputObj.MakeSign());//签名  
  149.         String xml = inputObj.ToXml();  
  150.   
  151.   
  152.         HttpsRequest https=new HttpsRequest();  
  153.         https.setSocketTimeout(timeOut);  
  154.         String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API  
  155.         WxPayData result = new WxPayData();  
  156.         result.FromXml(response);  
  157.   
  158.         return result;  
  159.     }  
  160.   
  161.   
  162.     /** 
  163.     *  
  164.     * 申请退款 
  165.     * @param WxPayData inputObj 提交给申请退款API的参数 
  166.     * @param int timeOut 超时时间 
  167.     * @throws WxPayException 
  168.     * @return 成功时返回接口调用结果,其他抛异常 
  169.      * @throws IOException  
  170.      * @throws KeyStoreException  
  171.      * @throws NoSuchAlgorithmException  
  172.      * @throws KeyManagementException  
  173.      * @throws UnrecoverableKeyException  
  174.      * @throws SAXException  
  175.      * @throws ParserConfigurationException  
  176.     */  
  177.     public static WxPayData Refund(WxPayData inputObj, int timeOut) throws WxPayException, UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, ParserConfigurationException, SAXException  
  178.     {  
  179.         String url = Configure.REFUND_API;  
  180.         //检测必填参数  
  181.         if (!inputObj.IsSet(“out_trade_no”) && !inputObj.IsSet(“transaction_id”))  
  182.         {  
  183.             throw new WxPayException(“退款申请接口中,out_trade_no、transaction_id至少填一个!”);  
  184.         }  
  185.         else if (!inputObj.IsSet(“out_refund_no”))  
  186.         {  
  187.             throw new WxPayException(“退款申请接口中,缺少必填参数out_refund_no!”);  
  188.         }  
  189.         else if (!inputObj.IsSet(“total_fee”))  
  190.         {  
  191.             throw new WxPayException(“退款申请接口中,缺少必填参数total_fee!”);  
  192.         }  
  193.         else if (!inputObj.IsSet(“refund_fee”))  
  194.         {  
  195.             throw new WxPayException(“退款申请接口中,缺少必填参数refund_fee!”);  
  196.         }  
  197.         else if (!inputObj.IsSet(“op_user_id”))  
  198.         {  
  199.             throw new WxPayException(“退款申请接口中,缺少必填参数op_user_id!”);  
  200.         }  
  201.   
  202.         inputObj.SetValue(”appid”, Configure.getAppid());//公众账号ID  
  203.         inputObj.SetValue(”mch_id”, Configure.getMchid());//商户号  
  204.         inputObj.SetValue(”nonce_str”, UUIDGenerator.getUUID().toString().replace(“-““”));//随机字符串  
  205.         inputObj.SetValue(”sign”, inputObj.MakeSign());//签名  
  206.           
  207.         String xml = inputObj.ToXml();  
  208.     
  209.         HttpsRequest https=new HttpsRequest();  
  210.         https.setSocketTimeout(timeOut);  
  211.         String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API  
  212.         WxPayData result = new WxPayData();  
  213.         result.FromXml(response);  
  214.   
  215.         return result;  
  216.     }  
  217.   
  218.   
  219.     /** 
  220.     *  
  221.     * 查询退款 
  222.     * 提交退款申请后,通过该接口查询退款状态。退款有一定延时, 
  223.     * 用零钱支付的退款20分钟内到账,银行卡支付的退款3个工作日后重新查询退款状态。 
  224.     * out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个 
  225.     * @param WxPayData inputObj 提交给查询退款API的参数 
  226.     * @param int timeOut 接口超时时间 
  227.     * @throws WxPayException 
  228.     * @return 成功时返回,其他抛异常 
  229.      * @throws IOException  
  230.      * @throws KeyStoreException  
  231.      * @throws NoSuchAlgorithmException  
  232.      * @throws KeyManagementException  
  233.      * @throws UnrecoverableKeyException  
  234.      * @throws SAXException  
  235.      * @throws ParserConfigurationException  
  236.     */  
  237.     public static WxPayData RefundQuery(WxPayData inputObj, int timeOut) throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, WxPayException, ParserConfigurationException, SAXException  
  238.     {  
  239.         String url = Configure.REFUND_QUERY_API;  
  240.         //检测必填参数  
  241.         if(!inputObj.IsSet(“out_refund_no”) && !inputObj.IsSet(“out_trade_no”) &&  
  242.             !inputObj.IsSet(”transaction_id”) && !inputObj.IsSet(“refund_id”))  
  243.         {  
  244.             throw new WxPayException(“退款查询接口中,out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个!”);  
  245.         }  
  246.   
  247.         inputObj.SetValue(”appid”,Configure.getAppid());//公众账号ID  
  248.         inputObj.SetValue(”mch_id”,Configure.getMchid());//商户号  
  249.         inputObj.SetValue(”nonce_str”,GenerateNonceStr());//随机字符串  
  250.         inputObj.SetValue(”sign”,inputObj.MakeSign());//签名  
  251.   
  252.         String xml = inputObj.ToXml();  
  253.       
  254.         
  255.         HttpsRequest https=new HttpsRequest();  
  256.         https.setSocketTimeout(timeOut);  
  257.         String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API  
  258.         WxPayData result = new WxPayData();  
  259.         result.FromXml(response);  
  260.   
  261.         return result;  
  262.     }  
  263.   
  264.   
  265.     /** 
  266.     * 下载对账单 
  267.     * @param WxPayData inputObj 提交给下载对账单API的参数 
  268.     * @param int timeOut 接口超时时间 
  269.     * @throws WxPayException 
  270.     * @return 成功时返回,其他抛异常 
  271.      * @throws IOException  
  272.      * @throws NoSuchAlgorithmException  
  273.      * @throws KeyStoreException  
  274.      * @throws KeyManagementException  
  275.      * @throws UnrecoverableKeyException  
  276.      * @throws SAXException  
  277.      * @throws ParserConfigurationException  
  278.     */  
  279.     public static WxPayData DownloadBill(WxPayData inputObj, int timeOut) throws UnrecoverableKeyException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, IOException, WxPayException, ParserConfigurationException, SAXException  
  280.     {  
  281.         String url = Configure.DOWNLOAD_BILL_API;  
  282.         //检测必填参数  
  283.         if (!inputObj.IsSet(“bill_date”))  
  284.         {  
  285.             throw new WxPayException(“对账单接口中,缺少必填参数bill_date!”);  
  286.         }  
  287.   
  288.         inputObj.SetValue(”appid”, Configure.getAppid());//公众账号ID  
  289.         inputObj.SetValue(”mch_id”, Configure.getMchid());//商户号  
  290.         inputObj.SetValue(”nonce_str”, GenerateNonceStr());//随机字符串  
  291.         inputObj.SetValue(”sign”, inputObj.MakeSign());//签名  
  292.   
  293.         String xml = inputObj.ToXml();  
  294.   
  295.         HttpsRequest https=new HttpsRequest();  
  296.         https.setSocketTimeout(timeOut);  
  297.         String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API  
  298.        
  299.         WxPayData result = new WxPayData();  
  300.         //若接口调用失败会返回xml格式的结果  
  301.         if (response.startsWith())  
  302.         {  
  303.           
  304.                result.FromXml(response);  
  305.         }  
  306.         //接口调用成功则返回非xml格式的数据  
  307.         else  
  308.             result.SetValue(”result”, response);  
  309.   
  310.         return result;  
  311.     }  
  312.   
  313.   
  314.     /** 
  315.     *  
  316.     * 转换短链接 
  317.     * 该接口主要用于扫码原生支付模式一中的二维码链接转成短链接(weixin://wxpay/s/XXXXXX), 
  318.     * 减小二维码数据量,提升扫描速度和精确度。 
  319.     * @param WxPayData inputObj 提交给转换短连接API的参数 
  320.     * @param int timeOut 接口超时时间 
  321.     * @throws WxPayException 
  322.     * @return 成功时返回,其他抛异常 
  323.      * @throws IOException  
  324.      * @throws KeyStoreException  
  325.      * @throws NoSuchAlgorithmException  
  326.      * @throws KeyManagementException  
  327.      * @throws UnrecoverableKeyException  
  328.      * @throws SAXException  
  329.      * @throws ParserConfigurationException  
  330.     */  
  331.     public static WxPayData ShortUrl(WxPayData inputObj, int timeOut) throws WxPayException, UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, ParserConfigurationException, SAXException  
  332.     {  
  333.         String url = Configure.Shorturl_API;  
  334.         //检测必填参数  
  335.         if(!inputObj.IsSet(“long_url”))  
  336.         {  
  337.             throw new WxPayException(“需要转换的URL,签名用原串,传输需URL encode!”);  
  338.         }  
  339.   
  340.         inputObj.SetValue(”appid”,Configure.getAppid());//公众账号ID  
  341.         inputObj.SetValue(”mch_id”,Configure.getMchid());//商户号  
  342.         inputObj.SetValue(”nonce_str”,GenerateNonceStr());//随机字符串     
  343.         inputObj.SetValue(”sign”,inputObj.MakeSign());//签名  
  344.         String xml = inputObj.ToXml();  
  345.       
  346.         HttpsRequest https=new HttpsRequest();  
  347.         https.setSocketTimeout(timeOut);  
  348.         String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API  
  349.         WxPayData result = new WxPayData();  
  350.         result.FromXml(response);  
  351.   
  352.   
  353.   
  354.       
  355.         return result;  
  356.     }  
  357.   
  358.   
  359.     /** 
  360.     *  
  361.     * 统一下单 
  362.     * @param WxPaydata inputObj 提交给统一下单API的参数 
  363.     * @param int timeOut 超时时间 
  364.     * @throws WxPayException 
  365.     * @return 成功时返回,其他抛异常 
  366.      * @throws IOException  
  367.      * @throws KeyStoreException  
  368.      * @throws NoSuchAlgorithmException  
  369.      * @throws KeyManagementException  
  370.      * @throws UnrecoverableKeyException  
  371.      * @throws SAXException  
  372.      * @throws ParserConfigurationException  
  373.     */  
  374.     public static WxPayData UnifiedOrder(WxPayData inputObj, int timeOut) throws WxPayException, UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, ParserConfigurationException, SAXException  
  375.     {  
  376.         String url =Configure.UnifiedOrder_API;  
  377.         //检测必填参数  
  378.         if (!inputObj.IsSet(“out_trade_no”))  
  379.         {  
  380.             throw new WxPayException(“缺少统一支付接口必填参数out_trade_no!”);  
  381.         }  
  382.         else if (!inputObj.IsSet(“body”))  
  383.         {  
  384.             throw new WxPayException(“缺少统一支付接口必填参数body!”);  
  385.         }  
  386.         else if (!inputObj.IsSet(“total_fee”))  
  387.         {  
  388.             throw new WxPayException(“缺少统一支付接口必填参数total_fee!”);  
  389.         }  
  390.         else if (!inputObj.IsSet(“trade_type”))  
  391.         {  
  392.             throw new WxPayException(“缺少统一支付接口必填参数trade_type!”);  
  393.         }  
  394.   
  395.         //关联参数  
  396.         if (inputObj.GetValue(“trade_type”).toString() == “JSAPI” && !inputObj.IsSet(“openid”))  
  397.         {  
  398.             throw new WxPayException(“统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!”);  
  399.         }  
  400.         if (inputObj.GetValue(“trade_type”).toString() == “NATIVE” && !inputObj.IsSet(“product_id”))  
  401.         {  
  402.             throw new WxPayException(“统一支付接口中,缺少必填参数product_id!trade_type为JSAPI时,product_id为必填参数!”);  
  403.         }  
  404.   
  405.         //异步通知url未设置,则使用配置文件中的url  
  406.         if (!inputObj.IsSet(“notify_url”))  
  407.         {  
  408.             inputObj.SetValue(”notify_url”, Configure.NOTIFY_URL);//异步通知url  
  409.         }  
  410.   
  411.         inputObj.SetValue(”appid”, Configure.getAppid());//公众账号ID  
  412.         inputObj.SetValue(”mch_id”, Configure.getMchid());//商户号  
  413.         inputObj.SetValue(”spbill_create_ip”, Configure.getIP());//终端ip           
  414.         inputObj.SetValue(”nonce_str”, GenerateNonceStr());//随机字符串  
  415.   
  416.         //签名  
  417.         inputObj.SetValue(”sign”, inputObj.MakeSign());  
  418.         String xml = inputObj.ToXml();  
  419.   
  420.      
  421.         HttpsRequest https=new HttpsRequest();  
  422.         https.setSocketTimeout(timeOut);  
  423.         String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API  
  424.         WxPayData result = new WxPayData();  
  425.         result.FromXml(response);  
  426.   
  427.   
  428.   
  429.         return result;  
  430.     }  
  431.   
  432.   
  433.     /** 
  434.     *  
  435.     * 关闭订单 
  436.     * @param WxPayData inputObj 提交给关闭订单API的参数 
  437.     * @param int timeOut 接口超时时间 
  438.     * @throws WxPayException 
  439.     * @return 成功时返回,其他抛异常 
  440.      * @throws IOException  
  441.      * @throws KeyStoreException  
  442.      * @throws NoSuchAlgorithmException  
  443.      * @throws KeyManagementException  
  444.      * @throws UnrecoverableKeyException  
  445.      * @throws SAXException  
  446.      * @throws ParserConfigurationException  
  447.     */  
  448.     public static WxPayData CloseOrder(WxPayData inputObj, int timeOut) throws WxPayException, UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, ParserConfigurationException, SAXException  
  449.     {  
  450.           
  451.         String url =Configure.CloseOrder_API;  
  452.         //检测必填参数  
  453.         if(!inputObj.IsSet(“out_trade_no”))  
  454.         {  
  455.             throw new WxPayException(“关闭订单接口中,out_trade_no必填!”);  
  456.         }  
  457.   
  458.         inputObj.SetValue(”appid”,Configure.getAppid());//公众账号ID  
  459.         inputObj.SetValue(”mch_id”,Configure.getMchid());//商户号  
  460.         inputObj.SetValue(”nonce_str”,GenerateNonceStr());//随机字符串         
  461.         inputObj.SetValue(”sign”,inputObj.MakeSign());//签名  
  462.         String xml = inputObj.ToXml();  
  463.       
  464.         HttpsRequest https=new HttpsRequest();  
  465.         https.setSocketTimeout(timeOut);  
  466.         String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API  
  467.         WxPayData result = new WxPayData();  
  468.         result.FromXml(response);  
  469.   
  470.       
  471.         return result;  
  472.     }  
  473.   
  474.   
  475.     /** 
  476.     *  
  477.     * 测速上报 
  478.     * @param String interface_url 接口URL 
  479.     * @param int timeCost 接口耗时 
  480.     * @param WxPayData inputObj参数数组 
  481.     */  
  482.     private static void ReportCostTime(String interface_url, int timeCost, WxPayData inputObj)  
  483.     {  
  484.         //如果不需要进行上报  
  485.         if(REPORT_LEVENL == 0)  
  486.         {  
  487.             return;  
  488.         }   
  489.   
  490.         //如果仅失败上报  
  491.         if(REPORT_LEVENL == 1 && inputObj.IsSet(“return_code”) && inputObj.GetValue(“return_code”).toString() == “SUCCESS” &&  
  492.          inputObj.IsSet(”result_code”) && inputObj.GetValue(“result_code”).toString() == “SUCCESS”)  
  493.         {  
  494.             return;  
  495.         }  
  496.        
  497.         //上报逻辑  
  498.         WxPayData data = new WxPayData();  
  499.         data.SetValue(”interface_url”,interface_url);  
  500.         data.SetValue(”execute_time_”,timeCost);  
  501.         //返回状态码  
  502.         if(inputObj.IsSet(“return_code”))  
  503.         {  
  504.             data.SetValue(”return_code”,inputObj.GetValue(“return_code”));  
  505.         }  
  506.         //返回信息  
  507.         if(inputObj.IsSet(“return_msg”))  
  508.         {  
  509.             data.SetValue(”return_msg”,inputObj.GetValue(“return_msg”));  
  510.         }  
  511.         //业务结果  
  512.         if(inputObj.IsSet(“result_code”))  
  513.         {  
  514.             data.SetValue(”result_code”,inputObj.GetValue(“result_code”));  
  515.         }  
  516.         //错误代码  
  517.         if(inputObj.IsSet(“err_code”))  
  518.         {  
  519.             data.SetValue(”err_code”,inputObj.GetValue(“err_code”));  
  520.         }  
  521.         //错误代码描述  
  522.         if(inputObj.IsSet(“err_code_des”))  
  523.         {  
  524.             data.SetValue(”err_code_des”,inputObj.GetValue(“err_code_des”));  
  525.         }  
  526.         //商户订单号  
  527.         if(inputObj.IsSet(“out_trade_no”))  
  528.         {  
  529.             data.SetValue(”out_trade_no”,inputObj.GetValue(“out_trade_no”));  
  530.         }  
  531.         //设备号  
  532.         if(inputObj.IsSet(“device_info”))  
  533.         {  
  534.             data.SetValue(”device_info”,inputObj.GetValue(“device_info”));  
  535.         }  
  536.       
  537.     }  
  538.   
  539.   
  540.     /** 
  541.     *  
  542.     * 测速上报接口实现 
  543.     * @param WxPayData inputObj 提交给测速上报接口的参数 
  544.     * @param int timeOut 测速上报接口超时时间 
  545.     * @throws WxPayException 
  546.     * @return 成功时返回测速上报接口返回的结果,其他抛异常 
  547.      * @throws IOException  
  548.      * @throws KeyStoreException  
  549.      * @throws NoSuchAlgorithmException  
  550.      * @throws KeyManagementException  
  551.      * @throws UnrecoverableKeyException  
  552.      * @throws SAXException  
  553.      * @throws ParserConfigurationException  
  554.     */  
  555.     public static WxPayData Report(WxPayData inputObj, int timeOut) throws WxPayException, UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, ParserConfigurationException, SAXException  
  556.     {  
  557.         String url = Configure.REPORT_API;  
  558.         //检测必填参数  
  559.         if(!inputObj.IsSet(“interface_url”))  
  560.         {  
  561.             throw new WxPayException(“接口URL,缺少必填参数interface_url!”);  
  562.         }   
  563.         if(!inputObj.IsSet(“return_code”))  
  564.         {  
  565.             throw new WxPayException(“返回状态码,缺少必填参数return_code!”);  
  566.         }   
  567.         if(!inputObj.IsSet(“result_code”))  
  568.         {  
  569.             throw new WxPayException(“业务结果,缺少必填参数result_code!”);  
  570.         }   
  571.         if(!inputObj.IsSet(“user_ip”))  
  572.         {  
  573.             throw new WxPayException(“访问接口IP,缺少必填参数user_ip!”);  
  574.         }   
  575.         if(!inputObj.IsSet(“execute_time_”))  
  576.         {  
  577.             throw new WxPayException(“接口耗时,缺少必填参数execute_time_!”);  
  578.         }  
  579.   
  580.         inputObj.SetValue(”appid”,Configure.getAppid());//公众账号ID  
  581.         inputObj.SetValue(”mch_id”,Configure.getMchid());//商户号  
  582.         inputObj.SetValue(”user_ip”,Configure.getIP());//终端ip  
  583.         inputObj.SetValue(”time”,CommonClass.GetCurrentDateTimeTextNosplit());//商户上报时间     
  584.         inputObj.SetValue(”nonce_str”,GenerateNonceStr());//随机字符串  
  585.         inputObj.SetValue(”sign”,inputObj.MakeSign());//签名  
  586.         String xml = inputObj.ToXml();  
  587.   
  588.         HttpsRequest https=new HttpsRequest();  
  589.         https.setSocketTimeout(timeOut);  
  590.         String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API  
  591.         WxPayData result = new WxPayData();  
  592.         result.FromXml(response);  
  593.   
  594.         return result;  
  595.     }  
  596.   
  597.     /** 
  598.     * 根据当前系统时间加随机序列来生成订单号 
  599.      * @return 订单号 
  600.     */  
  601.     public static String GenerateOutTradeNo()  
  602.     {  
  603.         Random ran = new Random();  
  604.         return String.format(“{0}{1}{2}”, Configure.getMchid(),CommonClass.GetCurrentDateTimeTextNosplit(), ran.nextInt(999));  
  605.     }  
  606.   
  607.     /** 
  608.     * 生成时间戳,标准北京时间,时区为东八区,自1970年1月1日 0点0分0秒以来的秒数 
  609.      * @return 时间戳 
  610.     */  
  611.     public static String GenerateTimeStamp()  
  612.     {  
  613.         //Java中的getTime方法默认的是从1970 1 1 算起所以可以直接调用  
  614.         //date.getTime获得的是毫秒数,不是秒,所以最后的结果day应当再除以1000才对。  
  615.         return String.valueOf(Calendar.getInstance().getTimeInMillis()/1000);  
  616.     }  
  617.   
  618.     /** 
  619.     * 生成随机串,随机串包含字母或数字 
  620.     * @return 随机串 
  621.     */  
  622.     public static String GenerateNonceStr()  
  623.     {  
  624.         return UUIDGenerator.getUUID().toString().replace(“-““”);  
  625.     }  
  626. }  
package com.luozhuang;

import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;

import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.SAXException;

import com.fastwixinextend.CommonClass;
import com.luozhuang.util.Configure;
import com.luozhuang.util.HttpsRequest;

public class WxPayApi
{
    private static final int REPORT_LEVENL = 0;

    /**
    * 提交被扫支付API
    * 收银员使用扫码设备读取微信用户刷卡授权码以后,二维码或条码信息传送至商户收银台,
    * 由商户收银台或者商户后台调用该接口发起支付。
    * @param WxPayData inputObj 提交给被扫支付API的参数
    * @param int timeOut 超时时间
    * @throws WxPayException
    * @return 成功时返回调用结果,其他抛异常
     * @throws IOException 
     * @throws KeyStoreException 
     * @throws NoSuchAlgorithmException 
     * @throws KeyManagementException 
     * @throws UnrecoverableKeyException 
     * @throws SAXException 
     * @throws ParserConfigurationException 
    */
    public static WxPayData Micropay(WxPayData inputObj, int timeOut) throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, WxPayException, ParserConfigurationException, SAXException
    {
        String url =Configure.PAY_API;
        //检测必填参数
        if (!inputObj.IsSet("body"))
        {
            throw new WxPayException("提交被扫支付API接口中,缺少必填参数body!");
        }
        else if (!inputObj.IsSet("out_trade_no"))
        {
            throw new WxPayException("提交被扫支付API接口中,缺少必填参数out_trade_no!");
        }
        else if (!inputObj.IsSet("total_fee"))
        {
            throw new WxPayException("提交被扫支付API接口中,缺少必填参数total_fee!");
        }
        else if (!inputObj.IsSet("auth_code"))
        {
            throw new WxPayException("提交被扫支付API接口中,缺少必填参数auth_code!");
        }

        inputObj.SetValue("spbill_create_ip", Configure.getIP());//终端ip
        inputObj.SetValue("appid", Configure.getAppid());//公众账号ID
        inputObj.SetValue("mch_id", Configure.getMchid());//商户号
        inputObj.SetValue("nonce_str", UUIDGenerator.getUUID().toString().replace("-", ""));//随机字符串
        inputObj.SetValue("sign", inputObj.MakeSign());//签名
        String xml = inputObj.ToXml();

        HttpsRequest https=new HttpsRequest();
        https.setSocketTimeout(timeOut);
        String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API
        WxPayData result = new WxPayData();
        result.FromXml(response);



        return result;
    }


    /**
    *    
    * 查询订单
    * @param WxPayData inputObj 提交给查询订单API的参数
    * @param int timeOut 超时时间
    * @throws WxPayException
    * @return 成功时返回订单查询结果,其他抛异常
     * @throws IOException 
     * @throws KeyStoreException 
     * @throws NoSuchAlgorithmException 
     * @throws KeyManagementException 
     * @throws UnrecoverableKeyException 
     * @throws SAXException 
     * @throws ParserConfigurationException 
    */
    public static WxPayData OrderQuery(WxPayData inputObj, int timeOut) throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, WxPayException, ParserConfigurationException, SAXException
    {
        String url = Configure.PAY_QUERY_API;
        //检测必填参数
        if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id"))
        {
            throw new WxPayException("订单查询接口中,out_trade_no、transaction_id至少填一个!");
        }

        inputObj.SetValue("appid", Configure.getAppid());//公众账号ID
        inputObj.SetValue("mch_id", Configure.getMchid());//商户号
        inputObj.SetValue("nonce_str", WxPayApi.GenerateNonceStr());//随机字符串
        inputObj.SetValue("sign", inputObj.MakeSign());//签名

        String xml = inputObj.ToXml();

        HttpsRequest https=new HttpsRequest();
        https.setSocketTimeout(timeOut);
        String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API
        WxPayData result = new WxPayData();
        result.FromXml(response);

        return result;
    }


    /**
    * 
    * 撤销订单API接口
    * @param WxPayData inputObj 提交给撤销订单API接口的参数,out_trade_no和transaction_id必填一个
    * @param int timeOut 接口超时时间
    * @throws WxPayException
    * @return 成功时返回API调用结果,其他抛异常
     * @throws IOException 
     * @throws KeyStoreException 
     * @throws NoSuchAlgorithmException 
     * @throws KeyManagementException 
     * @throws UnrecoverableKeyException 
     * @throws SAXException 
     * @throws ParserConfigurationException 
    */
    public static WxPayData Reverse(WxPayData inputObj, int timeOut) throws WxPayException, UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, ParserConfigurationException, SAXException
    {
        String url =Configure.REVERSE_API;
        //检测必填参数
        if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id"))
        {
            throw new WxPayException("撤销订单API接口中,参数out_trade_no和transaction_id必须填写一个!");
        }

        inputObj.SetValue("appid", Configure.getAppid());//公众账号ID
        inputObj.SetValue("mch_id", Configure.getMchid());//商户号
        inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串
        inputObj.SetValue("sign", inputObj.MakeSign());//签名
        String xml = inputObj.ToXml();


        HttpsRequest https=new HttpsRequest();
        https.setSocketTimeout(timeOut);
        String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API
        WxPayData result = new WxPayData();
        result.FromXml(response);

        return result;
    }


    /**
    * 
    * 申请退款
    * @param WxPayData inputObj 提交给申请退款API的参数
    * @param int timeOut 超时时间
    * @throws WxPayException
    * @return 成功时返回接口调用结果,其他抛异常
     * @throws IOException 
     * @throws KeyStoreException 
     * @throws NoSuchAlgorithmException 
     * @throws KeyManagementException 
     * @throws UnrecoverableKeyException 
     * @throws SAXException 
     * @throws ParserConfigurationException 
    */
    public static WxPayData Refund(WxPayData inputObj, int timeOut) throws WxPayException, UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, ParserConfigurationException, SAXException
    {
        String url = Configure.REFUND_API;
        //检测必填参数
        if (!inputObj.IsSet("out_trade_no") && !inputObj.IsSet("transaction_id"))
        {
            throw new WxPayException("退款申请接口中,out_trade_no、transaction_id至少填一个!");
        }
        else if (!inputObj.IsSet("out_refund_no"))
        {
            throw new WxPayException("退款申请接口中,缺少必填参数out_refund_no!");
        }
        else if (!inputObj.IsSet("total_fee"))
        {
            throw new WxPayException("退款申请接口中,缺少必填参数total_fee!");
        }
        else if (!inputObj.IsSet("refund_fee"))
        {
            throw new WxPayException("退款申请接口中,缺少必填参数refund_fee!");
        }
        else if (!inputObj.IsSet("op_user_id"))
        {
            throw new WxPayException("退款申请接口中,缺少必填参数op_user_id!");
        }

        inputObj.SetValue("appid", Configure.getAppid());//公众账号ID
        inputObj.SetValue("mch_id", Configure.getMchid());//商户号
        inputObj.SetValue("nonce_str", UUIDGenerator.getUUID().toString().replace("-", ""));//随机字符串
        inputObj.SetValue("sign", inputObj.MakeSign());//签名

        String xml = inputObj.ToXml();

        HttpsRequest https=new HttpsRequest();
        https.setSocketTimeout(timeOut);
        String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API
        WxPayData result = new WxPayData();
        result.FromXml(response);

        return result;
    }


    /**
    * 
    * 查询退款
    * 提交退款申请后,通过该接口查询退款状态。退款有一定延时,
    * 用零钱支付的退款20分钟内到账,银行卡支付的退款3个工作日后重新查询退款状态。
    * out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个
    * @param WxPayData inputObj 提交给查询退款API的参数
    * @param int timeOut 接口超时时间
    * @throws WxPayException
    * @return 成功时返回,其他抛异常
     * @throws IOException 
     * @throws KeyStoreException 
     * @throws NoSuchAlgorithmException 
     * @throws KeyManagementException 
     * @throws UnrecoverableKeyException 
     * @throws SAXException 
     * @throws ParserConfigurationException 
    */
    public static WxPayData RefundQuery(WxPayData inputObj, int timeOut) throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, WxPayException, ParserConfigurationException, SAXException
    {
        String url = Configure.REFUND_QUERY_API;
        //检测必填参数
        if(!inputObj.IsSet("out_refund_no") && !inputObj.IsSet("out_trade_no") &&
            !inputObj.IsSet("transaction_id") && !inputObj.IsSet("refund_id"))
        {
            throw new WxPayException("退款查询接口中,out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个!");
        }

        inputObj.SetValue("appid",Configure.getAppid());//公众账号ID
        inputObj.SetValue("mch_id",Configure.getMchid());//商户号
        inputObj.SetValue("nonce_str",GenerateNonceStr());//随机字符串
        inputObj.SetValue("sign",inputObj.MakeSign());//签名

        String xml = inputObj.ToXml();


        HttpsRequest https=new HttpsRequest();
        https.setSocketTimeout(timeOut);
        String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API
        WxPayData result = new WxPayData();
        result.FromXml(response);

        return result;
    }


    /**
    * 下载对账单
    * @param WxPayData inputObj 提交给下载对账单API的参数
    * @param int timeOut 接口超时时间
    * @throws WxPayException
    * @return 成功时返回,其他抛异常
     * @throws IOException 
     * @throws NoSuchAlgorithmException 
     * @throws KeyStoreException 
     * @throws KeyManagementException 
     * @throws UnrecoverableKeyException 
     * @throws SAXException 
     * @throws ParserConfigurationException 
    */
    public static WxPayData DownloadBill(WxPayData inputObj, int timeOut) throws UnrecoverableKeyException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, IOException, WxPayException, ParserConfigurationException, SAXException
    {
        String url = Configure.DOWNLOAD_BILL_API;
        //检测必填参数
        if (!inputObj.IsSet("bill_date"))
        {
            throw new WxPayException("对账单接口中,缺少必填参数bill_date!");
        }

        inputObj.SetValue("appid", Configure.getAppid());//公众账号ID
        inputObj.SetValue("mch_id", Configure.getMchid());//商户号
        inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串
        inputObj.SetValue("sign", inputObj.MakeSign());//签名

        String xml = inputObj.ToXml();

        HttpsRequest https=new HttpsRequest();
        https.setSocketTimeout(timeOut);
        String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API

        WxPayData result = new WxPayData();
        //若接口调用失败会返回xml格式的结果
        if (response.startsWith(""))
        {

               result.FromXml(response);
        }
        //接口调用成功则返回非xml格式的数据
        else
            result.SetValue("result", response);

        return result;
    }


    /**
    * 
    * 转换短链接
    * 该接口主要用于扫码原生支付模式一中的二维码链接转成短链接(weixin://wxpay/s/XXXXXX),
    * 减小二维码数据量,提升扫描速度和精确度。
    * @param WxPayData inputObj 提交给转换短连接API的参数
    * @param int timeOut 接口超时时间
    * @throws WxPayException
    * @return 成功时返回,其他抛异常
     * @throws IOException 
     * @throws KeyStoreException 
     * @throws NoSuchAlgorithmException 
     * @throws KeyManagementException 
     * @throws UnrecoverableKeyException 
     * @throws SAXException 
     * @throws ParserConfigurationException 
    */
    public static WxPayData ShortUrl(WxPayData inputObj, int timeOut) throws WxPayException, UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, ParserConfigurationException, SAXException
    {
        String url = Configure.Shorturl_API;
        //检测必填参数
        if(!inputObj.IsSet("long_url"))
        {
            throw new WxPayException("需要转换的URL,签名用原串,传输需URL encode!");
        }

        inputObj.SetValue("appid",Configure.getAppid());//公众账号ID
        inputObj.SetValue("mch_id",Configure.getMchid());//商户号
        inputObj.SetValue("nonce_str",GenerateNonceStr());//随机字符串   
        inputObj.SetValue("sign",inputObj.MakeSign());//签名
        String xml = inputObj.ToXml();

        HttpsRequest https=new HttpsRequest();
        https.setSocketTimeout(timeOut);
        String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API
        WxPayData result = new WxPayData();
        result.FromXml(response);




        return result;
    }


    /**
    * 
    * 统一下单
    * @param WxPaydata inputObj 提交给统一下单API的参数
    * @param int timeOut 超时时间
    * @throws WxPayException
    * @return 成功时返回,其他抛异常
     * @throws IOException 
     * @throws KeyStoreException 
     * @throws NoSuchAlgorithmException 
     * @throws KeyManagementException 
     * @throws UnrecoverableKeyException 
     * @throws SAXException 
     * @throws ParserConfigurationException 
    */
    public static WxPayData UnifiedOrder(WxPayData inputObj, int timeOut) throws WxPayException, UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, ParserConfigurationException, SAXException
    {
        String url =Configure.UnifiedOrder_API;
        //检测必填参数
        if (!inputObj.IsSet("out_trade_no"))
        {
            throw new WxPayException("缺少统一支付接口必填参数out_trade_no!");
        }
        else if (!inputObj.IsSet("body"))
        {
            throw new WxPayException("缺少统一支付接口必填参数body!");
        }
        else if (!inputObj.IsSet("total_fee"))
        {
            throw new WxPayException("缺少统一支付接口必填参数total_fee!");
        }
        else if (!inputObj.IsSet("trade_type"))
        {
            throw new WxPayException("缺少统一支付接口必填参数trade_type!");
        }

        //关联参数
        if (inputObj.GetValue("trade_type").toString() == "JSAPI" && !inputObj.IsSet("openid"))
        {
            throw new WxPayException("统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!");
        }
        if (inputObj.GetValue("trade_type").toString() == "NATIVE" && !inputObj.IsSet("product_id"))
        {
            throw new WxPayException("统一支付接口中,缺少必填参数product_id!trade_type为JSAPI时,product_id为必填参数!");
        }

        //异步通知url未设置,则使用配置文件中的url
        if (!inputObj.IsSet("notify_url"))
        {
            inputObj.SetValue("notify_url", Configure.NOTIFY_URL);//异步通知url
        }

        inputObj.SetValue("appid", Configure.getAppid());//公众账号ID
        inputObj.SetValue("mch_id", Configure.getMchid());//商户号
        inputObj.SetValue("spbill_create_ip", Configure.getIP());//终端ip         
        inputObj.SetValue("nonce_str", GenerateNonceStr());//随机字符串

        //签名
        inputObj.SetValue("sign", inputObj.MakeSign());
        String xml = inputObj.ToXml();


        HttpsRequest https=new HttpsRequest();
        https.setSocketTimeout(timeOut);
        String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API
        WxPayData result = new WxPayData();
        result.FromXml(response);



        return result;
    }


    /**
    * 
    * 关闭订单
    * @param WxPayData inputObj 提交给关闭订单API的参数
    * @param int timeOut 接口超时时间
    * @throws WxPayException
    * @return 成功时返回,其他抛异常
     * @throws IOException 
     * @throws KeyStoreException 
     * @throws NoSuchAlgorithmException 
     * @throws KeyManagementException 
     * @throws UnrecoverableKeyException 
     * @throws SAXException 
     * @throws ParserConfigurationException 
    */
    public static WxPayData CloseOrder(WxPayData inputObj, int timeOut) throws WxPayException, UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, ParserConfigurationException, SAXException
    {

        String url =Configure.CloseOrder_API;
        //检测必填参数
        if(!inputObj.IsSet("out_trade_no"))
        {
            throw new WxPayException("关闭订单接口中,out_trade_no必填!");
        }

        inputObj.SetValue("appid",Configure.getAppid());//公众账号ID
        inputObj.SetValue("mch_id",Configure.getMchid());//商户号
        inputObj.SetValue("nonce_str",GenerateNonceStr());//随机字符串       
        inputObj.SetValue("sign",inputObj.MakeSign());//签名
        String xml = inputObj.ToXml();

        HttpsRequest https=new HttpsRequest();
        https.setSocketTimeout(timeOut);
        String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API
        WxPayData result = new WxPayData();
        result.FromXml(response);


        return result;
    }


    /**
    * 
    * 测速上报
    * @param String interface_url 接口URL
    * @param int timeCost 接口耗时
    * @param WxPayData inputObj参数数组
    */
    private static void ReportCostTime(String interface_url, int timeCost, WxPayData inputObj)
    {
        //如果不需要进行上报
        if(REPORT_LEVENL == 0)
        {
            return;
        } 

        //如果仅失败上报
        if(REPORT_LEVENL == 1 && inputObj.IsSet("return_code") && inputObj.GetValue("return_code").toString() == "SUCCESS" &&
         inputObj.IsSet("result_code") && inputObj.GetValue("result_code").toString() == "SUCCESS")
        {
            return;
        }

        //上报逻辑
        WxPayData data = new WxPayData();
        data.SetValue("interface_url",interface_url);
        data.SetValue("execute_time_",timeCost);
        //返回状态码
        if(inputObj.IsSet("return_code"))
        {
            data.SetValue("return_code",inputObj.GetValue("return_code"));
        }
        //返回信息
        if(inputObj.IsSet("return_msg"))
        {
            data.SetValue("return_msg",inputObj.GetValue("return_msg"));
        }
        //业务结果
        if(inputObj.IsSet("result_code"))
        {
            data.SetValue("result_code",inputObj.GetValue("result_code"));
        }
        //错误代码
        if(inputObj.IsSet("err_code"))
        {
            data.SetValue("err_code",inputObj.GetValue("err_code"));
        }
        //错误代码描述
        if(inputObj.IsSet("err_code_des"))
        {
            data.SetValue("err_code_des",inputObj.GetValue("err_code_des"));
        }
        //商户订单号
        if(inputObj.IsSet("out_trade_no"))
        {
            data.SetValue("out_trade_no",inputObj.GetValue("out_trade_no"));
        }
        //设备号
        if(inputObj.IsSet("device_info"))
        {
            data.SetValue("device_info",inputObj.GetValue("device_info"));
        }

    }


    /**
    * 
    * 测速上报接口实现
    * @param WxPayData inputObj 提交给测速上报接口的参数
    * @param int timeOut 测速上报接口超时时间
    * @throws WxPayException
    * @return 成功时返回测速上报接口返回的结果,其他抛异常
     * @throws IOException 
     * @throws KeyStoreException 
     * @throws NoSuchAlgorithmException 
     * @throws KeyManagementException 
     * @throws UnrecoverableKeyException 
     * @throws SAXException 
     * @throws ParserConfigurationException 
    */
    public static WxPayData Report(WxPayData inputObj, int timeOut) throws WxPayException, UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException, ParserConfigurationException, SAXException
    {
        String url = Configure.REPORT_API;
        //检测必填参数
        if(!inputObj.IsSet("interface_url"))
        {
            throw new WxPayException("接口URL,缺少必填参数interface_url!");
        } 
        if(!inputObj.IsSet("return_code"))
        {
            throw new WxPayException("返回状态码,缺少必填参数return_code!");
        } 
        if(!inputObj.IsSet("result_code"))
        {
            throw new WxPayException("业务结果,缺少必填参数result_code!");
        } 
        if(!inputObj.IsSet("user_ip"))
        {
            throw new WxPayException("访问接口IP,缺少必填参数user_ip!");
        } 
        if(!inputObj.IsSet("execute_time_"))
        {
            throw new WxPayException("接口耗时,缺少必填参数execute_time_!");
        }

        inputObj.SetValue("appid",Configure.getAppid());//公众账号ID
        inputObj.SetValue("mch_id",Configure.getMchid());//商户号
        inputObj.SetValue("user_ip",Configure.getIP());//终端ip
        inputObj.SetValue("time",CommonClass.GetCurrentDateTimeTextNosplit());//商户上报时间   
        inputObj.SetValue("nonce_str",GenerateNonceStr());//随机字符串
        inputObj.SetValue("sign",inputObj.MakeSign());//签名
        String xml = inputObj.ToXml();

        HttpsRequest https=new HttpsRequest();
        https.setSocketTimeout(timeOut);
        String response = https.sendPost(url, xml);//调用HTTP通信接口以提交数据到API
        WxPayData result = new WxPayData();
        result.FromXml(response);

        return result;
    }

    /**
    * 根据当前系统时间加随机序列来生成订单号
     * @return 订单号
    */
    public static String GenerateOutTradeNo()
    {
        Random ran = new Random();
        return String.format("{0}{1}{2}", Configure.getMchid(),CommonClass.GetCurrentDateTimeTextNosplit(), ran.nextInt(999));
    }

    /**
    * 生成时间戳,标准北京时间,时区为东八区,自1970年1月1日 0点0分0秒以来的秒数
     * @return 时间戳
    */
    public static String GenerateTimeStamp()
    {
        //Java中的getTime方法默认的是从1970 1 1 算起所以可以直接调用
        //date.getTime获得的是毫秒数,不是秒,所以最后的结果day应当再除以1000才对。
        return String.valueOf(Calendar.getInstance().getTimeInMillis()/1000);
    }

    /**
    * 生成随机串,随机串包含字母或数字
    * @return 随机串
    */
    public static String GenerateNonceStr()
    {
        return UUIDGenerator.getUUID().toString().replace("-", "");
    }
}

[java] view plain copy
print ?
  1. package com.luozhuang;  
  2.   
  3. import java.io.IOException;  
  4. import java.util.Map;  
  5. import java.util.SortedMap;  
  6. import java.util.TreeMap;  
  7. import java.util.regex.Matcher;  
  8. import java.util.regex.Pattern;  
  9.   
  10. import javax.xml.parsers.ParserConfigurationException;  
  11.   
  12. import org.slf4j.Logger;  
  13. import org.xml.sax.SAXException;  
  14.   
  15. import com.alibaba.fastjson.JSON;  
  16. import com.luozhuang.util.Configure;  
  17. import com.luozhuang.util.MD5;  
  18. import com.luozhuang.util.PayCommonUtil;  
  19. import com.luozhuang.util.XMLParser;  
  20.   
  21. ///   
  22. /// 微信支付协议接口数据类,所有的API接口通信都依赖这个数据结构,  
  23. /// 在调用接口之前先填充各个字段的值,然后进行接口通信,  
  24. /// 这样设计的好处是可扩展性强,用户可随意对协议进行更改而不用重新设计数据结构,  
  25. /// 还可以随意组合出不同的协议数据包,不用为每个协议设计一个数据包结构  
  26. ///   
  27. public class WxPayData {  
  28.   
  29.     private static Logger Log = new Logger();  
  30.   
  31.     public WxPayData() {  
  32.   
  33.     }  
  34.   
  35.     // 采用排序的Dictionary的好处是方便对数据包进行签名,不用再签名之前再做一次排序  
  36.     private SortedMap m_values = new TreeMap();  
  37.   
  38.       
  39.     public void put(String key, String value) {  
  40.         SetValue(key, value);  
  41.           
  42.     }  
  43.     /** 
  44.      * 设置某个字段的值 
  45.      *  
  46.      * @param key 
  47.      *            字段名 
  48.      * @param value 
  49.      *            字段值 
  50.      */  
  51.     public void SetValue(String key, Object value) {  
  52.         m_values.put(key, value);  
  53.     }  
  54.   
  55.     /** 
  56.      * 根据字段名获取某个字段的值 
  57.      *  
  58.      * @param key 
  59.      *            字段名 
  60.      * @return key对应的字段值 
  61.      */  
  62.     public Object GetValue(String key) {  
  63.         Object o = m_values.get(key);  
  64.         return o;  
  65.     }  
  66.   
  67.     /** 
  68.      * 判断某个字段是否已设置 
  69.      *  
  70.      * @param key 
  71.      *            字段名 
  72.      * @return 若字段key已被设置,则返回true,否则返回false 
  73.      */  
  74.     public boolean IsSet(String key) {  
  75.   
  76.         Object o = m_values.get(key);  
  77.         if (null != o)  
  78.             return true;  
  79.         else  
  80.             return false;  
  81.     }  
  82.   
  83.     /** 
  84.      * @将Dictionary转成xml 
  85.      * @return 经转换得到的xml串 
  86.      * @throws WxPayException 
  87.      **/  
  88.     public String ToXml() throws WxPayException {  
  89.         // 数据为空时不能转化为xml格式  
  90.         if (0 == m_values.size()) {  
  91.   
  92.             throw new WxPayException(“WxPayData数据为空!”);  
  93.         }  
  94.   
  95.         /* 
  96.          * String xml = ””; for (Map.Entry pair : 
  97.          * m_values.entrySet()) 
  98.          *  
  99.          * { // 字段值不能为null,会影响后续流程 if (pair.getValue() == null) { 
  100.          *  
  101.          * throw new WxPayException(“WxPayData内部含有值为null的字段!”); } 
  102.          *  
  103.          * if (pair.getValue() instanceof Integer) { xml += ”<” + pair.getKey() 
  104.          * + ”>” + pair.getValue() + ””; } else if 
  105.          * (pair.getValue() instanceof String) { xml += ”<” + pair.getKey() + 
  106.          * ”>” + ””; 
  107.          * } else// 除了String和int类型不能含有其他数据类型 { 
  108.          *  
  109.          * throw new WxPayException(“WxPayData字段数据类型错误!”); } } xml += ””; 
  110.          */  
  111.         return PayCommonUtil.getRequestXml(m_values);  
  112.     }  
  113.   
  114.     /** 
  115.      * @将xml转为WxPayData对象并返回对象内部的数据 
  116.      * @param String 
  117.      *            待转换的xml串 
  118.      * @return 经转换得到的Dictionary 
  119.      * @throws WxPayException 
  120.      * @throws SAXException 
  121.      * @throws IOException 
  122.      * @throws ParserConfigurationException 
  123.      */  
  124.     public SortedMap FromXml(String xml)  
  125.             throws WxPayException, ParserConfigurationException, IOException, SAXException {  
  126.         if (xml == null) {  
  127.   
  128.             throw new WxPayException(“将空的xml串转换为WxPayData不合法!”);  
  129.         }  
  130.   
  131.         m_values = XMLParser.getMapFromXML(xml);  
  132.   
  133.         // 2015-06-29 错误是没有签名  
  134.         if (m_values.get(“return_code”) != “SUCCESS”) {  
  135.             return m_values;  
  136.         }  
  137.         CheckSign();// 验证签名,不通过会抛异常  
  138.   
  139.         return m_values;  
  140.     }  
  141.   
  142.     /** 
  143.      * @throws WxPayException  
  144.      * @Dictionary格式转化成url参数格式 @ return url格式串, 该串不包含sign字段值 
  145.      */  
  146.     public String ToUrl() throws WxPayException {  
  147.         String buff = ”“;  
  148.         for (Map.Entry pair : m_values.entrySet()) {  
  149.             if (pair.getValue() == null) {  
  150.                 throw new WxPayException(“WxPayData内部含有值为null的字段!”);  
  151.             }  
  152.   
  153.             if (pair.getKey() != “sign” && pair.getValue().toString() != “”) {  
  154.                 buff += pair.getKey() + ”=” + pair.getValue() + “&”;  
  155.             }  
  156.         }  
  157.         buff = sideTrim(buff, ”&”);  
  158.         return buff;  
  159.     }  
  160.   
  161.     /** 
  162.      * 
  163.      *  
  164.      * 去掉指定字符串的开头和结尾的指定字符 
  165.      *  
  166.      * 
  167.      *  
  168.      * @param stream 
  169.      *            要处理的字符串 
  170.      * @param trimstr 
  171.      *            要去掉的字符串 
  172.      * @return 处理后的字符串 
  173.      */  
  174.     public static String sideTrim(String stream, String trimstr) {  
  175.         // null或者空字符串的时候不处理  
  176.         if (stream == null || stream.length() == 0 || trimstr == null || trimstr.length() == 0) {  
  177.             return stream;  
  178.         }  
  179.   
  180.         // 结束位置  
  181.         int epos = 0;  
  182.   
  183.         // 正规表达式  
  184.         String regpattern = ”[“ + trimstr + “]*+”;  
  185.         Pattern pattern = Pattern.compile(regpattern, Pattern.CASE_INSENSITIVE);  
  186.   
  187.         // 去掉结尾的指定字符  
  188.         StringBuffer buffer = new StringBuffer(stream).reverse();  
  189.         Matcher matcher = pattern.matcher(buffer);  
  190.         if (matcher.lookingAt()) {  
  191.             epos = matcher.end();  
  192.             stream = new StringBuffer(buffer.substring(epos)).reverse().toString();  
  193.         }  
  194.   
  195.         // 去掉开头的指定字符  
  196.         matcher = pattern.matcher(stream);  
  197.         if (matcher.lookingAt()) {  
  198.             epos = matcher.end();  
  199.             stream = stream.substring(epos);  
  200.         }  
  201.   
  202.         // 返回处理后的字符串  
  203.         return stream;  
  204.     }  
  205.   
  206.     /** 
  207.      * @Dictionary格式化成Json 
  208.      * @return json串数据 
  209.      */  
  210.     public String ToJson() {  
  211.         String jsonStr = JSON.toJSONString(m_values);  
  212.         return jsonStr;  
  213.     }  
  214.   
  215.     /** 
  216.      * @throws WxPayException 
  217.      * @values格式化成能在Web页面上显示的结果(因为web页面上不能直接输出xml格式的字符串) 
  218.      */  
  219.     public String ToPrintStr() throws WxPayException {  
  220.         String str = ”“;  
  221.         for (Map.Entry pair : m_values.entrySet()) {  
  222.             if (pair.getValue() == null) {  
  223.   
  224.                 throw new WxPayException(“WxPayData内部含有值为null的字段!”);  
  225.             }  
  226.   
  227.             str += String.format(”{0}={1}
    , pair.getKey(), pair.getValue().toString());  
  228.         }  
  229.   
  230.         return str;  
  231.     }  
  232.   
  233.     /** 
  234.      * @生成签名,详见签名生成算法 
  235.      * @return 签名, sign字段不参加签名 
  236.      * @throws WxPayException  
  237.      */  
  238.     public String MakeSign() throws WxPayException {  
  239.         // 转url格式  
  240.         String str = ToUrl();  
  241.         // 在String后加入API KEY  
  242.         str += ”&key=” + Configure.getKey();  
  243.         // MD5加密  
  244. //PayCommonUtil.createSign(“UTF-8”, packageParams,key)  
  245.         // 所有字符转为大写  
  246.         return MD5.MD5Encode(str, “UTF-8”).toUpperCase();  
  247.     }  
  248.   
  249.     /** 
  250.      *  
  251.      * 检测签名是否正确 正确返回true,错误抛异常 
  252.      *  
  253.      * @throws WxPayException 
  254.      */  
  255.     public boolean CheckSign() throws WxPayException {  
  256.         // 如果没有设置签名,则跳过检测  
  257.         if (!IsSet(“sign”)) {  
  258.   
  259.             throw new WxPayException(“WxPayData签名存在但不合法!”);  
  260.         }  
  261.         // 如果设置了签名但是签名为空,则抛异常  
  262.         else if (GetValue(“sign”) == null || GetValue(“sign”).toString() == “”) {  
  263.   
  264.             throw new WxPayException(“WxPayData签名存在但不合法!”);  
  265.         }  
  266.   
  267.         // 获取接收到的签名  
  268.         String return_sign = GetValue(”sign”).toString();  
  269.   
  270.         // 在本地计算新的签名  
  271.         String cal_sign = MakeSign();  
  272.   
  273.         if (cal_sign == return_sign) {  
  274.             return true;  
  275.         }  
  276.   
  277.         throw new WxPayException(“WxPayData签名验证错误!”);  
  278.     }  
  279.   
  280.     /** 
  281.      * @获取Dictionary 
  282.      */  
  283.     public SortedMap GetValues() {  
  284.         return m_values;  
  285.     }  
  286.   
  287.       
  288. }  
package com.luozhuang;

import java.io.IOException;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.parsers.ParserConfigurationException;

import org.slf4j.Logger;
import org.xml.sax.SAXException;

import com.alibaba.fastjson.JSON;
import com.luozhuang.util.Configure;
import com.luozhuang.util.MD5;
import com.luozhuang.util.PayCommonUtil;
import com.luozhuang.util.XMLParser;

/// 
/// 微信支付协议接口数据类,所有的API接口通信都依赖这个数据结构,
/// 在调用接口之前先填充各个字段的值,然后进行接口通信,
/// 这样设计的好处是可扩展性强,用户可随意对协议进行更改而不用重新设计数据结构,
/// 还可以随意组合出不同的协议数据包,不用为每个协议设计一个数据包结构
/// 
public class WxPayData {

    private static Logger Log = new Logger();

    public WxPayData() {

    }

    // 采用排序的Dictionary的好处是方便对数据包进行签名,不用再签名之前再做一次排序
    private SortedMap m_values = new TreeMap();


    public void put(String key, String value) {
        SetValue(key, value);

    }
    /**
     * 设置某个字段的值
     * 
     * @param key
     *            字段名
     * @param value
     *            字段值
     */
    public void SetValue(String key, Object value) {
        m_values.put(key, value);
    }

    /**
     * 根据字段名获取某个字段的值
     * 
     * @param key
     *            字段名
     * @return key对应的字段值
     */
    public Object GetValue(String key) {
        Object o = m_values.get(key);
        return o;
    }

    /**
     * 判断某个字段是否已设置
     * 
     * @param key
     *            字段名
     * @return 若字段key已被设置,则返回true,否则返回false
     */
    public boolean IsSet(String key) {

        Object o = m_values.get(key);
        if (null != o)
            return true;
        else
            return false;
    }

    /**
     * @将Dictionary转成xml
     * @return 经转换得到的xml串
     * @throws WxPayException
     **/
    public String ToXml() throws WxPayException {
        // 数据为空时不能转化为xml格式
        if (0 == m_values.size()) {

            throw new WxPayException("WxPayData数据为空!");
        }

        /*
         * String xml = ""; for (Map.Entry pair :
         * m_values.entrySet())
         * 
         * { // 字段值不能为null,会影响后续流程 if (pair.getValue() == null) {
         * 
         * throw new WxPayException("WxPayData内部含有值为null的字段!"); }
         * 
         * if (pair.getValue() instanceof Integer) { xml += "<" + pair.getKey()
         * + ">" + pair.getValue() + ""; } else if
         * (pair.getValue() instanceof String) { xml += "<" + pair.getKey() +
         * ">" + "";
         * } else// 除了String和int类型不能含有其他数据类型 {
         * 
         * throw new WxPayException("WxPayData字段数据类型错误!"); } } xml += "";
         */
        return PayCommonUtil.getRequestXml(m_values);
    }

    /**
     * @将xml转为WxPayData对象并返回对象内部的数据
     * @param String
     *            待转换的xml串
     * @return 经转换得到的Dictionary
     * @throws WxPayException
     * @throws SAXException
     * @throws IOException
     * @throws ParserConfigurationException
     */
    public SortedMap FromXml(String xml)
            throws WxPayException, ParserConfigurationException, IOException, SAXException {
        if (xml == null) {

            throw new WxPayException("将空的xml串转换为WxPayData不合法!");
        }

        m_values = XMLParser.getMapFromXML(xml);

        // 2015-06-29 错误是没有签名
        if (m_values.get("return_code") != "SUCCESS") {
            return m_values;
        }
        CheckSign();// 验证签名,不通过会抛异常

        return m_values;
    }

    /**
     * @throws WxPayException 
     * @Dictionary格式转化成url参数格式 @ return url格式串, 该串不包含sign字段值
     */
    public String ToUrl() throws WxPayException {
        String buff = "";
        for (Map.Entry pair : m_values.entrySet()) {
            if (pair.getValue() == null) {
                throw new WxPayException("WxPayData内部含有值为null的字段!");
            }

            if (pair.getKey() != "sign" && pair.getValue().toString() != "") {
                buff += pair.getKey() + "=" + pair.getValue() + "&";
            }
        }
        buff = sideTrim(buff, "&");
        return buff;
    }

    /**
     *
     * 
     * 去掉指定字符串的开头和结尾的指定字符
     * 
     *
     * 
     * @param stream
     *            要处理的字符串
     * @param trimstr
     *            要去掉的字符串
     * @return 处理后的字符串
     */
    public static String sideTrim(String stream, String trimstr) {
        // null或者空字符串的时候不处理
        if (stream == null || stream.length() == 0 || trimstr == null || trimstr.length() == 0) {
            return stream;
        }

        // 结束位置
        int epos = 0;

        // 正规表达式
        String regpattern = "[" + trimstr + "]*+";
        Pattern pattern = Pattern.compile(regpattern, Pattern.CASE_INSENSITIVE);

        // 去掉结尾的指定字符
        StringBuffer buffer = new StringBuffer(stream).reverse();
        Matcher matcher = pattern.matcher(buffer);
        if (matcher.lookingAt()) {
            epos = matcher.end();
            stream = new StringBuffer(buffer.substring(epos)).reverse().toString();
        }

        // 去掉开头的指定字符
        matcher = pattern.matcher(stream);
        if (matcher.lookingAt()) {
            epos = matcher.end();
            stream = stream.substring(epos);
        }

        // 返回处理后的字符串
        return stream;
    }

    /**
     * @Dictionary格式化成Json
     * @return json串数据
     */
    public String ToJson() {
        String jsonStr = JSON.toJSONString(m_values);
        return jsonStr;
    }

    /**
     * @throws WxPayException
     * @values格式化成能在Web页面上显示的结果(因为web页面上不能直接输出xml格式的字符串)
     */
    public String ToPrintStr() throws WxPayException {
        String str = "";
        for (Map.Entry pair : m_values.entrySet()) {
            if (pair.getValue() == null) {

                throw new WxPayException("WxPayData内部含有值为null的字段!");
            }

            str += String.format("{0}={1}
", pair.getKey(), pair.getValue().toString()); } return str; } /** * @生成签名,详见签名生成算法 * @return 签名, sign字段不参加签名 * @throws WxPayException */ public String MakeSign() throws WxPayException { // 转url格式 String str = ToUrl(); // 在String后加入API KEY str += "&key=" + Configure.getKey(); // MD5加密 //PayCommonUtil.createSign("UTF-8", packageParams,key) // 所有字符转为大写 return MD5.MD5Encode(str, "UTF-8").toUpperCase(); } /** * * 检测签名是否正确 正确返回true,错误抛异常 * * @throws WxPayException */ public boolean CheckSign() throws WxPayException { // 如果没有设置签名,则跳过检测 if (!IsSet("sign")) { throw new WxPayException("WxPayData签名存在但不合法!"); } // 如果设置了签名但是签名为空,则抛异常 else if (GetValue("sign") == null || GetValue("sign").toString() == "") { throw new WxPayException("WxPayData签名存在但不合法!"); } // 获取接收到的签名 String return_sign = GetValue("sign").toString(); // 在本地计算新的签名 String cal_sign = MakeSign(); if (cal_sign == return_sign) { return true; } throw new WxPayException("WxPayData签名验证错误!"); } /** * @获取Dictionary */ public SortedMap GetValues() { return m_values; } }

[java] view plain copy
print ?
  1. package com.luozhuang;  
  2.   
  3. public class WxPayException extends Exception {  
  4.   
  5.     public WxPayException(String string) {  
  6.         super(string);  
  7.     }  
  8.    
  9. }  
package com.luozhuang;

public class WxPayException extends Exception {

    public WxPayException(String string) {
        super(string);
    }

}

[java] view plain copy
print ?
  1. package com.luozhuang.util;  
  2.   
  3. /** 
  4.  * luozhuang 这里放置各种配置数据 
  5.  */  
  6. public class Configure {  
  7.   
  8.     // 回调地址  
  9.   
  10.     public static final String NOTIFY_URL = “http://www.weixin.qq.com/wxpay/pay.php”;  
  11.   
  12.     /** 
  13.      * 这个就是自己要保管好的私有Key了(切记只能放在自己的后台代码里,不能放在任何可能被看到源代码的客户端程序中) 
  14.      *  
  15.      * 每次自己Post数据给API的时候都要用这个key来对所有字段进行签名,生成的签名会放在Sign这个字段,API收到Post数据的时候也会用同样的签名算法对Post过来的数据进行签名和验证 
  16.      * 收到API的返回的时候也要用这个key来对返回的数据算下签名,跟API的Sign数据进行比较,如果值不一致,有可能数据被第三方给篡改 
  17.      */  
  18.     private static String key = “luozhuang”;  
  19.   
  20.     /** 
  21.      * 微信分配的公众号ID(开通公众号之后可以获取到) 
  22.      *  
  23.      */  
  24.     private static String appID = “luozhuang”;  
  25.   
  26.     /** 
  27.      * 微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到) 
  28.      *  
  29.      */  
  30.     private static String mchID = “luozhuang”;  
  31.   
  32.     /** 
  33.      * 受理模式下给子商户分配的子商户号 
  34.      *  
  35.      */  
  36.     private static String subMchID = “luozhuang”;  
  37.   
  38.     /** 
  39.      * HTTPS证书的本地路径 
  40.      *  
  41.      */  
  42.     private static String certLocalPath = “C:\\Users\\luozhuang\\my.store”;  
  43.   
  44.     /** 
  45.      * HTTPS证书密码,默认密码等于商户号MCHID 
  46.      *  
  47.      */  
  48.     private static String certPassword = “luozhuang”;  
  49.   
  50.     /** 
  51.      * 是否使用异步线程的方式来上报API测速,默认为异步模式 
  52.      *  
  53.      */  
  54.     private static boolean useThreadToDoReport = true;  
  55.   
  56.     /** 
  57.      * 机器IP 
  58.      *  
  59.      */  
  60.     private static String ip = “luozhuang”;  
  61.   
  62.     // 以下是几个API的路径:  
  63.     /** 
  64.      * 1)被扫支付API 
  65.      *  
  66.      */  
  67.     public static String PAY_API = “https://api.mch.weixin.qq.com/pay/micropay”;  
  68.   
  69.     /** 
  70.      * 2)被扫支付查询API 
  71.      *  
  72.      */  
  73.     public static String PAY_QUERY_API = “https://api.mch.weixin.qq.com/pay/orderquery”;  
  74.   
  75.     /** 
  76.      * 3)退款API 
  77.      *  
  78.      */  
  79.     public static String REFUND_API = “https://api.mch.weixin.qq.com/secapi/pay/refund”;  
  80.   
  81.     /** 
  82.      * 4)退款查询API 
  83.      *  
  84.      */  
  85.     public static String REFUND_QUERY_API = “https://api.mch.weixin.qq.com/pay/refundquery”;  
  86.   
  87.     /** 
  88.      * 5)撤销API 
  89.      *  
  90.      */  
  91.     public static String REVERSE_API = “https://api.mch.weixin.qq.com/secapi/pay/reverse”;  
  92.   
  93.     /** 
  94.      * 6)下载对账单API 
  95.      *  
  96.      */  
  97.     public static String DOWNLOAD_BILL_API = “https://api.mch.weixin.qq.com/pay/downloadbill”;  
  98.   
  99.     /** 
  100.      * 7) 统计上报API 
  101.      *  
  102.      */  
  103.     public static String REPORT_API = “https://api.mch.weixin.qq.com/payitil/report”;  
  104.   
  105.     /** 
  106.      * 转换短链接 
  107.      */  
  108.     public static String Shorturl_API = “https://api.mch.weixin.qq.com/tools/shorturl”;  
  109.   
  110.     /** 
  111.      * 统一下单 
  112.      */  
  113.     public static String UnifiedOrder_API = “https://api.mch.weixin.qq.com/pay/unifiedorder”;  
  114.   
  115.     /** 
  116.      * 关闭订单 
  117.      */  
  118.     public static String CloseOrder_API = “https://api.mch.weixin.qq.com/pay/closeorder”;  
  119.   
  120.     public static boolean isUseThreadToDoReport() {  
  121.         return useThreadToDoReport;  
  122.     }  
  123.   
  124.     public static void setUseThreadToDoReport(boolean useThreadToDoReport) {  
  125.         Configure.useThreadToDoReport = useThreadToDoReport;  
  126.     }  
  127.   
  128.     public static String HttpsRequestClassName = “com.tencent.common.HttpsRequest”;  
  129.   
  130.     public static void setKey(String key) {  
  131.         Configure.key = key;  
  132.     }  
  133.   
  134.     public static void setAppID(String appID) {  
  135.         Configure.appID = appID;  
  136.     }  
  137.   
  138.     public static void setMchID(String mchID) {  
  139.         Configure.mchID = mchID;  
  140.     }  
  141.   
  142.     public static void setSubMchID(String subMchID) {  
  143.         Configure.subMchID = subMchID;  
  144.     }  
  145.   
  146.     public static void setCertLocalPath(String certLocalPath) {  
  147.         Configure.certLocalPath = certLocalPath;  
  148.     }  
  149.   
  150.     public static void setCertPassword(String certPassword) {  
  151.         Configure.certPassword = certPassword;  
  152.     }  
  153.   
  154.     public static void setIp(String ip) {  
  155.         Configure.ip = ip;  
  156.     }  
  157.   
  158.     public static String getKey() {  
  159.         return key;  
  160.     }  
  161.   
  162.     public static String getAppid() {  
  163.         return appID;  
  164.     }  
  165.   
  166.     public static String getMchid() {  
  167.         return mchID;  
  168.     }  
  169.   
  170.     public static String getSubMchid() {  
  171.         return subMchID;  
  172.     }  
  173.   
  174.     public static String getCertLocalPath() {  
  175.         return certLocalPath;  
  176.     }  
  177.   
  178.     public static String getCertPassword() {  
  179.         return certPassword;  
  180.     }  
  181.   
  182.     public static String getIP() {  
  183.         return ip;  
  184.     }  
  185.   
  186.     public static void setHttpsRequestClassName(String name) {  
  187.         HttpsRequestClassName = name;  
  188.     }  
  189.   
  190. }  
package com.luozhuang.util;

/**
 * luozhuang 这里放置各种配置数据
 */
public class Configure {

    // 回调地址

    public static final String NOTIFY_URL = "http://www.weixin.qq.com/wxpay/pay.php";

    /**
     * 这个就是自己要保管好的私有Key了(切记只能放在自己的后台代码里,不能放在任何可能被看到源代码的客户端程序中)
     * 
     * 每次自己Post数据给API的时候都要用这个key来对所有字段进行签名,生成的签名会放在Sign这个字段,API收到Post数据的时候也会用同样的签名算法对Post过来的数据进行签名和验证
     * 收到API的返回的时候也要用这个key来对返回的数据算下签名,跟API的Sign数据进行比较,如果值不一致,有可能数据被第三方给篡改
     */
    private static String key = "luozhuang";

    /**
     * 微信分配的公众号ID(开通公众号之后可以获取到)
     * 
     */
    private static String appID = "luozhuang";

    /**
     * 微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
     * 
     */
    private static String mchID = "luozhuang";

    /**
     * 受理模式下给子商户分配的子商户号
     * 
     */
    private static String subMchID = "luozhuang";

    /**
     * HTTPS证书的本地路径
     * 
     */
    private static String certLocalPath = "C:\\Users\\luozhuang\\my.store";

    /**
     * HTTPS证书密码,默认密码等于商户号MCHID
     * 
     */
    private static String certPassword = "luozhuang";

    /**
     * 是否使用异步线程的方式来上报API测速,默认为异步模式
     * 
     */
    private static boolean useThreadToDoReport = true;

    /**
     * 机器IP
     * 
     */
    private static String ip = "luozhuang";

    // 以下是几个API的路径:
    /**
     * 1)被扫支付API
     * 
     */
    public static String PAY_API = "https://api.mch.weixin.qq.com/pay/micropay";

    /**
     * 2)被扫支付查询API
     * 
     */
    public static String PAY_QUERY_API = "https://api.mch.weixin.qq.com/pay/orderquery";

    /**
     * 3)退款API
     * 
     */
    public static String REFUND_API = "https://api.mch.weixin.qq.com/secapi/pay/refund";

    /**
     * 4)退款查询API
     * 
     */
    public static String REFUND_QUERY_API = "https://api.mch.weixin.qq.com/pay/refundquery";

    /**
     * 5)撤销API
     * 
     */
    public static String REVERSE_API = "https://api.mch.weixin.qq.com/secapi/pay/reverse";

    /**
     * 6)下载对账单API
     * 
     */
    public static String DOWNLOAD_BILL_API = "https://api.mch.weixin.qq.com/pay/downloadbill";

    /**
     * 7) 统计上报API
     * 
     */
    public static String REPORT_API = "https://api.mch.weixin.qq.com/payitil/report";

    /**
     * 转换短链接
     */
    public static String Shorturl_API = "https://api.mch.weixin.qq.com/tools/shorturl";

    /**
     * 统一下单
     */
    public static String UnifiedOrder_API = "https://api.mch.weixin.qq.com/pay/unifiedorder";

    /**
     * 关闭订单
     */
    public static String CloseOrder_API = "https://api.mch.weixin.qq.com/pay/closeorder";

    public static boolean isUseThreadToDoReport() {
        return useThreadToDoReport;
    }

    public static void setUseThreadToDoReport(boolean useThreadToDoReport) {
        Configure.useThreadToDoReport = useThreadToDoReport;
    }

    public static String HttpsRequestClassName = "com.tencent.common.HttpsRequest";

    public static void setKey(String key) {
        Configure.key = key;
    }

    public static void setAppID(String appID) {
        Configure.appID = appID;
    }

    public static void setMchID(String mchID) {
        Configure.mchID = mchID;
    }

    public static void setSubMchID(String subMchID) {
        Configure.subMchID = subMchID;
    }

    public static void setCertLocalPath(String certLocalPath) {
        Configure.certLocalPath = certLocalPath;
    }

    public static void setCertPassword(String certPassword) {
        Configure.certPassword = certPassword;
    }

    public static void setIp(String ip) {
        Configure.ip = ip;
    }

    public static String getKey() {
        return key;
    }

    public static String getAppid() {
        return appID;
    }

    public static String getMchid() {
        return mchID;
    }

    public static String getSubMchid() {
        return subMchID;
    }

    public static String getCertLocalPath() {
        return certLocalPath;
    }

    public static String getCertPassword() {
        return certPassword;
    }

    public static String getIP() {
        return ip;
    }

    public static void setHttpsRequestClassName(String name) {
        HttpsRequestClassName = name;
    }

}

[java] view plain copy
print ?
  1. package com.luozhuang.util;  
  2.   
  3. import com.thoughtworks.xstream.XStream;  
  4. import com.thoughtworks.xstream.io.xml.DomDriver;  
  5. import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;  
  6. import org.apache.http.HttpEntity;  
  7. import org.apache.http.HttpResponse;  
  8. import org.apache.http.client.config.RequestConfig;  
  9. import org.apache.http.client.methods.HttpPost;  
  10. import org.apache.http.conn.ConnectTimeoutException;  
  11. import org.apache.http.conn.ConnectionPoolTimeoutException;  
  12. import org.apache.http.conn.ssl.SSLConnectionSocketFactory;  
  13. import org.apache.http.conn.ssl.SSLContexts;  
  14. import org.apache.http.entity.StringEntity;  
  15. import org.apache.http.impl.client.CloseableHttpClient;  
  16. import org.apache.http.impl.client.HttpClients;  
  17. import org.apache.http.util.EntityUtils;  
  18. import org.slf4j.Logger;  
  19. import org.slf4j.LoggerFactory;  
  20.   
  21. import javax.net.ssl.SSLContext;  
  22. import java.io.File;  
  23. import java.io.FileInputStream;  
  24. import java.io.IOException;  
  25. import java.io.InputStream;  
  26. import java.net.SocketTimeoutException;  
  27. import java.security.*;  
  28. import java.security.cert.CertificateException;  
  29.   
  30. /** 
  31.  * luozhuang 
  32.  */  
  33. public class HttpsRequest {  
  34.   
  35.     public interface ResultListener {  
  36.   
  37.         public void onConnectionPoolTimeoutError();  
  38.   
  39.     }  
  40.   
  41.     private static Logger log = new Logger();  
  42.   
  43.     // 表示请求器是否已经做了初始化工作  
  44.     private boolean hasInit = false;  
  45.   
  46.     // 连接超时时间,默认10秒  
  47.     private int socketTimeout = 10000;  
  48.   
  49.     // 传输超时时间,默认30秒  
  50.     private int connectTimeout = 30000;  
  51.   
  52.     // 请求器的配置  
  53.     private RequestConfig requestConfig;  
  54.   
  55.     // HTTP请求器  
  56.     private CloseableHttpClient httpClient;  
  57.   
  58.     public HttpsRequest() throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException,  
  59.             KeyStoreException, IOException {  
  60.         init();  
  61.     }  
  62.   
  63.     /** 
  64.      * 对安全性有要求的网站一般使用https来加密传输的请求和响应。https离不开证书,关于证书不在多说。Apache的HttpClient支持https, 
  65.      * 面是官方的样例程序,程序中使用了my.store这个文件, 
  66.      * 这个文件不是网站的证书,而是一份包含自己密码的自己的证书库。这个文件是需要自己生成的,使用jdk中的keytool命令可以很方便的生成my.store文件。步骤如下(以支付宝为例): 
  67.      * 浏览器(以chrome为例)访问https://www.alipay.com/,点击域名左侧的小锁,可以查看支付宝的证书信息 
  68.      *  
  69.      *  
  70.      * 将支付包的证书信息导出,证书格式有很多中,der、cer等。随便选择即可。 命令行或者shell执行 keytool -import -alias 
  71.      * “my alipay cert” -file www.alipay.com.cert -keystore my.store, 
  72.      * 如果keytool命令不识别,去检查一下jdk的环境变量是否设置正确。”my alipay 
  73.      * cert”是个别名,随便取。“www.alipay.com.cert”这个文件就是从浏览器中导出的支付宝的证书。 
  74.      *  
  75.      * @throws IOException 
  76.      * @throws KeyStoreException 
  77.      * @throws UnrecoverableKeyException 
  78.      * @throws NoSuchAlgorithmException 
  79.      * @throws KeyManagementException 
  80.      */  
  81.     private void init() throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException,  
  82.             KeyManagementException {  
  83.         if (Configure.getCertLocalPath() == null || Configure.getCertLocalPath().length() < 1) {  
  84.   
  85.         }  
  86.          KeyStore keyStore  = KeyStore.getInstance(KeyStore.getDefaultType());  
  87.         FileInputStream instream = new FileInputStream(new File(Configure.getCertLocalPath()));// 加载本地的证书进行https加密传输  
  88.         try {  
  89.             keyStore.load(instream, Configure.getCertPassword().toCharArray());// 设置证书密码  
  90.         } catch (CertificateException e) {  
  91.             e.printStackTrace();  
  92.         } catch (NoSuchAlgorithmException e) {  
  93.             e.printStackTrace();  
  94.         } finally {  
  95.             instream.close();  
  96.         }  
  97.   
  98.         // Trust own CA and all self-signed certs  
  99.         SSLContext sslcontext = SSLContexts.custom()  
  100.                 .loadKeyMaterial(keyStore, Configure.getCertPassword().toCharArray()).build();  
  101.         // Allow TLSv1 protocol only  
  102.         SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { “TLSv1” }, null,  
  103.                 SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);  
  104.   
  105.         httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();  
  106.   
  107.         // 根据默认超时限制初始化requestConfig  
  108.         requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout)  
  109.                 .build();  
  110.   
  111.         hasInit = true;  
  112.     }  
  113.   
  114.     /** 
  115.      * 通过Https往API post xml数据 
  116.      * 
  117.      * @param url 
  118.      *            API地址 
  119.      * @param xmlObj 
  120.      *            要提交的XML数据对象 
  121.      * @return API回包的实际数据 
  122.      * @throws IOException 
  123.      * @throws KeyStoreException 
  124.      * @throws UnrecoverableKeyException 
  125.      * @throws NoSuchAlgorithmException 
  126.      * @throws KeyManagementException 
  127.      */  
  128.   
  129.     public String sendPost(String url, String postDataXML) throws IOException, KeyStoreException,  
  130.             UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException {  
  131.   
  132.         if (!hasInit) {  
  133.             init();  
  134.         }  
  135.   
  136.         String result = null;  
  137.   
  138.         HttpPost httpPost = new HttpPost(url);  
  139.   
  140.         Util.log(”API,POST过去的数据是:”);  
  141.         Util.log(postDataXML);  
  142.   
  143.         // 得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别  
  144.         StringEntity postEntity = new StringEntity(postDataXML, “UTF-8”);  
  145.         httpPost.addHeader(”Content-Type”“text/xml”);  
  146.         httpPost.setEntity(postEntity);  
  147.   
  148.         // 设置请求器的配置  
  149.         httpPost.setConfig(requestConfig);  
  150.   
  151.         Util.log(”executing request” + httpPost.getRequestLine());  
  152.   
  153.         try {  
  154.             HttpResponse response = httpClient.execute(httpPost);  
  155.   
  156.             HttpEntity entity = response.getEntity();  
  157.   
  158.             result = EntityUtils.toString(entity, ”UTF-8”);  
  159.   
  160.         } catch (ConnectionPoolTimeoutException e) {  
  161.             log.error(”http get throw ConnectionPoolTimeoutException(wait time out)”, e);  
  162.   
  163.         } catch (ConnectTimeoutException e) {  
  164.             log.error(”http get throw ConnectTimeoutException”, e);  
  165.   
  166.         } catch (SocketTimeoutException e) {  
  167.             log.error(”http get throw SocketTimeoutException”, e);  
  168.   
  169.         } catch (Exception e) {  
  170.             log.error(”http get throw Exception”, e);  
  171.   
  172.         } finally {  
  173.             httpPost.abort();  
  174.         }  
  175.   
  176.         return result;  
  177.     }  
  178.   
  179.     /** 
  180.      * 设置连接超时时间 
  181.      * 
  182.      * @param socketTimeout 
  183.      *            连接时长,默认10秒 
  184.      */  
  185.     public void setSocketTimeout(int socketTimeout) {  
  186.         socketTimeout = socketTimeout;  
  187.         resetRequestConfig();  
  188.     }  
  189.   
  190.     /** 
  191.      * 设置传输超时时间 
  192.      * 
  193.      * @param connectTimeout 
  194.      *            传输时长,默认30秒 
  195.      */  
  196.     public void setConnectTimeout(int connectTimeout) {  
  197.         connectTimeout = connectTimeout;  
  198.         resetRequestConfig();  
  199.     }  
  200.   
  201.     private void resetRequestConfig() {  
  202.         requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout)  
  203.                 .build();  
  204.     }  
  205.   
  206.     /** 
  207.      * 允许商户自己做更高级更复杂的请求器配置 
  208.      * 
  209.      * @param requestConfig 
  210.      *            设置HttpsRequest的请求器配置 
  211.      */  
  212.     public void setRequestConfig(RequestConfig requestConfig) {  
  213.         requestConfig = requestConfig;  
  214.     }  
  215.   
  216. }  
package com.luozhuang.util;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ConnectionPoolTimeoutException;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.SocketTimeoutException;
import java.security.*;
import java.security.cert.CertificateException;

/**
 * luozhuang
 */
public class HttpsRequest {

    public interface ResultListener {

        public void onConnectionPoolTimeoutError();

    }

    private static Logger log = new Logger();

    // 表示请求器是否已经做了初始化工作
    private boolean hasInit = false;

    // 连接超时时间,默认10秒
    private int socketTimeout = 10000;

    // 传输超时时间,默认30秒
    private int connectTimeout = 30000;

    // 请求器的配置
    private RequestConfig requestConfig;

    // HTTP请求器
    private CloseableHttpClient httpClient;

    public HttpsRequest() throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException,
            KeyStoreException, IOException {
        init();
    }

    /**
     * 对安全性有要求的网站一般使用https来加密传输的请求和响应。https离不开证书,关于证书不在多说。Apache的HttpClient支持https,
     * 面是官方的样例程序,程序中使用了my.store这个文件,
     * 这个文件不是网站的证书,而是一份包含自己密码的自己的证书库。这个文件是需要自己生成的,使用jdk中的keytool命令可以很方便的生成my.store文件。步骤如下(以支付宝为例):
     * 浏览器(以chrome为例)访问https://www.alipay.com/,点击域名左侧的小锁,可以查看支付宝的证书信息
     * 
     * 
     * 将支付包的证书信息导出,证书格式有很多中,der、cer等。随便选择即可。 命令行或者shell执行 keytool -import -alias
     * "my alipay cert" -file www.alipay.com.cert -keystore my.store,
     * 如果keytool命令不识别,去检查一下jdk的环境变量是否设置正确。”my alipay
     * cert”是个别名,随便取。“www.alipay.com.cert”这个文件就是从浏览器中导出的支付宝的证书。
     * 
     * @throws IOException
     * @throws KeyStoreException
     * @throws UnrecoverableKeyException
     * @throws NoSuchAlgorithmException
     * @throws KeyManagementException
     */
    private void init() throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException,
            KeyManagementException {
        if (Configure.getCertLocalPath() == null || Configure.getCertLocalPath().length() < 1) {

        }
         KeyStore keyStore  = KeyStore.getInstance(KeyStore.getDefaultType());
        FileInputStream instream = new FileInputStream(new File(Configure.getCertLocalPath()));// 加载本地的证书进行https加密传输
        try {
            keyStore.load(instream, Configure.getCertPassword().toCharArray());// 设置证书密码
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } finally {
            instream.close();
        }

        // Trust own CA and all self-signed certs
        SSLContext sslcontext = SSLContexts.custom()
                .loadKeyMaterial(keyStore, Configure.getCertPassword().toCharArray()).build();
        // Allow TLSv1 protocol only
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);

        httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();

        // 根据默认超时限制初始化requestConfig
        requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout)
                .build();

        hasInit = true;
    }

    /**
     * 通过Https往API post xml数据
     *
     * @param url
     *            API地址
     * @param xmlObj
     *            要提交的XML数据对象
     * @return API回包的实际数据
     * @throws IOException
     * @throws KeyStoreException
     * @throws UnrecoverableKeyException
     * @throws NoSuchAlgorithmException
     * @throws KeyManagementException
     */

    public String sendPost(String url, String postDataXML) throws IOException, KeyStoreException,
            UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException {

        if (!hasInit) {
            init();
        }

        String result = null;

        HttpPost httpPost = new HttpPost(url);

        Util.log("API,POST过去的数据是:");
        Util.log(postDataXML);

        // 得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
        StringEntity postEntity = new StringEntity(postDataXML, "UTF-8");
        httpPost.addHeader("Content-Type", "text/xml");
        httpPost.setEntity(postEntity);

        // 设置请求器的配置
        httpPost.setConfig(requestConfig);

        Util.log("executing request" + httpPost.getRequestLine());

        try {
            HttpResponse response = httpClient.execute(httpPost);

            HttpEntity entity = response.getEntity();

            result = EntityUtils.toString(entity, "UTF-8");

        } catch (ConnectionPoolTimeoutException e) {
            log.error("http get throw ConnectionPoolTimeoutException(wait time out)", e);

        } catch (ConnectTimeoutException e) {
            log.error("http get throw ConnectTimeoutException", e);

        } catch (SocketTimeoutException e) {
            log.error("http get throw SocketTimeoutException", e);

        } catch (Exception e) {
            log.error("http get throw Exception", e);

        } finally {
            httpPost.abort();
        }

        return result;
    }

    /**
     * 设置连接超时时间
     *
     * @param socketTimeout
     *            连接时长,默认10秒
     */
    public void setSocketTimeout(int socketTimeout) {
        socketTimeout = socketTimeout;
        resetRequestConfig();
    }

    /**
     * 设置传输超时时间
     *
     * @param connectTimeout
     *            传输时长,默认30秒
     */
    public void setConnectTimeout(int connectTimeout) {
        connectTimeout = connectTimeout;
        resetRequestConfig();
    }

    private void resetRequestConfig() {
        requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout)
                .build();
    }

    /**
     * 允许商户自己做更高级更复杂的请求器配置
     *
     * @param requestConfig
     *            设置HttpsRequest的请求器配置
     */
    public void setRequestConfig(RequestConfig requestConfig) {
        requestConfig = requestConfig;
    }

}

[java] view plain copy
print ?
  1. package com.luozhuang.util;  
  2.   
  3. import java.security.MessageDigest;  
  4.   
  5. /** 
  6.  * luozhuang 
  7.  */  
  8. public class MD5 {  
  9.     private final static String[] hexDigits = {“0”“1”“2”“3”“4”“5”“6”“7”,  
  10.             ”8”“9”“a”“b”“c”“d”“e”“f”};  
  11.   
  12.     /** 
  13.      * 转换字节数组为16进制字串 
  14.      * @param b 字节数组 
  15.      * @return 16进制字串 
  16.      */  
  17.     public static String byteArrayToHexString(byte[] b) {  
  18.         StringBuilder resultSb = new StringBuilder();  
  19.         for (byte aB : b) {  
  20.             resultSb.append(byteToHexString(aB));  
  21.         }  
  22.         return resultSb.toString();  
  23.     }  
  24.   
  25.     /** 
  26.      * 转换byte到16进制 
  27.      * @param b 要转换的byte 
  28.      * @return 16进制格式 
  29.      */  
  30.     private static String byteToHexString(byte b) {  
  31.         int n = b;  
  32.         if (n < 0) {  
  33.             n = 256 + n;  
  34.         }  
  35.         int d1 = n / 16;  
  36.         int d2 = n % 16;  
  37.         return hexDigits[d1] + hexDigits[d2];  
  38.     }  
  39.   
  40.     /** 
  41.      * MD5编码 
  42.      * @param origin 原始字符串 
  43.      * @param characterEncoding  
  44.      * @return 经过MD5加密之后的结果 
  45.      */  
  46.     public static String MD5Encode(String origin, String charsetname) {  
  47.         String resultString = null;  
  48.         try {  
  49.             resultString = origin;  
  50.             MessageDigest md = MessageDigest.getInstance(”MD5”);  
  51.             if (charsetname == null || “”.equals(charsetname))    
  52.                 resultString = byteArrayToHexString(md.digest(resultString    
  53.                         .getBytes()));    
  54.             else    
  55.                 resultString = byteArrayToHexString(md.digest(resultString    
  56.                         .getBytes(charsetname)));    
  57.         } catch (Exception e) {  
  58.             e.printStackTrace();  
  59.         }  
  60.         return resultString;  
  61.     }  
  62.   
  63. }  
package com.luozhuang.util;

import java.security.MessageDigest;

/**
 * luozhuang
 */
public class MD5 {
    private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7",
            "8", "9", "a", "b", "c", "d", "e", "f"};

    /**
     * 转换字节数组为16进制字串
     * @param b 字节数组
     * @return 16进制字串
     */
    public static String byteArrayToHexString(byte[] b) {
        StringBuilder resultSb = new StringBuilder();
        for (byte aB : b) {
            resultSb.append(byteToHexString(aB));
        }
        return resultSb.toString();
    }

    /**
     * 转换byte到16进制
     * @param b 要转换的byte
     * @return 16进制格式
     */
    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0) {
            n = 256 + n;
        }
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }

    /**
     * MD5编码
     * @param origin 原始字符串
     * @param characterEncoding 
     * @return 经过MD5加密之后的结果
     */
    public static String MD5Encode(String origin, String charsetname) {
        String resultString = null;
        try {
            resultString = origin;
            MessageDigest md = MessageDigest.getInstance("MD5");
            if (charsetname == null || "".equals(charsetname))  
                resultString = byteArrayToHexString(md.digest(resultString  
                        .getBytes()));  
            else  
                resultString = byteArrayToHexString(md.digest(resultString  
                        .getBytes(charsetname)));  
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultString;
    }

}

[java] view plain copy
print ?
  1. package com.luozhuang.util;  
  2.   
  3. import java.text.SimpleDateFormat;  
  4. import java.util.Date;  
  5. import java.util.Iterator;  
  6. import java.util.Map;  
  7. import java.util.Set;  
  8. import java.util.SortedMap;  
  9.   
  10. import com.luozhuang.WxPayException;  
  11.   
  12. public class PayCommonUtil {  
  13.   
  14.     /** 
  15.      * 是否签名正确,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。 
  16.      *  
  17.      * @return boolean 
  18.      */  
  19.     public static boolean isTenpaySign(String characterEncoding, SortedMap packageParams,  
  20.             String API_KEY) {  
  21.         StringBuffer sb = new StringBuffer();  
  22.         Set es = packageParams.entrySet();  
  23.         Iterator it = es.iterator();  
  24.         while (it.hasNext()) {  
  25.             Map.Entry entry = (Map.Entry) it.next();  
  26.             String k = (String) entry.getKey();  
  27.             String v = (String) entry.getValue();  
  28.             if (!“sign”.equals(k) && null != v && !“”.equals(v)) {  
  29.                 sb.append(k + ”=” + v + “&”);  
  30.             }  
  31.         }  
  32.   
  33.         sb.append(”key=” + API_KEY);  
  34.   
  35.         // 算出摘要  
  36.         String mysign = MD5.MD5Encode(sb.toString(), characterEncoding).toLowerCase();  
  37.         String tenpaySign = ((String) packageParams.get(”sign”)).toLowerCase();  
  38.   
  39.         return tenpaySign.equals(mysign);  
  40.     }  
  41.   
  42.     /** 
  43.      * @author 
  44.      * @date 2016-4-22 
  45.      * @Description:sign签名 
  46.      * @param characterEncoding 
  47.      *            编码格式 
  48.      * @param parameters 
  49.      *            请求参数 
  50.      * @return 
  51.      */  
  52.     public static String createSign(String characterEncoding, SortedMap packageParams, String API_KEY) {  
  53.         StringBuffer sb = new StringBuffer();  
  54.         Set es = packageParams.entrySet();  
  55.         Iterator it = es.iterator();  
  56.         while (it.hasNext()) {  
  57.             Map.Entry entry = (Map.Entry) it.next();  
  58.             String k = (String) entry.getKey();  
  59.             String v = (String) entry.getValue();  
  60.             if (null != v && !“”.equals(v) && !“sign”.equals(k) && !“key”.equals(k)) {  
  61.                 sb.append(k + ”=” + v + “&”);  
  62.             }  
  63.         }  
  64.         sb.append(”key=” + API_KEY);  
  65.         String sign = MD5.MD5Encode(sb.toString(), characterEncoding).toUpperCase();  
  66.         return sign;  
  67.     }  
  68.   
  69.     /** 
  70.      * @author 
  71.      * @date 2016-4-22 
  72.      * @Description:将请求参数转换为xml格式的string 
  73.      * @param parameters 
  74.      *            请求参数 
  75.      * @return 
  76.      * @throws WxPayException 
  77.      */  
  78.     public static String getRequestXml(SortedMap parameters) throws WxPayException {  
  79.         StringBuffer sb = new StringBuffer();  
  80.         sb.append();  
  81.         Set> es = parameters.entrySet();  
  82.         Iterator> it = es.iterator();  
  83.         while (it.hasNext()) {  
  84.             Map.Entry entry = (Map.Entry) it.next();  
  85.             String k = entry.getKey();  
  86.             String v = (String) entry.getValue();  
  87.   
  88.             // 字段值不能为null,会影响后续流程  
  89.             if (v == null) {  
  90.   
  91.                 throw new WxPayException(“WxPayData内部含有值为null的字段!”);  
  92.             }  
  93.   
  94.             if (“attach”.equalsIgnoreCase(k) || “body”.equalsIgnoreCase(k) || “sign”.equalsIgnoreCase(k)) {  
  95.                 sb.append(”<” + k + “>” +  + v + “]]> + k + “>”);  
  96.             } else {  
  97.                 sb.append(”<” + k + “>” + v +  + k + “>”);  
  98.             }  
  99.         }  
  100.         sb.append(””);  
  101.         return sb.toString();  
  102.     }  
  103.   
  104.     /** 
  105.      * 取出一个指定长度大小的随机正整数. 
  106.      *  
  107.      * @param length 
  108.      *            int 设定所取出随机数的长度。length小于11 
  109.      * @return int 返回生成的随机数。 
  110.      */  
  111.     public static int buildRandom(int length) {  
  112.         int num = 1;  
  113.         double random = Math.random();  
  114.         if (random < 0.1) {  
  115.             random = random + 0.1;  
  116.         }  
  117.         for (int i = 0; i < length; i++) {  
  118.             num = num * 10;  
  119.         }  
  120.         return (int) ((random * num));  
  121.     }  
  122.   
  123.     /** 
  124.      * 获取当前时间 yyyyMMddHHmmss 
  125.      *  
  126.      * @return String 
  127.      */  
  128.     public static String getCurrTime() {  
  129.         Date now = new Date();  
  130.         SimpleDateFormat outFormat = new SimpleDateFormat(“yyyyMMddHHmmss”);  
  131.         String s = outFormat.format(now);  
  132.         return s;  
  133.     }  
  134.   
  135. }  
package com.luozhuang.util;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;

import com.luozhuang.WxPayException;

public class PayCommonUtil {

    /**
     * 是否签名正确,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。
     * 
     * @return boolean
     */
    public static boolean isTenpaySign(String characterEncoding, SortedMap packageParams,
            String API_KEY) {
        StringBuffer sb = new StringBuffer();
        Set es = packageParams.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (!"sign".equals(k) && null != v && !"".equals(v)) {
                sb.append(k + "=" + v + "&");
            }
        }

        sb.append("key=" + API_KEY);

        // 算出摘要
        String mysign = MD5.MD5Encode(sb.toString(), characterEncoding).toLowerCase();
        String tenpaySign = ((String) packageParams.get("sign")).toLowerCase();

        return tenpaySign.equals(mysign);
    }

    /**
     * @author
     * @date 2016-4-22
     * @Description:sign签名
     * @param characterEncoding
     *            编码格式
     * @param parameters
     *            请求参数
     * @return
     */
    public static String createSign(String characterEncoding, SortedMap packageParams, String API_KEY) {
        StringBuffer sb = new StringBuffer();
        Set es = packageParams.entrySet();
        Iterator it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            String v = (String) entry.getValue();
            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + API_KEY);
        String sign = MD5.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
        return sign;
    }

    /**
     * @author
     * @date 2016-4-22
     * @Description:将请求参数转换为xml格式的string
     * @param parameters
     *            请求参数
     * @return
     * @throws WxPayException
     */
    public static String getRequestXml(SortedMap parameters) throws WxPayException {
        StringBuffer sb = new StringBuffer();
        sb.append("");
        Set> es = parameters.entrySet();
        Iterator> it = es.iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = entry.getKey();
            String v = (String) entry.getValue();

            // 字段值不能为null,会影响后续流程
            if (v == null) {

                throw new WxPayException("WxPayData内部含有值为null的字段!");
            }

            if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {
                sb.append("<" + k + ">" + "");
            } else {
                sb.append("<" + k + ">" + v + "");
            }
        }
        sb.append("");
        return sb.toString();
    }

    /**
     * 取出一个指定长度大小的随机正整数.
     * 
     * @param length
     *            int 设定所取出随机数的长度。length小于11
     * @return int 返回生成的随机数。
     */
    public static int buildRandom(int length) {
        int num = 1;
        double random = Math.random();
        if (random < 0.1) {
            random = random + 0.1;
        }
        for (int i = 0; i < length; i++) {
            num = num * 10;
        }
        return (int) ((random * num));
    }

    /**
     * 获取当前时间 yyyyMMddHHmmss
     * 
     * @return String
     */
    public static String getCurrTime() {
        Date now = new Date();
        SimpleDateFormat outFormat = new SimpleDateFormat("yyyyMMddHHmmss");
        String s = outFormat.format(now);
        return s;
    }

}

[java] view plain copy
print ?
  1. package com.luozhuang.util;  
  2.   
  3. import java.util.Random;  
  4.   
  5. /** 
  6.  * luozhuang 
  7.  */  
  8. public class RandomStringGenerator {  
  9.   
  10.     /** 
  11.      * 获取一定长度的随机字符串 
  12.      * @param length 指定字符串长度 
  13.      * @return 一定长度的字符串 
  14.      */  
  15.     public static String getRandomStringByLength(int length) {  
  16.         String base = ”abcdefghijklmnopqrstuvwxyz0123456789”;  
  17.         Random random = new Random();  
  18.         StringBuffer sb = new StringBuffer();  
  19.         for (int i = 0; i < length; i++) {  
  20.             int number = random.nextInt(base.length());  
  21.             sb.append(base.charAt(number));  
  22.         }  
  23.         return sb.toString();  
  24.     }  
  25.   
  26. }  
package com.luozhuang.util;

import java.util.Random;

/**
 * luozhuang
 */
public class RandomStringGenerator {

    /**
     * 获取一定长度的随机字符串
     * @param length 指定字符串长度
     * @return 一定长度的字符串
     */
    public static String getRandomStringByLength(int length) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

}

[java] view plain copy
print ?
  1. package com.luozhuang.util;  
  2.   
  3. import org.xml.sax.SAXException;  
  4.   
  5. import javax.xml.parsers.ParserConfigurationException;  
  6. import java.io.IOException;  
  7. import java.lang.reflect.Field;  
  8. import java.util.ArrayList;  
  9. import java.util.Arrays;  
  10. import java.util.Map;  
  11.   
  12. /** 
  13.  * luozhuang 
  14.  */  
  15. public class Signature {  
  16.     /** 
  17.      * 签名算法 
  18.      * @param o 要参与签名的数据对象 
  19.      * @return 签名 
  20.      * @throws IllegalAccessException 
  21.      */  
  22.     public static String getSign(Object o) throws IllegalAccessException {  
  23.         ArrayList list = new ArrayList();  
  24.         Class cls = o.getClass();  
  25.         Field[] fields = cls.getDeclaredFields();  
  26.         for (Field f : fields) {  
  27.             f.setAccessible(true);  
  28.             if (f.get(o) != null && f.get(o) != “”) {  
  29.                 list.add(f.getName() + ”=” + f.get(o) + “&”);  
  30.             }  
  31.         }  
  32.         int size = list.size();  
  33.         String [] arrayToSort = list.toArray(new String[size]);  
  34.         Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);  
  35.         StringBuilder sb = new StringBuilder();  
  36.         for(int i = 0; i < size; i ++) {  
  37.             sb.append(arrayToSort[i]);  
  38.         }  
  39.         String result = sb.toString();  
  40.         result += ”key=” + Configure.getKey();  
  41.         Util.log(”Sign Before MD5:” + result);  
  42.         result = MD5.MD5Encode(result,null).toUpperCase();  
  43.         Util.log(”Sign Result:” + result);  
  44.         return result;  
  45.     }  
  46.   
  47.     public static String getSign(Map map){  
  48.         ArrayList list = new ArrayList();  
  49.         for(Map.Entry entry:map.entrySet()){  
  50.             if(entry.getValue()!=“”){  
  51.                 list.add(entry.getKey() + ”=” + entry.getValue() + “&”);  
  52.             }  
  53.         }  
  54.         int size = list.size();  
  55.         String [] arrayToSort = list.toArray(new String[size]);  
  56.         Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);  
  57.         StringBuilder sb = new StringBuilder();  
  58.         for(int i = 0; i < size; i ++) {  
  59.             sb.append(arrayToSort[i]);  
  60.         }  
  61.         String result = sb.toString();  
  62.         result += ”key=” + Configure.getKey();  
  63.         //Util.log(“Sign Before MD5:” + result);  
  64.         result = MD5.MD5Encode(result,null).toUpperCase();  
  65.         //Util.log(“Sign Result:” + result);  
  66.         return result;  
  67.     }  
  68.   
  69.     /** 
  70.      * 从API返回的XML数据里面重新计算一次签名 
  71.      * @param responseString API返回的XML数据 
  72.      * @return 新鲜出炉的签名 
  73.      * @throws ParserConfigurationException 
  74.      * @throws IOException 
  75.      * @throws SAXException 
  76.      */  
  77.     public static String getSignFromResponseString(String responseString) throws IOException, SAXException, ParserConfigurationException {  
  78.         Map map = XMLParser.getMapFromXML(responseString);  
  79.         //清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名  
  80.         map.put(”sign”,“”);  
  81.         //将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较  
  82.         return Signature.getSign(map);  
  83.     }  
  84.   
  85.     /** 
  86.      * 检验API返回的数据里面的签名是否合法,避免数据在传输的过程中被第三方篡改 
  87.      * @param responseString API返回的XML数据字符串 
  88.      * @return API签名是否合法 
  89.      * @throws ParserConfigurationException 
  90.      * @throws IOException 
  91.      * @throws SAXException 
  92.      */  
  93.     public static boolean checkIsSignValidFromResponseString(String responseString) throws ParserConfigurationException, IOException, SAXException {  
  94.   
  95.         Map map = XMLParser.getMapFromXML(responseString);  
  96.         Util.log(map.toString());  
  97.   
  98.         String signFromAPIResponse = map.get(”sign”).toString();  
  99.         if(signFromAPIResponse==“” || signFromAPIResponse == null){  
  100.             Util.log(”API返回的数据签名数据不存在,有可能被第三方篡改!!!”);  
  101.             return false;  
  102.         }  
  103.         Util.log(”服务器回包里面的签名是:” + signFromAPIResponse);  
  104.         //清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名  
  105.         map.put(”sign”,“”);  
  106.         //将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较  
  107.         String signForAPIResponse = Signature.getSign(map);  
  108.   
  109.         if(!signForAPIResponse.equals(signFromAPIResponse)){  
  110.             //签名验不过,表示这个API返回的数据有可能已经被篡改了  
  111.             Util.log(”API返回的数据签名验证不通过,有可能被第三方篡改!!!”);  
  112.             return false;  
  113.         }  
  114.         Util.log(”恭喜,API返回的数据签名验证通过!!!”);  
  115.         return true;  
  116.     }  
  117.   
  118. }  
package com.luozhuang.util;

import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;

/**
 * luozhuang
 */
public class Signature {
    /**
     * 签名算法
     * @param o 要参与签名的数据对象
     * @return 签名
     * @throws IllegalAccessException
     */
    public static String getSign(Object o) throws IllegalAccessException {
        ArrayList list = new ArrayList();
        Class cls = o.getClass();
        Field[] fields = cls.getDeclaredFields();
        for (Field f : fields) {
            f.setAccessible(true);
            if (f.get(o) != null && f.get(o) != "") {
                list.add(f.getName() + "=" + f.get(o) + "&");
            }
        }
        int size = list.size();
        String [] arrayToSort = list.toArray(new String[size]);
        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < size; i ++) {
            sb.append(arrayToSort[i]);
        }
        String result = sb.toString();
        result += "key=" + Configure.getKey();
        Util.log("Sign Before MD5:" + result);
        result = MD5.MD5Encode(result,null).toUpperCase();
        Util.log("Sign Result:" + result);
        return result;
    }

    public static String getSign(Map map){
        ArrayList list = new ArrayList();
        for(Map.Entry entry:map.entrySet()){
            if(entry.getValue()!=""){
                list.add(entry.getKey() + "=" + entry.getValue() + "&");
            }
        }
        int size = list.size();
        String [] arrayToSort = list.toArray(new String[size]);
        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < size; i ++) {
            sb.append(arrayToSort[i]);
        }
        String result = sb.toString();
        result += "key=" + Configure.getKey();
        //Util.log("Sign Before MD5:" + result);
        result = MD5.MD5Encode(result,null).toUpperCase();
        //Util.log("Sign Result:" + result);
        return result;
    }

    /**
     * 从API返回的XML数据里面重新计算一次签名
     * @param responseString API返回的XML数据
     * @return 新鲜出炉的签名
     * @throws ParserConfigurationException
     * @throws IOException
     * @throws SAXException
     */
    public static String getSignFromResponseString(String responseString) throws IOException, SAXException, ParserConfigurationException {
        Map map = XMLParser.getMapFromXML(responseString);
        //清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名
        map.put("sign","");
        //将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较
        return Signature.getSign(map);
    }

    /**
     * 检验API返回的数据里面的签名是否合法,避免数据在传输的过程中被第三方篡改
     * @param responseString API返回的XML数据字符串
     * @return API签名是否合法
     * @throws ParserConfigurationException
     * @throws IOException
     * @throws SAXException
     */
    public static boolean checkIsSignValidFromResponseString(String responseString) throws ParserConfigurationException, IOException, SAXException {

        Map map = XMLParser.getMapFromXML(responseString);
        Util.log(map.toString());

        String signFromAPIResponse = map.get("sign").toString();
        if(signFromAPIResponse=="" || signFromAPIResponse == null){
            Util.log("API返回的数据签名数据不存在,有可能被第三方篡改!!!");
            return false;
        }
        Util.log("服务器回包里面的签名是:" + signFromAPIResponse);
        //清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名
        map.put("sign","");
        //将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较
        String signForAPIResponse = Signature.getSign(map);

        if(!signForAPIResponse.equals(signFromAPIResponse)){
            //签名验不过,表示这个API返回的数据有可能已经被篡改了
            Util.log("API返回的数据签名验证不通过,有可能被第三方篡改!!!");
            return false;
        }
        Util.log("恭喜,API返回的数据签名验证通过!!!");
        return true;
    }

}

[java] view plain copy
print ?
  1. package com.luozhuang.util;  
  2.   
  3.   
  4. import com.thoughtworks.xstream.XStream;  
  5.   
  6. import org.slf4j.Logger;  
  7. import org.slf4j.LoggerFactory;  
  8.   
  9. import java.io.*;  
  10. import java.lang.reflect.Field;  
  11. import java.text.SimpleDateFormat;  
  12. import java.util.Date;  
  13. import java.util.Map;  
  14.   
  15. /** 
  16.  * luozhuang 
  17.  */  
  18. public class Util {  
  19.   
  20.     //打log用  
  21.     private static Logger logger = new Logger();  
  22.   
  23.     /** 
  24.      * 通过反射的方式遍历对象的属性和属性值,方便调试 
  25.      * 
  26.      * @param o 要遍历的对象 
  27.      * @throws Exception 
  28.      */  
  29.     public static void reflect(Object o) throws Exception {  
  30.         Class cls = o.getClass();  
  31.         Field[] fields = cls.getDeclaredFields();  
  32.         for (int i = 0; i < fields.length; i++) {  
  33.             Field f = fields[i];  
  34.             f.setAccessible(true);  
  35.             Util.log(f.getName() + ” -> ” + f.get(o));  
  36.         }  
  37.     }  
  38.   
  39.     public static byte[] readInput(InputStream in) throws IOException {  
  40.         ByteArrayOutputStream out = new ByteArrayOutputStream();  
  41.         int len = 0;  
  42.         byte[] buffer = new byte[1024];  
  43.         while ((len = in.read(buffer)) > 0) {  
  44.             out.write(buffer, 0, len);  
  45.         }  
  46.         out.close();  
  47.         in.close();  
  48.         return out.toByteArray();  
  49.     }  
  50.   
  51.     public static String inputStreamToString(InputStream is) throws IOException {  
  52.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  53.         int i;  
  54.         while ((i = is.read()) != -1) {  
  55.             baos.write(i);  
  56.         }  
  57.         return baos.toString();  
  58.     }  
  59.   
  60.   
  61.     public static InputStream getStringStream(String sInputString) throws UnsupportedEncodingException {  
  62.         ByteArrayInputStream tInputStringStream = null;  
  63.         if (sInputString != null && !sInputString.trim().equals(“”)) {  
  64.             tInputStringStream = new ByteArrayInputStream(sInputString.getBytes(“UTF-8”));  
  65.         }  
  66.         return tInputStringStream;  
  67.     }  
  68.   
  69.     public static Object getObjectFromXML(String xml, Class tClass) {  
  70.         //将从API返回的XML数据映射到Java对象  
  71.         XStream xStreamForResponseData = new XStream();  
  72.         xStreamForResponseData.alias(”xml”, tClass);  
  73.         xStreamForResponseData.ignoreUnknownElements();//暂时忽略掉一些新增的字段  
  74.         return xStreamForResponseData.fromXML(xml);  
  75.     }  
  76.   
  77.     public static String getStringFromMap(Map map, String key, String defaultValue) {  
  78.         if (key == “” || key == null) {  
  79.             return defaultValue;  
  80.         }  
  81.         String result = (String) map.get(key);  
  82.         if (result == null) {  
  83.             return defaultValue;  
  84.         } else {  
  85.             return result;  
  86.         }  
  87.     }  
  88.   
  89.     public static int getIntFromMap(Map map, String key) {  
  90.         if (key == “” || key == null) {  
  91.             return 0;  
  92.         }  
  93.         if (map.get(key) == null) {  
  94.             return 0;  
  95.         }  
  96.         return Integer.parseInt((String) map.get(key));  
  97.     }  
  98.   
  99.     /** 
  100.      * 打log接口 
  101.      * @param log 要打印的log字符串 
  102.      * @return 返回log 
  103.      */  
  104.     public static String log(Object log){  
  105.         logger.info(log.toString());  
  106.         //System.out.println(log);  
  107.         return log.toString();  
  108.     }  
  109.   
  110.     /** 
  111.      * 读取本地的xml数据,一般用来自测用 
  112.      * @param localPath 本地xml文件路径 
  113.      * @return 读到的xml字符串 
  114.      */  
  115.     public static String getLocalXMLString(String localPath) throws IOException {  
  116.         return Util.inputStreamToString(Util.class.getResourceAsStream(localPath));  
  117.     }  
  118.   
  119. }  
package com.luozhuang.util;


import com.thoughtworks.xstream.XStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

/**
 * luozhuang
 */
public class Util {

    //打log用
    private static Logger logger = new Logger();

    /**
     * 通过反射的方式遍历对象的属性和属性值,方便调试
     *
     * @param o 要遍历的对象
     * @throws Exception
     */
    public static void reflect(Object o) throws Exception {
        Class cls = o.getClass();
        Field[] fields = cls.getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            Field f = fields[i];
            f.setAccessible(true);
            Util.log(f.getName() + " -> " + f.get(o));
        }
    }

    public static byte[] readInput(InputStream in) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int len = 0;
        byte[] buffer = new byte[1024];
        while ((len = in.read(buffer)) > 0) {
            out.write(buffer, 0, len);
        }
        out.close();
        in.close();
        return out.toByteArray();
    }

    public static String inputStreamToString(InputStream is) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int i;
        while ((i = is.read()) != -1) {
            baos.write(i);
        }
        return baos.toString();
    }


    public static InputStream getStringStream(String sInputString) throws UnsupportedEncodingException {
        ByteArrayInputStream tInputStringStream = null;
        if (sInputString != null && !sInputString.trim().equals("")) {
            tInputStringStream = new ByteArrayInputStream(sInputString.getBytes("UTF-8"));
        }
        return tInputStringStream;
    }

    public static Object getObjectFromXML(String xml, Class tClass) {
        //将从API返回的XML数据映射到Java对象
        XStream xStreamForResponseData = new XStream();
        xStreamForResponseData.alias("xml", tClass);
        xStreamForResponseData.ignoreUnknownElements();//暂时忽略掉一些新增的字段
        return xStreamForResponseData.fromXML(xml);
    }

    public static String getStringFromMap(Map map, String key, String defaultValue) {
        if (key == "" || key == null) {
            return defaultValue;
        }
        String result = (String) map.get(key);
        if (result == null) {
            return defaultValue;
        } else {
            return result;
        }
    }

    public static int getIntFromMap(Map map, String key) {
        if (key == "" || key == null) {
            return 0;
        }
        if (map.get(key) == null) {
            return 0;
        }
        return Integer.parseInt((String) map.get(key));
    }

    /**
     * 打log接口
     * @param log 要打印的log字符串
     * @return 返回log
     */
    public static String log(Object log){
        logger.info(log.toString());
        //System.out.println(log);
        return log.toString();
    }

    /**
     * 读取本地的xml数据,一般用来自测用
     * @param localPath 本地xml文件路径
     * @return 读到的xml字符串
     */
    public static String getLocalXMLString(String localPath) throws IOException {
        return Util.inputStreamToString(Util.class.getResourceAsStream(localPath));
    }

}

[java] view plain copy
print ?
  1. package com.luozhuang.util;  
  2.   
  3.   
  4. import org.w3c.dom.Document;  
  5. import org.w3c.dom.Element;  
  6. import org.w3c.dom.Node;  
  7. import org.w3c.dom.NodeList;  
  8. import org.xml.sax.SAXException;  
  9.   
  10. import javax.xml.parsers.DocumentBuilder;  
  11. import javax.xml.parsers.DocumentBuilderFactory;  
  12. import javax.xml.parsers.ParserConfigurationException;  
  13. import java.io.IOException;  
  14. import java.io.InputStream;  
  15. import java.util.ArrayList;  
  16. import java.util.HashMap;  
  17. import java.util.List;  
  18. import java.util.Map;  
  19. import java.util.SortedMap;  
  20. import java.util.TreeMap;  
  21.   
  22. /** 
  23.  * luozhuang 
  24.  */  
  25. public class XMLParser {  
  26.   
  27.      
  28.   
  29.     public static SortedMap getMapFromXML(String xmlString) throws ParserConfigurationException, IOException, SAXException {  
  30.   
  31.         //这里用Dom的方式解析回包的最主要目的是防止API新增回包字段  
  32.         DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();  
  33.         DocumentBuilder builder = factory.newDocumentBuilder();  
  34.         InputStream is =  Util.getStringStream(xmlString);  
  35.         Document document = builder.parse(is);  
  36.   
  37.         //获取到document里面的全部结点  
  38.         NodeList allNodes = document.getFirstChild().getChildNodes();  
  39.         Node node;  
  40.         SortedMap map = new TreeMap();  
  41.         int i=0;  
  42.         while (i < allNodes.getLength()) {  
  43.             node = allNodes.item(i);  
  44.             if(node instanceof Element){  
  45.                 map.put(node.getNodeName(),node.getTextContent());  
  46.             }  
  47.             i++;  
  48.         }  
  49.         return map;  
  50.   
  51.     }  
  52.   
  53.   
  54. }  
package com.luozhuang.util;


import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * luozhuang
 */
public class XMLParser {



    public static SortedMap getMapFromXML(String xmlString) throws ParserConfigurationException, IOException, SAXException {

        //这里用Dom的方式解析回包的最主要目的是防止API新增回包字段
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        InputStream is =  Util.getStringStream(xmlString);
        Document document = builder.parse(is);

        //获取到document里面的全部结点
        NodeList allNodes = document.getFirstChild().getChildNodes();
        Node node;
        SortedMap map = new TreeMap();
        int i=0;
        while (i < allNodes.getLength()) {
            node = allNodes.item(i);
            if(node instanceof Element){
                map.put(node.getNodeName(),node.getTextContent());
            }
            i++;
        }
        return map;

    }


}


你可能感兴趣的:(技术)