package cn.wisenergy.service.util; import cn.wisenergy.common.utils.R; import cn.wisenergy.model.dto.PayPageDto; import cn.wisenergy.service.httpClient.WechatPayHttpClientBuilder; import cn.wisenergy.service.httpClient.auth.AutoUpdateCertificatesVerifier; import cn.wisenergy.service.httpClient.auth.PrivateKeySigner; import cn.wisenergy.service.httpClient.auth.WechatPay2Credentials; import cn.wisenergy.service.httpClient.auth.WechatPay2Validator; import cn.wisenergy.service.httpClient.util.PemUtil; import cn.wisenergy.service.wxpay.WxCommon; import okhttp3.HttpUrl; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang.RandomStringUtils; import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.util.EntityUtils; import org.junit.After; import javax.servlet.http.HttpServletRequest; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.SignatureException; import java.security.spec.InvalidKeySpecException; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.*; public class WxPayUtil { /** * 商户号 */ private static String mchId = WxCommon.MCHID; // 商户证书序列号 private static String mchSerialNo = WxCommon.SERIAL_NO; // api密钥 private static String apiV3Key = WxCommon.SECRET_KEY; // 你的商户私钥 private static String privateKey = "-----BEGIN PRIVATE KEY-----\n" +WxCommon.SECRET_KEY + "-----END PRIVATE KEY-----\n"; private static CloseableHttpClient httpClient; private static AutoUpdateCertificatesVerifier verifier; static { PrivateKey merchantPrivateKey = null; try { merchantPrivateKey = PemUtil.loadPrivateKey( new ByteArrayInputStream(privateKey.getBytes("utf-8"))); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } //使用自动更新的签名验证器,不需要传入证书 try { verifier = new AutoUpdateCertificatesVerifier( new WechatPay2Credentials(mchId, new PrivateKeySigner(mchSerialNo, merchantPrivateKey)), apiV3Key.getBytes("utf-8")); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } httpClient = WechatPayHttpClientBuilder.create() .withMerchant(mchId, mchSerialNo, merchantPrivateKey) .withValidator(new WechatPay2Validator(verifier)) .build(); } @After public void after() throws IOException { httpClient.close(); } public static void main(String[] args) throws IOException, NoSuchAlgorithmException, SignatureException, InvalidKeySpecException, InvalidKeyException { HttpPost httpPost = new HttpPost(WxCommon.WX_PAY_URL_pc); long timestamp = System.currentTimeMillis() / 1000; String nonceStr = UUID.randomUUID().toString().replace("-", ""); String method = "POST"; String tradeNo = "21" + System.currentTimeMillis(); HttpUrl httpurl = HttpUrl.parse(WxCommon.WX_PAY_URL_pc); // 请求body参数 String reqdata = "{" + "\"time_expire\":\"2021-02-07T10:34:56+08:00\"," + "\"amount\":{" + "\"total\":100," + "\"currency\":\"CNY\"" + "}," + "\"mchid\":\""+WxCommon.MCHID+"\"," + "\"description\":\"Image形象店-深圳腾大-QQ公仔\"," + "\"notify_url\":\""+WxCommon.NOTIFY_URL+"\"," + "\"out_trade_no\":\""+tradeNo+"\"," + "\"goods_tag\":\"WXG\"," + "\"appid\":\""+WxCommon.APP_ID+"\"" // + "\"attach\":\"自定义数据说明\"," // + "\"detail\": {" // + "\"invoice_id\":\"wx123\"," // + "\"goods_detail\": [" // + "{" // + "\"goods_name\":\"iPhoneX 256G\"," // + "\"wechatpay_goods_id\":\"1001\"," // + "\"quantity\":1," // + "\"merchant_goods_id\":\"商品编码\"," // + "\"unit_price\":828800" // + "}," // + "{" // + "\"goods_name\":\"iPhoneX 256G\"," // + "\"wechatpay_goods_id\":\"1001\"," // + "\"quantity\":1," // + "\"merchant_goods_id\":\"商品编码\"," // + "\"unit_price\":828800" // + "}" // + "]," // + "\"cost_price\":608800" // + "}," // + "\"scene_info\": {" // + "\"store_info\": {" // + "\"address\":\"广东省深圳市南山区科技中一道10000号\"," // + "\"area_code\":\"440305\"," // + "\"name\":\"腾讯大厦分店\"," // + "\"id\":\"0001\"" // + "}," // + "\"device_id\":\"013467007045764\"," // + "\"payer_client_ip\":\"14.23.150.211\"" // + "}" + "}"; StringEntity reqEntity = new StringEntity( reqdata, ContentType.create("application/json", "utf-8")); httpPost.setEntity(reqEntity); httpPost.addHeader("Accept", "application/json"); // //构造签名参数 // //构造签名参数 // JSONObject jsonObject = new JSONObject();jsonObject.put("appid", WxCommon.APP_ID); // jsonObject.put("mchid", WxCommon.MCHID); // jsonObject.put("description", "充值"); // jsonObject.put("out_trade_no", tradeNo); // jsonObject.put("notify_url", WxCommon.NOTIFY_URL); // jsonObject.put("signType", "RSA"); // PayPageDto payPageDto=new PayPageDto(); // payPageDto.setTotal(100); // jsonObject.put("amount", payPageDto); // String token = SignDemo.getToken(method, httpurl,jsonObject.toJSONString() , nonceStr, timestamp); // httpPost.setHeader("Authorization", "WECHATPAY2-SHA256-RSA2048" + " " + token); // httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); //完成签名并执行请求 try (CloseableHttpResponse response = httpClient.execute(httpPost)) { if (response.getStatusLine().getStatusCode() == 200) { HttpEntity httpEntity = response.getEntity(); String content = EntityUtils.toString(httpEntity, "utf8"); System.out.println(content.length()); } } catch (IOException e) { e.printStackTrace(); } } /*** * pc端生成统一下单格式的订单,生成一个XML格式的字符串 */ public static String createOrderInfo(PayPageDto payPageDto,String tradeNo,String product_id,String time_expire,String appid,String mchid,String key) throws UnsupportedEncodingException { String nonce_str = RandomStringUtils.randomAlphanumeric(16); SortedMap<String,String> parameters = new TreeMap<>(); parameters.put("appid", appid); parameters.put("mch_id",mchid); parameters.put("body", "充值"); parameters.put("out_trade_no",tradeNo); parameters.put("notify_url",WxCommon.NOTIFY_URL); DecimalFormat df = new DecimalFormat("#"); parameters.put("total_fee", df.format(payPageDto.getTotal()*100)); parameters.put("nonce_str", nonce_str); parameters.put("trade_type","NATIVE"); parameters.put("product_id", product_id); parameters.put("spbill_create_ip","0.0.0.0"); parameters.put("time_expire",time_expire); String sign = createSign(parameters,key); parameters.put("sign", sign);//签名 //将订单对象转为xml格式 String s = null; try { return MapToXmlUtils.mapToXml(parameters);//maptoXml方法是微信sdk自带的方法 } catch (Exception e) { e.printStackTrace(); } assert false; return new String(s.getBytes(StandardCharsets.UTF_8)); } /*** * h5生成统一下单格式的订单,生成一个XML格式的字符串 */ public static String createOrderInfoH5(PayPageDto payPageDto,String tradeNo, HttpServletRequest request, String appid, String mchid, String key) { String nonce_str = RandomStringUtils.randomAlphanumeric(16); String sceneInfo="{'h5_info':{'type':'WAP','wap_url': 'https://jygkzy.com','wap_name': '充值'}}"; String spbill_create_ip = getRealIp(request); SortedMap<String,String> parameters = new TreeMap<>(); parameters.put("appid", appid); parameters.put("mch_id", mchid); parameters.put("body", "充值"); parameters.put("out_trade_no", tradeNo); parameters.put("nonce_str", nonce_str); DecimalFormat df = new DecimalFormat("#"); parameters.put("total_fee", df.format(payPageDto.getTotal()*100)); parameters.put("notify_url",WxCommon.NOTIFY_URL); parameters.put("trade_type","MWEB"); parameters.put("scene_info",sceneInfo); parameters.put("spbill_create_ip",spbill_create_ip); String sign = createSign(parameters,key); parameters.put("sign", sign);//签名 //将订单对象转为xml格式 String s = null; try { return MapToXmlUtils.mapToXml(parameters);//maptoXml方法是微信sdk自带的方法 } catch (Exception e) { e.printStackTrace(); } assert false; return new String(s.getBytes(StandardCharsets.UTF_8)); } /*** * 小程序生成统一下单格式的订单,生成一个XML格式的字符串 */ public static String createOrderInfoWx(PayPageDto payPageDto,String tradeNo,String nonce_str,String Applets_ID,String secrt_key,String mchid,String key) { Map<String, Object> infoByCode = WxUtil.getInfoByCode(payPageDto.getCode(), Applets_ID, secrt_key); SortedMap<String,String> parameters = new TreeMap<>(); parameters.put("appid", Applets_ID); parameters.put("mch_id", mchid); parameters.put("body", "充值"); parameters.put("out_trade_no", tradeNo); parameters.put("notify_url",WxCommon.NOTIFY_URL); parameters.put("nonce_str", nonce_str); DecimalFormat df = new DecimalFormat("#"); parameters.put("total_fee", df.format(payPageDto.getTotal()*100)); parameters.put("trade_type","JSAPI"); parameters.put("openid", infoByCode.get("openid").toString()); parameters.put("spbill_create_ip","0.0.0.0"); String sign = createSign(parameters,key); parameters.put("sign", sign);//签名 //将订单对象转为xml格式 String s = null; try { return MapToXmlUtils.mapToXml(parameters);//maptoXml方法是微信sdk自带的方法 } catch (Exception e) { e.printStackTrace(); } assert false; return new String(s.getBytes(StandardCharsets.UTF_8)); } /*** * 生成签名 */ public static String createSign(SortedMap<String,String> parameters,String key) { // 多线程访问的情况下需要用StringBuffer StringBuilder sb = new StringBuilder(); // 所有参与传参的key按照accsii排序(升序) Set es = parameters.keySet(); for (Object set : es) { String k = set.toString(); Object v = parameters.get(k); sb.append(k) .append("=") .append(v.toString()) .append("&"); } sb.append("key=") .append(key); return DigestUtils.md5Hex(sb.toString()).toUpperCase(); } /** * 获取真实ip地址 通过阿帕奇代理的也能获取到真实ip */ public static String getRealIp(HttpServletRequest request) { String ip = request.getHeader("x-forwarded-for"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } return ip; } /** * 设置微信二维码失效时间,并返回具体失效的时间点 */ public static String getOrderExpireTime(Long expire){ SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); Date now = new Date(); Date afterDate = new Date(now .getTime() + expire); return sdf.format(afterDate ); } }