企业微信+微信接口对接(企业微信消息推送, 微信native支付)

企业微信开放平台 https://developer.work.weixin.qq.com/document/path/91201
微信开放平台 https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_1.shtml

1, 企业微信消息推送接口对接

#企业微信相关配置
#wecom:
#企业ID
corpid=ww97923728bc80d3d5
#应用的凭证密钥
corpsecret=7lrL-8JsIGA6reMQe8dN2x4z5PjTB5Ya6CHMVvWdReA
#获取access_token的URL
accessTokenUrl=https://qyapi.weixin.qq.com/cgi-bin/gettoken
#发送应用信息URL
sendMessageUrl=https://qyapi.weixin.qq.com/cgi-bin/message/send
#企业应用的id
agentid=1000005
#获取userid的URL
useridUrl=https://qyapi.weixin.qq.com/cgi-bin/user/getuserid
@Service
public class AddVisitCouponListener implements ApplicationListener<AddVisitCouponModel> {

    @Autowired
    public RedisClient redisClient;
    @Autowired
    public UserInfoDAO userInfoDAO;

    public static String accToken = "CACHE_ACCESSTOKEN";

    @Async
    @Override
    public void onApplicationEvent(AddVisitCouponModel event) {
        String corpid = RequestRule_ParamUtils.getValue("corpid");//企业ID
        String corpsecret = RequestRule_ParamUtils.getValue("corpsecret");//应用的凭证密钥
        String accessTokenUrl = RequestRule_ParamUtils.getValue("accessTokenUrl");
        String sendMessageUrl = RequestRule_ParamUtils.getValue("sendMessageUrl");
        String agentid = RequestRule_ParamUtils.getValue("agentid");
        String useridUrl = RequestRule_ParamUtils.getValue("useridUrl");
        String msg = RequestRule_ParamUtils.getValue("msg");
        WriteLog.writeLog("YNHX", "onApplicationEvent", "corpid=" + corpid + "||corpsecret=" + corpsecret + "||agentid=" + agentid);
        WriteLog.writeLog("YNHX", "onApplicationEvent", "msg=" +msg);
        //推送消息到企业微信
        String accessToken = "";
        String expires = "";//accessToken有效期

        //1, 获取access_token
//        String corpid = "企业ID";
//        String corpsecret = "应用的凭证密钥";
        /**
         入参:
         corpid	是	企业ID,获取方式参考:术语说明-corpid
         corpsecret	是	应用的凭证密钥,注意应用需要是启用状态,获取方式参考:术语说明-secret
         出参:
         {
         "errcode": 0,
         "errmsg": "ok",
         "access_token": "accesstoken000001",
         "expires_in": 7200
         }
         */
        //String getAccessToken = " https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=ID&corpsecret=SECRET";
        String getAccessToken = " https://qyapi.weixin.qq.com/cgi-bin/gettoken";
        Map<String, Object> map = new HashMap<>();
        map.put("corpid", corpid);
        map.put("corpsecret", corpsecret);
        HttpResponse execute = HttpUtil.createGet(accessTokenUrl).form(map).execute();
        Map<String, Object> respMap = JSONUtil.toBean(execute.body(), Map.class);
        if (StrUtil.equals(MapUtil.getStr(respMap, "errcode"), "0")) {
            accessToken = MapUtil.getStr(respMap, "access_token");
            expires = MapUtil.getStr(respMap, "expires_in");//access_token有效期
        } else {
            throw new BusinessException("获取access_token错误,返回信息: " + MapUtil.getStr(respMap, "errmsg"));
        }

        if (redisClient.exists(accToken)) {
            accessToken = redisClient.get(accToken);
            WriteLog.writeLog("YNHX", "onApplicationEvent", "获取缓存accessToken=" + accessToken);
        } else {
            redisClient.set(accToken, accessToken, Convert.toInt(expires));
            WriteLog.writeLog("YNHX", "onApplicationEvent", "缓存accessToken=" + accessToken);
        }

        //2, 手机号获取userid
        //2.1 根据人员信息获取手机号
        String userPhone = "";
        String userid = "";
        UserInfo byId = userInfoDAO.findById(Convert.toLong(event.getUserid()));
        userPhone = byId.getTel();
        if (StrUtil.isBlank(userPhone)) {
            WriteLog.writeLog("YNHX", "onApplicationEvent", "获取手机号失败!userid=" + event.getUserid());
            throw new BusinessException("获取手机号失败!userid=" + event.getUserid());
        }
        //2.2 根据手机号获取企业微信useid
        /**
         {
         "mobile": "15877397212"
         }
         */

/*        //String getUseridUrl = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserid?access_token=ACCESS_TOKEN";
        String getUseridUrl = useridUrl + "?access_token=" + accessToken;
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("mobile", userPhone);
        HttpResponse execute1 = HttpUtil.createPost(getUseridUrl).body(jsonObject).execute();
        Map<String, Object> getUseridUrlRespMap = JSONUtil.toBean(execute1.body(), Map.class);
        if (StrUtil.equals(MapUtil.getStr(getUseridUrlRespMap, "errcode"), "0")) {
            userid = MapUtil.getStr(getUseridUrlRespMap, "userid");
        } else {
            throw new BusinessException("根据手机号获取userid失败");
        }*/
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("mobile", userPhone);
        ResponseEntity<String> getHttpResponseEntity = getHttpResponseEntity(accessToken, useridUrl, jsonObject);
        Map<String, Object> getUseridUrlRespMap = JSONUtil.toBean(getHttpResponseEntity.getBody(), Map.class);
        if (StrUtil.equals(MapUtil.getStr(getUseridUrlRespMap, "errcode"), "0")) {
            userid = MapUtil.getStr(getUseridUrlRespMap, "userid");
            WriteLog.writeLog("YNHX", "onApplicationEvent", "获取企业微信userid成功, userid=" + userid);
        } else {
            throw new BusinessException("根据手机号获取userid失败");
        }

        //3, 发送应用消息
        //3.1 消息模板
        /** 消息示例
         {
         "touser" : "UserID1|UserID2|UserID3", //可以输入多个userid
         "toparty" : "PartyID1|PartyID2",  // 部门ID列表
         "totag" : "TagID1 | TagID2",   //标签ID列表       touser/toparty/totag 不可同时为空
         "msgtype" : "text",
         "agentid" : 1,  // 企业应用的id,整型。企业内部开发,可在应用的设置页面查看;第三方服务商,可通过接口 获取企业授权信息 获取该参数值
         "text" : {
         "content" : "你的快递已到,请携带工卡前往邮件中心领取。\n出发前可查看<a href=\"http://work.weixin.qq.com\">邮件中心视频实况</a>,聪明避开排队。"
         },
         "safe":0,
         "enable_id_trans": 0,
         "enable_duplicate_check": 0,
         "duplicate_check_interval": 1800
         }
         */
/*        JSONObject jsonObject1 = new JSONObject();// 消息模板:以下四个字段必填
        jsonObject1.put("touser", userid);
        jsonObject1.put("msgtype", "text");
        jsonObject1.put("agentid", agentid);
        jsonObject1.put("text", new JSONObject("content", "测试: 有您的访客申请。\n请前去一卡通访客券进行审批!"));


        //String postContentUrl = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=ACCESS_TOKEN";
        String postContentUrl = sendMessageUrl + "?access_token=" + accessToken;
        HttpResponse execute2 = HttpUtil.createPost(postContentUrl).body(jsonObject1).execute();
        Map<String, Object> postContentMap = JSONUtil.toBean(execute2.body(), Map.class);
        if (StrUtil.equals(MapUtil.getStr(postContentMap, "errcode"), "0")) {
//	{ "errcode": 0, "errmsg": "ok", "msgid": "fcLc6UhB2absSaoEDgOVFHFJna2x-M_EI9XtgcXRzXLEWWyDf0xSlq8pytd6r4FbJzcfTo2eWn8fVaR5ovd2WA" }
            String msgid = MapUtil.getStr(postContentMap, "msgid");
            WriteLog.writeLog("YNHX", "onApplicationEvent", "消息推送成功, 消息msgid=" + msgid);
        } else {
            throw new BusinessException("消息推送失败");
        }*/
        JSONObject sendJsonObject = new JSONObject();// 消息模板:以下四个字段必填
        sendJsonObject.put("touser", userid);
        sendJsonObject.put("msgtype", "text");
        sendJsonObject.put("agentid", agentid);
        JSONObject jsonObject2 = new JSONObject();
        WriteLog.writeLog("YNHX", "onApplicationEvent", "msg=" +StrUtil.str(msg, "UTF-8"));
        jsonObject2.put("content", "温馨提示:有您的福利劵审批代办,请打开工作台进入智慧后勤应用,点击福利券审批进行处理");//
        sendJsonObject.put("text", jsonObject2);
        ResponseEntity<String> httpResponseEntitySend = getHttpResponseEntity(accessToken, sendMessageUrl, sendJsonObject);
        Map<String, Object> postContentMap = JSONUtil.toBean(httpResponseEntitySend.getBody(), Map.class);
        if (StrUtil.equals(MapUtil.getStr(postContentMap, "errcode"), "0")) {
//	{ "errcode": 0, "errmsg": "ok", "msgid": "fcLc6UhB2absSaoEDgOVFHFJna2x-M_EI9XtgcXRzXLEWWyDf0xSlq8pytd6r4FbJzcfTo2eWn8fVaR5ovd2WA" }
            String msgid = MapUtil.getStr(postContentMap, "msgid");
            WriteLog.writeLog("YNHX", "onApplicationEvent", "消息推送成功, 消息msgid=" + msgid);
        } else {
            throw new BusinessException("消息推送失败");
        }
    }

    public ResponseEntity<String> getHttpResponseEntity(String accToken, String url, JSONObject json) {
        RestTemplate restTemplate = new RestTemplate();
        // 1.设置请求头
        HttpHeaders httpHeaders = new HttpHeaders();
        //传递请求体时必须设置传递参数的格式,为Content-Type : application/json
        httpHeaders.add("Content-Type", "application/json");

        HttpEntity<String> httpEntity = new HttpEntity(json, httpHeaders);
        // 拼接地址
        StringBuilder sb = new StringBuilder(url).append("?").append("access_token=" + accToken);

        WriteLog.writeLog("YNHX", "onApplicationEvent", "tokenUrl=" + sb);

        url = sb.toString();
        System.out.println("请求URL: " + url);
        //返回类型,如果不确定返回类型,使用String接受,用fastjson处理Json字符串

        return restTemplate.exchange(
                url,
                HttpMethod.POST,
                httpEntity,
                String.class);
    }

2, 微信native支付接口

package com.datalook.nxykd.util.http.v3;

/**
 * 微信支付常量配置
 */
public interface PayConstants {
    String NATIVE_ORDER_KEY = "native_order_key_";
    String NATIVE_ORDER_ID_KEY = "native_order_id_key_";

    String NATIVE_ORDER_URL = "https://api.mch.weixin.qq.com/v3/pay/transactions/native";//微信支付地址

    String RECONCILIATION_URL= "https://api.mch.weixin.qq.com/v3/bill/tradebill";//微信对账接口(获取下载账单接口)

    String TRANSACTIONS_URL= "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/";//根据商户订单号查询支付结果接口地址

    String MCH_ID = "1604562573";//商户号

    String APP_ID = "wxd77863786f14c269";//appid

    String MCH_SERIAL_NO = "294A37239D1AE510A1B3A4BEADA2119F6C3FBF1D";//商户证书序列号

    String NOTIFY_URL = "https://www.baidu.com/";//支付成功回调地址

    String API_V3KEY = "nxykdxzyysfc67432581234567890000";//api密钥

