吐槽下:
经常有人问我,你不是在某软件公司么?我听说大公司都是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 自己根据需要选择替换。
“2067985” snippet_file_name=“blog_20161222_1_5457278” name=“code” class=“java”>package com.luozhuang;
”2067985”snippet_file_name=“blog_20161222_2_3079537” name=“code” class=“java”>package com.luozhuang;
”2067985”snippet_file_name=“blog_20161222_3_3558714” name=“code” class=“java”>package com.luozhuang;
”2067985”snippet_file_name=“blog_20161222_4_9512532” name=“code” class=“java”>package com.luozhuang;
”2067985”snippet_file_name=“blog_20161222_5_4386556” name=“code” class=“java”>package com.luozhuang.util;
”2067985”snippet_file_name=“blog_20161222_6_9293599” name=“code” class=“java”>package com.luozhuang.util;
”2067985”snippet_file_name=“blog_20161222_7_5629101” name=“code” class=“java”>package com.luozhuang.util;
”2067985”snippet_file_name=“blog_20161222_8_7471482” name=“code” class=“java”>package com.luozhuang.util;
”2067985”snippet_file_name=“blog_20161222_9_7046370” name=“code” class=“java”>package com.luozhuang.util;
”2067985”snippet_file_name=“blog_20161222_10_9968546” name=“code” class=“java”>package com.luozhuang.util;
”2067985”snippet_file_name=“blog_20161222_11_2367335” name=“code” class=“java”>package com.luozhuang.util;
”2067985”snippet_file_name=“blog_20161222_12_1178072” name=“code” class=“java”>package com.luozhuang.util;
- 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;
- }
- }
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; } }
- 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(“-“, “”);
- }
- }
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("-", ""); } }
- 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() + ”” + pair.getKey() + ”>”; } else if
- * (pair.getValue() instanceof String) { xml += ”<” + pair.getKey() +
- * ”>” + ”” + 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;
- }
- }
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 SortedMapm_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 "; */ return PayCommonUtil.getRequestXml(m_values); } /** * @将xml转为WxPayData对象并返回对象内部的数据 * @param String * 待转换的xml串 * @return 经转换得到的Dictionary * @throws WxPayException * @throws SAXException * @throws IOException * @throws ParserConfigurationException */ public SortedMappair : * m_values.entrySet()) * * { // 字段值不能为null,会影响后续流程 if (pair.getValue() == null) { * * throw new WxPayException("WxPayData内部含有值为null的字段!"); } * * if (pair.getValue() instanceof Integer) { xml += "<" + pair.getKey() * + ">" + pair.getValue() + "" + pair.getKey() + ">"; } else if * (pair.getValue() instanceof String) { xml += "<" + pair.getKey() + * ">" + "" + pair.getKey() + ">"; * } else// 除了String和int类型不能含有其他数据类型 { * * throw new WxPayException("WxPayData字段数据类型错误!"); } } xml += " 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 SortedMapGetValues() { return m_values; } }
- package com.luozhuang;
- public class WxPayException extends Exception {
- public WxPayException(String string) {
- super(string);
- }
- }
package com.luozhuang; public class WxPayException extends Exception { public WxPayException(String string) { super(string); } }
- 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;
- }
- }
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; } }
- 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;
- }
- }
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; } }
- 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;
- }
- }
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; } }
- 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
- 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
- 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 + “>” + “ + v + “]]>” + k + “>”);
- } else {
- sb.append(”<” + k + “>” + v + “” + k + “>”);
- }
- }
- 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;
- }
- }
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
- 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();
- }
- }
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(); } }
- 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;
- }
- }
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; } }
- 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));
- }
- }
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)); } }
- 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;
- }
- }
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; } }