admin管理员组

文章数量:1559090

微信支付开通支付方法在这里可以参考一下:申请开通微信支付教程_个人怎么申请微信支付_郑鹏川的博客-csdn博客

因为微信支付回调需要一个外网可访问的地址,我本地调试是采用的内网穿透的方式进行调试的。

cpolar是一款内网穿透工具,它支持http/https/tcp协议,不限制流量,操作简单,无需公网ip,也无需路由器,可以轻松把服务暴露到公网访问。

cpolar九游会下载官网:cpolar - 安全的内网穿透工具

1 下载安装cpolar内网穿透

访问cpolar九游会下载官网,注册一个账号,并下载安装cpolar客户端。详细可以参考文档教程进行下载安装。

2 创建隧道
cpolar安装成功后,我们在浏览器上访问本地9200端口,登录cpolar的web ui界面:http://localhost:9200。

点击左侧仪表盘的隧道管理——创建隧道,由于tomcat中配置的是82端口,因此我们要来创建一条http隧道,指向82端口:

隧道名称:可自定义,注意不要与已有隧道名称重复
协议:http协议
本地地址:82
域名类型:免费选择随机域名
地区:选择china top

 

点击左侧仪表盘的状态——在线隧道列表,可以看到刚刚创建的隧道已经有生成了相应的公网地址,一个http协议,一个https协议(免去配置ssl证书的繁琐步骤),将其复制想下来 

接下来我们就直接上代码了:

一、引入官方提供的pom依赖



  com.github.wechatpay-apiv3
  wechatpay-apache-httpclient
  0.4.2

二、配置微信支付必要的参数

weixin:
  appid:  # appid
  mch-serial-no:  # 证书序列号
  private-key-path: apiclient_key.pem # 证书路径  我这边保存在resource文件夹下读取文件时通过classpathresource去读取的
  mch-id: # 商户号
  key:  # api秘钥
  domain: https://api.mch.weixin.qq # 微信服务器地址
  notify-domain: http://303fe2d4.r5.cpolar.top/v3/wechat/callback # 回调,自己的回调地址需要外网可访问
 

三、编写微信支付配置类

import com.qzmon.exception.commonexception;
import com.wechat.pay.contrib.apache.httpclient.wechatpayhttpclientbuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.privatekeysigner;
import com.wechat.pay.contrib.apache.httpclient.auth.verifier;
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.cert.certificatesmanager;
import com.wechat.pay.contrib.apache.httpclient.exception.httpcodeexception;
import com.wechat.pay.contrib.apache.httpclient.exception.notfoundexception;
import com.wechat.pay.contrib.apache.httpclient.util.pemutil;
import lombok.data;
import org.apache.http.impl.client.closeablehttpclient;
import org.springframework.boot.context.properties.configurationproperties;
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;
import org.springframework.context.annotation.propertysource;
import org.springframework.core.io.classpathresource;
import java.io.ioexception;
import java.nio.charset.standardcharsets;
import java.security.generalsecurityexception;
import java.security.privatekey;
/**
 * @author lihao
 * @create 2023-03-22 17:24
 * @desc
 **/
@configuration
@propertysource("classpath:application.yml") //读取配置文件
@configurationproperties(prefix = "weixin") //读取weixin节点
@data //使用set方法将weixin节点中的值填充到当前类的属性中
public class wxpayconfig {
    // 商户号
    private string mchid;
    // 商户api证书序列号
    private string mchserialno;
    // 商户私钥文件
    private string privatekeypath;
    // apiv3密钥
    private string key;
    // appid
    private string appid;
    // 微信服务器地址
    private string domain;
    // 接收结果通知地址
    private string notifydomain;
    /**
     * 获取商户的私钥文件
     *
     * @param filename 证书地址
     * @return 私钥文件
     */
    public privatekey getprivatekey(string filename) {
        try {
            classpathresource classpathresource = new classpathresource(filename);
            return pemutil.loadprivatekey(classpathresource.getinputstream());
        } catch (ioexception e) {
            throw new commonexception("私钥文件不存在");
        }
    }
    /**
     * 获取签名验证器
     */
    @bean
    public verifier getverifier() {
        // 获取商户私钥
        final privatekey privatekey = getprivatekey(privatekeypath);
        // 私钥签名对象
        privatekeysigner privatekeysigner = new privatekeysigner(mchserialno, privatekey);
        // 身份认证对象
        wechatpay2credentials wechatpay2credentials = new wechatpay2credentials(mchid, privatekeysigner);
        // 获取证书管理器实例
        certificatesmanager certificatesmanager = certificatesmanager.getinstance();
        try {
            // 向证书管理器增加需要自动更新平台证书的商户信息
            certificatesmanager.putmerchant(mchid, wechatpay2credentials, key.getbytes(standardcharsets.utf_8));
        } catch (ioexception | generalsecurityexception | httpcodeexception e) {
            e.printstacktrace();
        }
        try {
            return certificatesmanager.getverifier(mchid);
        } catch (notfoundexception e) {
            e.printstacktrace();
            throw new commonexception("获取签名验证器失败");
        }
    }
    /**
     * 获取微信支付的远程请求对象
     *
     * @return http请求对象
     */
    @bean
    public closeablehttpclient getwxpayclient() {
        // 获取签名验证器
        verifier verifier = getverifier();
        // 获取商户私钥
        final privatekey privatekey = getprivatekey(privatekeypath);
        wechatpayhttpclientbuilder builder = wechatpayhttpclientbuilder.create().withmerchant(mchid, mchserialno, privatekey)
                .withvalidator(new wechatpay2validator(verifier));
        return builder.build();
    }
}

四、微信支付枚举类

import lombok.allargsconstructor;
import lombok.getter;
/**
 * @author lihao
 * @create 2023-03-22 17:21
 * @desc 微信支付枚举类
 **/
@allargsconstructor
@getter
public enum wxapitype {
    /**
     * native下单
     */
    native_pay("/v3/pay/transactions/native"),
    /**
     * jsapi下单
     */
    jsapi_pay("/v3/pay/transactions/jsapi"),
    /**
     * jsapi下单
     */
    h5_pay("/v3/pay/transactions/h5"),
    /**
     * app下单
     */
    app_pay("/v3/pay/transactions/app"),
    /**
     * 查询订单
     */
    order_query_by_no("/v3/pay/transactions/out-trade-no/%s/?mchid=%s"),
    /**
     * 查询订单
     */
    order_query_by_id("/v3/pay/transactions/id/%s?mchid=%s"),
    /**
     * 关闭订单
     */
    close_order_by_no("/v3/pay/transactions/out-trade-no/%s/close"),
    /**
     * 申请退款
     */
    domestic_refunds("/v3/refund/domestic/refunds"),
    /**
     * 查询单笔退款
     */
    domestic_refunds_query("/v3/refund/domestic/refunds/%s"),
    /**
     * 申请交易账单
     */
    trade_bills("/v3/bill/tradebill"),
    /**
     * 申请资金账单
     */
    fund_flow_bills("/v3/bill/fundflowbill"),
    /**
     * 发起商家转账
     */
    transfer_batches("/v3/transfer/batches");
    /**
     * 类型
     */
    private final string type;
}

五、微信支付工具类(这边以native扫码支付为例)

(1)创建native扫码支付工具类  后面需要用到时传入参数直接调用即可

/**
 * @author lihao
 * @create 2023-03-23 9:58
 * @desc native扫码支付工具类
 **/
@slf4j
public class wxpaynativeutils {
    public static map nativepay(wxpayconfig wxpayconfig, wechatpaynativeparam param, closeablehttpclient wxpayclient) throws exception {
        gson gson = new gson();
        // 创建post请求对象,里面输入的是地址,也就是那个https://api.wxpayxxxxx 那个,只不过我们直接去配置文件里面读取然后拼接出来了,懒得每次都输入一遍
        httppost httppost = new httppost(wxpayconfig.getdomain().concat(wxapitype.native_pay.gettype()));
        map paramsmap =new hashmap();
        paramsmap.put("appid",wxpayconfig.getappid()); // 我们的appid
        paramsmap.put("mchid",wxpayconfig.getmchid()); // 我们的商户id
        paramsmap.put("description",param.getdescription());  // 扫码之后显示的标题
        paramsmap.put("out_trade_no",param.getouttradeno()); // 商户订单号 我们自己生成的那个
        // 这里就是微信响应给我们系统的那个地址 必须是能外网访问的
        paramsmap.put("notify_url",wxpayconfig.getnotifydomain());
        map amountmap = new hashmap();
        amountmap.put("total",param.gettotal()); // 支付金额
        amountmap.put("currency","cny"); // 交易货币的类型
        paramsmap.put("amount",amountmap);
        paramsmap.put("attach",param.getdeviceinfo());
        // 将这个json对象转换成字符串,用于后面进行网络传输
        string jsonparams = gson.tojson(paramsmap);
        log.info("请求微信支付v3 native扫码支付接口参数 =========> "   jsonparams);
        // 设置请求体
        stringentity entity = new stringentity(jsonparams,"utf-8");
        entity.setcontenttype("application/json");
        httppost.setentity(entity);
        httppost.setheader("accept", "application/json");
        //完成签名并执行请求
        closeablehttpresponse response = wxpayclient.execute(httppost);
        hashmap returnmap = new hashmap<>();
        try {
            string body = entityutils.tostring(response.getentity());
            int statuscode = response.getstatusline().getstatuscode();
            if (statuscode == 200) { //处理成功 有返回就会进入这里
                log.info("请求微信支付v3 native扫码支付接口成功,返回结果 =========> "   body);
            } else if (statuscode == 204) { //处理成功,无返回就会进入到这里
                system.out.println("success");
            } else { // 接口调用失败的话就会进入这里
                log.info("native下单失败,响应码 =====> "   statuscode  ",返回结果= "   body);
                hashmap resultmap = gson.fromjson(body, hashmap.class);
                returnmap.put("err_code_des",resultmap.get("message"));
            }
            // 相微信那边返回的结果   我们将json返回转成一个map对象
            hashmap resultmap = gson.fromjson(body, hashmap.class);
            // 然后从这个map里面拿到code_url,这个是微信定义的,我们拿这个结果生成二维码
            string code_url = resultmap.get("code_url");
            returnmap.put("code_url",code_url);
            return returnmap;
        } finally {
            response.close();
        }
    }
}

(2)native支付成功回调工具类

/**
 * @author lihao
 * @create 2023-03-23 11:40
 * @desc
 **/
@slf4j
public class wxpaycallbackutil {
    /**
     * 微信支付创建订单回调方法
     * @param verifier 证书
     * @param wxpayconfig 微信配置
     * @param businesscallback 回调方法,用于处理业务逻辑
     * @return json格式的string数据,直接返回给微信
     */
    public static string wxpaysuccesscallback(httpservletrequest request, httpservletresponse response, verifier verifier, wxpayconfig wxpayconfig, consumer businesscallback) {
        gson gson = new gson();
        // 1.处理通知参数
        final string body = httputils.readdata(request);
        hashmap bodymap = gson.fromjson(body, hashmap.class);
        // 2.签名验证
        wechatpayvalidatorforrequest wechatforrequest = new wechatpayvalidatorforrequest(verifier, body, (string) bodymap.get("id"));
        try {
            if (!wechatforrequest.validate(request)) {
                // 通知验签失败
                response.setstatus(500);
                final hashmap map = new hashmap<>();
                map.put("code", "error");
                map.put("message", "通知验签失败");
                return gson.tojson(map);
            }
        } catch (ioexception e) {
            e.printstacktrace();
        }
        // 3.获取明文数据
        string plaintext = decryptfromresource(bodymap,wxpayconfig);
        hashmap plaintextmap = gson.fromjson(plaintext, hashmap.class);
        log.info("plaintextmap:{}",plaintextmap);
        // 4.封装微信返回的数据
        wxchatcallbacksuccessresult callbackdata = new wxchatcallbacksuccessresult();
        callbackdata.setsuccesstime(string.valueof(plaintextmap.get("success_time")));
        callbackdata.setorderid(string.valueof(plaintextmap.get("out_trade_no")));
        callbackdata.settransactionid(string.valueof(plaintextmap.get("transaction_id")));
        callbackdata.settradestate(string.valueof(plaintextmap.get("trade_state")));
        callbackdata.settradetype(string.valueof(plaintextmap.get("trade_type")));
        callbackdata.setattach(string.valueof(plaintextmap.get("attach")));
        string amount = string.valueof(plaintextmap.get("amount"));
        hashmap amountmap = gson.fromjson(amount, hashmap.class);
        string total = string.valueof(amountmap.get("total"));
        callbackdata.settotalmoney(new bigdecimal(total).movepointleft(2));
        log.info("callbackdata:{}",callbackdata);
        if ("success".equals(callbackdata.gettradestate())) {
            // 执行业务逻辑
            businesscallback.accept(callbackdata);
        }
        // 5.成功应答
        response.setstatus(200);
        final hashmap resultmap = new hashmap<>();
        resultmap.put("code", "success");
        resultmap.put("message", "成功");
        return gson.tojson(resultmap);
    }
    /**
     * 对称解密
     */
    private static string decryptfromresource(hashmap bodymap, wxpayconfig wxpayconfig) {
        // 通知数据
        map resourcemap = (map) bodymap.get("resource");
        // 数据密文
        string ciphertext = resourcemap.get("ciphertext");
        // 随机串
        string nonce = resourcemap.get("nonce");
        // 附加数据
        string associatedata = resourcemap.get("associated_data");
        aesutil aesutil = new aesutil(wxpayconfig.getkey().getbytes(standardcharsets.utf_8));
        try {
            return aesutil.decrypttostring(associatedata.getbytes(standardcharsets.utf_8), nonce.getbytes(standardcharsets.utf_8), ciphertext);
        } catch (generalsecurityexception e) {
            e.printstacktrace();
            throw new commonexception("解密失败");
        }
    }
}

(3)请求参数

/**
 * @author lihao
 * @create 2023-03-23 10:02
 * @desc 微信native支付参数
 **/
@data
public class wechatpaynativeparam {
    /**
     * 扫码之后显示的标题
     */
    private string description;
    /**
     * 商户订单号 我们自己生成的那个
     */
    private string outtradeno;
    /**
     * 支付金额
     */
    private bigdecimal total;
    /**
     * 自定义参数  具体看业务要求  无要求可不填
     */
    private string deviceinfo;
}

(4)controller中调用native扫码支付工具类

