admin管理员组文章数量:1559076
😊 @ 作者: 一恍过去
💖 @ j9九游会老哥俱乐部交流区主页: https://blog.csdn/zhuocailing3390
🎊 @ 社区: java技术栈交流
🎉 @ 主题: 微信支付统一支付接口(h5、jsapi、h5、app、小程序)
⏱️ @ 创作时间: 2022年07月10日
目录
- 前言
- 1、引入pom
- 2、配置yaml
- 3、配置密钥文件
- 4、配置payconfig
- 5、定义统一枚举
- 6、封装统一请求处理
- 7、封装统一代码
- 7.1、统一下单处理
- 7.2 、其他接口处理(退款、查询、取消订单等)
前言
对微信支付的h5、jsapi、h5、app、小程序j9九游会老哥俱乐部交流区的支付方式进行统一,此封装接口适用于普通商户模式支付,如果要进行服务商模式支付可以结合服务商官方api进行参数修改(未验证可行性)。
1、引入pom
<dependency>
<groupid>com.github.wechatpay-apiv3groupid>
<artifactid>wechatpay-apache-httpclientartifactid>
<version>0.4.7version>
dependency>
2、配置yaml
wxpay:
#应用编号
appid: xxxx
#商户号
mchid: xxx
# apiv2密钥
apikey: xxxx
# apiv3密钥
apiv3key: xxx
# 微信支付v3-url前缀
baseurl: https://api.mch.weixin.qq/v3
# 支付通知回调, pjm6m9.natappfree 为内网穿透地址
notifyurl: http://pjm6m9.natappfree/pay/paynotify
# 退款通知回调, pjm6m9.natappfree 为内网穿透地址
refundnotifyurl: http://pjm6m9.natappfree/pay/refundnotify
# 密钥路径,resources根目录下
keypempath: apiclient_key.pem
#商户证书序列号
serialno: xxxxx
3、配置密钥文件
在商户/服务商平台的”账户中心" => “api安全” 进行api证书、密钥的设置,api证书主要用于获取“商户证书序列号”以及“p12”、“key.pem”、”cert.pem“证书文件,j将获取的apiclient_key.pem
文件放在项目的resources
目录下。
4、配置payconfig
wechatpayconfig:
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 lombok.extern.slf4j.slf4j;
import org.apache.http.impl.client.closeablehttpclient;
import org.springframework.boot.context.properties.configurationproperties;
import org.springframework.context.annotation.bean;
import org.springframework.stereotype.component;
import java.io.ioexception;
import java.io.inputstream;
import java.nio.charset.standardcharsets;
import java.security.generalsecurityexception;
import java.security.privatekey;
/**
* @author:
* @description:
**/
@component
@data
@slf4j
@configurationproperties(prefix = "wxpay")
public class wechatpayconfig {
/**
* 应用编号
*/
private string appid;
/**
* 商户号
*/
private string mchid;
/**
* 服务商商户号
*/
private string slmchid;
/**
* apiv2密钥
*/
private string apikey;
/**
* apiv3密钥
*/
private string apiv3key;
/**
* 支付通知回调地址
*/
private string notifyurl;
/**
* 退款回调地址
*/
private string refundnotifyurl;
/**
* api 证书中的 key.pem
*/
private string keypempath;
/**
* 商户序列号
*/
private string serialno;
/**
* 微信支付v3-url前缀
*/
private string baseurl;
/**
* 获取商户的私钥文件
* @param keypempath
* @return
*/
public privatekey getprivatekey(string keypempath){
inputstream inputstream = this.getclass().getclassloader().getresourceasstream(keypempath);
if(inputstream==null){
throw new runtimeexception("私钥文件不存在");
}
return pemutil.loadprivatekey(inputstream);
}
/**
* 获取证书管理器实例
* @return
*/
@bean
public verifier getverifier() throws generalsecurityexception, ioexception, httpcodeexception, notfoundexception {
log.info("获取证书管理器实例");
//获取商户私钥
privatekey privatekey = getprivatekey(keypempath);
//私钥签名对象
privatekeysigner privatekeysigner = new privatekeysigner(serialno, privatekey);
//身份认证对象
wechatpay2credentials wechatpay2credentials = new wechatpay2credentials(mchid, privatekeysigner);
// 使用定时更新的签名验证器,不需要传入证书
certificatesmanager certificatesmanager = certificatesmanager.getinstance();
certificatesmanager.putmerchant(mchid,wechatpay2credentials,apiv3key.getbytes(standardcharsets.utf_8));
return certificatesmanager.getverifier(mchid);
}
/**
* 获取支付http请求对象
* @param verifier
* @return
*/
@bean(name = "wxpayclient")
public closeablehttpclient getwxpayclient(verifier verifier) {
//获取商户私钥
privatekey privatekey = getprivatekey(keypempath);
wechatpayhttpclientbuilder builder = wechatpayhttpclientbuilder.create()
.withmerchant(mchid, serialno, privatekey)
.withvalidator(new wechatpay2validator(verifier));
// 通过wechatpayhttpclientbuilder构造的httpclient,会自动的处理签名和验签,并进行证书自动更新
return builder.build();
}
/**
* 获取httpclient,无需进行应答签名验证,跳过验签的流程
*/
@bean(name = "wxpaynosignclient")
public closeablehttpclient getwxpaynosignclient(){
//获取商户私钥
privatekey privatekey = getprivatekey(keypempath);
//用于构造httpclient
wechatpayhttpclientbuilder builder = wechatpayhttpclientbuilder.create()
//设置商户信息
.withmerchant(mchid, serialno, privatekey)
//无需进行签名验证、通过withvalidator((response) -> true)实现
.withvalidator((response) -> true);
// 通过wechatpayhttpclientbuilder构造的httpclient,会自动的处理签名和验签,并进行证书自动更新
return builder.build();
}
}
5、定义统一枚举
wechatpayurlenum:
@allargsconstructor
@getter
public enum wechatpayurlenum {
/**
* native
*/
native("native"),
/**
* app
*/
app("app"),
/**
* h5
*/
h5("h5"),
/**
* jsapi
*/
jsapi("jsapi"),
/**
* 小程序jsapi
*/
sub_jsapi("sub_jsapi"),
/**
* native下单
*/
pay_transactions("/pay/transactions/"),
/**
* native下单
*/
native_pay_v2("/pay/unifiedorder"),
/**
* 查询订单
*/
order_query_by_no("/pay/transactions/out-trade-no/"),
/**
* 关闭订单
*/
close_order_by_no("/pay/transactions/out-trade-no/%s/close"),
/**
* 申请退款
*/
domestic_refunds("/refund/domestic/refunds"),
/**
* 查询单笔退款
*/
domestic_refunds_query("/refund/domestic/refunds/"),
/**
* 申请交易账单
*/
trade_bills("/bill/tradebill"),
/**
* 申请资金账单
*/
fund_flow_bills("/bill/fundflowbill");
/**
* 类型
*/
private final string type;
}
6、封装统一请求处理
wechatpayrequest:
import lombok.extern.slf4j.slf4j;
import org.apache.http.httpentity;
import org.apache.http.httpstatus;
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.stringentity;
import org.apache.http.impl.client.closeablehttpclient;
import org.apache.http.util.entityutils;
import org.springframework.stereotype.component;
import javax.annotation.resource;
import java.io.ioexception;
/**
* @author:
* @description:
**/
@component
@slf4j
public class wechatpayrequest {
@resource
private closeablehttpclient wxpayclient;
public string wechathttpget(string url) {
try {
// 拼接请求参数
httpget httpget = new httpget(url);
httpget.setheader("accept", "application/json");
//完成签名并执行请求
closeablehttpresponse response = wxpayclient.execute(httpget);
return getresponsebody(response);
}catch (exception e){
throw new runtimeexception(e.getmessage());
}
}
public string wechathttppost(string url,string paramsstr) {
try {
httppost httppost = new httppost(url);
stringentity entity = new stringentity(paramsstr, "utf-8");
entity.setcontenttype("application/json");
httppost.setentity(entity);
httppost.setheader("accept", "application/json");
closeablehttpresponse response = wxpayclient.execute(httppost);
return getresponsebody(response);
}catch (exception e){
throw new runtimeexception(e.getmessage());
}
}
private string getresponsebody(closeablehttpresponse response) throws ioexception {
//响应体
httpentity entity = response.getentity();
string body = entity==null?"":entityutils.tostring(entity);
//响应状态码
int statuscode = response.getstatusline().getstatuscode();
//处理成功,204是,关闭订单时微信返回的正常状态码
if (statuscode == httpstatus.sc_ok || statuscode == httpstatus.sc_no_content) {
log.info("成功, 返回结果 = " body);
} else {
string msg = "微信支付请求失败,响应码 = " statuscode ",返回结果 = " body;
log.error(msg);
throw new runtimeexception(msg);
}
return body;
}
}
7、封装统一代码
对支付接口进行统一的封装,通过传入不同类型(h5、jsapi、app)的j9九游会老哥俱乐部交流区的支付方式,封装公共的请求参数,对不同类型特定参数进行单独的处理。
商户系统先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易会话标识后再按native、jsapi、app、h5等不同场景生成交易串调起支付。
7.1、统一下单处理
paycontroller:
import com.alibaba.fastjson.json;
import com.alibaba.fastjson.jsonobject;
import com.alibaba.fastjson.typereference;
import com.github.xiaoymin.knife4j.annotations.apioperationsupport;
import com.lhz.demo.pay.wechatpayconfig;
import com.lhz.demo.model.enums.wechatpayurlenum;
import com.lhz.demo.pay.wechatpayrequest;
import io.swagger.annotations.api;
import io.swagger.annotations.apioperation;
import lombok.extern.slf4j.slf4j;
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.util.entityutils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.resource;
import javax.crypto.mac;
import javax.crypto.spec.secretkeyspec;
import java.io.*;
import java.nio.charset.standardcharsets;
import java.util.*;
/**
* @author:
* @description:
**/
@api(tags = "支付接口(api3)")
@restcontroller
@requestmapping("/test")
@slf4j
public class paycontroller {
@resource
private wechatpayconfig wechatpayconfig;
@resource
private wechatpayrequest wechatpayrequest;
/**
* 无需应答签名
*/
@resource
private closeablehttpclient wxpaynosignclient;
/**
* type:h5、jsapi、app、native、sub_jsapi
* @param type
* @return
*/
@apioperation(value = "统一下单-统一接口", notes = "统一下单-统一接口")
@apioperationsupport(order = 10)
@getmapping("/transactions")
public map<string,object> transactions(string type) {
log.info("统一下单api,j9九游会老哥俱乐部交流区的支付方式:{}",type);
// 统一参数封装
map<string, object> params = new hashmap<>(8);
params.put("appid", wechatpayconfig.getappid());
params.put("mchid", wechatpayconfig.getmchid());
params.put("description", "测试商品");
int outtradeno = new random().nextint(999999999);
params.put("out_trade_no", outtradeno "");
params.put("notify_url", wechatpayconfig.getnotifyurl());
map<string, object> amountmap = new hashmap<>(4);
// 金额单位为分
amountmap.put("total", 1);
amountmap.put("currency", "cny");
params.put("amount", amountmap);
// 场景信息
map<string, object> sceneinfomap = new hashmap<>(4);
// 客户端ip
sceneinfomap.put("payer_client_ip", "127.0.0.1");
// 商户端设备号(门店号或收银设备id)
sceneinfomap.put("device_id", "127.0.0.1");
// 除h5与jsapi有特殊参数外,其他的j9九游会老哥俱乐部交流区的支付方式都一样
if (type.equals(wechatpayurlenum.h5.gettype())) {
map<string, object> h5infomap = new hashmap<>(4);
// 场景类型:ios, android, wap
h5infomap.put("type", "ios");
sceneinfomap.put("h5_info", h5infomap);
} else if (type.equals(wechatpayurlenum.jsapi.gettype()) || type.equals(wechatpayurlenum.sub_jsapi.gettype())) {
map<string, object> payermap = new hashmap<>(4);
payermap.put("openid", "123123123");
params.put("payer", payermap);
}
params.put("scene_info", sceneinfomap);
string paramsstr = json.tojsonstring(params);
log.info("请求参数 ===> {}" paramsstr);
// 重写type值,因为小程序会多一个下划线(sub_type)
string[] split = type.split("_");
string newtype = split[split.length - 1];
string resstr = wechatpayrequest.wechathttppost(wechatpayconfig.getbaseurl().concat(wechatpayurlenum.pay_transactions.gettype().concat(newtype)), paramsstr);
map<string, object> resmap = jsonobject.parseobject(resstr, new typereference<map<string, object>>(){});
map<string, object> signmap = paysignmsg(resmap, type);
resmap.put("type",type);
resmap.put("signmap",signmap);
return resmap;
}
private map<string, object> paysignmsg(map<string, object> map,string type){
// 设置签名信息,native与h5不需要
if(type.equals(wechatpayurlenum.h5.gettype()) || type.equals(wechatpayurlenum.native.gettype()) ){
return null;
}
long timemillis = system.currenttimemillis();
string appid = wechatpayconfig.getappid();
string timestamp = timemillis/1000"";
string noncestr = timemillis"";
string prepayid = map.get("prepay_id").tostring();
string packagestr = "prepay_id="prepayid;
// 公共参数
map<string, object> resmap = new hashmap<>();
resmap.put("noncestr",noncestr);
resmap.put("timestamp",timestamp);
// jsapi、sub_jsapi(小程序)
if(type.equals(wechatpayurlenum.jsapi.gettype()) || type.equals(wechatpayurlenum.sub_jsapi.gettype()) ) {
resmap.put("appid",appid);
resmap.put("package", packagestr);
// 使用字段appid、timestamp、noncestr、package进行签名
string paysign = createsign(resmap);
resmap.put("paysign", paysign);
resmap.put("signtype", "hmac-sha256");
}
// app
if(type.equals(wechatpayurlenum.app.gettype())) {
resmap.put("appid",appid);
resmap.put("prepayid", prepayid);
// 使用字段appid、timestamp、noncestr、prepayid进行签名
string sign = createsign(resmap);
resmap.put("package", "sign=wxpay");
resmap.put("partnerid", wechatpayconfig.getmchid());
resmap.put("sign", sign);
resmap.put("signtype", "hmac-sha256");
}
return resmap;
}
/**
* 获取加密数据
*/
private string createsign(map<string, object> params){
try {
map<string, object> treemap = new treemap<>(params);
list<string> signlist = new arraylist<>(5);
for (map.entry<string, object> entry : treemap.entryset())
{
signlist.add(entry.getkey() "=" entry.getvalue());
}
string signstr = string.join("&", signlist);
signstr = signstr"&key="wechatpayconfig.getapiv3key();
system.out.println(signstr);
mac sha = mac.getinstance("hmacsha256");
secretkeyspec secretkey = new secretkeyspec(wechatpayconfig.getapiv3key().getbytes(standardcharsets.utf_8), "hmacsha256");
sha.init(secretkey);
byte[] array = sha.dofinal(signstr.getbytes(standardcharsets.utf_8));
stringbuilder sb = new stringbuilder();
for (byte item : array) {
sb.append(integer.tohexstring((item & 0xff) | 0x100), 1, 3);
}
signstr = sb.tostring().touppercase();
system.out.println(signstr);
return signstr;
}catch (exception e){
throw new runtimeexception("加密失败!");
}
}
}
7.2 、其他接口处理(退款、查询、取消订单等)
paycontroller:
import com.alibaba.fastjson.json;
import com.alibaba.fastjson.jsonobject;
import com.alibaba.fastjson.typereference;
import com.github.xiaoymin.knife4j.annotations.apioperationsupport;
import com.lhz.demo.pay.wechatpayconfig;
import com.lhz.demo.model.enums.wechatpayurlenum;
import com.lhz.demo.pay.wechatpayrequest;
import io.swagger.annotations.api;
import io.swagger.annotations.apioperation;
import lombok.extern.slf4j.slf4j;
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.util.entityutils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.resource;
import javax.crypto.mac;
import javax.crypto.spec.secretkeyspec;
import java.io.*;
import java.nio.charset.standardcharsets;
import java.util.*;
/**
* @author: lihuazhi
* @description:
**/
@api(tags = "支付接口(api3)")
@restcontroller
@requestmapping("/test")
@slf4j
public class paycontroller {
@resource
private wechatpayconfig wechatpayconfig;
@resource
private wechatpayrequest wechatpayrequest;
/**
* 无需应答签名
*/
@resource
private closeablehttpclient wxpaynosignclient;
@apioperation(value = "根据订单号查询订单-统一接口", notes = "根据订单号查询订单-统一接口")
@apioperationsupport(order = 15)
@getmapping("/transactions/{orderno}")
public map<string, object> transactionsbyorderno(@pathvariable("orderno") string orderno) {
// todo 如果是扫码支付时,该接口就很有必要,应该前端通过轮询的方式请求该接口查询订单是否支付成功
log.info("根据订单号查询订单,订单号: {}", orderno);
string url = wechatpayconfig.getbaseurl().concat(wechatpayurlenum.order_query_by_no.gettype().concat(orderno))
.concat("?mchid=").concat(wechatpayconfig.getmchid());
string res = wechatpayrequest.wechathttpget(url);
log.info("查询订单结果:{}",res);
map<string, object> resmap = jsonobject.parseobject(res, new typereference<map<string, object>>(){});
string outtradeno = resmap.get("out_trade_no").tostring();
string appid = resmap.get("appid").tostring();
string mchid = resmap.get("mchid").tostring();
/**
* 交易状态,枚举值:
* success:支付成功
* refund:转入退款
* notpay:未支付
* closed:已关闭
* revoked:已撤销(仅付款码支付会返回)
* userpaying:用户支付中(仅付款码支付会返回)
* payerror:支付失败(仅付款码支付会返回)
*/
string tradestate = resmap.get("trade_state").tostring();
log.info("outtradeno:"outtradeno);
log.info("appid:"appid);
log.info("mchid:"mchid);
log.info("tradestate:"tradestate);
return resmap;
}
/**
* 关闭(取消)订单
* @param orderno
* @return
*/
@apioperation(value = "关闭(取消)订单-统一接口", notes = "关闭(取消)订单-统一接口")
@apioperationsupport(order = 20)
@postmapping("/closeorder/{orderno}")
public void closeorder(@pathvariable("orderno") string orderno) {
// todo 用于在客户下单后,不进行支付,取消订单的场景
log.info("根据订单号取消订单,订单号: {}", orderno);
string url = string.format(wechatpayurlenum.close_order_by_no.gettype(), orderno);
url = wechatpayconfig.getbaseurl().concat(url);
// 设置参数
map<string, string> params = new hashmap<>(2);
params.put("mchid", wechatpayconfig.getmchid());
string paramsstr = json.tojsonstring(params);
log.info("请求参数 ===> {}" paramsstr);
string res = wechatpayrequest.wechathttppost(url,paramsstr);
}
/**
* 申请退款
* @param orderno
*/
@apioperation(value = "申请退款-统一接口", notes = "申请退款-统一接口")
@apioperationsupport(order = 25)
@postmapping("/refundorder/{orderno}")
public void refundorder(@pathvariable("orderno") string orderno) {
log.info("根据订单号申请退款,订单号: {}", orderno);
string url = wechatpayconfig.getbaseurl().concat(wechatpayurlenum.domestic_refunds.gettype());
// 设置参数
map<string, object> params = new hashmap<>(2);
// 订单编号
params.put("out_trade_no", orderno);
// 退款单编号 - 自定义
int outrefundno = new random().nextint(999999999);
log.info("退款申请号:{}",outrefundno);
params.put("out_refund_no",outrefundno"");
// 退款原因
params.put("reason","申请退款");
// 退款通知回调地址
params.put("notify_url", wechatpayconfig.getrefundnotifyurl());
map<string, object> amountmap =new hashmap<>();
//退款金额,单位:分
amountmap.put("refund", 1);
//原订单金额,单位:分
amountmap.put("total", 1);
//退款币种
amountmap.put("currency", "cny");
params.put("amount", amountmap);
string paramsstr = json.tojsonstring(params);
log.info("请求参数 ===> {}" paramsstr);
string res = wechatpayrequest.wechathttppost(url,paramsstr);
log.info("退款结果:{}",res);
}
/**
* 查询单笔退款信息
* @param refundno
* @return
*/
@apioperation(value = "查询单笔退款信息-统一接口", notes = "查询单笔退款信息-统一接口")
@apioperationsupport(order = 30)
@getmapping("/queryrefundorder/{refundno}")
public map<string, object> queryrefundorder(@pathvariable("refundno") string refundno) {
log.info("根据订单号查询退款订单,订单号: {}", refundno);
string url = wechatpayconfig.getbaseurl().concat(wechatpayurlenum.domestic_refunds_query.gettype().concat(refundno));
string res = wechatpayrequest.wechathttpget(url);
log.info("查询退款订单结果:{}",res);
map<string, object> resmap = jsonobject.parseobject(res, new typereference<map<string, object>>(){});
string successtime = resmap.get("success_time").tostring();
string refundid = resmap.get("refund_id").tostring();
/**
* 款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往商户平台-交易中心,手动处理此笔退款。
* 枚举值:
* success:退款成功
* closed:退款关闭
* processing:退款处理中
* abnormal:退款异常
*/
string status = resmap.get("status").tostring();
/**
* 枚举值:
* original:原路退款
* balance:退回到余额
* other_balance:原账户异常退到其他余额账户
* other_bankcard:原银行卡异常退到其他银行卡
*/
string channel = resmap.get("channel").tostring();
log.info("successtime:"successtime);
log.info("channel:"channel);
log.info("refundid:"refundid);
log.info("status:"status);
// todo 在查询单笔退款信息时,可以再去查询一次订单的状态,保证该订单已经退款完毕了
return resmap;
}
/**
* 申请交易账单
* @param billdate 格式yyyy-mm-dd 仅支持三个月内的账单下载申请 ,如果传入日期未为当天则会出错
* @param billtype 分为:all、success、refund
* all:返回当日所有订单信息(不含充值退款订单)
* success:返回当日成功支付的订单(不含充值退款订单)
* refund:返回当日退款订单(不含充值退款订单)
* @return
*/
@apioperation(value = "申请交易账单-统一接口", notes = "申请交易账单-统一接口")
@apioperationsupport(order = 35)
@getmapping("/tradebill")
public string tradebill(@requestparam("billdate") string billdate, @requestparam("billtype") string billtype) {
log.info("申请交易账单,billdate:{},billtype:{}", billdate,billtype);
string url = wechatpayconfig.getbaseurl().concat(wechatpayurlenum.trade_bills.gettype())
.concat("?bill_date=").concat(billdate).concat("&bill_type=").concat(billtype);
string res = wechatpayrequest.wechathttpget(url);
log.info("查询退款订单结果:{}",res);
map<string, object> resmap = jsonobject.parseobject(res, new typereference<map<string, object>>(){});
string downloadurl = resmap.get("download_url").tostring();
return downloadurl;
}
/**
*
* @param billdate 格式yyyy-mm-dd 仅支持三个月内的账单下载申请,如果传入日期未为当天则会出错
* @param accounttype 分为:basic、operation、fees
* basic:基本账户
* operation:运营账户
* fees:手续费账户
* @return
*/
@apioperation(value = "申请资金账单-统一接口", notes = "申请资金账单-统一接口")
@apioperationsupport(order = 40)
@getmapping("/fundflowbill")
public string fundflowbill(@requestparam("billdate") string billdate, @requestparam("accounttype") string accounttype) {
log.info("申请交易账单,billdate:{},accounttype:{}", billdate,accounttype);
string url = wechatpayconfig.getbaseurl().concat(wechatpayurlenum.fund_flow_bills.gettype())
.concat("?bill_date=").concat(billdate).concat("&account_type=").concat(accounttype);
string res = wechatpayrequest.wechathttpget(url);
log.info("查询退款订单结果:{}",res);
map<string, object> resmap = jsonobject.parseobject(res, new typereference<map<string, object>>(){});
string downloadurl = resmap.get("download_url").tostring();
return downloadurl;
}
@apioperation(value = "下载账单-统一接口", notes = "下载账单-统一接口")
@apioperationsupport(order = 45)
@getmapping("/downloadbill")
public void downloadbill(string downloadurl) {
log.info("下载账单,下载地址:{}",downloadurl);
httpget httpget = new httpget(downloadurl);
httpget.addheader("accept", "application/json");
closeablehttpresponse response =null;
try {
//使用wxpayclient发送请求得到响应
response = wxpaynosignclient.execute(httpget);
string body = entityutils.tostring(response.getentity());
int statuscode = response.getstatusline().getstatuscode();
if (statuscode == 200 || statuscode == 204) {
log.info("下载账单,返回结果 = " body);
} else {
throw new runtimeexception("下载账单异常, 响应码 = " statuscode ", 下载账单返回结果 = " body);
}
// todo 将body内容转为excel存入本地或者输出到浏览器,演示存入本地
writestringtofile(body);
}catch (exception e){
throw new runtimeexception(e.getmessage());
}
finally {
if(response!=null) {
try {
response.close();
} catch (ioexception e) {
e.printstacktrace();
}
}
}
}
private void writestringtofile(string body) {
filewriter fw = null;
try {
string filepath = "c:\\users\\lhz12\\desktop\\wxpay.txt";
fw = new filewriter(filepath, true);
bufferedwriter bw = new bufferedwriter(fw);
bw.write(body);
} catch (exception e) {
e.printstacktrace();
}finally {
try {
if(fw!=null) {
fw.close();
}
} catch (ioexception e) {
e.printstacktrace();
}
}
}
}
本文标签:
j9九游会老哥俱乐部交流区的版权声明:本文标题:微信支付apiv3统一支付接口(h5、jsapi、h5、app、小程序) 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/dongtai/1727372621a1111363.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论