    String PACKAGE = "Sign=WXPay";//签名固定字符串(微信要求的)

    String PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\n"
            + "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC4zVdO+P6T1MWI\n" +
            "auRDQUi1ZqUakqub+TCsqCMe3nfhPH7B4ikHOiDNtnxZEoJNedZgga+ZrFI8hPJi\n" +
            "k8Eik/2hKbR85VvG641wtmW2PXYrAOMcPIpEWgZ4WzRd0nDWA0jouG+VWLuFAI3m\n" +
            "DhfbQIKeaBlkDLMuj/Ss19Ep0Y1+YAHTHeQyV4Tzw1zY9D+hE6oWTBQeCB4MAkgp\n" +
            "RJvxzTScQ6gO47MYQXSztuFk1j0bO+8peNKavmNgmwYN9HAoMt8hjKJicZg3LS6H\n" +
            "xUw4w3lD+tbrw5P1oJ3aJeFfQkmdhhZbdk8B8OizFG20en/qVaR45bapeEM6zB/Y\n" +
            "mMdATIaLAgMBAAECggEBAK3zk6BhnniWyo07WLu54u/lu7nEn8aEjH2pEs4GyL76\n" +
            "C7MC6G3GGISqpmfNlVvKOLHEwP8dBpey6NlDjYO33ADs2djKqFYY+Z1EA3/EYMvf\n" +
            "3OeCUQA/4WE/MI6z/MRmeSWeHmJtEK4ENI19bJVUJt9my6eykKNenAhqaZc8ijyO\n" +
            "FZgyWDU6m+iRMP3slX49DwxEm8boII9oCR9IjM4VrciYtgbaEhPcjUOeXwlkSJ4n\n" +
            "/xqG6DWa79hXrSSRHtPmttaZSpkK0hvts1DWNx443yA6hx1xXhSkTpK4EkkuiofV\n" +
            "u1XyygpfGEz9tV3yOokVx6w0eoRMSKVGWeW0MCNMepkCgYEA7LJObPScsvDKpkg9\n" +
            "SHNJjAmRo1AKObllAgQwKIa9EQMn6VluwaVQ4quEiyVRzvVmc2QZ08kdpLThj+cj\n" +
            "3CuNURw7SAWDaFbArCGXlxJx035Rpm/K42jWPlRuscq+1GszT8RdMUQr329w9Ajx\n" +
            "cUh6G2ywmKaTjh4LpqTTE+23VZUCgYEAx9+YhjYepPbagys/n1oqa/Y2bwwQyuHF\n" +
            "+kjHOug3YFz4ixlVv8E8iGuWRmWMoV0HTBQo+Ufk0jpWAzZWl3XR7RA+aYmhf0fo\n" +
            "0BtiNSES1YDVPAVd5NvX8TcQobVNW3/Ih/hoSorZuGuwUDw5xbW2mTpeqZrWNlg1\n" +
            "/Pa+hqsPI58CgYEAuwhiZEIeGF+hIifvFPLUaO2ewVeb3OUcZa19iGh/uZOu0/sx\n" +
            "Q58n/RTfFTyWGl1baU7uAaXn4KB1pEpW0cEwV6lhRpXksmvqr5mTuXJ/s0kbp9Kq\n" +
            "lWvf7zy0g5Tbmepjj2Jw6V8e892ReaQfdQ56PnVyTg1Ch4hCWJnhmNu8hMkCgYAc\n" +
            "rVUZ9IvjCVQCu+LN/0bU5KecuTNzmH8qUOTc69J+LfivJHxsHdKMlDskcI+D23Af\n" +
            "l0jls03+Z8ZNga9c3de31rvNsqSMOYoKydMGYm9sWKa/jNmS64QJJOhq+zNVLHle\n" +
            "IOL9xvxD/Jd4e5uiZVcElx5b4U5Yz8E3QUPG2KY8awKBgQC/G2kmcVkUo7iaKvTC\n" +
            "Q7FwdkCp5xUYpxoqrvYs/fT/OEK5rU9MLdshD9jyEMjZgoZC+Soe2LnuNpkTMXlY\n" +
            "YxXoqADUaFW2orbKJRLDSmSyFOl8O6STKUYviQeqzwhYBHmxVEmilnGecQt+Pqpz\n" +
            "qtlvGvHcRHSdXQo7kDdInDZuMg=="
            + "-----END PRIVATE KEY-----\n";//商户私钥

    String FAIL = "FAIL";

    String SUCCESS= "SUCCESS";

    String ALL= "ALL";
}

2.1, 微信native下单接口

package com.datalook.nxykd.test;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONObject;
import com.datalook.nxykd.util.http.v3.PayConstants;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.Header;
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.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.spec.PKCS8EncodedKeySpec;

/**
 * 微信POST请求测试类
 */
public class Test{
    //商户私钥(拷贝apiclient_key.pem文件里-----BEGIN PRIVATE KEY-----和-----END PRIVATE KEY-----之间的内容)
    public static String rsaPrivateKey ="MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC4zVdO+P6T1MWI\n" +
            "auRDQUi1ZqUakqub+TCsqCMe3nfhPH7B4ikHOiDNtnxZEoJNedZgga+ZrFI8hPJi\n" +
            "k8Eik/2hKbR85VvG641wtmW2PXYrAOMcPIpEWgZ4WzRd0nDWA0jouG+VWLuFAI3m\n" +
            "DhfbQIKeaBlkDLMuj/Ss19Ep0Y1+YAHTHeQyV4Tzw1zY9D+hE6oWTBQeCB4MAkgp\n" +
            "RJvxzTScQ6gO47MYQXSztuFk1j0bO+8peNKavmNgmwYN9HAoMt8hjKJicZg3LS6H\n" +
            "xUw4w3lD+tbrw5P1oJ3aJeFfQkmdhhZbdk8B8OizFG20en/qVaR45bapeEM6zB/Y\n" +
            "mMdATIaLAgMBAAECggEBAK3zk6BhnniWyo07WLu54u/lu7nEn8aEjH2pEs4GyL76\n" +
            "C7MC6G3GGISqpmfNlVvKOLHEwP8dBpey6NlDjYO33ADs2djKqFYY+Z1EA3/EYMvf\n" +
            "3OeCUQA/4WE/MI6z/MRmeSWeHmJtEK4ENI19bJVUJt9my6eykKNenAhqaZc8ijyO\n" +
            "FZgyWDU6m+iRMP3slX49DwxEm8boII9oCR9IjM4VrciYtgbaEhPcjUOeXwlkSJ4n\n" +
            "/xqG6DWa79hXrSSRHtPmttaZSpkK0hvts1DWNx443yA6hx1xXhSkTpK4EkkuiofV\n" +
            "u1XyygpfGEz9tV3yOokVx6w0eoRMSKVGWeW0MCNMepkCgYEA7LJObPScsvDKpkg9\n" +
            "SHNJjAmRo1AKObllAgQwKIa9EQMn6VluwaVQ4quEiyVRzvVmc2QZ08kdpLThj+cj\n" +
            "3CuNURw7SAWDaFbArCGXlxJx035Rpm/K42jWPlRuscq+1GszT8RdMUQr329w9Ajx\n" +
            "cUh6G2ywmKaTjh4LpqTTE+23VZUCgYEAx9+YhjYepPbagys/n1oqa/Y2bwwQyuHF\n" +
            "+kjHOug3YFz4ixlVv8E8iGuWRmWMoV0HTBQo+Ufk0jpWAzZWl3XR7RA+aYmhf0fo\n" +
            "0BtiNSES1YDVPAVd5NvX8TcQobVNW3/Ih/hoSorZuGuwUDw5xbW2mTpeqZrWNlg1\n" +
            "/Pa+hqsPI58CgYEAuwhiZEIeGF+hIifvFPLUaO2ewVeb3OUcZa19iGh/uZOu0/sx\n" +
            "Q58n/RTfFTyWGl1baU7uAaXn4KB1pEpW0cEwV6lhRpXksmvqr5mTuXJ/s0kbp9Kq\n" +
            "lWvf7zy0g5Tbmepjj2Jw6V8e892ReaQfdQ56PnVyTg1Ch4hCWJnhmNu8hMkCgYAc\n" +
            "rVUZ9IvjCVQCu+LN/0bU5KecuTNzmH8qUOTc69J+LfivJHxsHdKMlDskcI+D23Af\n" +
            "l0jls03+Z8ZNga9c3de31rvNsqSMOYoKydMGYm9sWKa/jNmS64QJJOhq+zNVLHle\n" +
            "IOL9xvxD/Jd4e5uiZVcElx5b4U5Yz8E3QUPG2KY8awKBgQC/G2kmcVkUo7iaKvTC\n" +
            "Q7FwdkCp5xUYpxoqrvYs/fT/OEK5rU9MLdshD9jyEMjZgoZC+Soe2LnuNpkTMXlY\n" +
            "YxXoqADUaFW2orbKJRLDSmSyFOl8O6STKUYviQeqzwhYBHmxVEmilnGecQt+Pqpz\n" +
            "qtlvGvHcRHSdXQo7kDdInDZuMg==";
    public static void main(String[] args) throws Exception{

            //2, 微信native下单接口
            String url = PayConstants.NATIVE_ORDER_URL;//微信下单接口
            //时间戳
            String timestamp = Long.toString(System.currentTimeMillis() / 1000);
            //随机数
            String nonce_str = RandomUtil.randomString(32);

            //2, 微信下单
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("mchid", PayConstants.MCH_ID);
            jsonObject.put("appid", PayConstants.APP_ID);
            jsonObject.put("notify_url", PayConstants.NOTIFY_URL);
            jsonObject.put("description", "测试商户:一卡通充值");
            jsonObject.put("out_trade_no", "ykt-"+timestamp);//随机订单号
            JSONObject json = new JSONObject();
            json.put("total", 1);//订单金额, 单位:分
            json.put("currency", "CNY");//币种, 境内商户默认都是人民币
            jsonObject.put("amount", json);//随机订单号

            //拼签名串
            StringBuffer sb =new StringBuffer();
            sb.append("POST").append("\n");
            sb.append("/v3/pay/transactions/native").append("\n");
            sb.append(timestamp).append("\n");
            sb.append(nonce_str).append("\n");
            sb.append(jsonObject).append("\n");
            System.out.println("签名原串:"+sb.toString());

            //计算签名
            String sign =new String(Base64.encodeBase64(signRSA(sb.toString(),rsaPrivateKey)));
            System.out.println("签名sign值:"+sign);

            //拼装http头的Authorization内容
            String authorization ="WECHATPAY2-SHA256-RSA2048 mchid=\""+PayConstants.MCH_ID+"\",nonce_str=\""+nonce_str+"\",signature=\""+sign+"\",timestamp=\""+timestamp+"\",serial_no=\""+PayConstants.MCH_SERIAL_NO+"\"";
            System.out.println("authorization值:"+authorization);


            CloseableHttpClient httpclient = HttpClients.createDefault();
            HttpPost httpPost =new HttpPost(url);

            //设置头部
            httpPost.addHeader("Accept","application/json");
            httpPost.addHeader("Content-Type","application/json ");
            httpPost.addHeader("Authorization", authorization);

            HttpEntity Entity = new StringEntity(jsonObject.toString(), ContentType.APPLICATION_JSON);
            httpPost.setEntity(Entity);
            //获取返回内容
            CloseableHttpResponse response = httpclient.execute(httpPost);
            HttpEntity httpEntity = response.getEntity();
            String rescontent =new String(InputStreamTOByte(httpEntity.getContent()));
            System.out.println("返回内容:" + rescontent);
//        //获取返回的http header
//        Header[] headers = response.getAllHeaders();
//        int i =0;
//        while (i < headers.length) {
//            System.out.println(headers[i].getName() +":  " + headers[i].getValue());
//            i++;
//        }
//
//        //验证微信支付返回签名
//        String Wtimestamp = response.getHeaders("Wechatpay-Timestamp")[0].getValue();
//        String Wnonce = response.getHeaders("Wechatpay-Nonce")[0].getValue();
//        String Wsign = response.getHeaders("Wechatpay-Signature")[0].getValue();
//        String serial = response.getHeaders("Wechatpay-Serial")[0].getValue();
//        //拼装待签名串
//        StringBuffer ss =new StringBuffer();
//        ss.append(Wtimestamp).append("\n");
//        ss.append(Wnonce).append("\n");
//        ss.append(rescontent).append("\n");
//
//        //java.security.Signature.getInstance()
//        //验证签名
//        if(verifyRSA(ss.toString(), Base64.decodeBase64(Wsign.getBytes()), rsaPublicKeyFile)) {
//            System.out.println("签名验证成功");
//        }else {
//            System.out.println("签名验证失败");
//        }
//
//        EntityUtils.consume(httpEntity);
//        response.close();



/*        try {
            //商户号
            String mchid ="1604562573";

            String appid ="wxd77863786f14c269";
            //证书序列号
            String serial_no ="294A37239D1AE510A1B3A4BEADA2119F6C3FBF1D";//2023/07/26至2028/07/24
            //商户私钥(拷贝apiclient_key.pem文件里-----BEGIN PRIVATE KEY-----和-----END PRIVATE KEY-----之间的内容)
            //String rsaPrivateKey ="";
            //微信支付平台公钥
            String rsaPublicKeyFile = "D:\\n8_dingzhi\\n8-0303-sp3\\00-new\\n8-escp\\escp-manage\\src\\main\\resources\\apiclient_cert.p12";
            //时间戳
            String timestamp = Long.toString(System.currentTimeMillis()/1000);
            //随机数
            String nonce_str = RandomUtil.randomString(32);

*//*            //图片文件
            String filePath ="";//文件路径
            File file =new File(filePath);
            String filename = file.getName();//文件名
            String fileSha256 = DigestUtils.sha256Hex(new FileInputStream(file));//文件sha256*//*
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("mchid", mchid);
            jsonObject.put("appid", appid);
            jsonObject.put("notify_url","https://www.baidu.com/");
            jsonObject.put("description", "商品描述:一卡通微信充值");
            jsonObject.put("out_trade_no", "YKT"+System.currentTimeMillis()+"");//随机订单号
            JSONObject json = new JSONObject();
            json.put("total", 1);
            json.put("currency", "CNY");//币种, 境内商户默认都是人民币
            jsonObject.put("amount", json);//随机订单号

            //拼签名串
            StringBuffer sb =new StringBuffer();
            sb.append("POST").append("\n");
            sb.append("/v3/pay/transactions/native").append("\n");
            sb.append(timestamp).append("\n");
            sb.append(nonce_str).append("\n");
//            sb.append("{\"filename\":\""+filename+"\",\"sha256\":\""+fileSha256+"\"}").append("\n");//接口入参
            sb.append(jsonObject).append("\n");
            System.out.println("签名原串:"+sb.toString());

            //计算签名
            String sign =new String(Base64.encodeBase64(signRSA(sb.toString(),rsaPrivateKey)));
            System.out.println("签名sign值:"+sign);

            //拼装http头的Authorization内容
            String authorization ="WECHATPAY2-SHA256-RSA2048 mchid=\""+mchid+"\",nonce_str=\""+nonce_str+"\",signature=\""+sign+"\",timestamp=\""+timestamp+"\",serial_no=\""+serial_no+"\"";
            System.out.println("authorization值:"+authorization);

            //接口URL
            String url ="https://api.mch.weixin.qq.com/v3/pay/transactions/native";
            CloseableHttpClient httpclient = HttpClients.createDefault();
            HttpPost httpPost =new HttpPost(url);

            //设置头部
            httpPost.addHeader("Accept","application/json");
            httpPost.addHeader("Content-Type","application/json ");
            httpPost.addHeader("Authorization", authorization);

//            //创建MultipartEntityBuilder
//            MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create().setMode(HttpMultipartMode.RFC6532);
//            //设置boundary
//            multipartEntityBuilder.setBoundary("");
//            multipartEntityBuilder.setCharset(Charset.forName("UTF-8"));
//            //设置meta内容
//            //multipartEntityBuilder.addTextBody("meta","{\"filename\":\""+filename+"\",\"sha256\":\""+fileSha256+"\"}", ContentType.APPLICATION_JSON);
//            multipartEntityBuilder.addTextBody("meta","", ContentType.APPLICATION_JSON);
//            //设置图片内容
//            multipartEntityBuilder.addBinaryBody("file", file, ContentType.create("image/jpg"), filename);
//            //放入内容
//            httpPost.setEntity(multipartEntityBuilder.build());

            HttpEntity Entity = new StringEntity(jsonObject.toString(), ContentType.APPLICATION_JSON);
            httpPost.setEntity(Entity);

            //获取返回内容
            CloseableHttpResponse response = httpclient.execute(httpPost);
            HttpEntity httpEntity = response.getEntity();
            String rescontent =new String(InputStreamTOByte(httpEntity.getContent()));
            System.out.println("返回内容:" + rescontent);
//            //获取返回的http header
//            Header[] headers = response.getAllHeaders();
//            int i =0;
//            while (i < headers.length) {
//                System.out.println(headers[i].getName() +":  " + headers[i].getValue());
//                i++;
//            }
//
//            //验证微信支付返回签名
//            String Wtimestamp = response.getHeaders("Wechatpay-Timestamp")[0].getValue();
//            String Wnonce = response.getHeaders("Wechatpay-Nonce")[0].getValue();
//            String Wsign = response.getHeaders("Wechatpay-Signature")[0].getValue();
//            String serial = response.getHeaders("Wechatpay-Serial")[0].getValue();
//            //拼装待签名串
//            StringBuffer ss =new StringBuffer();
//            ss.append(Wtimestamp).append("\n");
//            ss.append(Wnonce).append("\n");
//            ss.append(rescontent).append("\n");
//
//            //java.security.Signature.getInstance()
//            //验证签名
//            if(verifyRSA(ss.toString(), Base64.decodeBase64(Wsign.getBytes()), rsaPublicKeyFile)) {
//                System.out.println("签名验证成功");
//            }else {
//                System.out.println("签名验证失败");
//            }
//
//            EntityUtils.consume(httpEntity);
            response.close();

        }catch (Exception e) {
            System.out.println("发送POST请求异常!" + e);
            e.printStackTrace();
        }*/

    }