@autowired
private wxpayconfig wxpayconfig;
@autowired
private closeablehttpclient wxpayclient;
@apioperation("微信支付v3版返回链接")
@saplatchecklogin
@postmapping("/nativepay")
public commonresult nativepay(@requestbody wechatpayparam payparam) throws exception {
        wechatpaynativeparam param = new wechatpaynativeparam();
        param.setdescription(payparam.getdescription());
        //这里注意要保持商户订单号唯一  
        param.setouttradeno(payparam.getorderid()  randomutil.randomnumbers(4));
        param.setdeviceinfo(payparam.getorderid());
        bigdecimal money = new bigdecimal(0.01);
        param.settotal((money.multiply(new bigdecimal(100))).setscale(0,bigdecimal.round_half_down));
        map map = wxpaynativeutils.nativepay(wxpayconfig,param,wxpayclient);
        if(objectutil.isempty(map) || objectutil.isnotempty(map.get("err_code_des"))){
            return commonresult.data(new wechatcoderesult(null,"fail",map.get("err_code_des").tostring()));
        }
        if(objectutil.isempty(map.get("code_url"))){
            throw new commonexception("生成支付二维码失败!");
        }
        return commonresult.data(new wechatcoderesult(map.get("code_url").tostring(),"success",null));
    }
@apioperation("微信支付回调接口")
@postmapping("/callback")
public string coursenative(httpservletrequest request, httpservletresponse response) {
        return wxpaycallbackutil.wxpaysuccesscallback(request, response, verifier, wxpayconfig, callbackdata -> {
         log.info("微信支付返回的信息:{}", callbackdata);
         //这里处理自己的业务
               wechatpayservice.payorder(callbackdata.getattach(),callbackdata.gettotalmoney().tostring(),        callbackdata.gettransactionid());
        });
    }

六、附下其他几种九游会下载的支付方式

(1)微信退款工具类

/**
 * @author lihao
 * @create 2023-03-23 11:18
 * @desc 微信退款工具类
 **/
@slf4j
public class wxpayrefundutil {
    /**
     * 发起微信退款申请
     *
     * @param wxpayconfig 微信配置信息
     * @param param       微信支付申请退款请求参数
     * @param wxpayclient 微信请求客户端
     * @return
     */
    public static string refundpay(wxpayconfig wxpayconfig, wechatrefundparam param, closeablehttpclient wxpayclient) {
        // 1.获取请求参数的map格式
        map paramsmap = getrefundparams(param);
        // 2.获取请求对象
        httppost httppost = gethttppost(wxpayconfig, wxapitype.domestic_refunds, paramsmap);
        // 3.完成签名并执行请求
        closeablehttpresponse response = null;
        try {
            response = wxpayclient.execute(httppost);
        } catch (ioexception e) {
            e.printstacktrace();
            throw new commonexception("微信支付请求失败");
        }
        // 4.解析response对象
        hashmap resultmap = resolverresponse(response);
        log.info("============>发起微信退款参数:{}",resultmap);
        if (resultmap != null) {
            // 返回微信支付退款单号
            return resultmap.get("out_refund_no");
        }
        return null;
    }
    /**
     * 查询单笔退款
     * @param wxpayconfig 微信配置信息
     * @param outrefundno 商户退款单号
     * @param wxpayclient 微信请求客户端
     * @return
     */
    public static map refundquery(wxpayconfig wxpayconfig, string outrefundno, closeablehttpclient wxpayclient) {
        // 1.请求路径和对象
        string url = string.format(wxpayconfig.getdomain().concat(wxapitype.domestic_refunds_query.gettype()),outrefundno);
        httpget httpget = new httpget(url);
        httpget.setheader("accept", "application/json");
        // 2.完成签名并执行请求
        closeablehttpresponse response = null;
        try {
            response = wxpayclient.execute(httpget);
        } catch (ioexception e) {
            e.printstacktrace();
            throw new commonexception("微信支付请求失败");
        }
        // 3.解析返回的数据
        map map = resolverresponse(response);
        log.info("微信支付查询单笔退款信息========>{}",map);
        return map;
    }
    /**
     * 解析响应数据
     *
     * @param response 发送请求成功后,返回的数据
     * @return 微信返回的参数
     */
    private static hashmap resolverresponse(closeablehttpresponse response) {
        try {
            // 1.获取请求码
            int statuscode = response.getstatusline().getstatuscode();
            // 2.获取返回值 string 格式
            final string bodyasstring = entityutils.tostring(response.getentity());
            gson gson = new gson();
            if (statuscode == 200) {
                // 3.如果请求成功则解析成map对象返回
                hashmap resultmap = gson.fromjson(bodyasstring, hashmap.class);
                return resultmap;
            } else {
                if (stringutils.isnoneblank(bodyasstring)) {
                    log.error("微信支付请求失败,提示信息:{}", bodyasstring);
                    // 4.请求码显示失败,则尝试获取提示信息
                    hashmap resultmap = gson.fromjson(bodyasstring, hashmap.class);
                    throw new commonexception(resultmap.get("message"));
                }
                log.error("微信支付请求失败,未查询到原因,提示信息:{}", response);
                // 其他异常,微信也没有返回数据,这就需要具体排查了
                throw new ioexception("request failed");
            }
        } catch (exception e) {
            e.printstacktrace();
            throw new commonexception(e.getmessage());
        } finally {
            try {
                response.close();
            } catch (ioexception e) {
                e.printstacktrace();
            }
        }
    }
    /**
     * 获取请求对象(post请求)
     *
     * @param wxpayconfig 微信配置类
     * @param apitype     接口请求地址
     * @param paramsmap   请求参数
     * @return post请求对象
     */
    private static httppost gethttppost(wxpayconfig wxpayconfig, wxapitype apitype, map paramsmap) {
        // 1.设置请求地址
        httppost httppost = new httppost(wxpayconfig.getdomain().concat(apitype.gettype()));
        // 2.设置请求数据
        gson gson = new gson();
        string jsonparams = gson.tojson(paramsmap);
        // 3.设置请求信息
        stringentity entity = new stringentity(jsonparams, "utf-8");
        entity.setcontenttype("application/json");
        httppost.setentity(entity);
        httppost.setheader("accept", "application/json");
        return httppost;
    }
    /**
     * 封装微信支付申请退款请求参数
     *
     * @param param 微信支付申请退款请求参数
     * @return 封装后的map微信支付申请退款请求参数对象
     */
    private static map getrefundparams(wechatrefundparam param) {
        map paramsmap = new hashmap<>();
        if (stringutils.isnoneblank(param.gettransactionid())) {
            paramsmap.put("transaction_id", param.gettransactionid());
        } else if (stringutils.isnoneblank(param.getorderid())) {
            paramsmap.put("out_trade_no", param.getorderid());
        } else {
            throw new commonexception("微信支付订单号和商户订单号必须填写一个");
        }
        paramsmap.put("out_refund_no", param.getrefundorderid());
        if (stringutils.isnoneblank(param.getreason())) {
            paramsmap.put("reason", param.getreason());
        }
        //paramsmap.put("notify_url", wxpayconfig.getnotifydomain().concat(param.getnotify().gettype()));
        map amountmap = new hashmap<>();
        amountmap.put("refund", param.getrefundmoney().multiply(new bigdecimal(100)).setscale(0,bigdecimal.round_half_down));
        amountmap.put("total", param.gettotalmoney().multiply(new bigdecimal(100)).setscale(0,bigdecimal.round_half_down));
        amountmap.put("currency", "cny");
        paramsmap.put("amount", amountmap);
        return paramsmap;
    }
}

