All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.binarywang.wxpay.service.impl.BaseWxPayServiceImpl Maven / Gradle / Ivy

The newest version!
package com.github.binarywang.wxpay.service.impl;

import com.github.binarywang.utils.qrcode.QrcodeUtils;
import com.github.binarywang.wxpay.bean.WxPayApiData;
import com.github.binarywang.wxpay.bean.coupon.*;
import com.github.binarywang.wxpay.bean.notify.*;
import com.github.binarywang.wxpay.bean.order.WxPayAppOrderResult;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.order.WxPayMwebOrderResult;
import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult;
import com.github.binarywang.wxpay.bean.request.*;
import com.github.binarywang.wxpay.bean.result.*;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.config.WxPayConfigHolder;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.constant.WxPayConstants.SignType;
import com.github.binarywang.wxpay.constant.WxPayConstants.TradeType;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.exception.WxSignTestException;
import com.github.binarywang.wxpay.service.*;
import com.github.binarywang.wxpay.util.SignUtils;
import com.github.binarywang.wxpay.util.XmlConfig;
import com.github.binarywang.wxpay.util.ZipUtils;
import com.github.binarywang.wxpay.v3.util.AesUtils;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.Getter;
import lombok.Setter;
import me.chanjar.weixin.common.error.WxRuntimeException;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.ConstructorUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.GeneralSecurityException;
import java.util.*;
import java.util.zip.ZipException;

import static com.github.binarywang.wxpay.constant.WxPayConstants.QUERY_COMMENT_DATE_FORMAT;
import static com.github.binarywang.wxpay.constant.WxPayConstants.TarType;