    public static byte[] InputStreamTOByte(InputStream in)throws IOException {

        int BUFFER_SIZE =4096;
        ByteArrayOutputStream outStream =new ByteArrayOutputStream();
        byte[] data =new byte[BUFFER_SIZE];
        int count = -1;

        while((count = in.read(data,0,BUFFER_SIZE)) != -1)
            outStream.write(data,0, count);

        data =null;
        byte[] outByte = outStream.toByteArray();
        outStream.close();

        return outByte;
    }


    public static byte[] signRSA(String data, String priKey) throws Exception {
        //签名的类型
        Signature sign = Signature.getInstance("SHA256withRSA");

        //读取商户私钥,该方法传入商户私钥证书的内容即可

        byte[] keyBytes = Base64.decodeBase64(priKey);

        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

        sign.initSign(privateKey);

        sign.update(data.getBytes("UTF-8"));

        return sign.sign();

    }


    public static boolean verifyRSA(String data, byte[] sign, String pubKey) throws Exception{

        if(data == null || sign == null || pubKey == null){

            return false;

        }


        try {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");

            FileInputStream in = new FileInputStream(pubKey);

            Certificate c = cf.generateCertificate(in);

            in.close();

            PublicKey publicKey = c.getPublicKey();

            Signature signature = Signature.getInstance("SHA256WithRSA");

            signature.initVerify(publicKey);

            signature.update(data.getBytes("UTF-8"));

            return signature.verify(sign);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }
}

2.2, 微信支付结果查询接口

package com.datalook.nxykd.test;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.RandomUtil;
import com.datalook.nxykd.util.http.v3.PayConstants;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.junit.After;
import org.junit.Before;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信支付结果查询接口
 */
public class FindPayStatusByOuttradenoTest {
    private static CloseableHttpClient httpClient = HttpClients.createDefault();
    private static AutoUpdateCertificatesVerifier verifier;
    public static String rsaPrivateKey ="MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC4zVdO+P6T1MWI\n" +
            "auRDQUi1ZqUakqub+TCsqCMe3nfhPH7B4ikHOiDNtnxZEoJNedZgga+ZrFI8hPJi\n" +
            "k8Eik/2hKbR85VvG641wtmW2PXYrAOMcPIpEWgZ4WzRd0nDWA0jouG+VWLuFAI3m\n" +
            "DhfbQIKeaBlkDLMuj/Ss19Ep0Y1+YAHTHeQyV4Tzw1zY9D+hE6oWTBQeCB4MAkgp\n" +
            "RJvxzTScQ6gO47MYQXSztuFk1j0bO+8peNKavmNgmwYN9HAoMt8hjKJicZg3LS6H\n" +
            "xUw4w3lD+tbrw5P1oJ3aJeFfQkmdhhZbdk8B8OizFG20en/qVaR45bapeEM6zB/Y\n" +
            "mMdATIaLAgMBAAECggEBAK3zk6BhnniWyo07WLu54u/lu7nEn8aEjH2pEs4GyL76\n" +
            "C7MC6G3GGISqpmfNlVvKOLHEwP8dBpey6NlDjYO33ADs2djKqFYY+Z1EA3/EYMvf\n" +
            "3OeCUQA/4WE/MI6z/MRmeSWeHmJtEK4ENI19bJVUJt9my6eykKNenAhqaZc8ijyO\n" +
            "FZgyWDU6m+iRMP3slX49DwxEm8boII9oCR9IjM4VrciYtgbaEhPcjUOeXwlkSJ4n\n" +
            "/xqG6DWa79hXrSSRHtPmttaZSpkK0hvts1DWNx443yA6hx1xXhSkTpK4EkkuiofV\n" +
            "u1XyygpfGEz9tV3yOokVx6w0eoRMSKVGWeW0MCNMepkCgYEA7LJObPScsvDKpkg9\n" +
            "SHNJjAmRo1AKObllAgQwKIa9EQMn6VluwaVQ4quEiyVRzvVmc2QZ08kdpLThj+cj\n" +
            "3CuNURw7SAWDaFbArCGXlxJx035Rpm/K42jWPlRuscq+1GszT8RdMUQr329w9Ajx\n" +
            "cUh6G2ywmKaTjh4LpqTTE+23VZUCgYEAx9+YhjYepPbagys/n1oqa/Y2bwwQyuHF\n" +
            "+kjHOug3YFz4ixlVv8E8iGuWRmWMoV0HTBQo+Ufk0jpWAzZWl3XR7RA+aYmhf0fo\n" +
            "0BtiNSES1YDVPAVd5NvX8TcQobVNW3/Ih/hoSorZuGuwUDw5xbW2mTpeqZrWNlg1\n" +
            "/Pa+hqsPI58CgYEAuwhiZEIeGF+hIifvFPLUaO2ewVeb3OUcZa19iGh/uZOu0/sx\n" +
            "Q58n/RTfFTyWGl1baU7uAaXn4KB1pEpW0cEwV6lhRpXksmvqr5mTuXJ/s0kbp9Kq\n" +
            "lWvf7zy0g5Tbmepjj2Jw6V8e892ReaQfdQ56PnVyTg1Ch4hCWJnhmNu8hMkCgYAc\n" +
            "rVUZ9IvjCVQCu+LN/0bU5KecuTNzmH8qUOTc69J+LfivJHxsHdKMlDskcI+D23Af\n" +
            "l0jls03+Z8ZNga9c3de31rvNsqSMOYoKydMGYm9sWKa/jNmS64QJJOhq+zNVLHle\n" +
            "IOL9xvxD/Jd4e5uiZVcElx5b4U5Yz8E3QUPG2KY8awKBgQC/G2kmcVkUo7iaKvTC\n" +
            "Q7FwdkCp5xUYpxoqrvYs/fT/OEK5rU9MLdshD9jyEMjZgoZC+Soe2LnuNpkTMXlY\n" +
            "YxXoqADUaFW2orbKJRLDSmSyFOl8O6STKUYviQeqzwhYBHmxVEmilnGecQt+Pqpz\n" +
            "qtlvGvHcRHSdXQo7kDdInDZuMg==";