(2)订单查询工具类

/**
 * @author lihao
 * @create 2023-03-23 15:49
 * @desc 微信支付查询订单信息工具类
 **/
@slf4j
public class wxpaysearchorderutil {
    /**
     * 根据微信支付系统生成的订单号查询订单详情
     * @param wxpayconfig 微信支付配置信息
     * @param transactionid 微信支付系统生成的订单号
     * @param wxpayclient 微信支付客户端请求对象
     * @return 微信订单对象
     */
    public static wxchatcallbacksuccessresult searchbytransactionid(wxpayconfig wxpayconfig, string transactionid, closeablehttpclient wxpayclient) {
        // 1.请求路径和对象
        string url = string.format(wxpayconfig.getdomain().concat(wxapitype.order_query_by_id.gettype()),transactionid,wxpayconfig.getmchid());;
        httpget httpget = new httpget(url);
        httpget.setheader("accept", "application/json");
        // 2.完成签名并执行请求
        closeablehttpresponse response = null;
        try {
            response = wxpayclient.execute(httpget);
        } catch (ioexception e) {
            e.printstacktrace();
            throw new commonexception("微信支付请求失败");
        }
        // 3.解析返回的数据
        wxchatcallbacksuccessresult callbackdata = resolverresponse(response);
        log.info("微信支付根据订单号查询信息========>callbackdata:{}",callbackdata);
        return callbackdata;
    }
    /**
     * 根据微信支付系统生成的订单号查询订单详情
     * @param wxpayconfig 微信支付配置信息
     * @param orderid 我们自己的订单id
     * @param wxpayclient 微信支付客户端请求对象
     * @return 微信订单对象
     */
    public static wxchatcallbacksuccessresult searchbyorderid(wxpayconfig wxpayconfig, string orderid, closeablehttpclient wxpayclient) {
        // 1.请求路径和对象
        string url = string.format(wxpayconfig.getdomain().concat(wxapitype.order_query_by_no.gettype()),orderid,wxpayconfig.getmchid());
        httpget httpget = new httpget(url);
        httpget.setheader("accept", "application/json");
        // 2.完成签名并执行请求
        closeablehttpresponse response = null;
        try {
            response = wxpayclient.execute(httpget);
        } catch (ioexception e) {
            e.printstacktrace();
            throw new commonexception("微信支付请求失败");
        }
        // 3.解析返回的数据
        wxchatcallbacksuccessresult callbackdata = resolverresponse(response);
        log.info("微信支付根据商户订单号查询信息========>callbackdata:{}",callbackdata);
        return callbackdata;
    }
    /**
     * 解析响应数据
     * @param response 发送请求成功后,返回的数据
     * @return 微信返回的参数
     */
    private static wxchatcallbacksuccessresult resolverresponse(closeablehttpresponse response) {
        try {
            // 1.获取请求码
            int statuscode = response.getstatusline().getstatuscode();
            // 2.获取返回值 string 格式
            final string bodyasstring = entityutils.tostring(response.getentity());
            gson gson = new gson();
            if (statuscode == 200) {
                // 3.如果请求成功则解析成map对象返回
                hashmap resultmap = gson.fromjson(bodyasstring, hashmap.class);
                // 4.封装成我们需要的数据
                wxchatcallbacksuccessresult callbackdata = new wxchatcallbacksuccessresult();
                callbackdata.setsuccesstime(string.valueof(resultmap.get("success_time")));
                callbackdata.setorderid(string.valueof(resultmap.get("out_trade_no")));
                callbackdata.settransactionid(string.valueof(resultmap.get("transaction_id")));
                callbackdata.settradestate(string.valueof(resultmap.get("trade_state")));
                callbackdata.settradetype(string.valueof(resultmap.get("trade_type")));
                callbackdata.setattach(string.valueof(resultmap.get("attach")));
                string amount = string.valueof(resultmap.get("amount"));
                hashmap amountmap = gson.fromjson(amount, hashmap.class);
                string total = string.valueof(amountmap.get("total"));
                callbackdata.settotalmoney(new bigdecimal(total).movepointleft(2));
                return callbackdata;
            } else {
                if (stringutils.isnoneblank(bodyasstring)) {
                    log.error("微信支付请求失败,提示信息:{}", bodyasstring);
                    // 4.请求码显示失败,则尝试获取提示信息
                    hashmap resultmap = gson.fromjson(bodyasstring, hashmap.class);
                    throw new commonexception(resultmap.get("message"));
                }
                log.error("微信支付请求失败,未查询到原因,提示信息:{}", response);
                // 其他异常,微信也没有返回数据,这就需要具体排查了
                throw new ioexception("request failed");
            }
        } catch (exception e) {
            e.printstacktrace();
            throw new commonexception(e.getmessage());
        } finally {
            try {
                response.close();
            } catch (ioexception e) {
                e.printstacktrace();
            }
        }
    }
}

(3)商家发起转账工具类

/**
 * @author lihao
 * @create 2023-03-22 17:21
 * @desc 发起商家转账工具类
 **/
@slf4j
public class wxpaytransferbatchesutils {
    /**
     * 发起商家转账,支持批量转账
     *
     * @param wxpayconfig 微信配置信息
     * @param param 转账请求参数
     * @param wxpayclient 微信请求客户端()
     * @return 微信支付二维码地址
     */
    public static string transferbatches(wxpayconfig wxpayconfig, wechattransferbatchesparam param, closeablehttpclient wxpayclient) {
        // 1.获取请求参数的map格式
        map paramsmap = getparams(wxpayconfig, param);
        // 2.获取请求对象,wxapitype.transfer_batches="/v3/transfer/batches"
        httppost httppost = gethttppost(wxpayconfig, wxapitype.transfer_batches , paramsmap);
        // 3.完成签名并执行请求
        closeablehttpresponse response = null;
        try {
            response = wxpayclient.execute(httppost);
        } catch (ioexception e) {
            e.printstacktrace();
            throw new commonexception("商家转账请求失败");
        }
        // 4.解析response对象
        hashmap resultmap = resolverresponse(response);
        if (resultmap != null) {
            // batch_id微信批次单号,微信商家转账系统返回的唯一标识
            return resultmap.get("batch_id");
        }
        return null;
    }
    /**
     * 解析响应数据
     * @param response 发送请求成功后,返回的数据
     * @return 微信返回的参数
     */
    private static hashmap resolverresponse(closeablehttpresponse response) {
        try {
            // 1.获取请求码
            int statuscode = response.getstatusline().getstatuscode();
            // 2.获取返回值 string 格式
            final string bodyasstring = entityutils.tostring(response.getentity());
            gson gson = new gson();
            if (statuscode == 200) {
                // 3.如果请求成功则解析成map对象返回
                hashmap resultmap = gson.fromjson(bodyasstring, hashmap.class);
                return resultmap;
            } else {
                if (stringutils.isnoneblank(bodyasstring)) {
                    log.error("商户转账请求失败,提示信息:{}", bodyasstring);
                    // 4.请求码显示失败,则尝试获取提示信息
                    hashmap resultmap = gson.fromjson(bodyasstring, hashmap.class);
                    throw new commonexception(resultmap.get("message"));
                }
                log.error("商户转账请求失败,未查询到原因,提示信息:{}", response);
                // 其他异常,微信也没有返回数据,这就需要具体排查了
                throw new ioexception("request failed");
            }
        } catch (exception e) {
            e.printstacktrace();
            throw new commonexception(e.getmessage());
        } finally {
            try {
                response.close();
            } catch (ioexception e) {
                e.printstacktrace();
            }
        }
    }
    /**
     * 获取请求对象(post请求)
     *
     * @param wxpayconfig 微信配置类
     * @param apitype     接口请求地址
     * @param paramsmap   请求参数
     * @return post请求对象
     */
    private static httppost gethttppost(wxpayconfig wxpayconfig, wxapitype apitype, map paramsmap) {
        // 1.设置请求地址
        httppost httppost = new httppost(wxpayconfig.getdomain().concat(apitype.gettype()));
        // 2.设置请求数据
        gson gson = new gson();
        string jsonparams = gson.tojson(paramsmap);
        // 3.设置请求信息
        stringentity entity = new stringentity(jsonparams, "utf-8");
        entity.setcontenttype("application/json");
        httppost.setentity(entity);
        httppost.setheader("accept", "application/json");
        return httppost;
    }
    /**
     * 封装转账请求参数
     *
     * @param wxpayconfig 微信的配置文件
     * @param param 批量转账请求数据
     * @return 封装后的map对象
     */
    private static map getparams(wxpayconfig wxpayconfig, wechattransferbatchesparam param) {
        map paramsmap = new hashmap<>();
        paramsmap.put("appid", wxpayconfig.getappid());
        paramsmap.put("out_batch_no", param.getbatchid());
        paramsmap.put("batch_name", param.gettitle());
        paramsmap.put("batch_remark", param.getremark());
        paramsmap.put("total_amount", param.gettotalmoney().multiply(new bigdecimal("100")).intvalue());
        paramsmap.put("total_num", param.gettransferdetaillist().size());
        // 存储转账明细,一次最多三千笔
        if (param.gettransferdetaillist().size() > 3000) {
            throw new commonexception("发起批量转账一次最多三千笔");
        }
        list> detaillist = new arraylist<>();
        for (wechattransferbatchesparam.transferdetail detail : param.gettransferdetaillist()) {
            map detailmap = new hashmap<>();
            detailmap.put("out_detail_no",detail.getbatchid());
            detailmap.put("transfer_amount",detail.gettotaldetailmoney().multiply(new bigdecimal("100")).intvalue());
            detailmap.put("transfer_remark",detail.getdetailremark());
            detailmap.put("openid",detail.getopenid());
            detaillist.add(detailmap);
        }
        paramsmap.put("transfer_detail_list", detaillist);
        return paramsmap;
    }
}

