WxPayUtil.java 13.9 KB
package cn.wisenergy.service.util;


import cn.wisenergy.common.utils.Md5Util;
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 com.fasterxml.jackson.core.JsonProcessingException;
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.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 {

 /*   @Value("${wxPay.APP_ID}")
    private static String appid;
    @Value("${wxPay.MCH_ID}")
    private static String mchid;
    @Value("${wxPay.PRIVATE_KEY}")
    private static String key;*/
    /**
     * 商户号
     */
    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)");

        //完成签名并执行请求
        CloseableHttpResponse response = httpClient.execute(httpPost);


        try {
            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();
        }finally {
            response.close();
        }
    }


    /***
     * pc端生成统一下单格式的订单,生成一个XML格式的字符串
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String createOrderInfo(PayPageDto payPageDto,String tradeNo,String product_id,String time_expire) throws UnsupportedEncodingException {
        String nonce_str = RandomStringUtils.randomAlphanumeric(16);

        SortedMap<String,String> parameters = new TreeMap<String,String>();
        parameters.put("appid", WxCommon.APP_ID);
        parameters.put("mch_id",mchId);
        parameters.put("body", "充值");
        parameters.put("out_trade_no",tradeNo);
        parameters.put("notify_url", "http://raux9u.natappfree.cc/pay/wxPayCallBack.do");
        //parameters.put("notify_url",WxCommon.NOTIFY_URL);
        DecimalFormat df = new DecimalFormat("#");
        //parameters.put("total_fee",  df.format(payPageDto.getTotal()*100));
        parameters.put("total_fee", df.format(1));
        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 characterEncoding = "UTF-8";
        String sign = createSign(characterEncoding,parameters);
        parameters.put("sign", sign);//签名
        //将订单对象转为xml格式
        String s = null;
        try {
            return MapToXmlUtils.mapToXml(parameters);//maptoXml方法是微信sdk自带的方法
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new String(s.getBytes("UTF-8"));
    }


    /***
     * h5生成统一下单格式的订单,生成一个XML格式的字符串
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String createOrderInfoH5(PayPageDto payPageDto,String tradeNo,HttpServletRequest request) throws UnsupportedEncodingException, JsonProcessingException {

        String nonce_str = RandomStringUtils.randomAlphanumeric(16);
        String sceneInfo="{'h5_info':{'type':'WAP','wap_url': 'http://111.203.232.171:8999/','wap_name': '充值'}}";
        String spbill_create_ip = getRealIp(request);

        SortedMap<String,String> parameters = new TreeMap<String,String>();
        parameters.put("appid", WxCommon.APP_ID);
        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("total_fee", df.format(1));
        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 characterEncoding = "UTF-8";
        String sign = createSign(characterEncoding,parameters);
        parameters.put("sign", sign);//签名
        //将订单对象转为xml格式
        String s = null;
        try {
            return MapToXmlUtils.mapToXml(parameters);//maptoXml方法是微信sdk自带的方法
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new String(s.getBytes("UTF-8"));
    }


    /***
     * 小程序生成统一下单格式的订单,生成一个XML格式的字符串
     * @return
     * @throws UnsupportedEncodingException
     */
    public static String createOrderInfoWx(PayPageDto payPageDto,String tradeNo,HttpServletRequest request,String nonce_str) throws UnsupportedEncodingException, JsonProcessingException {

        SortedMap<String,String> parameters = new TreeMap<String,String>();
        parameters.put("appid", WxCommon.APP_ID);
        parameters.put("mch_id", mchId);
        parameters.put("body", "充值");
        parameters.put("description","充值");
        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("total_fee", df.format(1));
        parameters.put("trade_type","JSAPI");
        String characterEncoding = "UTF-8";
        String sign = createSign(characterEncoding,parameters);
        parameters.put("sign", sign);//签名
        //将订单对象转为xml格式
        String s = null;
        try {
            return MapToXmlUtils.mapToXml(parameters);//maptoXml方法是微信sdk自带的方法
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new String(s.getBytes("UTF-8"));
    }

    /***
     * 生成签名
     * @param characterEncoding
     * @param parameters
     * @return
     */
    public static String createSign(String characterEncoding, SortedMap<String,String> parameters)  {
        StringBuilder sb = new StringBuilder();       // 多线程访问的情况下需要用StringBuffer
        Set es = parameters.keySet();                 // 所有参与传参的key按照accsii排序(升序)
        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(WxCommon.PRIVATE_KEY);
        return DigestUtils.md5Hex(sb.toString()).toUpperCase();

    }

    /**
     * 获取真实ip地址 通过阿帕奇代理的也能获取到真实ip
     * @param request
     * @return
     */
    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;
    }

    /**
     * 设置微信二维码失效时间,并返回具体失效的时间点
     * @param expire 二维码的有效时间,单位是毫秒
     * @return
     */
    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 );
    }

}