    @Before
    public void setup() {
        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(PayConstants.PRIVATE_KEY);

        //使用自动更新的签名验证器,不需要传入证书
        verifier = new AutoUpdateCertificatesVerifier(
                new WechatPay2Credentials(PayConstants.MCH_ID, new PrivateKeySigner(PayConstants.MCH_SERIAL_NO, merchantPrivateKey)),
                PayConstants.API_V3KEY.getBytes(StandardCharsets.UTF_8));

        httpClient = WechatPayHttpClientBuilder.create()
                .withMerchant(PayConstants.MCH_ID, PayConstants.MCH_SERIAL_NO, merchantPrivateKey)
                .withValidator(new WechatPay2Validator(verifier))
                .build();
    }

    @After
    public void after() throws IOException {
        httpClient.close();
    }
    public static void main(String[] args) throws Exception{

        String reconciliationUrl = PayConstants.TRANSACTIONS_URL;//查询订单接口

        String out_trade_no = "YKT-967wcp1691147868";

        String url = "?mchid=" + PayConstants.MCH_ID;
        reconciliationUrl = reconciliationUrl + out_trade_no + url;
        System.out.println(reconciliationUrl);

        //拼签名串
        Map<String, Object> str = getsign("GET", "/v3/pay/transactions/out-trade-no/"+ out_trade_no + url, "");
        System.out.println("签名原串:" + str.get("signStr"));
        System.out.println("签名sign值:" + str.get("sign"));
        System.out.println("authorization值:" + str.get("authorization"));


        HttpGet httpGet = new HttpGet(reconciliationUrl);
        //设置头部
        httpGet.addHeader("Accept", "application/json");
        httpGet.addHeader("Content-Type", "application/json");
        httpGet.addHeader("Authorization", Convert.toStr(str.get("authorization")));

        CloseableHttpResponse response = httpClient.execute(httpGet);

        HttpEntity httpEntity = response.getEntity();
        String rescontent = new String(InputStreamTOByte(httpEntity.getContent()));
        System.out.println("返回内容:" + rescontent);
        //返回内容:{"amount":{"payer_currency":"CNY","total":1},"appid":"wxd77863786f14c269","mchid":"1604562573","out_trade_no":"YKT-967wcp1691147868","promotion_detail":[],"scene_info":{"device_id":""},"trade_state":"NOTPAY","trade_state_desc":"订单未支付"}
    }

    /**
     * 获取签名串
     *
     * @param type      GET/POST
     * @param url       接口地址:GET请求要带query参数(/v3/bill/tradebill?bill_date=2023-07-31&bill_type=ALL),POST参数只接口参数(/v3/pay/transactions/native)
     *        timestamp 时间戳(System.currentTimeMillis() / 1000)
     *        nonce_str 32位随机字符串
     * @param bodystr   接口入参:GET请求的这个参数为空, POST请求的这个字段为接口入参
     * @return
     */
    public static Map getsign(String type, String url, String bodystr) throws Exception {
        Map<String, Object> map = new HashMap<>();
        //时间戳
        String timestamp = Long.toString(System.currentTimeMillis() / 1000);
        //随机数
        String nonce_str = RandomUtil.randomString(32);

        //拼签名串
        StringBuffer sb = new StringBuffer();
        sb.append(type).append("\n");
        sb.append(url).append("\n");
        sb.append(timestamp).append("\n");
        sb.append(nonce_str).append("\n");
        sb.append(bodystr).append("\n");
        System.out.println("签名原串:" + sb.toString());

        String sign = new String(Base64.encodeBase64(signRSA(sb.toString(), rsaPrivateKey)));

        String authorization = "WECHATPAY2-SHA256-RSA2048 mchid=\"" + PayConstants.MCH_ID + "\",nonce_str=\"" + nonce_str + "\",signature=\"" + sign + "\",timestamp=\"" + timestamp + "\",serial_no=\"" + PayConstants.MCH_SERIAL_NO + "\"";
        map.put("signStr", sb);
        map.put("sign", sign);
        map.put("authorization", authorization);
        return map;
    }


    public static byte[] InputStreamTOByte(InputStream in) throws IOException {

        int BUFFER_SIZE = 4096;
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] data = new byte[BUFFER_SIZE];
        int count = -1;

        while ((count = in.read(data, 0, BUFFER_SIZE)) != -1)
            outStream.write(data, 0, count);

        data = null;
        byte[] outByte = outStream.toByteArray();
        outStream.close();

        return outByte;
    }


    public static byte[] signRSA(String data, String priKey) throws Exception {
        //签名的类型
        Signature sign = Signature.getInstance("SHA256withRSA");

        //读取商户私钥,该方法传入商户私钥证书的内容即可

        byte[] keyBytes = Base64.decodeBase64(priKey);

        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

        sign.initSign(privateKey);

        sign.update(data.getBytes("UTF-8"));

        return sign.sign();

    }


    public static boolean verifyRSA(String data, byte[] sign, String pubKey) throws Exception {

        if (data == null || sign == null || pubKey == null) {

            return false;

        }


        try {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");

            FileInputStream in = new FileInputStream(pubKey);

            Certificate c = cf.generateCertificate(in);

            in.close();

            PublicKey publicKey = c.getPublicKey();

            Signature signature = Signature.getInstance("SHA256WithRSA");

            signature.initVerify(publicKey);

            signature.update(data.getBytes("UTF-8"));

            return signature.verify(sign);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

}

2.3, 微信支付对账接口

package com.datalook.nxykd.test;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.datalook.event.IEventManager;
import com.datalook.event.model.handle.BilldownloadModel;
import com.datalook.nxykd.model.BilldownloadData;
import com.datalook.nxykd.util.http.v3.PayConstants;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.junit.After;
import org.junit.Before;

import javax.annotation.Resource;
import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;



/**
 * api3接口 微信对账     微信GET请求测试类
 */
public class ReconciliationTest {
    private static CloseableHttpClient httpClient = HttpClients.createDefault();
    private static AutoUpdateCertificatesVerifier verifier;
    public static String rsaPrivateKey ="MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC4zVdO+P6T1MWI\n" +
            "auRDQUi1ZqUakqub+TCsqCMe3nfhPH7B4ikHOiDNtnxZEoJNedZgga+ZrFI8hPJi\n" +
            "k8Eik/2hKbR85VvG641wtmW2PXYrAOMcPIpEWgZ4WzRd0nDWA0jouG+VWLuFAI3m\n" +
            "DhfbQIKeaBlkDLMuj/Ss19Ep0Y1+YAHTHeQyV4Tzw1zY9D+hE6oWTBQeCB4MAkgp\n" +
            "RJvxzTScQ6gO47MYQXSztuFk1j0bO+8peNKavmNgmwYN9HAoMt8hjKJicZg3LS6H\n" +
            "xUw4w3lD+tbrw5P1oJ3aJeFfQkmdhhZbdk8B8OizFG20en/qVaR45bapeEM6zB/Y\n" +
            "mMdATIaLAgMBAAECggEBAK3zk6BhnniWyo07WLu54u/lu7nEn8aEjH2pEs4GyL76\n" +
            "C7MC6G3GGISqpmfNlVvKOLHEwP8dBpey6NlDjYO33ADs2djKqFYY+Z1EA3/EYMvf\n" +
            "3OeCUQA/4WE/MI6z/MRmeSWeHmJtEK4ENI19bJVUJt9my6eykKNenAhqaZc8ijyO\n" +
            "FZgyWDU6m+iRMP3slX49DwxEm8boII9oCR9IjM4VrciYtgbaEhPcjUOeXwlkSJ4n\n" +
            "/xqG6DWa79hXrSSRHtPmttaZSpkK0hvts1DWNx443yA6hx1xXhSkTpK4EkkuiofV\n" +
            "u1XyygpfGEz9tV3yOokVx6w0eoRMSKVGWeW0MCNMepkCgYEA7LJObPScsvDKpkg9\n" +
            "SHNJjAmRo1AKObllAgQwKIa9EQMn6VluwaVQ4quEiyVRzvVmc2QZ08kdpLThj+cj\n" +
            "3CuNURw7SAWDaFbArCGXlxJx035Rpm/K42jWPlRuscq+1GszT8RdMUQr329w9Ajx\n" +
            "cUh6G2ywmKaTjh4LpqTTE+23VZUCgYEAx9+YhjYepPbagys/n1oqa/Y2bwwQyuHF\n" +
            "+kjHOug3YFz4ixlVv8E8iGuWRmWMoV0HTBQo+Ufk0jpWAzZWl3XR7RA+aYmhf0fo\n" +
            "0BtiNSES1YDVPAVd5NvX8TcQobVNW3/Ih/hoSorZuGuwUDw5xbW2mTpeqZrWNlg1\n" +
            "/Pa+hqsPI58CgYEAuwhiZEIeGF+hIifvFPLUaO2ewVeb3OUcZa19iGh/uZOu0/sx\n" +
            "Q58n/RTfFTyWGl1baU7uAaXn4KB1pEpW0cEwV6lhRpXksmvqr5mTuXJ/s0kbp9Kq\n" +
            "lWvf7zy0g5Tbmepjj2Jw6V8e892ReaQfdQ56PnVyTg1Ch4hCWJnhmNu8hMkCgYAc\n" +
            "rVUZ9IvjCVQCu+LN/0bU5KecuTNzmH8qUOTc69J+LfivJHxsHdKMlDskcI+D23Af\n" +
            "l0jls03+Z8ZNga9c3de31rvNsqSMOYoKydMGYm9sWKa/jNmS64QJJOhq+zNVLHle\n" +
            "IOL9xvxD/Jd4e5uiZVcElx5b4U5Yz8E3QUPG2KY8awKBgQC/G2kmcVkUo7iaKvTC\n" +
            "Q7FwdkCp5xUYpxoqrvYs/fT/OEK5rU9MLdshD9jyEMjZgoZC+Soe2LnuNpkTMXlY\n" +
            "YxXoqADUaFW2orbKJRLDSmSyFOl8O6STKUYviQeqzwhYBHmxVEmilnGecQt+Pqpz\n" +
            "qtlvGvHcRHSdXQo7kDdInDZuMg==";

//    @Resource
//    private IEventManager eventManager;

    @Before
    public void setup() {
        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(PayConstants.PRIVATE_KEY);

        //使用自动更新的签名验证器,不需要传入证书
        verifier = new AutoUpdateCertificatesVerifier(
                new WechatPay2Credentials(PayConstants.MCH_ID, new PrivateKeySigner(PayConstants.MCH_SERIAL_NO, merchantPrivateKey)),
                PayConstants.API_V3KEY.getBytes(StandardCharsets.UTF_8));

        httpClient = WechatPayHttpClientBuilder.create()
                .withMerchant(PayConstants.MCH_ID, PayConstants.MCH_SERIAL_NO, merchantPrivateKey)
                .withValidator(new WechatPay2Validator(verifier))
                .build();
    }

    @After
    public void after() throws IOException {
        httpClient.close();
    }

    public static void main(String[] args) throws Exception {
        String reconciliationUrl = PayConstants.RECONCILIATION_URL;//微信对账接口(获取下载账单接口)
/*        //时间戳
        String timestamp = Long.toString(System.currentTimeMillis() / 1000);
        //随机数
        String nonce_str = RandomUtil.randomString(32);*/

        String yesterday = DateUtil.format(DateUtil.yesterday(), "yyyy-MM-dd");//获取前一天的账单日期


        //reconciliationUrl += "?bill_date=" + yesterday + "&bill_type=" + PayConstants.ALL;
        String url = "?bill_date=" + yesterday + "&bill_type=" + PayConstants.SUCCESS;
        reconciliationUrl += url;
        System.out.println(reconciliationUrl);

        //拼签名串
/*        StringBuffer sb = new StringBuffer();
        sb.append("GET").append("\n");
        sb.append("/v3/bill/tradebill?bill_date=2023-07-31&bill_type=ALL").append("\n");
        sb.append(timestamp).append("\n");
        sb.append(nonce_str).append("\n");
        sb.append("").append("\n");
        System.out.println("签名原串:" + sb.toString());*/
        Map<String, Object> str = getsign("GET", "/v3/bill/tradebill"+ url, "");
        System.out.println("签名原串:" + str.get("signStr"));

        //计算签名
        //String sign = new String(Base64.encodeBase64(signRSA(Convert.toStr(str.get("sign")), rsaPrivateKey)));
        System.out.println("签名sign值:" + str.get("sign"));

        //拼装http头的Authorization内容
        //String authorization = "WECHATPAY2-SHA256-RSA2048 mchid=\"" + PayConstants.MCH_ID + "\",nonce_str=\"" + nonce_str + "\",signature=\"" + sign + "\",timestamp=\"" + timestamp + "\",serial_no=\"" + PayConstants.MCH_SERIAL_NO + "\"";
        System.out.println("authorization值:" + str.get("authorization"));


        //CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(reconciliationUrl);

        //设置头部
        httpGet.addHeader("Accept", "application/json");
        httpGet.addHeader("Content-Type", "application/json");
        httpGet.addHeader("Authorization", Convert.toStr(str.get("authorization")));

        //HttpEntity Entity = new StringEntity(jsonObject.toString(), ContentType.APPLICATION_JSON);

//        HttpParams httpParams = new BasicHttpParams();
//        httpParams.setParameter("bill_date", yesterday);
//        httpParams.setParameter("bill_type", PayConstants.SUCCESS);
//
//        httpGet.setParams(httpParams);
        CloseableHttpResponse response = httpClient.execute(httpGet);
        //获取返回内容
        //CloseableHttpResponse response = httpClient.execute(httpGet);
        HttpEntity httpEntity = response.getEntity();
        String rescontent = new String(InputStreamTOByte(httpEntity.getContent()));
        System.out.println("返回内容:" + rescontent);


        /**
         * //获取下载账单地址
         * {
         * 	"download_url": "https://api.mch.weixin.qq.com/v3/billdownload/file?token=6XIv5TUPto7pByrTQKhd6kwvyKLG2uY2wMMR8cNXqaA_Cv_isgaUtBzp4QtiozLO",
         * 	"hash_type": "SHA1",
         * 	"hash_value": "8823044c286bea726f149bfcfce0b0318122d755"
         * }
         */
        JSONObject jsonRescontent = JSONUtil.parseObj(rescontent);
        if (jsonRescontent.containsKey("download_url")) {
            String downloadUrl = jsonRescontent.getStr("download_url");

            Map<String, Object> downloadStr = getsign("GET", downloadUrl.replace("https://api.mch.weixin.qq.com", ""), "");
            //下载账单
            System.out.println("签名原串:" + downloadStr.get("signStr"));
            System.out.println("签名sign值:" + downloadStr.get("sign"));
            System.out.println("authorization值:" + downloadStr.get("authorization"));

            httpGet = new HttpGet(downloadUrl);
            //设置头部
            httpGet.addHeader("Accept", "application/json");
            httpGet.addHeader("Content-Type", "application/json");
            httpGet.addHeader("Authorization", Convert.toStr(downloadStr.get("authorization")));

            response = httpClient.execute(httpGet);
            //获取返回内容
            //CloseableHttpResponse response = httpClient.execute(httpGet);
            httpEntity = response.getEntity();
            rescontent = new String(InputStreamTOByte(httpEntity.getContent()));
            System.out.println("返回内容:" + rescontent);

            List<BilldownloadData> dataList = new ArrayList<>();
            String[] split = StrUtil.split(rescontent, "\n");
            for (int i = 0; i < split.length; i++) {
                System.out.println(split[i]);

                if (i == 0){
                    continue;
                }
                String[] splitBilldownload = StrUtil.split(split[i], ",");
                if (splitBilldownload.length > 19){
                    BilldownloadData billdownload = new BilldownloadData();
                    // 交易时间 格式为yyyy-MM-dd HH:MM:SS
                    billdownload.setBillDateTime(StrUtil.replace(splitBilldownload[0], "`",""));
                    // 公众账号ID
                    billdownload.setAppid(StrUtil.replace(splitBilldownload[1], "`",""));
                    // 商户号
                    billdownload.setMchid(StrUtil.replace(splitBilldownload[2], "`",""));
                    // 特约商户号
                    billdownload.setTyMchid(StrUtil.replace(splitBilldownload[3], "`",""));
                    // 设备号
                    billdownload.setDeviceInfoCode(StrUtil.replace(splitBilldownload[4], "`",""));
                    // 微信订单号
                    billdownload.setWxPayOrder(StrUtil.replace(splitBilldownload[5], "`",""));
                    // 商户订单号
                    billdownload.setOrderno(StrUtil.replace(splitBilldownload[6], "`",""));
                    // 用户标识
                    billdownload.setUserIdentify(StrUtil.replace(splitBilldownload[7], "`",""));
                    // 交易类型
                    billdownload.setPayType(StrUtil.replace(splitBilldownload[8], "`",""));
                    // 交易状态
                    billdownload.setPayStatus(StrUtil.replace(splitBilldownload[9], "`",""));
                    // 付款银行
                    billdownload.setPayBank(StrUtil.replace(splitBilldownload[10], "`",""));
                    // 货币种类
                    billdownload.setCurrencyType(StrUtil.replace(splitBilldownload[11], "`",""));
                    // 应结订单金额
                    billdownload.setPayTotal(StrUtil.replace(splitBilldownload[12], "`",""));//(订单金额)
                    // 代金券金额
                    billdownload.setVoucherTotal(StrUtil.replace(splitBilldownload[13], "`",""));
                    // 商品名称
                    billdownload.setDescription(StrUtil.replace(splitBilldownload[14], "`",""));
                    // 商户数据包(商户传入的该笔订单)
                    billdownload.setPayertotal(StrUtil.replace(splitBilldownload[15], "`",""));
                    // 手续费
                    billdownload.setServiceCharge(StrUtil.replace(splitBilldownload[16], "`",""));
                    // 费率
                    billdownload.setRate(StrUtil.replace(splitBilldownload[17], "`",""));
                    // 订单金额
                    billdownload.setOrdernoTotal(StrUtil.replace(splitBilldownload[18], "`",""));
                    // 费率备注
                    billdownload.setRateRemark(StrUtil.replace(splitBilldownload[19], "`",""));

                    dataList.add(billdownload);
                }

            }

            System.out.println(dataList);
//            /*List<BilldownloadData> list = new ArrayList<>();
//            //读取文件流内容
//            BufferedReader reader = null;
//            try {
//                System.out.println("以行为单位读取文件内容,一次读一整行:");
//                reader = new BufferedReader(new InputStreamReader((httpEntity.getContent())));
//                String tempString = null;
//                String[] strings = null;
//
//                int line = 1;
//                //一次读入一行,直到读入null为文件结束
//                while ((tempString = reader.readLine()) != null){
//                    //显示行号
//                    System.out.println("line " + line + ": " + tempString);
//
//                    if (line == 1){
//                        System.out.println();
//                        line++;
//                    }else {
//                        strings = StrUtil.split(tempString, ",");
//
//                        BilldownloadData billdownloadData = new BilldownloadData();
//                        billdownloadData.setBillDateTime(strings[0]);
//                        billdownloadData.setAppid(strings[1]);
//                        billdownloadData.setMchid(strings[2]);
//                        billdownloadData.setTyMchid(strings[3]);
//                        billdownloadData.setDeviceInfoCode(strings[4]);
//                        billdownloadData.setWxPayOrder(strings[5]);
//                        billdownloadData.setOrderno(strings[6]);
//                        billdownloadData.setUserIdentify(strings[7]);
//                        billdownloadData.setPayType(strings[8]);
//                        billdownloadData.setPayStatus(strings[9]);
//                        billdownloadData.setPayBank(strings[10]);
//                        billdownloadData.setCurrencyType(strings[11]);
//                        billdownloadData.setPayTotal(strings[12]);
//                        billdownloadData.setVoucherTotal(strings[13]);
//                        billdownloadData.setDescription(strings[14]);
//                        billdownloadData.setPayertotal(strings[15]);
//                        billdownloadData.setServiceCharge(strings[16]);
//                        billdownloadData.setRate(strings[17]);
//                        billdownloadData.setOrdernoTotal(strings[18]);
//                        billdownloadData.setRateRemark(strings[19]);
//
//                        list.add(billdownloadData);
//                        line++;
//                    }
//
//                }
//                reader.close();
//            } catch (IOException e) {
//                e.printStackTrace();
//            } finally {
//                if (reader != null){
//                    try {
//                        reader.close();
//                    } catch (IOException e1) {
//                    }
//                }
//            }*/

            billdownloadModel.setListData(list);
            eventManager.publishHandle(billdownloadModel);
//            //System.out.println(list);
        } else {
            throw new Exception(jsonRescontent.getStr("message"));
        }

    }

    /**
     * 获取签名串
     *
     * @param type      GET/POST
     * @param url       接口地址:GET请求要带query参数(/v3/bill/tradebill?bill_date=2023-07-31&bill_type=ALL),POST参数只接口参数(/v3/pay/transactions/native)
     *        timestamp 时间戳(System.currentTimeMillis() / 1000)
     *        nonce_str 32位随机字符串
     * @param bodystr   接口入参:GET请求的这个参数为空, POST请求的这个字段为接口入参
     * @return
     */
    public static Map getsign(String type, String url, String bodystr) throws Exception {
        Map<String, Object> map = new HashMap<>();
        //时间戳
        String timestamp = Long.toString(System.currentTimeMillis() / 1000);
        //随机数
        String nonce_str = RandomUtil.randomString(32);

        //拼签名串
        StringBuffer sb = new StringBuffer();
        sb.append(type).append("\n");
        sb.append(url).append("\n");
        sb.append(timestamp).append("\n");
        sb.append(nonce_str).append("\n");
        sb.append(bodystr).append("\n");
        System.out.println("签名原串:" + sb.toString());

        String sign = new String(Base64.encodeBase64(signRSA(sb.toString(), rsaPrivateKey)));

        String authorization = "WECHATPAY2-SHA256-RSA2048 mchid=\"" + PayConstants.MCH_ID + "\",nonce_str=\"" + nonce_str + "\",signature=\"" + sign + "\",timestamp=\"" + timestamp + "\",serial_no=\"" + PayConstants.MCH_SERIAL_NO + "\"";
        map.put("signStr", sb);
        map.put("sign", sign);
        map.put("authorization", authorization);
        return map;
    }

    public static byte[] signRSA(String data, String priKey) throws Exception {
        //签名的类型
        Signature sign = Signature.getInstance("SHA256withRSA");

        //读取商户私钥,该方法传入商户私钥证书的内容即可

        byte[] keyBytes = Base64.decodeBase64(priKey);

        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

        sign.initSign(privateKey);

        sign.update(data.getBytes("UTF-8"));

        return sign.sign();

    }

    public static byte[] InputStreamTOByte(InputStream in) throws IOException {

        int BUFFER_SIZE = 4096;
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] data = new byte[BUFFER_SIZE];
        int count = -1;

        while ((count = in.read(data, 0, BUFFER_SIZE)) != -1)
            outStream.write(data, 0, count);

        data = null;
        byte[] outByte = outStream.toByteArray();
        outStream.close();

        return outByte;
    }

    /**
     * 以行为单位读取文件,常用于读面向行的格式化文件
     * @param fileName 文件名
     */
    public static void readFileByLines(String fileName){
        File file = new File(fileName);
        BufferedReader reader = null;
        try {
            System.out.println("以行为单位读取文件内容,一次读一整行:");
            reader = new BufferedReader(new FileReader(file));
            String tempString = null;
            int line = 1;
            //一次读入一行,直到读入null为文件结束
            while ((tempString = reader.readLine()) != null){
            //显示行号
                System.out.println("line " + line + ": " + tempString);
                line++;
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null){
                try {
                    reader.close();
                } catch (IOException e1) {
                }
            }
        }
    }

}

3, 微信支付对接service

package com.datalook.nxykd.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.datalook.daointerface.IAccountInfoDAO;
import com.datalook.daointerface.ISysUserDAO;
import com.datalook.daointerface.IUserInfoDAO;
import com.datalook.exception.BusinessException;
import com.datalook.model.SysUser;
import com.datalook.model.UserInfo;
import com.datalook.model.WxNativePay;
import com.datalook.nxykd.dao.INativePayDao;
import com.datalook.nxykd.model.BilldownloadData;
import com.datalook.nxykd.model.NativePayCallback;
import com.datalook.nxykd.service.WXnativePayService;
import com.datalook.nxykd.util.PayUtils;
import com.datalook.nxykd.util.http.v3.PayConstants;
import com.datalook.nxykd.util.http.v3.TreadeStateEnum;
import com.datalook.service.BaseService;
import com.datalook.service.UserInfoService;
import com.datalook.util.common.WriteLog;
import com.datalook.util.redis.RedisClient;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import com.swetake.util.Qrcode;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class WXnativePayServiceImpl extends BaseService implements WXnativePayService {
    private static final Logger logger = LoggerFactory.getLogger(WXnativePayServiceImpl.class);

    @Autowired
    private IAccountInfoDAO accountInfoDAO;
    @Autowired
    private INativePayDao nativePayDao;
    @Autowired
    private RedisClient redisClient;
    @Autowired
    private IUserInfoDAO userInfoDAO;//档案信息dao
    @Autowired
    private UserInfoService userInfoService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String getWxPayQRcode(WxNativePay nativePay) {

        String idserial = nativePay.getIdserial();//工号
        String cardid = nativePay.getCardid();//获取卡物理号
        Integer total = nativePay.getTotal();//单位:分

        List<UserInfo> userInfoList = userInfoDAO.findByProperty("idserial", idserial);
        UserInfo userInfo = new UserInfo();
        if (userInfoList != null && userInfoList.size() > 0) {
            userInfo = userInfoList.get(0);

            nativePay.setUserid(userInfo.getId());
        }

        //1, 保存订单 NativePay-订单表
        nativePay.setOrderno("YKT-" + RandomUtil.randomString(6) + Long.toString(System.currentTimeMillis() / 1000));//一卡通生成订单号
        nativePay.setDescription("人员:" + idserial + "一卡通微信充值");
        nativePay.setStatus("0");//订单初始化状态
        nativePay.setAppid(PayConstants.APP_ID);
        nativePay.setMechid(PayConstants.MCH_ID);
        try {
            nativePayDao.save(nativePay);
        } catch (Exception e) {
            System.out.println(e);
        }
        //将cardid与订单表的主键id缓存redis
        redisClient.hset(PayConstants.NATIVE_ORDER_KEY, nativePay.getCardid(), Convert.toStr(nativePay.getId()), 60 * 60);

        String resBody = "";
        String codeUrl = "";
        try {
            resBody = PayUtils.nativePayOrder(nativePay);
            nativePay.setCreateOrderTime(new Timestamp(System.currentTimeMillis()));
            nativePayDao.update(nativePay);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException("微信下单接口调用出错");
        }
        if (StrUtil.isNotBlank(resBody)) {
            JSONObject parse = JSONUtil.parseObj(resBody);
            if (parse.containsKey("code") && !StrUtil.equals(parse.getStr("code"), "SUCCESS")) {
                logger.error(parse.getStr("message"));
                throw new BusinessException("微信下单接口返回错误");
            } else {
                codeUrl = parse.containsKey("code_url") ? parse.getStr("code_url") : "";
            }

        }

        //3, 将返回值链接转化为二维码返回
        //String content = "www.baidu.com";//测试使用链接
        String content = codeUrl;//将微信订单下单成功链接转化为二维码展示
        String imgType = "jpg";
        int size = 15;
        BufferedImage bufferedImage = qRCodeCommon(content, imgType, size);

        return BufferedImageToBase64(bufferedImage);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String wxNativeCallback(NativePayCallback nativePayCallback) {
        String flag = "0";
        //拼装待签名串
        StringBuffer ss = new StringBuffer();
        ss.append(nativePayCallback.getTimestamp()).append("\n");
        ss.append(nativePayCallback.getNonce()).append("\n");
        ss.append(nativePayCallback.getJsonObjectData()).append("\n");
        //验签
        logger.info("微信支付回调接口验签...");
        boolean b = PayUtils.signVerify(nativePayCallback.getSerial(), ss.toString(), nativePayCallback.getSignature());
        if (!b) {
            logger.error("wxNativeCallback:微信支付回调接口验签失败!nativePayCallback验签数据:" + nativePayCallback);
            flag = "1";//验签失败
            return flag;
        }
        logger.info("微信支付回调接口验签成功...下面进行数据解密");

        //数据解密,如果这里报错,就一定是APIv3密钥错误
        String resource = nativePayCallback.getJsonObjectData().containsKey("resource") ? nativePayCallback.getJsonObjectData().getStr("resource") : "";
        JSONObject jsonObject = JSONUtil.parseObj(resource);

        String associated_data = jsonObject.containsKey("associated_data") ? jsonObject.getStr("associated_data") : "";
        String nonce = jsonObject.containsKey("nonce") ? jsonObject.getStr("nonce") : "";
        String ciphertext = jsonObject.containsKey("ciphertext") ? jsonObject.getStr("ciphertext") : "";

//        String associated_data = requestMap2.get("associated_data");
//        String nonce = requestMap2.get("nonce");
//        String ciphertext = requestMap2.get("ciphertext");
        AesUtil aesUtil = new AesUtil(PayConstants.API_V3KEY.getBytes());
        String aes = "";
        try {
            aes = aesUtil.decryptToString(associated_data.getBytes(), nonce.getBytes(), ciphertext);
        } catch (GeneralSecurityException e) {

            e.printStackTrace();
            logger.error("数据解密出错(检查APIv3密钥是否错误)");
            flag = "2";//解密数据出错
            return flag;
        }
        logger.info("数据解密成功aes:" + aes);

        JSONObject jsonaes = JSONUtil.parseObj(aes);
        WxNativePay nativePay = new WxNativePay();
        Map<String, Object> map = new HashMap<>();
        map.put("order", jsonaes.getStr("out_trade_no"));
        List<WxNativePay> nativePays = nativePayDao.sqlExecuteFind(" SELECT * FROM wx_native_pay where order = :order ", map);
        if (nativePays != null && nativePays.size() > 0) {
            nativePay = nativePays.get(0);
        } else {
            logger.error("订单不存在");
            flag = "3";
            return flag;
        }

        nativePay.setWxtransaction(jsonaes.getStr("transaction_id"));
        nativePay.setSuccessTime(new Timestamp(DateTime.parse(jsonaes.getStr("success_time"))));

        String payerTotal = JSONUtil.parseObj(jsonaes.getStr("amount")).getStr("payer_total");//用户支付金额
        String total = JSONUtil.parseObj(jsonaes.getStr("amount")).getStr("total");//订单总金额
        if (!StrUtil.equals(payerTotal, total)) {
            logger.info("支付金额与订单金额不一致||用户支付金额:" + payerTotal + "==订单总金额:" + total);
        }
        nativePay.setTotal(Convert.toInt(total));
        nativePay.setPayertotal(Convert.toInt(payerTotal));

        nativePay.setStatus(TreadeStateEnum.getStatus(jsonaes.getStr("trade_state")));
        //若支付成功, 根据订单号将订单状态修改
        nativePayDao.update(nativePay);

        redisClient.hset(PayConstants.NATIVE_ORDER_ID_KEY, Convert.toStr(nativePay.getId()), TreadeStateEnum.getStatus(jsonaes.getStr("trade_state")), 60 * 60);
        if (!StrUtil.equals(TreadeStateEnum.getStatus(jsonaes.getStr("trade_state")), "1")) {
            flag = jsonaes.getStr("trade_state");
        }
        logger.info("nativePay修改订单状态|flag=" + flag);
        return flag;
    }


    @Override
    @Transactional
    public JSONObject findWxPayQRcodeStatus(String cardid) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("flag", "0");

        String hgetOrderId = "";
        String hgetOrderStatus = "";
        if (StrUtil.isNotBlank(cardid)) {
                hgetOrderId = redisClient.hget(PayConstants.NATIVE_ORDER_KEY, cardid);//根据卡物理号获取订单id

            if (redisClient.exists(PayConstants.NATIVE_ORDER_ID_KEY) && StrUtil.isNotBlank(hgetOrderId)) {
                hgetOrderStatus = redisClient.hget(PayConstants.NATIVE_ORDER_ID_KEY, hgetOrderId);//根据订单号id获取订单状态
                if (StrUtil.equals(hgetOrderStatus, "1")) {

                    jsonObject.put("flag", "1");
                }
            }
        }

        if (StrUtil.isNotBlank(hgetOrderId)) {
            boolean payStatus = false;
            WxNativePay wxNativePay = nativePayDao.find(Convert.toLong(hgetOrderId));

            try {
                payStatus = PayUtils.findPayStatusByOuttradeno(wxNativePay);
            } catch (Exception e) {
                e.printStackTrace();
                logger.error("订单查询失败");
            }
            if (payStatus){
                redisClient.hdel(PayConstants.NATIVE_ORDER_KEY, cardid);
                wxNativePay.setStatus("1");//支付成功
                nativePayDao.update(wxNativePay);
                jsonObject.put("flag", "1");
            }
        }

        return jsonObject;
    }

    @Autowired
    private ISysUserDAO sysUserInfo;

    @Override
    @Transactional
    public void wxTradebillService(String organcode, String date) {
        String message = null;
        String mes = null;

        SysUser sysUser = new SysUser();
        try {
            List<SysUser> byOrgancode = sysUserInfo.findByOrgancode(organcode);
            if (byOrgancode != null && byOrgancode.size() > 0) {
                sysUser = byOrgancode.get(0);
            }

            Map<String, Object> map = new HashMap<>();
            if (StrUtil.isNotBlank(date)){
                map.put("startTime", date + " 00:00:00");
                map.put("endTime", DateUtil.offsetDay(DateUtil.parse(date), 1));
            }else {
                map.put("startTime", DateUtil.format(DateUtil.yesterday(), DatePattern.NORM_DATE_PATTERN) + " 00:00:00");
                map.put("endTime", DateUtil.format(new DateTime(), DatePattern.NORM_DATE_PATTERN) + " 00:00:00");
            }

            List<WxNativePay> wxNativePays = nativePayDao.sqlExecuteFind(" SELECT * from wx_native_pay where `STATUS` != '1' and createOrderTime >= :startTime AND createOrderTime < :endTime ", map);


            List<BilldownloadData> billdownloadDataList = PayUtils.wxTradebill(date);
            Map<String, BilldownloadData> dataMap = new HashMap<>();
            for (BilldownloadData billdownloadData : billdownloadDataList) {
                dataMap.put(billdownloadData.getOrderno(), billdownloadData);
            }

            for (WxNativePay wxNativePay : wxNativePays) {
                BilldownloadData billdownloadData = dataMap.get(wxNativePay.getOrderno());

                if (billdownloadData != null) {
                    UserInfo userInfobyId = userInfoDAO.findById(wxNativePay.getUserid());
                    try {
                        mes = userInfoService.saveCardNum(userInfobyId, sysUser, Convert.toStr(wxNativePay.getCashPledge()), Convert.toStr(wxNativePay.getRechargeAmount()), wxNativePay.getPledgecode(), wxNativePay.getCardid());
                        if (StrUtil.equals(mes, "1")) {
                            mes = userInfoService.saveMoney(userInfobyId, sysUser, Convert.toStr(wxNativePay.getCashPledge()), Convert.toStr(wxNativePay.getRechargeAmount()), wxNativePay.getPledgecode(), wxNativePay.getCardid());
                            if (StrUtil.equals(mes, "1")) {
                                wxNativePay.setPayertotal(Convert.toInt(billdownloadData.getPayertotal()));
                                wxNativePay.setWxtransaction(billdownloadData.getWxPayOrder());
                                wxNativePay.setStatus("1");
                                wxNativePay.setSuccessTime(new Timestamp(DateUtil.parse(billdownloadData.getBillDateTime(), DatePattern.NORM_DATETIME_PATTERN).getTime()));

                                nativePayDao.update(wxNativePay);
                            }
                        }

                    } catch (Exception e) {
                        logger.error("微信对账充值加款失败!");
                        WriteLog.writeLog("wx", "wxTradebill", "微信对账充值加款失败!失败商品描述:" + billdownloadData.getDescription());
                    }
                }

            }

        } catch (Exception e) {
            e.printStackTrace();
            logger.error("对账出错!");
        }
    }

    /**
     * 生成二维码
     *
     * @param content
     * @param imgType
     * @param size
     * @return
     */
    public BufferedImage qRCodeCommon(String content, String imgType, int size) {
        BufferedImage bufImg = null;
        try {
            Qrcode qrcodeHandler = new Qrcode();
            qrcodeHandler.setQrcodeErrorCorrect('M');
            qrcodeHandler.setQrcodeEncodeMode('B');
            qrcodeHandler.setQrcodeVersion(size);
            byte[] contentBytes = content.getBytes("utf-8");
            int imgSize = 67 + 12 * (size - 1);
            bufImg = new BufferedImage(imgSize, imgSize,
                    BufferedImage.TYPE_INT_RGB);
            Graphics2D gs = bufImg.createGraphics();
            gs.setBackground(Color.WHITE);
            gs.clearRect(0, 0, imgSize, imgSize);

            gs.setColor(Color.BLACK);
            int pixoff = 2;
            if (contentBytes.length > 0 && contentBytes.length < 800) {
                boolean[][] codeOut = qrcodeHandler.calQrcode(contentBytes);
                for (int i = 0; i < codeOut.length; i++) {
                    for (int j = 0; j < codeOut.length; j++) {
                        if (codeOut[j][i]) {
                            gs.fillRect(j * 3 + pixoff, i * 3 + pixoff, 3, 3);
                        }
                    }
                }
            } else {
                throw new Exception("QRCode content bytes length = "
                        + contentBytes.length + " not in [0, 800].");
            }
            gs.dispose();
            bufImg.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bufImg;
    }

    /**
     * 给二维码下方附加说明文字
     *
     * @param pressText 文字
     * @param newImg    带文字的图片
     * @param image     需要添加文字的图片
     * @为图片添加文字
     */
    public void pressText(String pressText, String newImg, BufferedImage image, int fontStyle,
                          Color color, int fontSize) {
        //计算文字开始的位置
        //x开始的位置:(图片宽度-字体大小*字的个数)/2
        int startX = (image.getWidth(null) - (fontSize * pressText.length())) / 2;
        //y开始的位置:图片高度-(图片高度-图片宽度)/2
        int startY = image.getHeight() - (fontSize * 4) / 2;
        try {
            int imageW = image.getWidth();
            int imageH = image.getHeight();
            Graphics g = image.createGraphics();
            g.drawImage(image, 0, 0, imageW, imageH, null);
            g.setColor(color);
            g.setFont(new Font("粗体", Font.BOLD, 16));
            g.drawString(pressText, startX, startY - 100);
            g.dispose();

            FileOutputStream out = new FileOutputStream(newImg);
            ImageIO.write(image, "png", out);
            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
            encoder.encode(image);
            out.close();
            System.out.println("image press success");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e);
        }
    }

    /**
     * BufferedImage 编码转换为 base64
     *
     * @param bufferedImage
     * @return
     */
    private static String BufferedImageToBase64(BufferedImage bufferedImage) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();//io流
        try {
            ImageIO.write(bufferedImage, "png", baos);//写入流中
        } catch (IOException e) {
            e.printStackTrace();
        }
        byte[] bytes = baos.toByteArray();//转换成字节
        BASE64Encoder encoder = new BASE64Encoder();
        String png_base64 = encoder.encodeBuffer(bytes).trim();//转换成base64串
        png_base64 = png_base64.replaceAll("\n", "").replaceAll("\r", "");//删除 \r\n
        System.out.println("值为:" + "data:image/jpg;base64," + png_base64);
        return "data:image/jpg;base64," + png_base64;
    }

    /**
     * base64 编码转换为 BufferedImage
     *
     * @param base64
     * @return
     */
    private static BufferedImage base64ToBufferedImage(String base64) {
        BASE64Decoder decoder = new sun.misc.BASE64Decoder();
        try {
            byte[] bytes1 = decoder.decodeBuffer(base64);
            ByteArrayInputStream bais = new ByteArrayInputStream(bytes1);
            return ImageIO.read(bais);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

}

4, 微信支付payUtils

package com.datalook.nxykd.util;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.datalook.model.WxNativePay;
import com.datalook.nxykd.model.BilldownloadData;
import com.datalook.nxykd.util.http.v3.PayConstants;
import com.datalook.util.common.WriteLog;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
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.impl.client.HttpClients;
import org.junit.After;
import org.junit.Before;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class PayUtils {

    public static CloseableHttpClient httpClient = HttpClients.createDefault();
    public static  AutoUpdateCertificatesVerifier verifier;

    @Before
    public static void setup() {
        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(PayConstants.PRIVATE_KEY);

        //使用自动更新的签名验证器,不需要传入证书
        verifier = new AutoUpdateCertificatesVerifier(
                new WechatPay2Credentials(PayConstants.MCH_ID, new PrivateKeySigner(PayConstants.MCH_SERIAL_NO, merchantPrivateKey)),
                PayConstants.API_V3KEY.getBytes(StandardCharsets.UTF_8));

        httpClient = WechatPayHttpClientBuilder.create()
                .withMerchant(PayConstants.MCH_ID, PayConstants.MCH_SERIAL_NO, merchantPrivateKey)
                .withValidator(new WechatPay2Validator(verifier))
                .build();
    }

    @After
    public static void after() throws IOException {
        httpClient.close();
    }

    /**
     * 验签
     *
     * @param serial    请求头中的Wechatpay-Serial
     * @param message
     * @param signature 请求头中的Wechatpay-Signature
     * @return
     */
    public static boolean signVerify(String serial, String message, String signature) {
        try {
            PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(PayConstants.PRIVATE_KEY.getBytes("utf-8")));

            AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(new WechatPay2Credentials(PayConstants.MCH_ID, new PrivateKeySigner(PayConstants.MCH_SERIAL_NO, merchantPrivateKey)),
                    PayConstants.API_V3KEY.getBytes("utf-8"));
            return verifier.verify(serial, message.getBytes("utf-8"), signature);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return false;
    }

    public static String nativePayOrder(WxNativePay nativePay) throws Exception {
        //2, 微信native下单接口
        String url = PayConstants.NATIVE_ORDER_URL;//微信下单接口
        //时间戳
        String timestamp = Long.toString(System.currentTimeMillis() / 1000);
        //随机数
        String nonce_str = RandomUtil.randomString(32);

        //2, 微信下单
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("mchid", PayConstants.MCH_ID);
        jsonObject.put("appid", PayConstants.APP_ID);
        jsonObject.put("notify_url", PayConstants.NOTIFY_URL);
        jsonObject.put("description", nativePay.getDescription());
        jsonObject.put("out_trade_no", nativePay.getOrderno());//随机订单号
        JSONObject json = new JSONObject();
        json.put("total", nativePay.getTotal());//订单金额, 单位:分
        json.put("currency", "CNY");//币种, 境内商户默认都是人民币
        jsonObject.put("amount", json);//随机订单号

        //拼签名串
        StringBuffer sb = new StringBuffer();
        sb.append("POST").append("\n");
        sb.append("/v3/pay/transactions/native").append("\n");
        sb.append(timestamp).append("\n");
        sb.append(nonce_str).append("\n");
        sb.append(jsonObject).append("\n");
        System.out.println("签名原串:" + sb.toString());

        String privateKey = PayConstants.PRIVATE_KEY.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "").replaceAll("\\s+", "");
        //计算签名
        String sign = new String(Base64.encodeBase64(signRSA(sb.toString(), privateKey)));
        System.out.println("签名sign值:" + sign);

        //拼装http头的Authorization内容
        String authorization = "WECHATPAY2-SHA256-RSA2048 mchid=\"" + PayConstants.MCH_ID + "\",nonce_str=\"" + nonce_str + "\",signature=\"" + sign + "\",timestamp=\"" + timestamp + "\",serial_no=\"" + PayConstants.MCH_SERIAL_NO + "\"";
        System.out.println("authorization值:" + authorization);


        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);

        //设置头部
        httpPost.addHeader("Accept", "application/json");
        httpPost.addHeader("Content-Type", "application/json ");
        httpPost.addHeader("Authorization", authorization);

        //设置请求内容
        HttpEntity Entity = new StringEntity(jsonObject.toString(), ContentType.APPLICATION_JSON);
        httpPost.setEntity(Entity);

        //获取返回内容
        CloseableHttpResponse response = httpclient.execute(httpPost);
        HttpEntity httpEntity = response.getEntity();
        String rescontent = new String(InputStreamTOByte(httpEntity.getContent()));
        System.out.println("返回内容:" + rescontent);

        return rescontent;
    }