本人针对九游会下载的支付方式做了一个简单的通用类(包含native方式、jsapi方式、app方式),如果用不到可不采用

支付通用参数

/**
 * @author lihao
 * @create 2023-03-22 17:48
 * @desc 微信支付通用参数
 **/
@data
public class wechatbasepaydata {
    /**
     * 商品描述
     */
    private string title;
    /**
     * 商家订单号,对应 out_trade_no
     */
    private string orderid;
    /**
     * 订单金额
     */
    private bigdecimal price;
    /**
     * 回调地址
     */
    private string notify;
}

微信支付通用配置

/**
 * @author lihao
 * @create 2023-03-22 17:45
 * @desc 微信通用配置
 **/
@slf4j
public class wxpaycommon {
    /**
     * 创建微信支付订单-native方式
     *
     * @param wxpayconfig 微信配置信息
     * @param basepaydata 基础请求信息,商品标题、商家订单id、订单价格
     * @param wxpayclient 微信请求客户端
     * @return 微信支付二维码地址
     */
    public static string wxnativepay(wxpayconfig wxpayconfig, wechatbasepaydata basepaydata, closeablehttpclient wxpayclient) {
        // 1.获取请求参数的map格式
        map paramsmap = getbasepayparams(wxpayconfig, basepaydata);
        // 2.获取请求对象
        httppost httppost = gethttppost(wxpayconfig, wxapitype.native_pay, paramsmap);
        // 3.完成签名并执行请求
        closeablehttpresponse response = null;
        try {
            response = wxpayclient.execute(httppost);
        } catch (ioexception e) {
            e.printstacktrace();
            throw new commonexception("微信支付请求失败");
        }
        // 4.解析response对象
        hashmap resultmap = resolverresponse(response);
        if (resultmap != null) {
            // native请求返回的是二维码链接,前端将链接转换成二维码即可
            return resultmap.get("code_url");
        }
        return null;
    }
    /**
     * 创建微信支付订单-jsapi方式
     *
     * @param wxpayconfig 微信配置信息
     * @param basepaydata 基础请求信息,商品标题、商家订单id、订单价格
     * @param openid 通过微信小程序或者公众号获取到用户的openid
     * @param wxpayclient 微信请求客户端
     * @return 微信支付二维码地址
     */
    public static string wxjsapipay(wxpayconfig wxpayconfig, wechatbasepaydata basepaydata, string openid,closeablehttpclient wxpayclient) {
        // 1.获取请求参数的map格式
        map paramsmap = getbasepayparams(wxpayconfig, basepaydata);
        // 1.1 添加支付者信息
        map payermap = new hashmap();
        payermap.put("openid",openid);
        paramsmap.put("payer",payermap);
        // 2.获取请求对象
        httppost httppost = gethttppost(wxpayconfig, wxapitype.jsapi_pay, paramsmap);
        // 3.完成签名并执行请求
        closeablehttpresponse response = null;
        try {
            response = wxpayclient.execute(httppost);
        } catch (ioexception e) {
            e.printstacktrace();
            throw new commonexception("微信支付请求失败");
        }
        // 4.解析response对象
        hashmap resultmap = resolverresponse(response);
        if (resultmap != null) {
            // native请求返回的是二维码链接,前端将链接转换成二维码即可
            return resultmap.get("prepay_id");
        }
        return null;
    }
    /**
     * 创建微信支付订单-app方式
     *
     * @param wxpayconfig 微信配置信息
     * @param basepaydata 基础请求信息,商品标题、商家订单id、订单价格
     * @param wxpayclient 微信请求客户端
     * @return 微信支付二维码地址
     */
    public static string wxapppay(wxpayconfig wxpayconfig, wechatbasepaydata basepaydata, closeablehttpclient wxpayclient) {
        // 1.获取请求参数的map格式
        map paramsmap = getbasepayparams(wxpayconfig, basepaydata);
        // 2.获取请求对象
        httppost httppost = gethttppost(wxpayconfig, wxapitype.app_pay, paramsmap);
        // 3.完成签名并执行请求
        closeablehttpresponse response = null;
        try {
            response = wxpayclient.execute(httppost);
        } catch (ioexception e) {
            e.printstacktrace();
            throw new commonexception("微信支付请求失败");
        }
        // 4.解析response对象
        hashmap resultmap = resolverresponse(response);
        if (resultmap != null) {
            // native请求返回的是二维码链接,前端将链接转换成二维码即可
            return resultmap.get("prepay_id");
        }
        return null;
    }
    /**
     * 解析响应数据
     * @param response 发送请求成功后,返回的数据
     * @return 微信返回的参数
     */
    private static hashmap resolverresponse(closeablehttpresponse response) {
        try {
            // 1.获取请求码
            int statuscode = response.getstatusline().getstatuscode();
            // 2.获取返回值 string 格式
            final string bodyasstring = entityutils.tostring(response.getentity());
            gson gson = new gson();
            if (statuscode == 200) {
                // 3.如果请求成功则解析成map对象返回
                hashmap resultmap = gson.fromjson(bodyasstring, hashmap.class);
                return resultmap;
            } else {
                if (stringutils.isnoneblank(bodyasstring)) {
                    log.error("微信支付请求失败,提示信息:{}", bodyasstring);
                    // 4.请求码显示失败,则尝试获取提示信息
                    hashmap resultmap = gson.fromjson(bodyasstring, hashmap.class);
                    throw new commonexception(resultmap.get("message"));
                }
                log.error("微信支付请求失败,未查询到原因,提示信息:{}", response);
                // 其他异常,微信也没有返回数据,这就需要具体排查了
                throw new ioexception("request failed");
            }
        } catch (exception e) {
            e.printstacktrace();
            throw new commonexception(e.getmessage());
        } finally {
            try {
                response.close();
            } catch (ioexception e) {
                e.printstacktrace();
            }
        }
    }
    /**
     * 获取请求对象(post请求)
     *
     * @param wxpayconfig 微信配置类
     * @param apitype     接口请求地址
     * @param paramsmap   请求参数
     * @return post请求对象
     */
    private static httppost gethttppost(wxpayconfig wxpayconfig, wxapitype apitype, map paramsmap) {
        // 1.设置请求地址
        httppost httppost = new httppost(wxpayconfig.getdomain().concat(apitype.gettype()));
        // 2.设置请求数据
        gson gson = new gson();
        string jsonparams = gson.tojson(paramsmap);
        // 3.设置请求信息
        stringentity entity = new stringentity(jsonparams, "utf-8");
        entity.setcontenttype("application/json");
        httppost.setentity(entity);
        httppost.setheader("accept", "application/json");
        return httppost;
    }
    /**
     * 封装基础通用请求参数
     *
     * @param wxpayconfig 微信的配置文件
     * @param basepaydata 微信支付基础请求数据
     * @return 封装后的map对象
     */
    private static map getbasepayparams(wxpayconfig wxpayconfig, wechatbasepaydata basepaydata) {
        map paramsmap = new hashmap<>();
        paramsmap.put("appid", wxpayconfig.getappid());
        paramsmap.put("mchid", wxpayconfig.getmchid());
        // 如果商品名称过长则截取
        string title = basepaydata.gettitle().length() > 62 ? basepaydata.gettitle().substring(0, 62) : basepaydata.gettitle();
        paramsmap.put("description", title);
        paramsmap.put("out_trade_no", basepaydata.getorderid());
        paramsmap.put("notify_url", wxpayconfig.getnotifydomain());
        map amountmap = new hashmap<>();
        amountmap.put("total", basepaydata.getprice().multiply(new bigdecimal("100")).intvalue());
        paramsmap.put("amount", amountmap);
        return paramsmap;
    }
}

支付返回值实体类

package com.qz.client.modular.pay.result;
import io.swagger.annotations.apimodelproperty;
import lombok.getter;
import lombok.setter;
/**
 * @author:lihao
 * @create: 2023-01-09 13:12
 * @description:
 */
@setter
@getter
public class wechatcoderesult {
    @apimodelproperty(value = "微信支付二维码链接")
    private string code_url;
    @apimodelproperty(value = "错误:fail 成功:success")
    private string result_code;
    @apimodelproperty(value = "错误详情")
    private string err_code_des;
    public wechatcoderesult() {
    }
    public wechatcoderesult(string code_url, string result_code, string err_code_des) {
        this.code_url = code_url;
        this.result_code = result_code;
        this.err_code_des = err_code_des;
    }
}

本文标签: springboot