|
@@ -0,0 +1,736 @@
|
|
|
+package cn.com.free.util;
|
|
|
+import java.io.BufferedReader;
|
|
|
+import java.io.ByteArrayInputStream;
|
|
|
+import java.io.File;
|
|
|
+import java.io.FileInputStream;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.InputStream;
|
|
|
+import java.io.InputStreamReader;
|
|
|
+import java.nio.charset.Charset;
|
|
|
+import java.security.KeyManagementException;
|
|
|
+import java.security.KeyStore;
|
|
|
+import java.security.KeyStoreException;
|
|
|
+import java.security.MessageDigest;
|
|
|
+import java.security.NoSuchAlgorithmException;
|
|
|
+import java.security.SecureRandom;
|
|
|
+import java.security.UnrecoverableKeyException;
|
|
|
+import java.security.cert.CertificateException;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.Iterator;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Random;
|
|
|
+import java.util.Set;
|
|
|
+import java.util.SortedMap;
|
|
|
+import java.util.TreeMap;
|
|
|
+import java.util.logging.FileHandler;
|
|
|
+import java.util.logging.Level;
|
|
|
+import java.util.logging.Logger;
|
|
|
+
|
|
|
+import javax.net.ssl.KeyManagerFactory;
|
|
|
+import javax.net.ssl.SSLContext;
|
|
|
+
|
|
|
+import org.apache.http.HttpResponse;
|
|
|
+import org.apache.http.client.methods.HttpPost;
|
|
|
+import org.apache.http.config.RegistryBuilder;
|
|
|
+import org.apache.http.conn.socket.ConnectionSocketFactory;
|
|
|
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
|
|
|
+import org.apache.http.conn.ssl.DefaultHostnameVerifier;
|
|
|
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
|
|
+import org.apache.http.entity.StringEntity;
|
|
|
+import org.apache.http.impl.client.CloseableHttpClient;
|
|
|
+import org.apache.http.impl.client.DefaultHttpClient;
|
|
|
+import org.apache.http.impl.client.HttpClientBuilder;
|
|
|
+import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
|
|
|
+import org.apache.http.util.EntityUtils;
|
|
|
+import org.jdom.Document;
|
|
|
+import org.jdom.Element;
|
|
|
+import org.jdom.JDOMException;
|
|
|
+import org.jdom.input.SAXBuilder;
|
|
|
+
|
|
|
+public class WechatUtil {
|
|
|
+
|
|
|
+ // 公众号支付APPID
|
|
|
+ public static final String APPID = "wx2556b4c38a1d0726";
|
|
|
+ // 公众号支付AppSecret
|
|
|
+ public static final String APP_SECRET = "40d9ae3553c7aa3c8d9610d405f60df8";
|
|
|
+ // 公众号支付商户号
|
|
|
+ public static final String MCH_ID = "1514694421";
|
|
|
+ // 商户后台配置的一个32位的key,位置:微信商户平台-账户中心-API安全
|
|
|
+ public static final String KEY = "EDrtyh544FT6tfdrh765F09okYM87Cs2";
|
|
|
+
|
|
|
+ // 证书地址
|
|
|
+ public static String certLocalPath = SystemStateConstant.CERTPATH+"apiclient_cert_1514694421.p12";
|
|
|
+
|
|
|
+ private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",
|
|
|
+ "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 刷卡支付查询
|
|
|
+ *
|
|
|
+ * @param body
|
|
|
+ * 商品或支付单简要描述
|
|
|
+ * @param out_trade_no
|
|
|
+ * 商户系统内部的订单号,32个字符内、可包含字母
|
|
|
+ * @param total_fee
|
|
|
+ * 订单总金额,单位为分
|
|
|
+ * @param IP
|
|
|
+ * APP和网页支付提交用户端ip
|
|
|
+ * @param notify_url
|
|
|
+ * 接收微信支付异步通知回调地址
|
|
|
+ * @param openid
|
|
|
+ * 用户openId
|
|
|
+ * @throws IOException
|
|
|
+ */
|
|
|
+ public static String micropayQuery(String outTradeNo) {
|
|
|
+ final Logger logger = Logger.getLogger("org.jediael.crawl.MyCrawler");
|
|
|
+ logger.setLevel(Level.INFO);
|
|
|
+ logger.setUseParentHandlers(false);
|
|
|
+ try {
|
|
|
+ FileHandler fileHandler = new FileHandler("E:\\log\\infoquery.log");
|
|
|
+ fileHandler.setLevel(Level.INFO);
|
|
|
+ logger.addHandler(fileHandler);
|
|
|
+ } catch (SecurityException e) {
|
|
|
+ // TODO Auto-generated catch block
|
|
|
+ e.printStackTrace();
|
|
|
+ } catch (IOException e) {
|
|
|
+ // TODO Auto-generated catch block
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ logger.info("micropayQuery查询开始订单号为="+outTradeNo);
|
|
|
+ HttpPost httppost = new HttpPost(
|
|
|
+ "https://api.mch.weixin.qq.com/pay/orderquery");
|
|
|
+ String nonce_str = getNonceStr();// 随机数据
|
|
|
+ SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
|
|
|
+ /**
|
|
|
+ * 组装请求参数 按照ASCII排序
|
|
|
+ */
|
|
|
+ parameters.put("appid", APPID);
|
|
|
+ parameters.put("mch_id", MCH_ID);
|
|
|
+ // parameters.put("sub_mch_id", MCH_ID);
|
|
|
+ parameters.put("nonce_str", nonce_str);
|
|
|
+ parameters.put("out_trade_no", outTradeNo);
|
|
|
+
|
|
|
+ String sign = createSign(parameters, KEY);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 组装XML
|
|
|
+ */
|
|
|
+ StringBuilder sb = new StringBuilder("");
|
|
|
+ sb.append("<xml>");
|
|
|
+ setXmlKV(sb, "appid", APPID);
|
|
|
+ setXmlKV(sb, "mch_id", MCH_ID);
|
|
|
+ // setXmlKV(sb,"sub_mch_id", MCH_ID);
|
|
|
+ setXmlKV(sb, "nonce_str", nonce_str);
|
|
|
+ setXmlKV(sb, "out_trade_no", outTradeNo);
|
|
|
+ setXmlKV(sb, "sign", sign);
|
|
|
+
|
|
|
+ sb.append("</xml>");
|
|
|
+ // 将xml型字符转换
|
|
|
+ String returnVal = "0";
|
|
|
+ try {
|
|
|
+ StringEntity reqEntity = new StringEntity(new String(sb.toString()
|
|
|
+ .getBytes("UTF-8"), "ISO8859-1"));
|
|
|
+ // 这个处理是为了防止传中文的时候出现签名错误
|
|
|
+ httppost.setEntity(reqEntity);
|
|
|
+ DefaultHttpClient httpclient = new DefaultHttpClient();
|
|
|
+ HttpResponse response = httpclient.execute(httppost);
|
|
|
+ String strResult = EntityUtils.toString(response.getEntity(),
|
|
|
+ Charset.forName("utf-8"));
|
|
|
+
|
|
|
+ Map mapResSel = doXMLParse(strResult);
|
|
|
+ String return_code_sel = (String) mapResSel.get("return_code");
|
|
|
+ logger.info("micropayQuery查询订单结果为="+return_code_sel);
|
|
|
+ if ("SUCCESS".equals(return_code_sel)) {
|
|
|
+ returnVal = "1";
|
|
|
+ } else {
|
|
|
+ returnVal = "0";
|
|
|
+ }
|
|
|
+ logger.info("micropayQuery查询结束returnVal="+returnVal);
|
|
|
+ } catch (Exception e) {
|
|
|
+ // TODO Auto-generated catch block
|
|
|
+ returnVal = "0";
|
|
|
+ logger.info("micropayQuery查询异常结束="+e.getMessage());
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return returnVal;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 刷卡支付
|
|
|
+ *
|
|
|
+ * @param body
|
|
|
+ * 商品或支付单简要描述
|
|
|
+ * @param out_trade_no
|
|
|
+ * 商户系统内部的订单号,32个字符内、可包含字母
|
|
|
+ * @param total_fee
|
|
|
+ * 订单总金额,单位为分
|
|
|
+ * @param IP
|
|
|
+ * APP和网页支付提交用户端ip
|
|
|
+ * @param notify_url
|
|
|
+ * 接收微信支付异步通知回调地址
|
|
|
+ * @param openid
|
|
|
+ * 用户openId
|
|
|
+ * @throws IOException
|
|
|
+ */
|
|
|
+ public static String micropay(String body, String out_trade_no,
|
|
|
+ Integer total_fee, String ip, String deviceInfo, String attach,
|
|
|
+ String auth_code) throws IOException {
|
|
|
+ /**
|
|
|
+ * 设置访问路径
|
|
|
+ */
|
|
|
+ HttpPost httppost = new HttpPost(
|
|
|
+ "https://api.mch.weixin.qq.com/pay/micropay");
|
|
|
+ String nonce_str = getNonceStr();// 随机数据
|
|
|
+ SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
|
|
|
+ /**
|
|
|
+ * 组装请求参数 按照ASCII排序
|
|
|
+ */
|
|
|
+ parameters.put("appid", APPID);
|
|
|
+ parameters.put("body", body);
|
|
|
+ parameters.put("mch_id", MCH_ID);
|
|
|
+ // parameters.put("sub_mch_id", MCH_ID);
|
|
|
+ parameters.put("device_info", deviceInfo);
|
|
|
+ parameters.put("nonce_str", nonce_str);
|
|
|
+ parameters.put("out_trade_no", out_trade_no);
|
|
|
+ parameters.put("spbill_create_ip", ip);
|
|
|
+ parameters.put("total_fee", total_fee.toString());
|
|
|
+ parameters.put("auth_code", auth_code);
|
|
|
+ parameters.put("attach", attach);
|
|
|
+
|
|
|
+ String sign = createSign(parameters, KEY);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 组装XML
|
|
|
+ */
|
|
|
+ StringBuilder sb = new StringBuilder("");
|
|
|
+ sb.append("<xml>");
|
|
|
+ setXmlKV(sb, "appid", APPID);
|
|
|
+ setXmlKV(sb, "body", body);
|
|
|
+ setXmlKV(sb, "mch_id", MCH_ID);
|
|
|
+ // setXmlKV(sb,"sub_mch_id", MCH_ID);
|
|
|
+ setXmlKV(sb, "device_info", deviceInfo);
|
|
|
+ setXmlKV(sb, "nonce_str", nonce_str);
|
|
|
+ setXmlKV(sb, "out_trade_no", out_trade_no);
|
|
|
+ setXmlKV(sb, "spbill_create_ip", ip);
|
|
|
+ setXmlKV(sb, "total_fee", total_fee.toString());
|
|
|
+ setXmlKV(sb, "auth_code", auth_code);
|
|
|
+ setXmlKV(sb, "sign", sign);
|
|
|
+ setXmlKV(sb, "attach", attach);
|
|
|
+
|
|
|
+ sb.append("</xml>");
|
|
|
+
|
|
|
+ StringEntity reqEntity = new StringEntity(new String(sb.toString()
|
|
|
+ .getBytes("UTF-8"), "ISO8859-1"));// 这个处理是为了防止传中文的时候出现签名错误
|
|
|
+ httppost.setEntity(reqEntity);
|
|
|
+ DefaultHttpClient httpclient = new DefaultHttpClient();
|
|
|
+ HttpResponse response = httpclient.execute(httppost);
|
|
|
+ String strResult = EntityUtils.toString(response.getEntity(),
|
|
|
+ Charset.forName("utf-8"));
|
|
|
+ return strResult;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 刷卡支付查询
|
|
|
+ *
|
|
|
+ * @param body
|
|
|
+ * 商品或支付单简要描述
|
|
|
+ * @param out_trade_no
|
|
|
+ * 商户系统内部的订单号,32个字符内、可包含字母
|
|
|
+ * @param total_fee
|
|
|
+ * 订单总金额,单位为分
|
|
|
+ * @param IP
|
|
|
+ * APP和网页支付提交用户端ip
|
|
|
+ * @param notify_url
|
|
|
+ * 接收微信支付异步通知回调地址
|
|
|
+ * @param openid
|
|
|
+ * 用户openId
|
|
|
+ * @throws IOException
|
|
|
+ */
|
|
|
+ public static String orderquery(String out_trade_no) throws IOException {
|
|
|
+ /**
|
|
|
+ * 设置访问路径
|
|
|
+ */
|
|
|
+ HttpPost httppost = new HttpPost(
|
|
|
+ "https://api.mch.weixin.qq.com/pay/orderquery");
|
|
|
+ String nonce_str = getNonceStr();// 随机数据
|
|
|
+ SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
|
|
|
+ /**
|
|
|
+ * 组装请求参数 按照ASCII排序
|
|
|
+ */
|
|
|
+ parameters.put("appid", APPID);
|
|
|
+ parameters.put("mch_id", MCH_ID);
|
|
|
+ // parameters.put("sub_mch_id", MCH_ID);
|
|
|
+ parameters.put("nonce_str", nonce_str);
|
|
|
+ parameters.put("out_trade_no", out_trade_no);
|
|
|
+
|
|
|
+ String sign = createSign(parameters, KEY);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 组装XML
|
|
|
+ */
|
|
|
+ StringBuilder sb = new StringBuilder("");
|
|
|
+ sb.append("<xml>");
|
|
|
+ setXmlKV(sb, "appid", APPID);
|
|
|
+ setXmlKV(sb, "mch_id", MCH_ID);
|
|
|
+ // setXmlKV(sb,"sub_mch_id", MCH_ID);
|
|
|
+ setXmlKV(sb, "nonce_str", nonce_str);
|
|
|
+ setXmlKV(sb, "out_trade_no", out_trade_no);
|
|
|
+ setXmlKV(sb, "sign", sign);
|
|
|
+
|
|
|
+ sb.append("</xml>");
|
|
|
+
|
|
|
+ StringEntity reqEntity = new StringEntity(new String(sb.toString()
|
|
|
+ .getBytes("UTF-8"), "ISO8859-1"));// 这个处理是为了防止传中文的时候出现签名错误
|
|
|
+ httppost.setEntity(reqEntity);
|
|
|
+ DefaultHttpClient httpclient = new DefaultHttpClient();
|
|
|
+ HttpResponse response = httpclient.execute(httppost);
|
|
|
+ String strResult = EntityUtils.toString(response.getEntity(),
|
|
|
+ Charset.forName("utf-8"));
|
|
|
+ return strResult;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 撤销订单
|
|
|
+ *
|
|
|
+ * @param body
|
|
|
+ * 商品或支付单简要描述
|
|
|
+ * @param out_trade_no
|
|
|
+ * 商户系统内部的订单号,32个字符内、可包含字母
|
|
|
+ * @param total_fee
|
|
|
+ * 订单总金额,单位为分
|
|
|
+ * @param IP
|
|
|
+ * APP和网页支付提交用户端ip
|
|
|
+ * @param notify_url
|
|
|
+ * 接收微信支付异步通知回调地址
|
|
|
+ * @param openid
|
|
|
+ * 用户openId
|
|
|
+ * @throws IOException
|
|
|
+ */
|
|
|
+ public static String reverse(String out_trade_no) {
|
|
|
+ final Logger logger = Logger.getLogger("org.jediael.crawl.MyCrawler");
|
|
|
+ logger.setLevel(Level.INFO);
|
|
|
+ logger.setUseParentHandlers(false);
|
|
|
+ try {
|
|
|
+ FileHandler fileHandler = new FileHandler("E:\\log\\info.log");
|
|
|
+ fileHandler.setLevel(Level.INFO);
|
|
|
+ logger.addHandler(fileHandler);
|
|
|
+ } catch (SecurityException e) {
|
|
|
+ // TODO Auto-generated catch block
|
|
|
+ e.printStackTrace();
|
|
|
+ } catch (IOException e) {
|
|
|
+ // TODO Auto-generated catch block
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ String resultVal = "0";
|
|
|
+ logger.info("撤销订单开始订单号="+out_trade_no);
|
|
|
+ try {
|
|
|
+ String path = certLocalPath;
|
|
|
+ char[] password = MCH_ID.toCharArray();
|
|
|
+ InputStream certStream = new FileInputStream(new File(path));;
|
|
|
+ KeyStore ks = KeyStore.getInstance("PKCS12");
|
|
|
+ ks.load(certStream, password);
|
|
|
+ logger.info("加载秘钥文件");
|
|
|
+ // 实例化密钥库 & 初始化密钥工厂
|
|
|
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
|
|
+ kmf.init(ks, password);
|
|
|
+
|
|
|
+ // 创建 SSLContext
|
|
|
+ SSLContext sslContext = SSLContext.getInstance("TLS");
|
|
|
+ sslContext.init(kmf.getKeyManagers(), null, new SecureRandom());
|
|
|
+
|
|
|
+ SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
|
|
|
+ sslContext,
|
|
|
+ new String[]{"TLSv1"},
|
|
|
+ null,
|
|
|
+ new DefaultHostnameVerifier());
|
|
|
+
|
|
|
+ BasicHttpClientConnectionManager connManager = new BasicHttpClientConnectionManager(
|
|
|
+ RegistryBuilder.<ConnectionSocketFactory>create()
|
|
|
+ .register("http", PlainConnectionSocketFactory.getSocketFactory())
|
|
|
+ .register("https", sslConnectionSocketFactory)
|
|
|
+ .build(),
|
|
|
+ null,
|
|
|
+ null,
|
|
|
+ null
|
|
|
+ );
|
|
|
+
|
|
|
+ CloseableHttpClient httpclient = HttpClientBuilder.create()
|
|
|
+ .setConnectionManager(connManager)
|
|
|
+ .build();
|
|
|
+ logger.info("加载秘钥文件成功");
|
|
|
+ /**
|
|
|
+ * 设置访问路径
|
|
|
+ */
|
|
|
+ HttpPost httppost = new HttpPost(
|
|
|
+ "https://api.mch.weixin.qq.com/secapi/pay/reverse");
|
|
|
+ String nonce_str = getNonceStr();// 随机数据
|
|
|
+ SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
|
|
|
+ /**
|
|
|
+ * 组装请求参数 按照ASCII排序
|
|
|
+ */
|
|
|
+ parameters.put("appid", APPID);
|
|
|
+ parameters.put("mch_id", MCH_ID);
|
|
|
+ // parameters.put("sub_mch_id", MCH_ID);
|
|
|
+ parameters.put("nonce_str", nonce_str);
|
|
|
+ parameters.put("out_trade_no", out_trade_no);
|
|
|
+
|
|
|
+ String sign = createSign(parameters, KEY);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 组装XML
|
|
|
+ */
|
|
|
+ StringBuilder sb = new StringBuilder("");
|
|
|
+ sb.append("<xml>");
|
|
|
+ setXmlKV(sb, "appid", APPID);
|
|
|
+ setXmlKV(sb, "mch_id", MCH_ID);
|
|
|
+ // setXmlKV(sb,"sub_mch_id", MCH_ID);
|
|
|
+ setXmlKV(sb, "nonce_str", nonce_str);
|
|
|
+ setXmlKV(sb, "out_trade_no", out_trade_no);
|
|
|
+ setXmlKV(sb, "sign", sign);
|
|
|
+
|
|
|
+ sb.append("</xml>");
|
|
|
+
|
|
|
+ StringEntity reqEntity = new StringEntity(new String(sb.toString()
|
|
|
+ .getBytes("UTF-8"), "ISO8859-1"));// 这个处理是为了防止传中文的时候出现签名错误
|
|
|
+ httppost.setEntity(reqEntity);
|
|
|
+ // DefaultHttpClient httpclient = new DefaultHttpClient();
|
|
|
+ HttpResponse response = httpclient.execute(httppost);
|
|
|
+ String strResult = EntityUtils.toString(response.getEntity(),
|
|
|
+ Charset.forName("utf-8"));
|
|
|
+ logger.info("撤销订单执行结束结果为strResult"+strResult);
|
|
|
+ // 将xml型字符转换
|
|
|
+ Map mapRes = doXMLParse(strResult);
|
|
|
+ String return_code = (String) mapRes.get("return_code");
|
|
|
+ logger.info("撤销订单执行return_code="+return_code);
|
|
|
+ if ("SUCCESS".equals(return_code)) {
|
|
|
+ String result_code = (String) mapRes.get("result_code");
|
|
|
+ logger.info("撤销订单执行result_code="+result_code);
|
|
|
+ if ("SUCCESS".equals(result_code)) {
|
|
|
+ resultVal = "1";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ // TODO: handle exception
|
|
|
+ logger.info("撤销订单执行异常="+e.getMessage());
|
|
|
+ resultVal = "0";
|
|
|
+ }
|
|
|
+ return resultVal;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 微信退费
|
|
|
+ *
|
|
|
+ * @param out_trade_no
|
|
|
+ * 商户订单号
|
|
|
+ * @param out_refund_no
|
|
|
+ * 商户退款单号
|
|
|
+ * @param total_fee
|
|
|
+ * 订单总金额,单位为分
|
|
|
+ * @param refund_fee
|
|
|
+ * 退款金额
|
|
|
+ * @param refund_desc
|
|
|
+ * 退款原因
|
|
|
+ * @throws IOException
|
|
|
+ * @throws NoSuchAlgorithmException
|
|
|
+ * @throws KeyStoreException
|
|
|
+ * @throws KeyManagementException
|
|
|
+ * @throws UnrecoverableKeyException
|
|
|
+ * @throws CertificateException
|
|
|
+ */
|
|
|
+ public static String refund(String out_trade_no, String out_refund_no,
|
|
|
+ String total_fee, String refund_fee, String refund_desc)
|
|
|
+ throws IOException, UnrecoverableKeyException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException {
|
|
|
+
|
|
|
+ String path = certLocalPath;
|
|
|
+ char[] password = MCH_ID.toCharArray();
|
|
|
+ InputStream certStream = new FileInputStream(new File(path));;
|
|
|
+ KeyStore ks = KeyStore.getInstance("PKCS12");
|
|
|
+ ks.load(certStream, password);
|
|
|
+
|
|
|
+ // 实例化密钥库 & 初始化密钥工厂
|
|
|
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
|
|
+ kmf.init(ks, password);
|
|
|
+
|
|
|
+ // 创建 SSLContext
|
|
|
+ SSLContext sslContext = SSLContext.getInstance("TLS");
|
|
|
+ sslContext.init(kmf.getKeyManagers(), null, new SecureRandom());
|
|
|
+
|
|
|
+ SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
|
|
|
+ sslContext,
|
|
|
+ new String[]{"TLSv1"},
|
|
|
+ null,
|
|
|
+ new DefaultHostnameVerifier());
|
|
|
+
|
|
|
+ BasicHttpClientConnectionManager connManager = new BasicHttpClientConnectionManager(
|
|
|
+ RegistryBuilder.<ConnectionSocketFactory>create()
|
|
|
+ .register("http", PlainConnectionSocketFactory.getSocketFactory())
|
|
|
+ .register("https", sslConnectionSocketFactory)
|
|
|
+ .build(),
|
|
|
+ null,
|
|
|
+ null,
|
|
|
+ null
|
|
|
+ );
|
|
|
+
|
|
|
+ CloseableHttpClient httpclient = HttpClientBuilder.create()
|
|
|
+ .setConnectionManager(connManager)
|
|
|
+ .build();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 设置访问路径
|
|
|
+ */
|
|
|
+ HttpPost httppost = new HttpPost(
|
|
|
+ "https://api.mch.weixin.qq.com/secapi/pay/refund");
|
|
|
+ String nonce_str = getNonceStr();// 随机数据
|
|
|
+ SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
|
|
|
+ /**
|
|
|
+ * 组装请求参数 按照ASCII排序
|
|
|
+ */
|
|
|
+ parameters.put("appid", APPID);
|
|
|
+ parameters.put("mch_id", MCH_ID);
|
|
|
+ parameters.put("nonce_str", nonce_str);
|
|
|
+ parameters.put("out_trade_no", out_trade_no);
|
|
|
+ parameters.put("out_refund_no", out_refund_no);
|
|
|
+ parameters.put("total_fee", total_fee);
|
|
|
+ parameters.put("refund_fee", refund_fee);
|
|
|
+ parameters.put("refund_desc", refund_desc);
|
|
|
+
|
|
|
+ String sign = createSign(parameters, KEY);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 组装XML
|
|
|
+ */
|
|
|
+ StringBuilder sb = new StringBuilder("");
|
|
|
+ sb.append("<xml>");
|
|
|
+ setXmlKV(sb, "appid", APPID);
|
|
|
+ setXmlKV(sb, "mch_id", MCH_ID);
|
|
|
+ setXmlKV(sb, "nonce_str", nonce_str);
|
|
|
+ setXmlKV(sb, "out_trade_no", out_trade_no);
|
|
|
+ setXmlKV(sb, "out_refund_no", out_refund_no);
|
|
|
+ setXmlKV(sb, "total_fee", total_fee);
|
|
|
+ setXmlKV(sb, "refund_fee", refund_fee);
|
|
|
+ setXmlKV(sb, "refund_desc", refund_desc);
|
|
|
+ setXmlKV(sb, "sign", sign);
|
|
|
+ sb.append("</xml>");
|
|
|
+
|
|
|
+ StringEntity reqEntity = new StringEntity(new String(sb.toString()
|
|
|
+ .getBytes("UTF-8"), "ISO8859-1"));// 这个处理是为了防止传中文的时候出现签名错误
|
|
|
+ httppost.setEntity(reqEntity);
|
|
|
+// DefaultHttpClient httpclient = new DefaultHttpClient();
|
|
|
+ HttpResponse response = httpclient.execute(httppost);
|
|
|
+ String strResult = EntityUtils.toString(response.getEntity(),
|
|
|
+ Charset.forName("utf-8"));
|
|
|
+ return strResult;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获得随机字符串
|
|
|
+ private static String getNonceStr() {
|
|
|
+ Random random = new Random();
|
|
|
+ return MD5Encode(String.valueOf(random.nextInt(10000)), "UTF-8");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 插入XML标签
|
|
|
+ private static StringBuilder setXmlKV(StringBuilder sb, String Key, String value) {
|
|
|
+ sb.append("<");
|
|
|
+ sb.append(Key);
|
|
|
+ sb.append(">");
|
|
|
+
|
|
|
+ sb.append(value);
|
|
|
+
|
|
|
+ sb.append("</");
|
|
|
+ sb.append(Key);
|
|
|
+ sb.append(">");
|
|
|
+
|
|
|
+ return sb;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
|
|
|
+ *
|
|
|
+ * @param strxml
|
|
|
+ * @return
|
|
|
+ * @throws JDOMException
|
|
|
+ * @throws IOException
|
|
|
+ */
|
|
|
+ public static Map doXMLParse(String strxml) throws Exception {
|
|
|
+ if (null == strxml || "".equals(strxml)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ Map m = new HashMap();
|
|
|
+ InputStream in = String2Inputstream(strxml);
|
|
|
+ BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF-8"));
|
|
|
+ SAXBuilder builder = new SAXBuilder();
|
|
|
+ Document doc = builder.build(br);
|
|
|
+ Element root = doc.getRootElement();
|
|
|
+ List list = root.getChildren();
|
|
|
+ Iterator it = list.iterator();
|
|
|
+ while (it.hasNext()) {
|
|
|
+ Element e = (Element) it.next();
|
|
|
+ String k = e.getName();
|
|
|
+ String v = "";
|
|
|
+ List children = e.getChildren();
|
|
|
+ if (children.isEmpty()) {
|
|
|
+ v = e.getTextNormalize();
|
|
|
+ } else {
|
|
|
+ v = getChildrenText(children);
|
|
|
+ }
|
|
|
+ m.put(k, v);
|
|
|
+ }
|
|
|
+ // 关闭流
|
|
|
+ in.close();
|
|
|
+ return m;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 刷卡支付查询
|
|
|
+ *
|
|
|
+ * @param body
|
|
|
+ * 商品或支付单简要描述
|
|
|
+ * @param out_trade_no
|
|
|
+ * 商户系统内部的订单号,32个字符内、可包含字母
|
|
|
+ * @param total_fee
|
|
|
+ * 订单总金额,单位为分
|
|
|
+ * @param IP
|
|
|
+ * APP和网页支付提交用户端ip
|
|
|
+ * @param notify_url
|
|
|
+ * 接收微信支付异步通知回调地址
|
|
|
+ * @param openid
|
|
|
+ * 用户openId
|
|
|
+ * @throws IOException
|
|
|
+ */
|
|
|
+ public static String downloadbill(String bill_date)
|
|
|
+ throws IOException {
|
|
|
+ /**
|
|
|
+ * 设置访问路径
|
|
|
+ */
|
|
|
+ HttpPost httppost = new HttpPost(
|
|
|
+ "https://api.mch.weixin.qq.com/pay/downloadbill");
|
|
|
+ String nonce_str = getNonceStr();// 随机数据
|
|
|
+ SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
|
|
|
+ /**
|
|
|
+ * 组装请求参数 按照ASCII排序
|
|
|
+ */
|
|
|
+ parameters.put("appid", APPID);
|
|
|
+ parameters.put("mch_id", MCH_ID);
|
|
|
+ //parameters.put("sub_mch_id", MCH_ID);
|
|
|
+ parameters.put("nonce_str", nonce_str);
|
|
|
+ parameters.put("bill_date", bill_date);
|
|
|
+ parameters.put("bill_type", "ALL");
|
|
|
+
|
|
|
+ String sign = createSign(parameters, KEY);
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 组装XML
|
|
|
+ */
|
|
|
+ StringBuilder sb = new StringBuilder("");
|
|
|
+ sb.append("<xml>");
|
|
|
+ setXmlKV(sb, "appid", APPID);
|
|
|
+ setXmlKV(sb, "mch_id", MCH_ID);
|
|
|
+ //setXmlKV(sb,"sub_mch_id", MCH_ID);
|
|
|
+ setXmlKV(sb, "nonce_str", nonce_str);
|
|
|
+ setXmlKV(sb, "bill_date", bill_date);
|
|
|
+ setXmlKV(sb, "bill_type", "ALL");
|
|
|
+ setXmlKV(sb, "sign", sign);
|
|
|
+
|
|
|
+ sb.append("</xml>");
|
|
|
+
|
|
|
+ StringEntity reqEntity = new StringEntity(new String(sb.toString()
|
|
|
+ .getBytes("UTF-8"), "ISO8859-1"));// 这个处理是为了防止传中文的时候出现签名错误
|
|
|
+ httppost.setEntity(reqEntity);
|
|
|
+ DefaultHttpClient httpclient = new DefaultHttpClient();
|
|
|
+ HttpResponse response = httpclient.execute(httppost);
|
|
|
+ String strResult = EntityUtils.toString(response.getEntity(),
|
|
|
+ Charset.forName("utf-8"));
|
|
|
+ return strResult;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private static InputStream String2Inputstream(String str) {
|
|
|
+ return new ByteArrayInputStream(str.getBytes());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取子结点的xml
|
|
|
+ *
|
|
|
+ * @param children
|
|
|
+ * @return String
|
|
|
+ */
|
|
|
+ private static String getChildrenText(List children) {
|
|
|
+ StringBuffer sb = new StringBuffer();
|
|
|
+ if (!children.isEmpty()) {
|
|
|
+ Iterator it = children.iterator();
|
|
|
+ while (it.hasNext()) {
|
|
|
+ Element e = (Element) it.next();
|
|
|
+ String name = e.getName();
|
|
|
+ String value = e.getTextNormalize();
|
|
|
+ List list = e.getChildren();
|
|
|
+ sb.append("<" + name + ">");
|
|
|
+ if (!list.isEmpty()) {
|
|
|
+ sb.append(getChildrenText(list));
|
|
|
+ }
|
|
|
+ sb.append(value);
|
|
|
+ sb.append("</" + name + ">");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return sb.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * * 创建签名 * @param parameters * @param key * @return
|
|
|
+ */
|
|
|
+ @SuppressWarnings("rawtypes")
|
|
|
+ private static String createSign(SortedMap<Object, Object> parameters, String key) {
|
|
|
+ StringBuffer sb = new StringBuffer();
|
|
|
+ Set es = parameters.entrySet();// 所有参与传参的参数按照accsii排序(升序)
|
|
|
+ Iterator it = es.iterator();
|
|
|
+ while (it.hasNext()) {
|
|
|
+ Map.Entry entry = (Map.Entry) it.next();
|
|
|
+ String k = (String) entry.getKey();
|
|
|
+ Object v = entry.getValue();
|
|
|
+ if (null != v && !"".equals(v) && !"sign".equals(k)
|
|
|
+ && !"key".equals(k)) {
|
|
|
+ sb.append(k + "=" + v + "&");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ sb.append("key=" + key);
|
|
|
+ String sign = MD5Encode(sb.toString(), "UTF-8").toUpperCase();
|
|
|
+ return sign;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String MD5Encode(String origin, String charsetname) {
|
|
|
+ String resultString = null;
|
|
|
+ try {
|
|
|
+ resultString = new String(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 exception) {
|
|
|
+
|
|
|
+ }
|
|
|
+ return resultString;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String byteArrayToHexString(byte b[]) {
|
|
|
+ StringBuffer resultSb = new StringBuffer();
|
|
|
+ for (int i = 0; i < b.length; i++)
|
|
|
+ resultSb.append(byteToHexString(b[i]));
|
|
|
+
|
|
|
+ return resultSb.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String byteToHexString(byte b) {
|
|
|
+ int n = b;
|
|
|
+ if (n < 0)
|
|
|
+ n += 256;
|
|
|
+ int d1 = n / 16;
|
|
|
+ int d2 = n % 16;
|
|
|
+ return hexDigits[d1] + hexDigits[d2];
|
|
|
+ }
|
|
|
+}
|