    public static List<BilldownloadData> wxTradebill(String yesterday) throws Exception {
        List<BilldownloadData> billdownloadDataList = new ArrayList<>();

        String reconciliationUrl = PayConstants.RECONCILIATION_URL;//微信对账接口(获取下载账单接口)

        if (StrUtil.isEmpty(yesterday)){
            yesterday = DateUtil.format(DateUtil.yesterday(), "yyyy-MM-dd");//获取前一天的账单日期
        }

        //reconciliationUrl += "?bill_date=" + yesterday + "&bill_type=" + PayConstants.ALL;
        String url = "?bill_date=" + yesterday + "&bill_type=" + PayConstants.SUCCESS;
        reconciliationUrl += url;
        System.out.println(reconciliationUrl);

        //拼签名串
        Map<String, Object> str = getsign("GET", "/v3/bill/tradebill" + url, "");
        System.out.println("签名原串:" + str.get("signStr"));
        WriteLog.writeLog("wx", "wxTradebill", "签名原串:" + str.get("signStr"));
        //计算签名
        //String sign = new String(Base64.encodeBase64(signRSA(Convert.toStr(str.get("sign")), rsaPrivateKey)));
        System.out.println("签名sign值:" + str.get("sign"));
        WriteLog.writeLog("wx", "wxTradebill", "签名sign值:" + str.get("sign"));
        //拼装http头的Authorization内容
        //String authorization = "WECHATPAY2-SHA256-RSA2048 mchid=\"" + PayConstants.MCH_ID + "\",nonce_str=\"" + nonce_str + "\",signature=\"" + sign + "\",timestamp=\"" + timestamp + "\",serial_no=\"" + PayConstants.MCH_SERIAL_NO + "\"";
        System.out.println("authorization值:" + str.get("authorization"));
        WriteLog.writeLog("wx", "wxTradebill", "authorization值:" + str.get("authorization"));

        //CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(reconciliationUrl);

        //设置头部
        httpGet.addHeader("Accept", "application/json");
        httpGet.addHeader("Content-Type", "application/json");
        httpGet.addHeader("Authorization", Convert.toStr(str.get("authorization")));

        //获取返回内容
        CloseableHttpResponse response = httpClient.execute(httpGet);
        HttpEntity httpEntity = response.getEntity();
        String rescontent = new String(InputStreamTOByte(httpEntity.getContent()));
        System.out.println("返回内容:" + rescontent);


        /**
         * //获取下载账单地址
         * {
         * 	"download_url": "https://api.mch.weixin.qq.com/v3/billdownload/file?token=6XIv5TUPto7pByrTQKhd6kwvyKLG2uY2wMMR8cNXqaA_Cv_isgaUtBzp4QtiozLO",
         * 	"hash_type": "SHA1",
         * 	"hash_value": "8823044c286bea726f149bfcfce0b0318122d755"
         * }
         */
        JSONObject jsonRescontent = JSONUtil.parseObj(rescontent);
        if (jsonRescontent.containsKey("download_url")) {
            String downloadUrl = jsonRescontent.getStr("download_url");

            Map<String, Object> downloadStr = getsign("GET", downloadUrl.replace("https://api.mch.weixin.qq.com", ""), "");
            //下载账单
            System.out.println("签名原串:" + downloadStr.get("signStr"));
            System.out.println("签名sign值:" + downloadStr.get("sign"));
            System.out.println("authorization值:" + downloadStr.get("authorization"));

            httpGet = new HttpGet(downloadUrl);
            //设置头部
            httpGet.addHeader("Accept", "application/json");
            httpGet.addHeader("Content-Type", "application/json");
            httpGet.addHeader("Authorization", Convert.toStr(downloadStr.get("authorization")));

            response = httpClient.execute(httpGet);
            //获取返回内容
            //CloseableHttpResponse response = httpClient.execute(httpGet);
            httpEntity = response.getEntity();
            rescontent = new String(InputStreamTOByte(httpEntity.getContent()));
            System.out.println("返回内容:" + rescontent);
            WriteLog.writeLog("wx", "wxTradebill", "对账数据:");

            String[] split = StrUtil.split(rescontent, "\n");
            for (int i = 0; i < split.length; i++) {
                System.out.println(split[i]);

                WriteLog.writeLog("wx", "wxTradebill", split[i]);
                if (i == 0){
                    continue;
                }
                String[] splitBilldownload = StrUtil.split(split[i], ",");
                if (splitBilldownload.length > 19) {
                    BilldownloadData billdownload = new BilldownloadData();
                    // 交易时间 格式为yyyy-MM-dd HH:MM:SS
                    billdownload.setBillDateTime(StrUtil.replace(splitBilldownload[0], "`", ""));
                    // 公众账号ID
                    billdownload.setAppid(StrUtil.replace(splitBilldownload[1], "`", ""));
                    // 商户号
                    billdownload.setMchid(StrUtil.replace(splitBilldownload[2], "`", ""));
                    // 特约商户号
                    billdownload.setTyMchid(StrUtil.replace(splitBilldownload[3], "`", ""));
                    // 设备号
                    billdownload.setDeviceInfoCode(StrUtil.replace(splitBilldownload[4], "`", ""));
                    // 微信订单号
                    billdownload.setWxPayOrder(StrUtil.replace(splitBilldownload[5], "`", ""));
                    // 商户订单号
                    billdownload.setOrderno(StrUtil.replace(splitBilldownload[6], "`", ""));
                    // 用户标识
                    billdownload.setUserIdentify(StrUtil.replace(splitBilldownload[7], "`", ""));
                    // 交易类型
                    billdownload.setPayType(StrUtil.replace(splitBilldownload[8], "`", ""));
                    // 交易状态
                    billdownload.setPayStatus(StrUtil.replace(splitBilldownload[9], "`", ""));
                    // 付款银行
                    billdownload.setPayBank(StrUtil.replace(splitBilldownload[10], "`", ""));
                    // 货币种类
                    billdownload.setCurrencyType(StrUtil.replace(splitBilldownload[11], "`", ""));
                    // 应结订单金额
                    billdownload.setPayTotal(StrUtil.replace(splitBilldownload[12], "`", ""));//(订单金额)
                    // 代金券金额
                    billdownload.setVoucherTotal(StrUtil.replace(splitBilldownload[13], "`", ""));
                    // 商品名称
                    billdownload.setDescription(StrUtil.replace(splitBilldownload[14], "`", ""));
                    // 商户数据包(商户传入的该笔订单)
                    billdownload.setPayertotal(StrUtil.replace(splitBilldownload[15], "`", ""));
                    // 手续费
                    billdownload.setServiceCharge(StrUtil.replace(splitBilldownload[16], "`", ""));
                    // 费率
                    billdownload.setRate(StrUtil.replace(splitBilldownload[17], "`", ""));
                    // 订单金额
                    billdownload.setOrdernoTotal(StrUtil.replace(splitBilldownload[18], "`", ""));
                    // 费率备注
                    billdownload.setRateRemark(StrUtil.replace(splitBilldownload[19], "`", ""));

                    billdownloadDataList.add(billdownload);
                }

            }
        } else {
            WriteLog.writeLog("wx", "wxTradebill", "对账出错:" + jsonRescontent.getStr("message"));
            throw new Exception(jsonRescontent.getStr("message"));
        }
        return billdownloadDataList;
    }