/**
 * 
 *  微信支付接口请求抽象实现类
 * Created by Binary Wang on 2017-7-8.
 * 
* * @author Binary Wang */ public abstract class BaseWxPayServiceImpl implements WxPayService { private static final String TOTAL_FUND_COUNT = "资金流水总笔数"; private static final Gson GSON = new GsonBuilder().create(); final Logger log = LoggerFactory.getLogger(this.getClass()); static ThreadLocal wxApiData = new ThreadLocal<>(); @Setter @Getter private EntPayService entPayService = new EntPayServiceImpl(this); @Getter private final ProfitSharingService profitSharingService = new ProfitSharingServiceImpl(this); @Getter private final RedpackService redpackService = new RedpackServiceImpl(this); @Getter private final PayScoreService payScoreService = new PayScoreServiceImpl(this); @Getter private final EcommerceService ecommerceService = new EcommerceServiceImpl(this); @Getter private final BusinessCircleService businessCircleService = new BusinessCircleServiceImpl(this); @Getter private final MerchantMediaService merchantMediaService = new MerchantMediaServiceImpl(this); @Getter private final MarketingMediaService marketingMediaService = new MarketingMediaServiceImpl(this); @Getter private final MarketingFavorService marketingFavorService = new MarketingFavorServiceImpl(this); @Getter private final MarketingBusiFavorService marketingBusiFavorService = new MarketingBusiFavorServiceImpl(this); @Getter private final WxEntrustPapService wxEntrustPapService = new WxEntrustPapServiceImpl(this); @Getter private final PartnerTransferService partnerTransferService = new PartnerTransferServiceImpl(this); @Getter private final PayrollService payrollService = new PayrollServiceImpl(this); @Getter private final ComplaintService complaintsService = new ComplaintServiceImpl(this); @Getter private final BankService bankService = new BankServiceImpl(this); @Getter private final TransferService transferService = new TransferServiceImpl(this); @Getter private final PartnerPayScoreService partnerPayScoreService = new PartnerPayScoreServiceImpl(this); @Getter private final PartnerPayScoreSignPlanService partnerPayScoreSignPlanService=new PartnerPayScoreSignPlanServiceImpl(this); @Getter private final MerchantTransferService merchantTransferService = new MerchantTransferServiceImpl(this); @Getter private final BrandMerchantTransferService brandMerchantTransferService = new BrandMerchantTransferServiceImpl(this); protected Map configMap = new HashMap<>(); @Override public WxPayConfig getConfig() { if (this.configMap.size() == 1) { // 只有一个商户号,直接返回其配置即可 return this.configMap.values().iterator().next(); } return this.configMap.get(WxPayConfigHolder.get()); } @Override public void setConfig(WxPayConfig config) { final String defaultMchId = config.getMchId(); this.setMultiConfig(ImmutableMap.of(defaultMchId, config), defaultMchId); } @Override public void addConfig(String mchId, WxPayConfig wxPayConfig) { synchronized (this) { if (this.configMap == null) { this.setConfig(wxPayConfig); } else { WxPayConfigHolder.set(mchId); this.configMap.put(mchId, wxPayConfig); } } } @Override public void removeConfig(String mchId) { synchronized (this) { if (this.configMap.size() == 1) { this.configMap.remove(mchId); log.warn("已删除最后一个商户号配置:{},须立即使用setConfig或setMultiConfig添加配置", mchId); return; } if (WxPayConfigHolder.get().equals(mchId)) { this.configMap.remove(mchId); final String defaultMpId = this.configMap.keySet().iterator().next(); WxPayConfigHolder.set(defaultMpId); log.warn("已删除默认商户号配置,商户号【{}】被设为默认配置", defaultMpId); return; } this.configMap.remove(mchId); } } @Override public void setMultiConfig(Map wxPayConfigs) { this.setMultiConfig(wxPayConfigs, wxPayConfigs.keySet().iterator().next()); } @Override public void setMultiConfig(Map wxPayConfigs, String defaultMchId) { this.configMap = Maps.newHashMap(wxPayConfigs); WxPayConfigHolder.set(defaultMchId); } @Override public boolean switchover(String mchId) { if (this.configMap.containsKey(mchId)) { WxPayConfigHolder.set(mchId); return true; } log.error("无法找到对应【{}】的商户号配置信息,请核实!", mchId); return false; } @Override public WxPayService switchoverTo(String mchId) { if (this.configMap.containsKey(mchId)) { WxPayConfigHolder.set(mchId); return this; } throw new WxRuntimeException(String.format("无法找到对应【%s】的商户号配置信息,请核实!", mchId)); } @Override public String getPayBaseUrl() { if (this.getConfig().isUseSandboxEnv()) { if (StringUtils.isNotBlank(this.getConfig().getApiV3Key())) { throw new WxRuntimeException("微信支付V3 目前不支持沙箱模式!"); } return this.getConfig().getPayBaseUrl() + "/xdc/apiv2sandbox"; } return this.getConfig().getPayBaseUrl(); } @Override public WxPayRefundResult refund(WxPayRefundRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/secapi/pay/refund"; String responseContent = this.post(url, request.toXML(), true); WxPayRefundResult result = BaseWxPayResult.fromXML(responseContent, WxPayRefundResult.class); result.composeRefundCoupons(); result.checkResult(this, request.getSignType(), true); return result; } @Override public WxPayRefundResult refundV2(WxPayRefundRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/secapi/pay/refundv2"; String responseContent = this.post(url, request.toXML(), true); WxPayRefundResult result = BaseWxPayResult.fromXML(responseContent, WxPayRefundResult.class); result.composePromotionDetails(); result.checkResult(this, request.getSignType(), true); return result; } @Override public WxPayRefundV3Result refundV3(WxPayRefundV3Request request) throws WxPayException { String url = String.format("%s/v3/refund/domestic/refunds", this.getPayBaseUrl()); String response = this.postV3(url, GSON.toJson(request)); return GSON.fromJson(response, WxPayRefundV3Result.class); } @Override public WxPayRefundQueryResult refundQuery(String transactionId, String outTradeNo, String outRefundNo, String refundId) throws WxPayException { WxPayRefundQueryRequest request = new WxPayRefundQueryRequest(); request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); request.setTransactionId(StringUtils.trimToNull(transactionId)); request.setOutRefundNo(StringUtils.trimToNull(outRefundNo)); request.setRefundId(StringUtils.trimToNull(refundId)); return this.refundQuery(request); } @Override public WxPayRefundQueryResult refundQuery(WxPayRefundQueryRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/refundquery"; String responseContent = this.post(url, request.toXML(), false); WxPayRefundQueryResult result = BaseWxPayResult.fromXML(responseContent, WxPayRefundQueryResult.class); result.composeRefundRecords(); result.checkResult(this, request.getSignType(), true); return result; } @Override public WxPayRefundQueryResult refundQueryV2(WxPayRefundQueryRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/refundqueryv2"; String responseContent = this.post(url, request.toXML(), false); WxPayRefundQueryResult result = BaseWxPayResult.fromXML(responseContent, WxPayRefundQueryResult.class); result.composePromotionDetails(); result.checkResult(this, request.getSignType(), true); return result; } @Override public WxPayRefundQueryV3Result refundQueryV3(String outRefundNo) throws WxPayException { String url = String.format("%s/v3/refund/domestic/refunds/%s", this.getPayBaseUrl(), outRefundNo); String response = this.getV3(url); return GSON.fromJson(response, WxPayRefundQueryV3Result.class); } @Override public WxPayRefundQueryV3Result refundQueryV3(WxPayRefundQueryV3Request request) throws WxPayException { String url = String.format("%s/v3/refund/domestic/refunds/%s", this.getPayBaseUrl(), request.getOutRefundNo()); String response = this.getV3(url); return GSON.fromJson(response, WxPayRefundQueryV3Result.class); } @Override public WxPayRefundQueryV3Result refundPartnerQueryV3(WxPayRefundQueryV3Request request) throws WxPayException { String url = String.format("%s/v3/refund/domestic/refunds/%s?sub_mchid=%s", this.getPayBaseUrl(), request.getOutRefundNo(),request.getSubMchid()); String response = this.getV3(url); return GSON.fromJson(response, WxPayRefundQueryV3Result.class); } @Override public WxPayOrderNotifyResult parseOrderNotifyResult(String xmlData) throws WxPayException { return this.parseOrderNotifyResult(xmlData, null); } @Override public WxPayOrderNotifyResult parseOrderNotifyResult(String xmlData, String signType) throws WxPayException { try { log.debug("微信支付异步通知请求参数:{}", xmlData); WxPayOrderNotifyResult result = WxPayOrderNotifyResult.fromXML(xmlData); if (signType == null) { if (result.getSignType() != null) { // 如果解析的通知对象中signType有值,则使用它进行验签 signType = result.getSignType(); } else if (configMap.get(result.getMchId()).getSignType() != null) { // 如果配置中signType有值,则使用它进行验签 signType = configMap.get(result.getMchId()).getSignType(); this.switchover(result.getMchId()); } } log.debug("微信支付异步通知请求解析后的对象:{}", result); result.checkResult(this, signType, false); return result; } catch (WxPayException e) { throw e; } catch (Exception e) { throw new WxPayException("发生异常!", e); } } /** * 校验通知签名 * * @param header 通知头信息 * @param data 通知数据 * @return true:校验通过 false:校验不通过 */ private boolean verifyNotifySign(SignatureHeader header, String data) throws WxSignTestException { String wxPaySign = header.getSignature(); if(wxPaySign.startsWith("WECHATPAY/SIGNTEST/")){ throw new WxSignTestException("微信支付签名探测流量"); } String beforeSign = String.format("%s\n%s\n%s\n", header.getTimeStamp(), header.getNonce(), data); return this.getConfig().getVerifier().verify(header.getSerial(), beforeSign.getBytes(StandardCharsets.UTF_8), header.getSignature()); } @Override public WxPayNotifyV3Result parseOrderNotifyV3Result(String notifyData, SignatureHeader header) throws WxPayException { return baseParseOrderNotifyV3Result(notifyData, header, WxPayNotifyV3Result.class, WxPayNotifyV3Result.DecryptNotifyResult.class); } @Override public WxPayPartnerNotifyV3Result parsePartnerOrderNotifyV3Result(String notifyData, SignatureHeader header) throws WxPayException { return this.baseParseOrderNotifyV3Result(notifyData, header, WxPayPartnerNotifyV3Result.class, WxPayPartnerNotifyV3Result.DecryptNotifyResult.class); } @Override public , E> T baseParseOrderNotifyV3Result(String notifyData, SignatureHeader header, Class resultType, Class dataType) throws WxPayException { if (Objects.nonNull(header) && !this.verifyNotifySign(header, notifyData)) { throw new WxPayException("非法请求,头部信息验证失败"); } OriginNotifyResponse response = GSON.fromJson(notifyData, OriginNotifyResponse.class); OriginNotifyResponse.Resource resource = response.getResource(); String cipherText = resource.getCiphertext(); String associatedData = resource.getAssociatedData(); String nonce = resource.getNonce(); String apiV3Key = this.getConfig().getApiV3Key(); try { String result = AesUtils.decryptToString(associatedData, nonce, cipherText, apiV3Key); E decryptNotifyResult = GSON.fromJson(result, dataType); T notifyResult = ConstructorUtils.invokeConstructor(resultType); notifyResult.setRawData(response); notifyResult.setResult(decryptNotifyResult); return notifyResult; } catch (Exception e) { throw new WxPayException("解析报文异常!", e); } } @Override public CombineNotifyResult parseCombineNotifyResult(String notifyData, SignatureHeader header) throws WxPayException { if (Objects.nonNull(header) && !this.verifyNotifySign(header, notifyData)) { throw new WxPayException("非法请求,头部信息验证失败"); } OriginNotifyResponse response = GSON.fromJson(notifyData, OriginNotifyResponse.class); OriginNotifyResponse.Resource resource = response.getResource(); String cipherText = resource.getCiphertext(); String associatedData = resource.getAssociatedData(); String nonce = resource.getNonce(); String apiV3Key = this.getConfig().getApiV3Key(); try { String result = AesUtils.decryptToString(associatedData, nonce, cipherText, apiV3Key); CombineNotifyResult.DecryptNotifyResult decryptNotifyResult = GSON.fromJson(result, CombineNotifyResult.DecryptNotifyResult.class); CombineNotifyResult notifyResult = new CombineNotifyResult(); notifyResult.setRawData(response); notifyResult.setResult(decryptNotifyResult); return notifyResult; } catch (GeneralSecurityException | IOException e) { throw new WxPayException("解析报文异常!", e); } } @Override public WxPayRefundNotifyResult parseRefundNotifyResult(String xmlData) throws WxPayException { try { log.debug("微信支付退款异步通知参数:{}", xmlData); WxPayRefundNotifyResult result; if (XmlConfig.fastMode) { result = BaseWxPayResult.fromXML(xmlData, WxPayRefundNotifyResult.class); this.switchover(result.getMchId()); result.decryptReqInfo(this.getConfig().getMchKey()); } else { result = WxPayRefundNotifyResult.fromXML(xmlData, this.getConfig().getMchKey()); } log.debug("微信支付退款异步通知解析后的对象:{}", result); return result; } catch (Exception e) { throw new WxPayException("发生异常," + e.getMessage(), e); } } @Override public WxPayRefundNotifyV3Result parseRefundNotifyV3Result(String notifyData, SignatureHeader header) throws WxPayException { return this.baseParseOrderNotifyV3Result(notifyData, header, WxPayRefundNotifyV3Result.class, WxPayRefundNotifyV3Result.DecryptNotifyResult.class); } @Override public WxPayTransferBatchesNotifyV3Result parseTransferBatchesNotifyV3Result(String notifyData, SignatureHeader header) throws WxPayException { return this.baseParseOrderNotifyV3Result(notifyData, header, WxPayTransferBatchesNotifyV3Result.class, WxPayTransferBatchesNotifyV3Result.DecryptNotifyResult.class); } @Override public WxPayPartnerRefundNotifyV3Result parsePartnerRefundNotifyV3Result(String notifyData, SignatureHeader header) throws WxPayException { return this.baseParseOrderNotifyV3Result(notifyData, header, WxPayPartnerRefundNotifyV3Result.class, WxPayPartnerRefundNotifyV3Result.DecryptNotifyResult.class); } @Override public WxScanPayNotifyResult parseScanPayNotifyResult(String xmlData, @Deprecated String signType) throws WxPayException { try { log.debug("扫码支付回调通知请求参数:{}", xmlData); WxScanPayNotifyResult result = BaseWxPayResult.fromXML(xmlData, WxScanPayNotifyResult.class); this.switchover(result.getMchId()); log.debug("扫码支付回调通知解析后的对象:{}", result); result.checkResult(this, this.getConfig().getSignType(), false); return result; } catch (WxPayException e) { throw e; } catch (Exception e) { throw new WxPayException("发生异常," + e.getMessage(), e); } } @Override public WxScanPayNotifyResult parseScanPayNotifyResult(String xmlData) throws WxPayException { // final String signType = this.getConfig().getSignType(); return this.parseScanPayNotifyResult(xmlData, null); } @Override public WxPayOrderQueryResult queryOrder(String transactionId, String outTradeNo) throws WxPayException { WxPayOrderQueryRequest request = new WxPayOrderQueryRequest(); request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); request.setTransactionId(StringUtils.trimToNull(transactionId)); return this.queryOrder(request); } @Override public WxPayOrderQueryResult queryOrder(WxPayOrderQueryRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/orderquery"; String responseContent = this.post(url, request.toXML(), false); if (StringUtils.isBlank(responseContent)) { throw new WxPayException("无响应结果"); } WxPayOrderQueryResult result = BaseWxPayResult.fromXML(responseContent, WxPayOrderQueryResult.class); result.composeCoupons(); result.checkResult(this, request.getSignType(), true); return result; } @Override public WxPayOrderQueryV3Result queryOrderV3(String transactionId, String outTradeNo) throws WxPayException { WxPayOrderQueryV3Request request = new WxPayOrderQueryV3Request(); request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); request.setTransactionId(StringUtils.trimToNull(transactionId)); return this.queryOrderV3(request); } @Override public WxPayOrderQueryV3Result queryOrderV3(WxPayOrderQueryV3Request request) throws WxPayException { if (StringUtils.isBlank(request.getMchid())) { request.setMchid(this.getConfig().getMchId()); } String url = String.format("%s/v3/pay/transactions/out-trade-no/%s", this.getPayBaseUrl(), request.getOutTradeNo()); if (Objects.isNull(request.getOutTradeNo())) { url = String.format("%s/v3/pay/transactions/id/%s", this.getPayBaseUrl(), request.getTransactionId()); } String query = String.format("?mchid=%s", request.getMchid()); String response = this.getV3(url + query); return GSON.fromJson(response, WxPayOrderQueryV3Result.class); } @Override public WxPayPartnerOrderQueryV3Result queryPartnerOrderV3(String transactionId, String outTradeNo) throws WxPayException { WxPayPartnerOrderQueryV3Request request = new WxPayPartnerOrderQueryV3Request(); request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); request.setTransactionId(StringUtils.trimToNull(transactionId)); return this.queryPartnerOrderV3(request); } @Override public WxPayPartnerOrderQueryV3Result queryPartnerOrderV3(WxPayPartnerOrderQueryV3Request request) throws WxPayException { if (StringUtils.isBlank(request.getSpMchId())) { request.setSpMchId(this.getConfig().getMchId()); } if (StringUtils.isBlank(request.getSubMchId())) { request.setSubMchId(this.getConfig().getSubMchId()); } String url = String.format("%s/v3/pay/partner/transactions/out-trade-no/%s", this.getPayBaseUrl(), request.getOutTradeNo()); if (Objects.isNull(request.getOutTradeNo())) { url = String.format("%s/v3/pay/partner/transactions/id/%s", this.getPayBaseUrl(), request.getTransactionId()); } String query = String.format("?sp_mchid=%s&sub_mchid=%s", request.getSpMchId(), request.getSubMchId()); String response = this.getV3(url + query); return GSON.fromJson(response, WxPayPartnerOrderQueryV3Result.class); } @Override public CombineQueryResult queryCombine(String combineOutTradeNo) throws WxPayException { String url = String.format("%s/v3/combine-transactions/out-trade-no/%s", this.getPayBaseUrl(), combineOutTradeNo); String response = this.getV3(url); return GSON.fromJson(response, CombineQueryResult.class); } @Override public WxPayOrderCloseResult closeOrder(String outTradeNo) throws WxPayException { if (StringUtils.isBlank(outTradeNo)) { throw new WxPayException("out_trade_no不能为空"); } WxPayOrderCloseRequest request = new WxPayOrderCloseRequest(); request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); return this.closeOrder(request); } @Override public WxPayOrderCloseResult closeOrder(WxPayOrderCloseRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/closeorder"; String responseContent = this.post(url, request.toXML(), false); WxPayOrderCloseResult result = BaseWxPayResult.fromXML(responseContent, WxPayOrderCloseResult.class); result.checkResult(this, request.getSignType(), true); return result; } @Override public void closeOrderV3(String outTradeNo) throws WxPayException { if (StringUtils.isBlank(outTradeNo)) { throw new WxPayException("out_trade_no不能为空"); } WxPayOrderCloseV3Request request = new WxPayOrderCloseV3Request(); request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); this.closeOrderV3(request); } @Override public void closePartnerOrderV3(String outTradeNo) throws WxPayException { if (StringUtils.isBlank(outTradeNo)) { throw new WxPayException("out_trade_no不能为空"); } WxPayPartnerOrderCloseV3Request request = new WxPayPartnerOrderCloseV3Request(); request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); this.closePartnerOrderV3(request); } @Override public void closeOrderV3(WxPayOrderCloseV3Request request) throws WxPayException { if (StringUtils.isBlank(request.getMchid())) { request.setMchid(this.getConfig().getMchId()); } String url = String.format("%s/v3/pay/transactions/out-trade-no/%s/close", this.getPayBaseUrl(), request.getOutTradeNo()); this.postV3(url, GSON.toJson(request)); } @Override public void closePartnerOrderV3(WxPayPartnerOrderCloseV3Request request) throws WxPayException { if (StringUtils.isBlank(request.getSpMchId())) { request.setSpMchId(this.getConfig().getMchId()); } if (StringUtils.isBlank(request.getSubMchId())) { request.setSubMchId(this.getConfig().getSubMchId()); } String url = String.format("%s/v3/pay/partner/transactions/out-trade-no/%s/close", this.getPayBaseUrl(), request.getOutTradeNo()); this.postV3(url, GSON.toJson(request)); } @Override public void closeCombine(CombineCloseRequest request) throws WxPayException { String url = String.format("%s/v3/combine-transactions/out-trade-no/%s/close", this.getPayBaseUrl(), request.getCombineOutTradeNo()); this.postV3(url, GSON.toJson(request)); } @Override public T createOrder(WxPayUnifiedOrderRequest request) throws WxPayException { WxPayUnifiedOrderResult unifiedOrderResult = this.unifiedOrder(request); String prepayId = unifiedOrderResult.getPrepayId(); if (StringUtils.isBlank(prepayId)) { throw new WxPayException(String.format("无法获取prepay id,错误代码: '%s',信息:%s。", unifiedOrderResult.getErrCode(), unifiedOrderResult.getErrCodeDes())); } String timestamp = String.valueOf(System.currentTimeMillis() / 1000); String nonceStr = unifiedOrderResult.getNonceStr(); switch (request.getTradeType()) { case TradeType.MWEB: { return (T) new WxPayMwebOrderResult(unifiedOrderResult.getMwebUrl()); } case TradeType.NATIVE: { return (T) new WxPayNativeOrderResult(unifiedOrderResult.getCodeURL()); } case TradeType.APP: { // APP支付绑定的是微信开放平台上的账号,APPID为开放平台上绑定APP后发放的参数 String appId = unifiedOrderResult.getAppid(); if (StringUtils.isNotEmpty(unifiedOrderResult.getSubAppId())) { appId = unifiedOrderResult.getSubAppId(); } Map configMap = new HashMap<>(8); // 此map用于参与调起sdk支付的二次签名,格式全小写,timestamp只能是10位,格式固定,切勿修改 String partnerId = unifiedOrderResult.getMchId(); if (StringUtils.isNotEmpty(unifiedOrderResult.getSubMchId())) { partnerId = unifiedOrderResult.getSubMchId(); } configMap.put("prepayid", prepayId); configMap.put("partnerid", partnerId); String packageValue = "Sign=WXPay"; configMap.put("package", packageValue); configMap.put("timestamp", timestamp); configMap.put("noncestr", nonceStr); configMap.put("appid", appId); final WxPayAppOrderResult result = WxPayAppOrderResult.builder() .sign(SignUtils.createSign(configMap, request.getSignType(), this.getConfig().getMchKey(), null)) .prepayId(prepayId) .partnerId(partnerId) .appId(appId) .packageValue(packageValue) .timeStamp(timestamp) .nonceStr(nonceStr) .build(); return (T) result; } case TradeType.JSAPI: { String signType = request.getSignType(); if (signType == null) { signType = SignType.MD5; } String appid = unifiedOrderResult.getAppid(); if (StringUtils.isNotEmpty(unifiedOrderResult.getSubAppId())) { appid = unifiedOrderResult.getSubAppId(); } WxPayMpOrderResult payResult = WxPayMpOrderResult.builder() .appId(appid) .timeStamp(timestamp) .nonceStr(nonceStr) .packageValue("prepay_id=" + prepayId) .signType(signType) .build(); payResult.setPaySign(SignUtils.createSign(payResult, signType, this.getConfig().getMchKey(), null)); return (T) payResult; } default: { throw new WxPayException("该交易类型暂不支持"); } } } @Override public T createOrder(TradeType.Specific specificTradeType, WxPayUnifiedOrderRequest request) throws WxPayException { if (specificTradeType == null) { throw new IllegalArgumentException("specificTradeType 不能为 null"); } request.setTradeType(specificTradeType.getType()); return createOrder(request); } @Override public WxPayUnifiedOrderResult unifiedOrder(WxPayUnifiedOrderRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/unifiedorder"; String responseContent = this.post(url, request.toXML(), false); WxPayUnifiedOrderResult result = BaseWxPayResult.fromXML(responseContent, WxPayUnifiedOrderResult.class); result.checkResult(this, request.getSignType(), true); return result; } @Override public T createOrderV3(TradeTypeEnum tradeType, WxPayUnifiedOrderV3Request request) throws WxPayException { WxPayUnifiedOrderV3Result result = this.unifiedOrderV3(tradeType, request); return result.getPayInfo(tradeType, request.getAppid(), request.getMchid(), this.getConfig().getPrivateKey()); } @Override public T createPartnerOrderV3(TradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException { WxPayUnifiedOrderV3Result result = this.unifiedPartnerOrderV3(tradeType, request); //获取应用ID String appId = StringUtils.isBlank(request.getSubAppid()) ? request.getSpAppid() : request.getSubAppid(); return result.getPayInfo(tradeType, appId, request.getSubMchId(), this.getConfig().getPrivateKey()); } @Override public WxPayUnifiedOrderV3Result unifiedPartnerOrderV3(TradeTypeEnum tradeType, WxPayPartnerUnifiedOrderV3Request request) throws WxPayException { if (StringUtils.isBlank(request.getSpAppid())) { request.setSpAppid(this.getConfig().getAppId()); } if (StringUtils.isBlank(request.getSpMchId())) { request.setSpMchId(this.getConfig().getMchId()); } if (StringUtils.isBlank(request.getNotifyUrl())) { request.setNotifyUrl(this.getConfig().getNotifyUrl()); } if (StringUtils.isBlank(request.getSubAppid())) { request.setSubAppid(this.getConfig().getSubAppId()); } if (StringUtils.isBlank(request.getSubMchId())) { request.setSubMchId(this.getConfig().getSubMchId()); } String url = this.getPayBaseUrl() + tradeType.getBasePartnerUrl(); String response = this.postV3(url, GSON.toJson(request)); return GSON.fromJson(response, WxPayUnifiedOrderV3Result.class); } @Override public WxPayUnifiedOrderV3Result unifiedOrderV3(TradeTypeEnum tradeType, WxPayUnifiedOrderV3Request request) throws WxPayException { if (StringUtils.isBlank(request.getAppid())) { request.setAppid(this.getConfig().getAppId()); } if (StringUtils.isBlank(request.getMchid())) { request.setMchid(this.getConfig().getMchId()); } if (StringUtils.isBlank(request.getNotifyUrl())) { request.setNotifyUrl(this.getConfig().getNotifyUrl()); } String url = this.getPayBaseUrl() + tradeType.getPartnerUrl(); String response = this.postV3(url, GSON.toJson(request)); return GSON.fromJson(response, WxPayUnifiedOrderV3Result.class); } @Override public CombineTransactionsResult combine(TradeTypeEnum tradeType, CombineTransactionsRequest request) throws WxPayException { if (StringUtils.isBlank(request.getCombineAppid())) { request.setCombineAppid(this.getConfig().getAppId()); } if (StringUtils.isBlank(request.getCombineMchid())) { request.setCombineMchid(this.getConfig().getMchId()); } String url = this.getPayBaseUrl() + tradeType.getCombineUrl(); String response = this.postV3(url, GSON.toJson(request)); return GSON.fromJson(response, CombineTransactionsResult.class); } @Override public T combineTransactions(TradeTypeEnum tradeType, CombineTransactionsRequest request) throws WxPayException { CombineTransactionsResult result = this.combine(tradeType, request); return result.getPayInfo(tradeType, request.getCombineAppid(), request.getCombineAppid(), this.getConfig().getPrivateKey()); } @Override @Deprecated public Map getPayInfo(WxPayUnifiedOrderRequest request) throws WxPayException { WxPayUnifiedOrderResult unifiedOrderResult = this.unifiedOrder(request); String prepayId = unifiedOrderResult.getPrepayId(); if (StringUtils.isBlank(prepayId)) { throw new WxRuntimeException(String.format("无法获取prepay id,错误代码: '%s',信息:%s。", unifiedOrderResult.getErrCode(), unifiedOrderResult.getErrCodeDes())); } Map payInfo = new HashMap<>(); String timestamp = String.valueOf(System.currentTimeMillis() / 1000); String nonceStr = unifiedOrderResult.getNonceStr(); if (TradeType.NATIVE.equals(request.getTradeType())) { payInfo.put("codeUrl", unifiedOrderResult.getCodeURL()); } else if (TradeType.APP.equals(request.getTradeType())) { // APP支付绑定的是微信开放平台上的账号,APPID为开放平台上绑定APP后发放的参数 String appId = getConfig().getAppId(); Map configMap = new HashMap<>(); // 此map用于参与调起sdk支付的二次签名,格式全小写,timestamp只能是10位,格式固定,切勿修改 String partnerId = getConfig().getMchId(); configMap.put("prepayid", prepayId); configMap.put("partnerid", partnerId); String packageValue = "Sign=WXPay"; configMap.put("package", packageValue); configMap.put("timestamp", timestamp); configMap.put("noncestr", nonceStr); configMap.put("appid", appId); // 此map用于客户端与微信服务器交互 payInfo.put("sign", SignUtils.createSign(configMap, request.getSignType(), this.getConfig().getMchKey(), null)); payInfo.put("prepayId", prepayId); payInfo.put("partnerId", partnerId); payInfo.put("appId", appId); payInfo.put("packageValue", packageValue); payInfo.put("timeStamp", timestamp); payInfo.put("nonceStr", nonceStr); } else if (TradeType.JSAPI.equals(request.getTradeType())) { payInfo.put("appId", unifiedOrderResult.getAppid()); // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符 payInfo.put("timeStamp", timestamp); payInfo.put("nonceStr", nonceStr); payInfo.put("package", "prepay_id=" + prepayId); payInfo.put("signType", request.getSignType()); payInfo.put("paySign", SignUtils.createSign(payInfo, request.getSignType(), this.getConfig().getMchKey(), null)); } return payInfo; } @Override public byte[] createScanPayQrcodeMode1(String productId, File logoFile, Integer sideLength) throws Exception { String content = this.createScanPayQrcodeMode1(productId); return this.createQrcode(content, logoFile, sideLength); } @Override public String createScanPayQrcodeMode1(String productId) { //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 params = Maps.newHashMap(); params.put("appid", this.getConfig().getAppId()); params.put("mch_id", this.getConfig().getMchId()); params.put("product_id", productId); //这里需要秒,10位数字 params.put("time_stamp", String.valueOf(System.currentTimeMillis() / 1000)); params.put("nonce_str", String.valueOf(System.currentTimeMillis())); String sign = SignUtils.createSign(params, SignType.MD5, this.getConfig().getMchKey(), null); params.put("sign", sign); for (String key : params.keySet()) { codeUrl.append(key).append("=").append(params.get(key)).append("&"); } String content = codeUrl.toString().substring(0, codeUrl.length() - 1); log.debug("扫码支付模式一生成二维码的URL:{}", content); return content; } @Override public byte[] createScanPayQrcodeMode2(String codeUrl, File logoFile, Integer sideLength) throws Exception { return this.createQrcode(codeUrl, logoFile, sideLength); } private byte[] createQrcode(String content, File logoFile, Integer sideLength) throws Exception { if (sideLength == null || sideLength < 1) { return QrcodeUtils.createQrcode(content, logoFile); } return QrcodeUtils.createQrcode(content, sideLength, logoFile); } @Override public void report(WxPayReportRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/payitil/report"; String responseContent = this.post(url, request.toXML(), false); WxPayCommonResult result = BaseWxPayResult.fromXML(responseContent, WxPayCommonResult.class); result.checkResult(this, request.getSignType(), true); } @Override public String downloadRawBill(String billDate, String billType, String tarType, String deviceInfo) throws WxPayException { return this.downloadRawBill(this.buildDownloadBillRequest(billDate, billType, tarType, deviceInfo)); } @Override public WxPayBillResult downloadBill(String billDate, String billType, String tarType, String deviceInfo) throws WxPayException { return this.downloadBill(this.buildDownloadBillRequest(billDate, billType, tarType, deviceInfo)); } private WxPayDownloadBillRequest buildDownloadBillRequest(String billDate, String billType, String tarType, String deviceInfo) { WxPayDownloadBillRequest request = new WxPayDownloadBillRequest(); request.setBillType(billType); request.setBillDate(billDate); request.setTarType(tarType); request.setDeviceInfo(deviceInfo); return request; } @Override public WxPayBillResult downloadBill(WxPayDownloadBillRequest request) throws WxPayException { String responseContent = this.downloadRawBill(request); if (StringUtils.isEmpty(responseContent)) { return null; } return this.handleBill(request.getBillType(), responseContent); } @Override public String downloadRawBill(WxPayDownloadBillRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/downloadbill"; String responseContent; if (TarType.GZIP.equals(request.getTarType())) { responseContent = this.handleGzipBill(url, request.toXML()); } else { responseContent = this.post(url, request.toXML(), false); if (responseContent.startsWith("<")) { throw WxPayException.from(BaseWxPayResult.fromXML(responseContent, WxPayCommonResult.class)); } } return responseContent; } private WxPayBillResult handleBill(String billType, String responseContent) { return WxPayBillResult.fromRawBillResultString(responseContent, billType); } private String handleGzipBill(String url, String requestStr) throws WxPayException { try { byte[] responseBytes = this.postForBytes(url, requestStr, false); Path tempDirectory = Files.createTempDirectory("bill"); Path path = Paths.get(tempDirectory.toString(), System.currentTimeMillis() + ".gzip"); Files.write(path, responseBytes); try { List allLines = Files.readAllLines(ZipUtils.unGzip(path.toFile()).toPath(), StandardCharsets.UTF_8); return Joiner.on("\n").join(allLines); } catch (ZipException e) { if (e.getMessage().contains("Not in GZIP format")) { throw WxPayException.from(BaseWxPayResult.fromXML(new String(responseBytes, StandardCharsets.UTF_8), WxPayCommonResult.class)); } else { throw new WxPayException("解压zip文件出错!", e); } } } catch (Exception e) { throw new WxPayException("解析对账单文件时出错!", e); } } @Override public WxPayFundFlowResult downloadFundFlow(String billDate, String accountType, String tarType) throws WxPayException { WxPayDownloadFundFlowRequest request = new WxPayDownloadFundFlowRequest(); request.setBillDate(billDate); request.setAccountType(accountType); request.setTarType(tarType); return this.downloadFundFlow(request); } @Override public WxPayFundFlowResult downloadFundFlow(WxPayDownloadFundFlowRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/downloadfundflow"; String responseContent; if (TarType.GZIP.equals(request.getTarType())) { responseContent = this.handleGzipFundFlow(url, request.toXML()); } else { responseContent = this.post(url, request.toXML(), true); if (responseContent.startsWith("<")) { throw WxPayException.from(BaseWxPayResult.fromXML(responseContent, WxPayCommonResult.class)); } } return this.handleFundFlow(responseContent); } private String handleGzipFundFlow(String url, String requestStr) throws WxPayException { try { byte[] responseBytes = this.postForBytes(url, requestStr, true); Path tempDirectory = Files.createTempDirectory("fundFlow"); Path path = Paths.get(tempDirectory.toString(), System.currentTimeMillis() + ".gzip"); Files.write(path, responseBytes); try { List allLines = Files.readAllLines(ZipUtils.unGzip(path.toFile()).toPath(), StandardCharsets.UTF_8); return Joiner.on("\n").join(allLines); } catch (ZipException e) { if (e.getMessage().contains("Not in GZIP format")) { throw WxPayException.from(BaseWxPayResult.fromXML(new String(responseBytes, StandardCharsets.UTF_8), WxPayCommonResult.class)); } else { throw new WxPayException("解压zip文件出错", e); } } } catch (WxPayException wxPayException) { throw wxPayException; } catch (Exception e) { throw new WxPayException("解压zip文件出错", e); } } private WxPayFundFlowResult handleFundFlow(String responseContent) { WxPayFundFlowResult wxPayFundFlowResult = new WxPayFundFlowResult(); String listStr = ""; String objStr = ""; if (StringUtils.isNotBlank(responseContent) && responseContent.contains(TOTAL_FUND_COUNT)) { listStr = responseContent.substring(0, responseContent.indexOf(TOTAL_FUND_COUNT)); objStr = responseContent.substring(responseContent.indexOf(TOTAL_FUND_COUNT)); } /* * 记账时间:2018-02-01 04:21:23 微信支付业务单号:50000305742018020103387128253 资金流水单号:1900009231201802015884652186 业务名称:退款 * 业务类型:退款 收支类型:支出 收支金额(元):0.02 账户结余(元):0.17 资金变更提交申请人:system 备注:缺货 业务凭证号:REF4200000068201801293084726067 * 参考以上格式进行取值 */ List wxPayFundFlowBaseResultList = new LinkedList<>(); // 去空格 String newStr = listStr.replaceAll(",", " "); // 数据分组 String[] tempStr = newStr.split("`"); // 分组标题 String[] t = tempStr[0].split(" "); // 计算循环次数 int j = tempStr.length / t.length; // 纪录数组下标 int k = 1; for (int i = 0; i < j; i++) { WxPayFundFlowBaseResult wxPayFundFlowBaseResult = new WxPayFundFlowBaseResult(); wxPayFundFlowBaseResult.setBillingTime(tempStr[k].trim()); wxPayFundFlowBaseResult.setBizTransactionId(tempStr[k + 1].trim()); wxPayFundFlowBaseResult.setFundFlowId(tempStr[k + 2].trim()); wxPayFundFlowBaseResult.setBizName(tempStr[k + 3].trim()); wxPayFundFlowBaseResult.setBizType(tempStr[k + 4].trim()); wxPayFundFlowBaseResult.setFinancialType(tempStr[k + 5].trim()); wxPayFundFlowBaseResult.setFinancialFee(tempStr[k + 6].trim()); wxPayFundFlowBaseResult.setAccountBalance(tempStr[k + 7].trim()); wxPayFundFlowBaseResult.setFundApplicant(tempStr[k + 8].trim()); wxPayFundFlowBaseResult.setMemo(tempStr[k + 9].trim()); wxPayFundFlowBaseResult.setBizVoucherId(tempStr[k + 10].trim()); wxPayFundFlowBaseResultList.add(wxPayFundFlowBaseResult); k += t.length; } wxPayFundFlowResult.setWxPayFundFlowBaseResultList(wxPayFundFlowBaseResultList); /* * 资金流水总笔数,收入笔数,收入金额,支出笔数,支出金额 `20.0,`17.0,`0.35,`3.0,`0.18 * 参考以上格式进行取值 */ String totalStr = objStr.replaceAll(",", " "); String[] totalTempStr = totalStr.split("`"); wxPayFundFlowResult.setTotalRecord(totalTempStr[1]); wxPayFundFlowResult.setIncomeRecord(totalTempStr[2]); wxPayFundFlowResult.setIncomeAmount(totalTempStr[3]); wxPayFundFlowResult.setExpenditureRecord(totalTempStr[4]); wxPayFundFlowResult.setExpenditureAmount(totalTempStr[5]); return wxPayFundFlowResult; } @Override public WxPayApplyBillV3Result applyTradeBill(WxPayApplyTradeBillV3Request request) throws WxPayException { String url; if (StringUtils.isBlank(request.getTarType())) { url = String.format("%s/v3/bill/tradebill?bill_date=%s&bill_type=%s", this.getPayBaseUrl(), request.getBillDate(), request.getBillType()); } else { url = String.format("%s/v3/bill/tradebill?bill_date=%s&bill_type=%s&tar_type=%s", this.getPayBaseUrl(), request.getBillDate(), request.getBillType(), request.getTarType()); } String response = this.getV3(url); return GSON.fromJson(response, WxPayApplyBillV3Result.class); } @Override public WxPayApplyBillV3Result applyFundFlowBill(WxPayApplyFundFlowBillV3Request request) throws WxPayException { String url; if (StringUtils.isBlank(request.getTarType())) { url = String.format("%s/v3/bill/fundflowbill?bill_date=%s&account_type=%s", this.getPayBaseUrl(), request.getBillDate(), request.getAccountType()); } else { url = String.format("%s/v3/bill/fundflowbill?bill_date=%s&account_type=%s&tar_type=%s", this.getPayBaseUrl(), request.getBillDate(), request.getAccountType(), request.getTarType()); } String response = this.getV3(url); return GSON.fromJson(response, WxPayApplyBillV3Result.class); } @Override public InputStream downloadBill(String url) throws WxPayException { return this.downloadV3(url); } @Override public WxPayMicropayResult micropay(WxPayMicropayRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/micropay"; String responseContent = this.post(url, request.toXML(), false); WxPayMicropayResult result = BaseWxPayResult.fromXML(responseContent, WxPayMicropayResult.class); result.checkResult(this, request.getSignType(), true); return result; } @Override public WxPayCodepayResult codepay(WxPayCodepayRequest request) throws WxPayException { if (StringUtils.isBlank(request.getAppid())) { request.setAppid(this.getConfig().getAppId()); } if (StringUtils.isBlank(request.getMchid())) { request.setMchid(this.getConfig().getMchId()); } String url = String.format("%s/v3/pay/transactions/codepay", this.getPayBaseUrl()); String body = this.postV3(url, GSON.toJson(request)); return GSON.fromJson(body, WxPayCodepayResult.class); } @Override public WxPayOrderReverseResult reverseOrder(WxPayOrderReverseRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/secapi/pay/reverse"; String responseContent = this.post(url, request.toXML(), true); WxPayOrderReverseResult result = BaseWxPayResult.fromXML(responseContent, WxPayOrderReverseResult.class); result.checkResult(this, request.getSignType(), true); return result; } @Override public WxPayOrderReverseV3Result reverseOrderV3(WxPayOrderReverseV3Request request) throws WxPayException { if (StringUtils.isBlank(request.getAppid())) { request.setAppid(this.getConfig().getAppId()); } if (StringUtils.isBlank(request.getMchid())) { request.setMchid(this.getConfig().getMchId()); } // 拼接参数请求路径并发送 String url = String.format("%s/v3/pay/transactions/out-trade-no/%s/reverse", this.getPayBaseUrl(), request.getOutTradeNo()); String response = this.postV3(url, GSON.toJson(request)); return GSON.fromJson(response, WxPayOrderReverseV3Result.class); } @Override public WxPayOrderReverseV3Result reverseOrderV3(String outTradeNo) throws WxPayException { if (StringUtils.isBlank(outTradeNo)) { throw new WxPayException("out_trade_no不能为空"); } WxPayOrderReverseV3Request request = new WxPayOrderReverseV3Request(); request.setOutTradeNo(StringUtils.trimToNull(outTradeNo)); return this.reverseOrderV3(request); } @Override public String shorturl(WxPayShorturlRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/tools/shorturl"; String responseContent = this.post(url, request.toXML(), false); WxPayShorturlResult result = BaseWxPayResult.fromXML(responseContent, WxPayShorturlResult.class); result.checkResult(this, request.getSignType(), true); return result.getShortUrl(); } @Override public String shorturl(String longUrl) throws WxPayException { return this.shorturl(new WxPayShorturlRequest(longUrl)); } @Override public String authcode2Openid(WxPayAuthcode2OpenidRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/tools/authcodetoopenid"; String responseContent = this.post(url, request.toXML(), false); WxPayAuthcode2OpenidResult result = BaseWxPayResult.fromXML(responseContent, WxPayAuthcode2OpenidResult.class); result.checkResult(this, request.getSignType(), true); return result.getOpenid(); } @Override public String authcode2Openid(String authCode) throws WxPayException { return this.authcode2Openid(new WxPayAuthcode2OpenidRequest(authCode)); } @Override public String getSandboxSignKey() throws WxPayException { WxPayDefaultRequest request = new WxPayDefaultRequest(); request.checkAndSign(this.getConfig()); String url = "https://api.mch.weixin.qq.com/xdc/apiv2getsignkey/sign/getsignkey"; String responseContent = this.post(url, request.toXML(), false); WxPaySandboxSignKeyResult result = BaseWxPayResult.fromXML(responseContent, WxPaySandboxSignKeyResult.class); result.checkResult(this, request.getSignType(), true); return result.getSandboxSignKey(); } @Override public WxPayCouponSendResult sendCoupon(WxPayCouponSendRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/mmpaymkttransfers/send_coupon"; String responseContent = this.post(url, request.toXML(), true); WxPayCouponSendResult result = BaseWxPayResult.fromXML(responseContent, WxPayCouponSendResult.class); result.checkResult(this, request.getSignType(), true); return result; } @Override public WxPayCouponStockQueryResult queryCouponStock(WxPayCouponStockQueryRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/mmpaymkttransfers/query_coupon_stock"; String responseContent = this.post(url, request.toXML(), false); WxPayCouponStockQueryResult result = BaseWxPayResult.fromXML(responseContent, WxPayCouponStockQueryResult.class); result.checkResult(this, request.getSignType(), true); return result; } @Override public WxPayCouponInfoQueryResult queryCouponInfo(WxPayCouponInfoQueryRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/mmpaymkttransfers/querycouponsinfo"; String responseContent = this.post(url, request.toXML(), false); WxPayCouponInfoQueryResult result = BaseWxPayResult.fromXML(responseContent, WxPayCouponInfoQueryResult.class); result.checkResult(this, request.getSignType(), true); return result; } @Override public WxPayApiData getWxApiData() { try { return wxApiData.get(); } finally { //一般来说,接口请求会在一个线程内进行,这种情况下,每个线程get的会是之前所存入的数据, // 但以防万一有同一线程多次请求的问题,所以每次获取完数据后移除对应数据 wxApiData.remove(); } } @Override public String queryComment(Date beginDate, Date endDate, Integer offset, Integer limit) throws WxPayException { WxPayQueryCommentRequest request = new WxPayQueryCommentRequest(); request.setBeginTime(QUERY_COMMENT_DATE_FORMAT.format(beginDate)); request.setEndTime(QUERY_COMMENT_DATE_FORMAT.format(endDate)); request.setOffset(offset); request.setLimit(limit); return this.queryComment(request); } @Override public String queryComment(WxPayQueryCommentRequest request) throws WxPayException { request.setSignType(SignType.HMAC_SHA256);// 签名类型,目前仅支持HMAC-SHA256,默认就是HMAC-SHA256 request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/billcommentsp/batchquerycomment"; String responseContent = this.post(url, request.toXML(), true); if (responseContent.startsWith("<")) { throw WxPayException.from(BaseWxPayResult.fromXML(responseContent, WxPayCommonResult.class)); } return responseContent; } @Override public WxPayFaceAuthInfoResult getWxPayFaceAuthInfo(WxPayFaceAuthInfoRequest request) throws WxPayException { if (StringUtils.isEmpty(request.getSignType())) { request.setSignType(WxPayConstants.SignType.MD5); } request.checkAndSign(this.getConfig()); String url = "https://payapp.weixin.qq.com/face/get_wxpayface_authinfo"; String responseContent = this.post(url, request.toXML(), false); WxPayFaceAuthInfoResult result = BaseWxPayResult.fromXML(responseContent, WxPayFaceAuthInfoResult.class); result.checkResult(this, request.getSignType(), true); return result; } @Override public WxPayFacepayResult facepay(WxPayFacepayRequest request) throws WxPayException { request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/facepay"; String responseContent = this.post(url, request.toXML(), false); WxPayFacepayResult result = BaseWxPayResult.fromXML(responseContent, WxPayFacepayResult.class); result.checkResult(this, request.getSignType(), true); return result; } @Override public WxPayQueryExchangeRateResult queryExchangeRate(String feeType, String date) throws WxPayException { WxPayQueryExchangeRateRequest request = new WxPayQueryExchangeRateRequest(); request.setFeeType(feeType); request.setDate(date); request.checkAndSign(this.getConfig()); String url = this.getPayBaseUrl() + "/pay/queryexchagerate"; String responseContent = this.post(url, request.toXML(), false); WxPayQueryExchangeRateResult result = BaseWxPayResult.fromXML(responseContent, WxPayQueryExchangeRateResult.class); result.checkResult(this, request.getSignType(), true); return result; } @Override public ComplaintNotifyResult parseComplaintNotifyResult(String notifyData, SignatureHeader header) throws WxPayException { if (Objects.nonNull(header) && !this.verifyNotifySign(header, notifyData)) { throw new WxPayException("非法请求,头部信息验证失败"); } OriginNotifyResponse response = GSON.fromJson(notifyData, OriginNotifyResponse.class); OriginNotifyResponse.Resource resource = response.getResource(); String cipherText = resource.getCiphertext(); String associatedData = resource.getAssociatedData(); String nonce = resource.getNonce(); String apiV3Key = this.getConfig().getApiV3Key(); try { String result = AesUtils.decryptToString(associatedData, nonce, cipherText, apiV3Key); ComplaintNotifyResult.DecryptNotifyResult decryptNotifyResult = GSON.fromJson(result, ComplaintNotifyResult.DecryptNotifyResult.class); ComplaintNotifyResult notifyResult = new ComplaintNotifyResult(); notifyResult.setRawData(response); notifyResult.setResult(decryptNotifyResult); return notifyResult; } catch (GeneralSecurityException | IOException e) { throw new WxPayException("解析报文异常!", e); } } @Override public ComplaintService getComplaintsService() { return complaintsService; } @Override public BankService getBankService() { return bankService; } @Override public TransferService getTransferService() { return transferService; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy