mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2026-03-10 00:13:40 +08:00
微信支付相关代码独立成一个子模块
This commit is contained in:
@@ -3,7 +3,6 @@ package me.chanjar.weixin.mp.api;
|
||||
import me.chanjar.weixin.common.bean.WxAccessToken;
|
||||
import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.io.File;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
@@ -80,39 +79,8 @@ public interface WxMpConfigStorage {
|
||||
|
||||
String getAppId();
|
||||
|
||||
/**
|
||||
* 服务商模式下的子商户公众账号ID
|
||||
*/
|
||||
String getSubAppId();
|
||||
|
||||
/**
|
||||
* 服务商模式下的子商户号
|
||||
*/
|
||||
String getSubMchId();
|
||||
|
||||
String getSecret();
|
||||
|
||||
String getPartnerId();
|
||||
|
||||
String getPartnerKey();
|
||||
|
||||
/**
|
||||
* 微信支付异步回掉地址,通知url必须为直接可访问的url,不能携带参数。
|
||||
*
|
||||
* @since 2.5.0
|
||||
*/
|
||||
String getNotifyURL();
|
||||
|
||||
/**
|
||||
* 交易类型
|
||||
* <pre>
|
||||
* JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付
|
||||
* </pre>
|
||||
*
|
||||
* @since 2.5.0
|
||||
*/
|
||||
String getTradeType();
|
||||
|
||||
String getToken();
|
||||
|
||||
String getAesKey();
|
||||
@@ -131,17 +99,6 @@ public interface WxMpConfigStorage {
|
||||
|
||||
File getTmpDirFile();
|
||||
|
||||
SSLContext getSslContext();
|
||||
|
||||
void setSslContext(SSLContext sslContext);
|
||||
|
||||
/**
|
||||
* 在此之前,必须将partnerId进行赋值
|
||||
*
|
||||
* @param filePath apiclient_cert.p12的文件的绝对路径
|
||||
*/
|
||||
void setSslContextFilePath(String filePath) throws Exception;
|
||||
|
||||
/**
|
||||
* http client builder
|
||||
*
|
||||
@@ -154,8 +111,4 @@ public interface WxMpConfigStorage {
|
||||
*/
|
||||
boolean autoRefreshToken();
|
||||
|
||||
/**
|
||||
* 微信支付是否使用仿真测试环境
|
||||
*/
|
||||
boolean useSandboxForWxPay();
|
||||
}
|
||||
|
||||
@@ -3,12 +3,8 @@ package me.chanjar.weixin.mp.api;
|
||||
import me.chanjar.weixin.common.bean.WxAccessToken;
|
||||
import me.chanjar.weixin.common.util.ToStringUtils;
|
||||
import me.chanjar.weixin.common.util.http.ApacheHttpClientBuilder;
|
||||
import org.apache.http.ssl.SSLContexts;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.security.KeyStore;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
@@ -20,13 +16,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
|
||||
|
||||
protected volatile String appId;
|
||||
protected volatile String subAppId;
|
||||
protected volatile String subMchId;
|
||||
protected volatile String secret;
|
||||
protected volatile String partnerId;
|
||||
protected volatile String partnerKey;
|
||||
protected volatile String notifyURL;
|
||||
protected volatile String tradeType;
|
||||
protected volatile String token;
|
||||
protected volatile String accessToken;
|
||||
protected volatile String aesKey;
|
||||
@@ -54,8 +44,6 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
|
||||
*/
|
||||
protected volatile File tmpDirFile;
|
||||
|
||||
protected volatile SSLContext sslContext;
|
||||
|
||||
protected volatile ApacheHttpClientBuilder apacheHttpClientBuilder;
|
||||
|
||||
@Override
|
||||
@@ -257,41 +245,6 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
|
||||
return ToStringUtils.toSimpleString(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPartnerId() {
|
||||
return this.partnerId;
|
||||
}
|
||||
|
||||
public void setPartnerId(String partnerId) {
|
||||
this.partnerId = partnerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPartnerKey() {
|
||||
return this.partnerKey;
|
||||
}
|
||||
|
||||
public void setPartnerKey(String partnerKey) {
|
||||
this.partnerKey = partnerKey;
|
||||
}
|
||||
|
||||
|
||||
public String getNotifyURL() {
|
||||
return notifyURL;
|
||||
}
|
||||
|
||||
public void setNotifyURL(String notifyURL) {
|
||||
this.notifyURL = notifyURL;
|
||||
}
|
||||
|
||||
public String getTradeType() {
|
||||
return tradeType;
|
||||
}
|
||||
|
||||
public void setTradeType(String tradeType) {
|
||||
this.tradeType = tradeType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getTmpDirFile() {
|
||||
return this.tmpDirFile;
|
||||
@@ -301,38 +254,6 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
|
||||
this.tmpDirFile = tmpDirFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLContext getSslContext() {
|
||||
return this.sslContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSslContext(SSLContext context) {
|
||||
this.sslContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSslContextFilePath(String filePath) {
|
||||
if (null == partnerId) {
|
||||
throw new IllegalArgumentException("请设置partnerId的值");
|
||||
}
|
||||
|
||||
File file = new File(filePath);
|
||||
if (!file.exists()) {
|
||||
throw new RuntimeException("证书文件:【" + file.getPath() + "】不存在!");
|
||||
}
|
||||
|
||||
try {
|
||||
FileInputStream inputStream = new FileInputStream(file);
|
||||
KeyStore keystore = KeyStore.getInstance("PKCS12");
|
||||
char[] partnerId2charArray = partnerId.toCharArray();
|
||||
keystore.load(inputStream, partnerId2charArray);
|
||||
this.sslContext = SSLContexts.custom().loadKeyMaterial(keystore, partnerId2charArray).build();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("证书文件有问题,请核实!", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApacheHttpClientBuilder getApacheHttpClientBuilder() {
|
||||
return this.apacheHttpClientBuilder;
|
||||
@@ -347,26 +268,4 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useSandboxForWxPay() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSubAppId() {
|
||||
return subAppId;
|
||||
}
|
||||
|
||||
public void setSubAppId(String subAppId) {
|
||||
this.subAppId = subAppId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSubMchId() {
|
||||
return subMchId;
|
||||
}
|
||||
|
||||
public void setSubMchId(String subMchId) {
|
||||
this.subMchId = subMchId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,299 +0,0 @@
|
||||
package me.chanjar.weixin.mp.api;
|
||||
|
||||
import me.chanjar.weixin.common.exception.WxErrorException;
|
||||
import me.chanjar.weixin.mp.bean.pay.request.*;
|
||||
import me.chanjar.weixin.mp.bean.pay.result.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 微信支付相关接口
|
||||
* Created by Binary Wang on 2016/7/28.
|
||||
*
|
||||
* @author binarywang (https://github.com/binarywang)
|
||||
*/
|
||||
public interface WxMpPayService {
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 查询订单(详见https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_2)
|
||||
* 该接口提供所有微信支付订单的查询,商户可以通过查询订单接口主动查询订单状态,完成下一步的业务逻辑。
|
||||
* 需要调用查询接口的情况:
|
||||
* ◆ 当商户后台、网络、服务器等出现异常,商户系统最终未接收到支付通知;
|
||||
* ◆ 调用支付接口后,返回系统错误或未知交易状态情况;
|
||||
* ◆ 调用被扫支付API,返回USERPAYING的状态;
|
||||
* ◆ 调用关单或撤销接口API之前,需确认支付状态;
|
||||
* 接口地址:https://api.mch.weixin.qq.com/pay/orderquery
|
||||
* </pre>
|
||||
*
|
||||
* @param transactionId 微信订单号
|
||||
* @param outTradeNo 商户系统内部的订单号,当没提供transactionId时需要传这个。
|
||||
*/
|
||||
WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 关闭订单
|
||||
* 应用场景
|
||||
* 以下情况需要调用关单接口:
|
||||
* 1. 商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付;
|
||||
* 2. 系统下单后,用户支付超时,系统退出不再受理,避免用户继续,请调用关单接口。
|
||||
* 注意:订单生成后不能马上调用关单接口,最短调用时间间隔为5分钟。
|
||||
* 接口地址:https://api.mch.weixin.qq.com/pay/closeorder
|
||||
* 是否需要证书: 不需要。
|
||||
* </pre>
|
||||
*
|
||||
* @param outTradeNo 商户系统内部的订单号
|
||||
*/
|
||||
WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 统一下单(详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1)
|
||||
* 在发起微信支付前,需要调用统一下单接口,获取"预支付交易会话标识"
|
||||
* 接口地址:https://api.mch.weixin.qq.com/pay/unifiedorder
|
||||
*
|
||||
* @param request 请求对象,注意一些参数如appid、mchid等不用设置,方法内会自动从配置对象中获取到(前提是对应配置中已经设置)
|
||||
*/
|
||||
WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 该接口调用“统一下单”接口,并拼装发起支付请求需要的参数
|
||||
* 详见http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN
|
||||
*
|
||||
* @param request 请求对象,注意一些参数如appid、mchid等不用设置,方法内会自动从配置对象中获取到(前提是对应配置中已经设置)
|
||||
*/
|
||||
Map<String, String> getPayInfo(WxPayUnifiedOrderRequest request) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 微信支付-申请退款
|
||||
* 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
|
||||
* 接口链接:https://api.mch.weixin.qq.com/secapi/pay/refund
|
||||
* </pre>
|
||||
*
|
||||
* @param request 请求对象
|
||||
* @return 退款操作结果
|
||||
*/
|
||||
WxPayRefundResult refund(WxPayRefundRequest request) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 微信支付-查询退款
|
||||
* 应用场景:
|
||||
* 提交退款申请后,通过调用该接口查询退款状态。退款有一定延时,用零钱支付的退款20分钟内到账,银行卡支付的退款3个工作日后重新查询退款状态。
|
||||
* 详见 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_5
|
||||
* 接口链接:https://api.mch.weixin.qq.com/pay/refundquery
|
||||
* </pre>
|
||||
* 以下四个参数四选一
|
||||
*
|
||||
* @param transactionId 微信订单号
|
||||
* @param outTradeNo 商户订单号
|
||||
* @param outRefundNo 商户退款单号
|
||||
* @param refundId 微信退款单号
|
||||
* @return 退款信息
|
||||
*/
|
||||
WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, String outRefundNo, String refundId) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 读取支付结果通知
|
||||
* 详见http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7
|
||||
*/
|
||||
WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 微信公众号支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3)
|
||||
*
|
||||
* @param xmlbean Bean需要标记有XML注解,默认使用配置中的PartnerKey进行签名
|
||||
* @return 签名字符串
|
||||
* @see #createSign(Map, String)
|
||||
* @since 2.5.0
|
||||
*/
|
||||
String createSign(Object xmlbean);
|
||||
|
||||
/**
|
||||
* 微信公众号支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3)
|
||||
*
|
||||
* @param xmlbean Bean需要标记有XML注解
|
||||
* @param signKey 签名Key
|
||||
* @return 签名字符串
|
||||
* @see #createSign(Map, String)
|
||||
*/
|
||||
String createSign(Object xmlbean, String signKey);
|
||||
|
||||
/**
|
||||
* 微信公众号支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3)
|
||||
*
|
||||
* @param prams 参数信息,默认使用配置中的PartnerKey进行签名
|
||||
* @return 签名字符串
|
||||
* @see #createSign(Map, String)
|
||||
*/
|
||||
String createSign(Map<String, String> prams);
|
||||
|
||||
|
||||
/**
|
||||
* 微信公众号支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3)
|
||||
*
|
||||
* @param prams 参数信息
|
||||
* @param signKey 签名Key
|
||||
* @return 签名字符串
|
||||
*/
|
||||
String createSign(Map<String, String> prams, String signKey);
|
||||
|
||||
|
||||
/**
|
||||
* 校验签名是否正确,默认使用配置中的PartnerKey进行签名
|
||||
*
|
||||
* @param xmlbean Bean需要标记有XML注解
|
||||
* @return true - 签名校验成功,false - 签名校验失败
|
||||
* @see #checkSign(Map, String)
|
||||
*/
|
||||
boolean checkSign(Object xmlbean);
|
||||
|
||||
/**
|
||||
* 校验签名是否正确
|
||||
*
|
||||
* @param xmlbean Bean需要标记有XML注解
|
||||
* @param signKey 校验的签名Key
|
||||
* @return true - 签名校验成功,false - 签名校验失败
|
||||
* @see #checkSign(Map, String)
|
||||
*/
|
||||
boolean checkSign(Object xmlbean, String signKey);
|
||||
|
||||
/**
|
||||
* 校验签名是否正确,默认使用配置中的PartnerKey进行签名
|
||||
*
|
||||
* @param prams 需要校验的参数Map
|
||||
* @return true - 签名校验成功,false - 签名校验失败
|
||||
* @see #checkSign(Map, String)
|
||||
*/
|
||||
boolean checkSign(Map<String, String> prams);
|
||||
|
||||
/**
|
||||
* 校验签名是否正确
|
||||
*
|
||||
* @param params 需要校验的参数Map
|
||||
* @param signKey 校验的签名Key
|
||||
* @return true - 签名校验成功,false - 签名校验失败
|
||||
* @see #checkSign(Map, String)
|
||||
*/
|
||||
boolean checkSign(Map<String, String> params, String signKey);
|
||||
|
||||
/**
|
||||
* 发送微信红包给个人用户
|
||||
* <pre>
|
||||
* 文档详见:
|
||||
* 发送普通红包 https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_4&index=3
|
||||
* 接口地址:https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack
|
||||
* 发送裂变红包 https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=13_5&index=4
|
||||
* 接口地址:https://api.mch.weixin.qq.com/mmpaymkttransfers/sendgroupredpack
|
||||
* </pre>
|
||||
*
|
||||
* @param request 请求对象
|
||||
*/
|
||||
WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 查询红包记录
|
||||
* 用于商户对已发放的红包进行查询红包的具体信息,可支持普通红包和裂变包。
|
||||
* 请求Url https://api.mch.weixin.qq.com/mmpaymkttransfers/gethbinfo
|
||||
* 是否需要证书 是(证书及使用说明详见商户证书)
|
||||
* 请求方式 POST
|
||||
* </pre>
|
||||
*
|
||||
* @param mchBillNo 商户发放红包的商户订单号,比如10000098201411111234567890
|
||||
*/
|
||||
WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 企业付款业务是基于微信支付商户平台的资金管理能力,为了协助商户方便地实现企业向个人付款,针对部分有开发能力的商户,提供通过API完成企业付款的功能。
|
||||
* 比如目前的保险行业向客户退保、给付、理赔。
|
||||
* 企业付款将使用商户的可用余额,需确保可用余额充足。查看可用余额、充值、提现请登录商户平台“资金管理”https://pay.weixin.qq.com/进行操作。
|
||||
* 注意:与商户微信支付收款资金并非同一账户,需要单独充值。
|
||||
* 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2
|
||||
* 接口链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers
|
||||
* </pre>
|
||||
*
|
||||
* @param request 请求对象
|
||||
*/
|
||||
WxEntPayResult entPay(WxEntPayRequest request) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 查询企业付款API
|
||||
* 用于商户的企业付款操作进行结果查询,返回付款操作详细结果。
|
||||
* 文档详见:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_3
|
||||
* 接口链接:https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo
|
||||
* </pre>
|
||||
*
|
||||
* @param partnerTradeNo 商户订单号
|
||||
*/
|
||||
WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 扫码支付模式一生成二维码的方法
|
||||
* 二维码中的内容为链接,形式为:
|
||||
* weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX
|
||||
* 其中XXXXX为商户需要填写的内容,商户将该链接生成二维码,如需要打印发布二维码,需要采用此格式。商户可调用第三方库生成二维码图片。
|
||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4
|
||||
* </pre>
|
||||
*
|
||||
* @param productId 产品Id
|
||||
* @param sideLength 要生成的二维码的边长,如果为空,则取默认值400
|
||||
* @param logoFile 商户logo图片的文件对象,可以为空
|
||||
* @return 生成的二维码的字节数组
|
||||
*/
|
||||
byte[] createScanPayQrcodeMode1(String productId, File logoFile, Integer sideLength);
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 扫码支付模式二生成二维码的方法
|
||||
* 对应链接格式:weixin://wxpay/bizpayurl?sr=XXXXX。请商户调用第三方库将code_url生成二维码图片。
|
||||
* 该模式链接较短,生成的二维码打印到结账小票上的识别率较高。
|
||||
* 文档详见: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5
|
||||
* </pre>
|
||||
*
|
||||
* @param codeUrl 微信返回的交易会话的二维码链接
|
||||
* @param logoFile 商户logo图片的文件对象,可以为空
|
||||
* @param sideLength 要生成的二维码的边长,如果为空,则取默认值400
|
||||
* @return 生成的二维码的字节数组
|
||||
*/
|
||||
byte[] createScanPayQrcodeMode2(String codeUrl, File logoFile, Integer sideLength);
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 交易保障
|
||||
* 应用场景:
|
||||
* 商户在调用微信支付提供的相关接口时,会得到微信支付返回的相关信息以及获得整个接口的响应时间。
|
||||
* 为提高整体的服务水平,协助商户一起提高服务质量,微信支付提供了相关接口调用耗时和返回信息的主动上报接口,
|
||||
* 微信支付可以根据商户侧上报的数据进一步优化网络部署,完善服务监控,和商户更好的协作为用户提供更好的业务体验。
|
||||
* 接口地址: https://api.mch.weixin.qq.com/payitil/report
|
||||
* 是否需要证书:不需要
|
||||
* </pre>
|
||||
*/
|
||||
void report(WxPayReportRequest request) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 下载对账单
|
||||
* 商户可以通过该接口下载历史交易清单。比如掉单、系统错误等导致商户侧和微信侧数据不一致,通过对账单核对后可校正支付状态。
|
||||
* 注意:
|
||||
* 1、微信侧未成功下单的交易不会出现在对账单中。支付成功后撤销的交易会出现在对账单中,跟原支付单订单号一致,bill_type为REVOKED;
|
||||
* 2、微信在次日9点启动生成前一天的对账单,建议商户10点后再获取;
|
||||
* 3、对账单中涉及金额的字段单位为“元”。
|
||||
* 4、对账单接口只能下载三个月以内的账单。
|
||||
* 接口链接:https://api.mch.weixin.qq.com/pay/downloadbill
|
||||
* 详情请见: <a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_6">下载对账单</a>
|
||||
* </pre>
|
||||
*
|
||||
* @param billDate 对账单日期 bill_date 下载对账单的日期,格式:20140603
|
||||
* @param billType 账单类型 bill_type ALL,返回当日所有订单信息,默认值,SUCCESS,返回当日成功支付的订单,REFUND,返回当日退款订单
|
||||
* @param tarType 压缩账单 tar_type 非必传参数,固定值:GZIP,返回格式为.gzip的压缩包账单。不传则默认为数据流形式。
|
||||
* @param deviceInfo 设备号 device_info 非必传参数,终端设备号
|
||||
* @return 保存到本地的临时文件
|
||||
*/
|
||||
File downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxErrorException;
|
||||
}
|
||||
@@ -311,13 +311,6 @@ public interface WxMpService {
|
||||
*/
|
||||
WxMpCardService getCardService();
|
||||
|
||||
/**
|
||||
* 返回微信支付相关接口方法的实现类对象,以方便调用其各个接口
|
||||
*
|
||||
* @return WxMpPayService
|
||||
*/
|
||||
WxMpPayService getPayService();
|
||||
|
||||
/**
|
||||
* 返回数据分析统计相关接口方法的实现类对象,以方便调用其各个接口
|
||||
*
|
||||
|
||||
@@ -1,533 +0,0 @@
|
||||
package me.chanjar.weixin.mp.api.impl;
|
||||
|
||||
import com.github.binarywang.utils.qrcode.QrcodeUtils;
|
||||
import com.google.common.collect.Maps;
|
||||
import me.chanjar.weixin.common.bean.result.WxError;
|
||||
import me.chanjar.weixin.common.exception.WxErrorException;
|
||||
import me.chanjar.weixin.common.util.BeanUtils;
|
||||
import me.chanjar.weixin.mp.api.WxMpConfigStorage;
|
||||
import me.chanjar.weixin.mp.api.WxMpPayService;
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
import me.chanjar.weixin.mp.bean.pay.request.*;
|
||||
import me.chanjar.weixin.mp.bean.pay.result.*;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.Consts;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
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 org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Created by Binary Wang on 2016/7/28.
|
||||
*
|
||||
* @author binarywang (https://github.com/binarywang)
|
||||
*/
|
||||
public class WxMpPayServiceImpl implements WxMpPayService {
|
||||
|
||||
private static final String PAY_BASE_URL = "https://api.mch.weixin.qq.com";
|
||||
private static final String[] TRADE_TYPES = new String[]{"JSAPI", "NATIVE", "APP"};
|
||||
private static final String[] REFUND_ACCOUNT = new String[]{"REFUND_SOURCE_RECHARGE_FUNDS", "REFUND_SOURCE_UNSETTLED_FUNDS"};
|
||||
private static final String[] BILL_TYPE = new String[]{"ALL","REFUND","SUCCESS"};;
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
private WxMpService wxMpService;
|
||||
|
||||
public WxMpPayServiceImpl(WxMpService wxMpService) {
|
||||
this.wxMpService = wxMpService;
|
||||
}
|
||||
|
||||
private WxMpConfigStorage getConfig() {
|
||||
return wxMpService.getWxMpConfigStorage();
|
||||
}
|
||||
|
||||
private String getPayBaseUrl(){
|
||||
if(this.getConfig().useSandboxForWxPay()){
|
||||
return PAY_BASE_URL + "/sandboxnew";
|
||||
}
|
||||
|
||||
return PAY_BASE_URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxPayRefundResult refund(WxPayRefundRequest request) throws WxErrorException {
|
||||
this.initRequest(request);
|
||||
if (StringUtils.isBlank(request.getOpUserId())) {
|
||||
request.setOpUserId(this.getConfig().getPartnerId());
|
||||
}
|
||||
this.checkParameters(request);
|
||||
request.setSign(this.createSign(request));
|
||||
|
||||
String url = this.getPayBaseUrl() + "/secapi/pay/refund";
|
||||
String responseContent = this.executeWithKey(url, request.toXML());
|
||||
WxPayRefundResult result = WxPayRefundResult.fromXML(responseContent, WxPayRefundResult.class);
|
||||
this.checkResult(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, String outRefundNo, String refundId) throws WxErrorException {
|
||||
if ((StringUtils.isBlank(transactionId) && StringUtils.isBlank(outTradeNo) && StringUtils.isBlank(outRefundNo) && StringUtils.isBlank(refundId)) ||
|
||||
(StringUtils.isNotBlank(transactionId) && StringUtils.isNotBlank(outTradeNo) && StringUtils.isNotBlank(outRefundNo) && StringUtils.isNotBlank(refundId))) {
|
||||
throw new IllegalArgumentException("transaction_id , out_trade_no,out_refund_no, refund_id 必须四选一");
|
||||
}
|
||||
|
||||
WxPayRefundQueryRequest request = new WxPayRefundQueryRequest();
|
||||
this.initRequest(request);
|
||||
request.setOutTradeNo(StringUtils.trimToNull(outTradeNo));
|
||||
request.setTransactionId(StringUtils.trimToNull(transactionId));
|
||||
request.setOutRefundNo(StringUtils.trimToNull(outRefundNo));
|
||||
request.setRefundId(StringUtils.trimToNull(refundId));
|
||||
request.setSign(this.createSign(request));
|
||||
|
||||
String url = this.getPayBaseUrl() + "/pay/refundquery";
|
||||
String responseContent = this.executeRequest(url, request.toXML());
|
||||
WxPayRefundQueryResult result = WxPayRefundQueryResult.fromXML(responseContent, WxPayRefundQueryResult.class);
|
||||
result.composeRefundRecords();
|
||||
this.checkResult(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private void checkResult(WxPayBaseResult result) throws WxErrorException {
|
||||
//校验返回结果签名
|
||||
Map<String, String> map = result.toMap();
|
||||
if (result.getSign() != null &&!this.checkSign(map)) {
|
||||
log.debug("校验结果签名失败,参数:{}", map);
|
||||
throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg("参数格式校验错误!").build());
|
||||
}
|
||||
|
||||
//校验结果是否成功
|
||||
if (!"SUCCESS".equalsIgnoreCase(result.getReturnCode())
|
||||
|| !"SUCCESS".equalsIgnoreCase(result.getResultCode())) {
|
||||
WxError error = WxError.newBuilder().setErrorCode(-1)
|
||||
.setErrorMsg("返回代码: " + result.getReturnCode() + ", 返回信息: "
|
||||
+ result.getReturnMsg() + ", 结果代码: " + result.getResultCode() + ", 错误代码: "
|
||||
+ result.getErrCode() + ", 错误详情: " + result.getErrCodeDes())
|
||||
.build();
|
||||
log.error("结果业务代码异常,参数:{},详细:{}", map, error);
|
||||
throw new WxErrorException(error);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkParameters(WxPayDownloadBillRequest request) throws WxErrorException {
|
||||
BeanUtils.checkRequiredFields(request);
|
||||
|
||||
if (StringUtils.isNotBlank(request.getTarType()) && !"GZIP".equals(request.getTarType())) {
|
||||
throw new IllegalArgumentException("tar_type值如果存在,只能为GZIP");
|
||||
}
|
||||
|
||||
if ( !ArrayUtils.contains(BILL_TYPE, request.getBillType())) {
|
||||
throw new IllegalArgumentException("bill_tpye目前必须为" + Arrays.toString(BILL_TYPE) + "其中之一,实际值:" + request.getBillType());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void checkParameters(WxPayRefundRequest request) throws WxErrorException {
|
||||
BeanUtils.checkRequiredFields(request);
|
||||
|
||||
if (StringUtils.isNotBlank(request.getRefundAccount())) {
|
||||
if (!ArrayUtils.contains(REFUND_ACCOUNT, request.getRefundAccount())) {
|
||||
throw new IllegalArgumentException("refund_account目前必须为" + Arrays.toString(REFUND_ACCOUNT) + "其中之一,实际值:" + request.getRefundAccount());
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(request.getOutTradeNo()) && StringUtils.isBlank(request.getTransactionId())) {
|
||||
throw new IllegalArgumentException("transaction_id 和 out_trade_no 不能同时为空,必须提供一个");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxPayOrderNotifyResult getOrderNotifyResult(String xmlData) throws WxErrorException {
|
||||
try {
|
||||
log.trace("微信支付回调参数详细:{}", xmlData);
|
||||
WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlData);
|
||||
log.debug("微信支付回调结果对象:{}", result);
|
||||
this.checkResult(result);
|
||||
return result;
|
||||
} catch (WxErrorException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw new WxErrorException(WxError.newBuilder().setErrorMsg("发生异常" + e.getMessage()).build());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxPaySendRedpackResult sendRedpack(WxPaySendRedpackRequest request)
|
||||
throws WxErrorException {
|
||||
this.initRequest(request);
|
||||
request.setSign(this.createSign(request));
|
||||
|
||||
String url = this.getPayBaseUrl() + "/mmpaymkttransfers/sendredpack";
|
||||
if (request.getAmtType() != null) {
|
||||
//裂变红包
|
||||
url = this.getPayBaseUrl() + "/mmpaymkttransfers/sendgroupredpack";
|
||||
}
|
||||
String responseContent = this.executeWithKey(url, request.toXML());
|
||||
WxPaySendRedpackResult result = WxPaySendRedpackResult.fromXML(responseContent, WxPaySendRedpackResult.class);
|
||||
//毋须校验,因为没有返回签名信息
|
||||
// this.checkResult(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxPayRedpackQueryResult queryRedpack(String mchBillNo) throws WxErrorException {
|
||||
WxPayRedpackQueryRequest request = new WxPayRedpackQueryRequest();
|
||||
request.setMchBillNo(mchBillNo);
|
||||
request.setBillType("MCHT");
|
||||
initRequest(request);
|
||||
request.setSign(this.createSign(request));
|
||||
|
||||
String url = this.getPayBaseUrl() + "/mmpaymkttransfers/gethbinfo";
|
||||
String responseContent = this.executeWithKey(url, request.toXML());
|
||||
WxPayRedpackQueryResult result = WxPayRedpackQueryResult.fromXML(responseContent, WxPayRedpackQueryResult.class);
|
||||
this.checkResult(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxErrorException {
|
||||
if ((StringUtils.isBlank(transactionId) && StringUtils.isBlank(outTradeNo)) ||
|
||||
(StringUtils.isNotBlank(transactionId) && StringUtils.isNotBlank(outTradeNo))) {
|
||||
throw new IllegalArgumentException("transaction_id 和 out_trade_no 不能同时存在或同时为空,必须二选一");
|
||||
}
|
||||
|
||||
WxPayOrderQueryRequest request = new WxPayOrderQueryRequest();
|
||||
request.setOutTradeNo(StringUtils.trimToNull(outTradeNo));
|
||||
request.setTransactionId(StringUtils.trimToNull(transactionId));
|
||||
initRequest(request);
|
||||
request.setSign(this.createSign(request));
|
||||
|
||||
String url = this.getPayBaseUrl() + "/pay/orderquery";
|
||||
String responseContent = this.executeRequest(url, request.toXML());
|
||||
WxPayOrderQueryResult result = WxPayOrderQueryResult.fromXML(responseContent, WxPayOrderQueryResult.class);
|
||||
result.composeCoupons();
|
||||
this.checkResult(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxErrorException {
|
||||
if (StringUtils.isBlank(outTradeNo)) {
|
||||
throw new IllegalArgumentException("out_trade_no 不能为空");
|
||||
}
|
||||
|
||||
WxPayOrderCloseRequest request = new WxPayOrderCloseRequest();
|
||||
request.setOutTradeNo(StringUtils.trimToNull(outTradeNo));
|
||||
initRequest(request);
|
||||
request.setSign(this.createSign(request));
|
||||
|
||||
String url = this.getPayBaseUrl() + "/pay/closeorder";
|
||||
String responseContent = this.executeRequest(url, request.toXML());
|
||||
WxPayOrderCloseResult result = WxPayOrderCloseResult.fromXML(responseContent, WxPayOrderCloseResult.class);
|
||||
this.checkResult(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request)
|
||||
throws WxErrorException {
|
||||
|
||||
this.initRequest(request);
|
||||
if (StringUtils.isBlank(request.getNotifyURL())) {
|
||||
request.setNotifyURL(getConfig().getNotifyURL());
|
||||
}
|
||||
if (StringUtils.isBlank(request.getTradeType())) {
|
||||
request.setTradeType(getConfig().getTradeType());
|
||||
}
|
||||
checkParameters(request);//校验参数
|
||||
request.setSign(this.createSign(request));
|
||||
|
||||
String url = this.getPayBaseUrl() + "/pay/unifiedorder";
|
||||
String xmlParam = request.toXML();
|
||||
log.debug("微信统一下单接口,URL:{},参数:{}", url, xmlParam);
|
||||
|
||||
String responseContent = this.executeRequest(url, xmlParam);
|
||||
log.debug("微信统一下单接口,URL:{},结果:{}", url, responseContent);
|
||||
WxPayUnifiedOrderResult result = WxPayUnifiedOrderResult.fromXML(responseContent, WxPayUnifiedOrderResult.class);
|
||||
this.checkResult(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void initRequest(WxPayBaseRequest request) {
|
||||
if (StringUtils.isBlank(request.getAppid())) {
|
||||
request.setAppid(getConfig().getAppId());
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(request.getMchId())) {
|
||||
request.setMchId(getConfig().getPartnerId());
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(request.getSubAppId())) {
|
||||
request.setAppid(getConfig().getSubAppId());
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(request.getSubMchId())) {
|
||||
request.setMchId(getConfig().getSubMchId());
|
||||
}
|
||||
|
||||
if (StringUtils.isBlank(request.getNonceStr())) {
|
||||
request.setNonceStr(String.valueOf(System.currentTimeMillis()));
|
||||
}
|
||||
}
|
||||
|
||||
private void checkParameters(WxPayUnifiedOrderRequest request) throws WxErrorException {
|
||||
BeanUtils.checkRequiredFields(request);
|
||||
|
||||
if (!ArrayUtils.contains(TRADE_TYPES, request.getTradeType())) {
|
||||
throw new IllegalArgumentException("trade_type目前必须为" + Arrays.toString(TRADE_TYPES) + "其中之一,实际值:" + request.getTradeType());
|
||||
}
|
||||
|
||||
if ("JSAPI".equals(request.getTradeType()) && request.getOpenid() == null) {
|
||||
throw new IllegalArgumentException("当 trade_type是'JSAPI'时未指定openid");
|
||||
}
|
||||
|
||||
if ("NATIVE".equals(request.getTradeType()) && request.getProductId() == null) {
|
||||
throw new IllegalArgumentException("当 trade_type是'NATIVE'时未指定product_id");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getPayInfo(WxPayUnifiedOrderRequest request) throws WxErrorException {
|
||||
WxPayUnifiedOrderResult unifiedOrderResult = this.unifiedOrder(request);
|
||||
String prepayId = unifiedOrderResult.getPrepayId();
|
||||
if (StringUtils.isBlank(prepayId)) {
|
||||
throw new RuntimeException(String.format("Failed to get prepay id due to error code '%s'(%s).",
|
||||
unifiedOrderResult.getErrCode(), unifiedOrderResult.getErrCodeDes()));
|
||||
}
|
||||
|
||||
Map<String, String> payInfo = new HashMap<>();
|
||||
payInfo.put("appId", getConfig().getAppId());
|
||||
// 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
|
||||
payInfo.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
|
||||
payInfo.put("nonceStr", String.valueOf(System.currentTimeMillis()));
|
||||
payInfo.put("package", "prepay_id=" + prepayId);
|
||||
payInfo.put("signType", "MD5");
|
||||
if ("NATIVE".equals(request.getTradeType())) {
|
||||
payInfo.put("codeUrl", unifiedOrderResult.getCodeURL());
|
||||
}
|
||||
payInfo.put("paySign", this.createSign(payInfo));
|
||||
return payInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxEntPayResult entPay(WxEntPayRequest request) throws WxErrorException {
|
||||
this.initRequest(request);
|
||||
BeanUtils.checkRequiredFields(request);
|
||||
request.setSign(this.createSign(request));
|
||||
|
||||
String url = this.getPayBaseUrl() + "/mmpaymkttransfers/promotion/transfers";
|
||||
|
||||
String responseContent = this.executeWithKey(url, request.toXML());
|
||||
WxEntPayResult result = WxEntPayResult.fromXML(responseContent, WxEntPayResult.class);
|
||||
this.checkResult(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxErrorException {
|
||||
WxEntPayQueryRequest request = new WxEntPayQueryRequest();
|
||||
this.initRequest(request);
|
||||
request.setSign(this.createSign(request));
|
||||
|
||||
String url = this.getPayBaseUrl() + "/mmpaymkttransfers/gettransferinfo";
|
||||
String responseContent = this.executeWithKey(url, request.toXML());
|
||||
WxEntPayQueryResult result = WxEntPayQueryResult.fromXML(responseContent, WxEntPayQueryResult.class);
|
||||
this.checkResult(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] createScanPayQrcodeMode1(String productId, File logoFile, Integer sideLength) {
|
||||
//weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX
|
||||
StringBuilder codeUrl = new StringBuilder("weixin://wxpay/bizpayurl?");
|
||||
Map<String, String> params = Maps.newHashMap();
|
||||
params.put("appid", this.getConfig().getAppId());
|
||||
params.put("mch_id", this.getConfig().getPartnerId());
|
||||
params.put("product_id", productId);
|
||||
params.put("time_stamp", String.valueOf(System.currentTimeMillis()));
|
||||
params.put("nonce_str", String.valueOf(System.currentTimeMillis()));
|
||||
|
||||
String sign = this.createSign(params);
|
||||
params.put("sign", sign);
|
||||
|
||||
for (String key : params.keySet()) {
|
||||
codeUrl.append(key + "=" + params.get(key) + "&");
|
||||
}
|
||||
|
||||
String content = codeUrl.toString().substring(0, codeUrl.length() - 1);
|
||||
if (sideLength == null || sideLength < 1) {
|
||||
return QrcodeUtils.createQrcode(content, logoFile);
|
||||
}
|
||||
|
||||
return QrcodeUtils.createQrcode(content, sideLength, logoFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] createScanPayQrcodeMode2(String codeUrl, File logoFile, Integer sideLength) {
|
||||
if (sideLength == null || sideLength < 1) {
|
||||
return QrcodeUtils.createQrcode(codeUrl, logoFile);
|
||||
}
|
||||
|
||||
return QrcodeUtils.createQrcode(codeUrl, sideLength, logoFile);
|
||||
}
|
||||
|
||||
public void report(WxPayReportRequest request) throws WxErrorException {
|
||||
BeanUtils.checkRequiredFields(request);
|
||||
this.initRequest(request);
|
||||
request.setSign(this.createSign(request));
|
||||
|
||||
String url = this.getPayBaseUrl() + "/payitil/report";
|
||||
String responseContent = this.wxMpService.post(url, request.toXML());
|
||||
WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class);
|
||||
this.checkResult(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxErrorException {
|
||||
WxPayDownloadBillRequest request = new WxPayDownloadBillRequest();
|
||||
this.initRequest(request);
|
||||
request.setBillType(billType);
|
||||
request.setBillDate(billDate);
|
||||
request.setTarType(tarType);
|
||||
request.setDeviceInfo(deviceInfo);
|
||||
this.checkParameters(request);
|
||||
request.setSign(this.createSign(request));
|
||||
|
||||
String url = this.getPayBaseUrl() + "/pay/downloadbill";
|
||||
//TODO 返回的内容可能是文件流,也有可能是xml,需要区分对待
|
||||
String responseContent = this.wxMpService.post(url, request.toXML());
|
||||
|
||||
WxPayCommonResult result = WxPayBaseResult.fromXML(responseContent, WxPayCommonResult.class);
|
||||
this.checkResult(result);
|
||||
//TODO 待实现,暂时无测试帐号,无法调试
|
||||
return null;
|
||||
}
|
||||
|
||||
private String executeRequest(String url, String requestStr) throws WxErrorException {
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
if (this.wxMpService.getHttpProxy() != null) {
|
||||
httpPost.setConfig(RequestConfig.custom().setProxy(this.wxMpService.getHttpProxy()).build());
|
||||
}
|
||||
|
||||
try (CloseableHttpClient httpclient = HttpClients.custom().build()) {
|
||||
httpPost.setEntity(new StringEntity(new String(requestStr.getBytes("UTF-8"), "ISO-8859-1")));
|
||||
|
||||
try (CloseableHttpResponse response = httpclient.execute(httpPost)) {
|
||||
String result = EntityUtils.toString(response.getEntity(), Consts.UTF_8);
|
||||
this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", url, requestStr, result);
|
||||
return result;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", url, requestStr, e.getMessage());
|
||||
throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg(e.getMessage()).build(), e);
|
||||
} finally {
|
||||
httpPost.releaseConnection();
|
||||
}
|
||||
}
|
||||
|
||||
private String executeWithKey(String url, String requestStr) throws WxErrorException {
|
||||
try {
|
||||
SSLContext sslContext = getConfig().getSslContext();
|
||||
if (null == sslContext) {
|
||||
throw new IllegalArgumentException("请先初始化配置类(即WxMpConfigStorage的实现类)中的SSLContext!");
|
||||
}
|
||||
|
||||
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new String[]{"TLSv1"}, null,
|
||||
new DefaultHostnameVerifier());
|
||||
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
if (this.wxMpService.getHttpProxy() != null) {
|
||||
httpPost.setConfig(RequestConfig.custom().setProxy(this.wxMpService.getHttpProxy()).build());
|
||||
}
|
||||
|
||||
try (CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build()) {
|
||||
httpPost.setEntity(new StringEntity(new String(requestStr.getBytes("UTF-8"), "ISO-8859-1")));
|
||||
try (CloseableHttpResponse response = httpclient.execute(httpPost)) {
|
||||
String result = EntityUtils.toString(response.getEntity(), Consts.UTF_8);
|
||||
this.log.debug("\n[URL]: {}\n[PARAMS]: {}\n[RESPONSE]: {}", url, requestStr, result);
|
||||
return result;
|
||||
}
|
||||
} finally {
|
||||
httpPost.releaseConnection();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
this.log.error("\n[URL]: {}\n[PARAMS]: {}\n[EXCEPTION]: {}", url, requestStr, e.getMessage());
|
||||
throw new WxErrorException(WxError.newBuilder().setErrorCode(-1).setErrorMsg(e.getMessage()).build(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createSign(Object xmlBean) {
|
||||
return this.createSign(BeanUtils.xmlBean2Map(xmlBean), getConfig().getPartnerKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createSign(Object xmlBean, String signKey) {
|
||||
return this.createSign(BeanUtils.xmlBean2Map(xmlBean), signKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createSign(Map<String, String> params) {
|
||||
return this.createSign(params, this.getConfig().getPartnerKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createSign(Map<String, String> params, String signKey) {
|
||||
if(this.getConfig().useSandboxForWxPay()){
|
||||
//使用仿真测试环境
|
||||
//TODO 目前测试发现,以下两行代码都会出问题,所以暂不建议使用这个仿真测试环境
|
||||
signKey = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456";
|
||||
//return "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456";
|
||||
}
|
||||
|
||||
SortedMap<String, String> sortedMap = new TreeMap<>(params);
|
||||
|
||||
StringBuilder toSign = new StringBuilder();
|
||||
for (String key : sortedMap.keySet()) {
|
||||
String value = params.get(key);
|
||||
if (StringUtils.isNotEmpty(value) && !"sign".equals(key) && !"key".equals(key)) {
|
||||
toSign.append(key + "=" + value + "&");
|
||||
}
|
||||
}
|
||||
|
||||
toSign.append("key=" + signKey);
|
||||
return DigestUtils.md5Hex(toSign.toString()).toUpperCase();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkSign(Object xmlBean) {
|
||||
return this.checkSign(BeanUtils.xmlBean2Map(xmlBean), getConfig().getPartnerKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkSign(Object xmlBean, String signKey) {
|
||||
return this.checkSign(BeanUtils.xmlBean2Map(xmlBean), signKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkSign(Map<String, String> params) {
|
||||
return this.checkSign(params, getConfig().getPartnerKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkSign(Map<String, String> params, String signKey) {
|
||||
String sign = this.createSign(params, signKey);
|
||||
return sign.equals(params.get("sign"));
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,6 @@ public class WxMpServiceImpl implements WxMpService {
|
||||
private WxMpUserTagService tagService = new WxMpUserTagServiceImpl(this);
|
||||
private WxMpQrcodeService qrCodeService = new WxMpQrcodeServiceImpl(this);
|
||||
private WxMpCardService cardService = new WxMpCardServiceImpl(this);
|
||||
private WxMpPayService payService = new WxMpPayServiceImpl(this);
|
||||
private WxMpStoreService storeService = new WxMpStoreServiceImpl(this);
|
||||
private WxMpDataCubeService dataCubeService = new WxMpDataCubeServiceImpl(this);
|
||||
private WxMpUserBlacklistService blackListService = new WxMpUserBlacklistServiceImpl(this);
|
||||
@@ -505,11 +504,6 @@ public class WxMpServiceImpl implements WxMpService {
|
||||
return this.cardService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxMpPayService getPayService() {
|
||||
return this.payService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxMpDataCubeService getDataCubeService() {
|
||||
return this.dataCubeService;
|
||||
|
||||
Reference in New Issue
Block a user