    /**
     * 获取签名串
     *
     * @param type    GET/POST
     * @param url     接口地址:GET请求要带query参数(/v3/bill/tradebill?bill_date=2023-07-31&bill_type=ALL),POST参数只接口参数(/v3/pay/transactions/native)
     *                timestamp 时间戳(System.currentTimeMillis() / 1000)
     *                nonce_str 32位随机字符串
     * @param bodystr 接口入参:GET请求的这个参数为空, POST请求的这个字段为接口入参
     * @return
     */
    public static Map getsign(String type, String url, String bodystr) throws Exception {
        String privateKey = PayConstants.PRIVATE_KEY.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "").replaceAll("\\s+", "");

        Map<String, Object> map = new HashMap<>();
        //时间戳
        String timestamp = Long.toString(System.currentTimeMillis() / 1000);
        //随机数
        String nonce_str = RandomUtil.randomString(32);

        //拼签名串
        StringBuffer sb = new StringBuffer();
        sb.append(type).append("\n");
        sb.append(url).append("\n");
        sb.append(timestamp).append("\n");
        sb.append(nonce_str).append("\n");
        sb.append(bodystr).append("\n");
        System.out.println("签名原串:" + sb.toString());

        String sign = new String(Base64.encodeBase64(signRSA(sb.toString(), privateKey)));

        String authorization = "WECHATPAY2-SHA256-RSA2048 mchid=\"" + PayConstants.MCH_ID + "\",nonce_str=\"" + nonce_str + "\",signature=\"" + sign + "\",timestamp=\"" + timestamp + "\",serial_no=\"" + PayConstants.MCH_SERIAL_NO + "\"";
        map.put("signStr", sb);
        map.put("sign", sign);
        map.put("authorization", authorization);
        return map;
    }

    public static byte[] signRSA(String data, String priKey) throws Exception {
        //签名的类型
        Signature sign = Signature.getInstance("SHA256withRSA");

        //读取商户私钥,该方法传入商户私钥证书的内容即可

        byte[] keyBytes = Base64.decodeBase64(priKey);

        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

        sign.initSign(privateKey);

        sign.update(data.getBytes("UTF-8"));

        return sign.sign();

    }

    public static byte[] InputStreamTOByte(InputStream in) throws IOException {

        int BUFFER_SIZE = 4096;
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] data = new byte[BUFFER_SIZE];
        int count = -1;

        while ((count = in.read(data, 0, BUFFER_SIZE)) != -1)
            outStream.write(data, 0, count);

        data = null;
        byte[] outByte = outStream.toByteArray();
        outStream.close();

        return outByte;
    }

    /**
     * 商户订单号查询
     * 请求URL: https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{out_trade_no}
     * out_trade_no 商户订单号
     * 请求方式:GET
     * @param wxNativePay 订单数据
     */
    public static boolean findPayStatusByOuttradeno(WxNativePay wxNativePay) throws Exception {

        String reconciliationUrl = PayConstants.TRANSACTIONS_URL;//查询订单接口

        //String out_trade_no = "YKT-967wcp1691147868";
        String out_trade_no = wxNativePay.getOrderno();

        String url = "?mchid=" + PayConstants.MCH_ID;
        reconciliationUrl = reconciliationUrl + out_trade_no + url;
        System.out.println(reconciliationUrl);

        //拼签名串
        Map<String, Object> str = getsign("GET", "/v3/pay/transactions/out-trade-no/"+ out_trade_no + url, "");
        System.out.println("签名原串:" + str.get("signStr"));
        System.out.println("签名sign值:" + str.get("sign"));
        System.out.println("authorization值:" + str.get("authorization"));


        HttpGet httpGet = new HttpGet(reconciliationUrl);
        //设置头部
        httpGet.addHeader("Accept", "application/json");
        httpGet.addHeader("Content-Type", "application/json");
        httpGet.addHeader("Authorization", Convert.toStr(str.get("authorization")));

        CloseableHttpResponse response = httpClient.execute(httpGet);

        HttpEntity httpEntity = response.getEntity();
        String rescontent = new String(InputStreamTOByte(httpEntity.getContent()));
        System.out.println("返回内容:" + rescontent);

        JSONObject jsonObject = JSONUtil.parseObj(rescontent);
        if (jsonObject.containsKey("trade_state") && StrUtil.equals(jsonObject.getStr("trade_state"), PayConstants.SUCCESS)){
            return true;
        }
        return false;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值