@@ -1,15 +1,17 @@
package me.chanjar.weixin.mp.api.impl ;
import com.thoughtworks.xstream.XStream ;
import me.chanjar.weixin.common.bean.result.WxError ;
import me.chanjar.weixin.common.exception.WxError Exception;
import me.chanjar.weixin.common.util.BeanUtils ;
import me.chanjar.weixin.common.util.xml.XStreamInitializer ;
import me.chanjar.weixin.mp.api.WxMpPayService ;
import me.chanjar.weixin.mp.api.WxMpService ;
import me.chanjar.weixin.mp.bean.pay.WxPayJsSDKCallback ;
import me.chanjar.weixin.mp.bean.pay.request.* ;
import me.chanjar.weixin.mp.bean.pay.result.* ;
import java.io.File ;
import java.io.FileInputStream ;
import java.io.IO Exception;
import java.security.KeyStore ;
import java.util.Arrays ;
import java.util.HashMap ;
import java.util.Map ;
import java.util.SortedMap ;
import java.util.TreeMap ;
import javax.net.ssl.SSLContext ;
import org.apache.commons.codec.digest.DigestUtils ;
import org.apache.commons.lang3.ArrayUtils ;
import org.apache.commons.lang3.StringUtils ;
@@ -27,12 +29,36 @@ 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.FileInputStream ;
import java.io.IO Exception;
import java.security.KeyStore ;
import java.util.* ;
import com.thoughtworks.xstream.XStream ;
import me.chanjar.weixin.common.bean.result.WxError ;
import me.chanjar.weixin.common.exception.WxError Exception;
import me.chanjar.weixin.common.util.BeanUtils ;
import me.chanjar.weixin.common.util.xml.XStreamInitializer ;
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.WxPayOrderNotifyResultConverter ;
import me.chanjar.weixin.mp.bean.pay.request.WxEntPayQueryRequest ;
import me.chanjar.weixin.mp.bean.pay.request.WxEntPayRequest ;
import me.chanjar.weixin.mp.bean.pay.request.WxPayOrderCloseRequest ;
import me.chanjar.weixin.mp.bean.pay.request.WxPayOrderQueryRequest ;
import me.chanjar.weixin.mp.bean.pay.request.WxPayRedpackQueryRequest ;
import me.chanjar.weixin.mp.bean.pay.request.WxPayRefundQueryRequest ;
import me.chanjar.weixin.mp.bean.pay.request.WxPayRefundRequest ;
import me.chanjar.weixin.mp.bean.pay.request.WxPaySendRedpackRequest ;
import me.chanjar.weixin.mp.bean.pay.request.WxPayUnifiedOrderRequest ;
import me.chanjar.weixin.mp.bean.pay.result.WxEntPayQueryResult ;
import me.chanjar.weixin.mp.bean.pay.result.WxEntPayResult ;
import me.chanjar.weixin.mp.bean.pay.result.WxPayBaseResult ;
import me.chanjar.weixin.mp.bean.pay.result.WxPayOrderCloseResult ;
import me.chanjar.weixin.mp.bean.pay.result.WxPayOrderNotifyResult ;
import me.chanjar.weixin.mp.bean.pay.result.WxPayOrderQueryResult ;
import me.chanjar.weixin.mp.bean.pay.result.WxPayRedpackQueryResult ;
import me.chanjar.weixin.mp.bean.pay.result.WxPayRefundQueryResult ;
import me.chanjar.weixin.mp.bean.pay.result.WxPayRefundResult ;
import me.chanjar.weixin.mp.bean.pay.result.WxPaySendRedpackResult ;
import me.chanjar.weixin.mp.bean.pay.result.WxPayUnifiedOrderResult ;
/**
* Created by Binary Wang on 2016/7/28.
@@ -47,9 +73,11 @@ public class WxMpPayServiceImpl implements WxMpPayService {
" REFUND_SOURCE_UNSETTLED_FUNDS " } ;
protected final Logger log = LoggerFactory . getLogger ( this . getClass ( ) ) ;
private WxMpService wxMpService ;
private WxMpConfigStorage config ;
public WxMpPayServiceImpl ( WxMpService wxMpService ) {
this . wxMpService = wxMpService ;
this . config = wxMpService . getWxMpConfigStorage ( ) ;
}
@Override
@@ -61,13 +89,12 @@ public class WxMpPayServiceImpl implements WxMpPayService {
xstream . processAnnotations ( WxPayRefundRequest . class ) ;
xstream . processAnnotations ( WxPayRefundResult . class ) ;
request . setAppid ( this . wxMpService . getWxMpConfigStorage ( ) . getAppId ( ) ) ;
String partnerId = this . wxMpService . getWxMpConfigStorage ( ) . getPartnerId ( ) ;
request . setAppid ( this . config . getAppId ( ) ) ;
String partnerId = this . config . getPartnerId ( ) ;
request . setMchId ( partnerId ) ;
request . setNonceStr ( System . currentTimeMillis ( ) + " " ) ;
request . setOpUserId ( partnerId ) ;
String sign = this . createSign ( BeanUtils . xmlBean2Map ( request ) , this . wxMpService . getWxMpConfigStorage ( ) . getPartnerKey ( ) ) ;
request . setSign ( sign ) ;
request . setSign ( this . createSign ( request ) ) ;
String url = PAY_BASE_URL + " /secapi/pay/refund " ;
String responseContent = this . executeRequestWithKeyFile ( url , keyFile , xstream . toXML ( request ) , partnerId ) ;
@@ -93,13 +120,10 @@ public class WxMpPayServiceImpl implements WxMpPayService {
request . setOutRefundNo ( StringUtils . trimToNull ( outRefundNo ) ) ;
request . setRefundId ( StringUtils . trimToNull ( refundId ) ) ;
request . setAppid ( this . wxMpService . getWxMpConfigStorage ( ) . getAppId ( ) ) ;
request . setMchId ( this . wxMpService . getWxMpConfigStorage ( ) . getPartnerId ( ) ) ;
request . setAppid ( this . config . getAppId ( ) ) ;
request . setMchId ( this . config . getPartnerId ( ) ) ;
request . setNonceStr ( System . currentTimeMillis ( ) + " " ) ;
String sign = this . createSign ( BeanUtils . xmlBean2Map ( request ) ,
this . wxMpService . getWxMpConfigStorage ( ) . getPartnerKey ( ) ) ;
request . setSign ( sign ) ;
request . setSign ( this . createSign ( request ) ) ;
String url = PAY_BASE_URL + " /pay/refundquery " ;
@@ -109,8 +133,15 @@ public class WxMpPayServiceImpl implements WxMpPayService {
this . checkResult ( result ) ;
return result ;
}
private void checkResult ( WxPayBaseResult result ) throws WxErrorException {
//校验返回结果签名
if ( ! checkSign ( result . toMap ( ) ) ) {
throw new WxErrorException ( WxError . newBuilder ( ) . setErrorCode ( - 1 ) . setErrorMsg ( " 参数格式校验错误! " ) . build ( ) ) ;
}
//校验结果是否成功
if ( ! " SUCCESS " . equalsIgnoreCase ( result . getReturnCode ( ) )
| | ! " SUCCESS " . equalsIgnoreCase ( result . getResultCode ( ) ) ) {
throw new WxErrorException ( WxError . newBuilder ( ) . setErrorCode ( - 1 )
@@ -136,23 +167,23 @@ public class WxMpPayServiceImpl implements WxMpPayService {
}
@Override
public WxPayJsSDKCallback getJSSDKCallbackData ( String xmlData ) throws WxErrorException {
public WxPayOrderNotifyResult getOrderNotifyResult ( String xmlData ) throws WxErrorException {
try {
XStream xstream = XStreamInitializer . getInstance ( ) ;
xstream . alias ( " xml " , WxPayJsSDKCallback . class ) ;
return ( WxPayJsSDKCallback ) xstream . fromXML ( xmlData ) ;
} catch ( Exception e ) {
e . printStackTrace ( ) ;
xstream . autodetectAnnotations ( true ) ;
xstream . registerConverter ( new WxPayOrderNotifyResultConverter ( xstream . getMapper ( ) , xstream . getReflectionProvider ( ) ) ) ;
WxPayOrderNotifyResult result = ( WxPayOrderNotifyResult ) xstream . fromXML ( xmlData ) ;
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 boolean checkJSSDKCallbackDataSignature ( Map < String , String > kvm ,
String signature ) {
return signature . equals ( this . createSign ( kvm ,
this . wxMpService . getWxMpConfigStorage ( ) . getPartnerKey ( ) ) ) ;
}
@Override
public WxPaySendRedpackResult sendRedpack ( WxPaySendRedpackRequest request , File keyFile )
@@ -161,14 +192,11 @@ public class WxMpPayServiceImpl implements WxMpPayService {
xstream . processAnnotations ( WxPaySendRedpackRequest . class ) ;
xstream . processAnnotations ( WxPaySendRedpackResult . class ) ;
request . setWxAppid ( this . wxMpService . getWxMpConfigStorage ( ) . getAppId ( ) ) ;
String mchId = this . wxMpService . getWxMpConfigStorage ( ) . getPartnerId ( ) ;
request . setWxAppid ( this . config . getAppId ( ) ) ;
String mchId = this . config . getPartnerId ( ) ;
request . setMchId ( mchId ) ;
request . setNonceStr ( System . currentTimeMillis ( ) + " " ) ;
String sign = this . createSign ( BeanUtils . xmlBean2Map ( request ) ,
this . wxMpService . getWxMpConfigStorage ( ) . getPartnerKey ( ) ) ;
request . setSign ( sign ) ;
request . setSign ( this . createSign ( request ) ) ;
String url = PAY_BASE_URL + " /mmpaymkttransfers/sendredpack " ;
if ( request . getAmtType ( ) ! = null ) {
@@ -177,8 +205,7 @@ public class WxMpPayServiceImpl implements WxMpPayService {
}
String responseContent = this . executeRequestWithKeyFile ( url , keyFile , xstream . toXML ( request ) , mchId ) ;
WxPaySendRedpackResult result = ( WxPaySendRedpackResult ) xstream
. fromXML ( responseContent ) ;
WxPaySendRedpackResult result = ( WxPaySendRedpackResult ) xstream . fromXML ( responseContent ) ;
this . checkResult ( result ) ;
return result ;
}
@@ -193,13 +220,12 @@ public class WxMpPayServiceImpl implements WxMpPayService {
request . setMchBillNo ( mchBillNo ) ;
request . setBillType ( " MCHT " ) ;
request . setAppid ( this . wxMpService . getWxMpConfigStorage ( ) . getAppId ( ) ) ;
String mchId = this . wxMpService . getWxMpConfigStorage ( ) . getPartnerId ( ) ;
request . setAppid ( this . config . getAppId ( ) ) ;
String mchId = this . config . getPartnerId ( ) ;
request . setMchId ( mchId ) ;
request . setNonceStr ( System . currentTimeMillis ( ) + " " ) ;
String sign = this . createSign ( BeanUtils . xmlBean2Map ( request) ,
this . wxMpService . getWxMpConfigStorage ( ) . getPartnerKey ( ) ) ;
String sign = this . createSign ( request ) ;
request . setSign ( sign ) ;
String url = PAY_BASE_URL + " /mmpaymkttransfers/gethbinfo " ;
@@ -208,30 +234,59 @@ public class WxMpPayServiceImpl implements WxMpPayService {
this . checkResult ( result ) ;
return result ;
}
@Override
public String createSign ( Object xmlBean ) {
return createSign ( BeanUtils . xmlBean2Map ( xmlBean ) , this . config . getPartnerKey ( ) ) ;
}
@Override
public String createSign ( Object xmlBean , String signKey ) {
return createSign ( BeanUtils . xmlBean2Map ( xmlBean ) , signKey ) ;
}
@Override
public String createSign ( Map < String , String > params ) {
return createSign ( params , this . config . getPartnerKey ( ) ) ;
}
/**
* 微信公众号支付签名算法(详见:https://pay.weixin.qq.com/wiki/doc/api/tools/cash_coupon.php?chapter=4_3)
*
* @param packageParams 原始参数
* @param signKey 加密Key(即 商户Key)
* @return 签名字符串
*/
private String createSign ( Map < String , String > packageParams , String signKey ) {
SortedMap < String , String > sortedMap = new TreeMap < > ( packageParams ) ;
@Override
public String createSign ( Map < String , String > params , String signKey ) {
SortedMap < String , String > sortedMap = new TreeMap < > ( params ) ;
StringBuilder toSign = new StringBuilder ( ) ;
for ( String key : sortedMap . keySet ( ) ) {
String value = packagePa rams . get ( key ) ;
if ( null ! = value & & ! " " . equals ( value ) & & ! " sign " . equals ( key )
& & ! " key " . equals ( key ) ) {
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 checkSign ( BeanUtils . xmlBean2Map ( xmlBean ) , this . config . getPartnerKey ( ) ) ;
}
@Override
public boolean checkSign ( Object xmlBean , String signKey ) {
return checkSign ( BeanUtils . xmlBean2Map ( xmlBean ) , signKey ) ;
}
@Override
public boolean checkSign ( Map < String , String > params ) {
return checkSign ( params , this . config . getPartnerKey ( ) ) ;
}
@Override
public boolean checkSign ( Map < String , String > params , String signKey ) {
String sign = this . createSign ( params , signKey ) ;
return sign . equals ( params . get ( " sign " ) ) ;
}
@Override
public WxPayOrderQueryResult queryOrder ( String transactionId , String outTradeNo ) throws WxErrorException {
@@ -247,13 +302,10 @@ public class WxMpPayServiceImpl implements WxMpPayService {
WxPayOrderQueryRequest request = new WxPayOrderQueryRequest ( ) ;
request . setOutTradeNo ( StringUtils . trimToNull ( outTradeNo ) ) ;
request . setTransactionId ( StringUtils . trimToNull ( transactionId ) ) ;
request . setAppid ( this . wxMpService . getWxMpConfigStorage ( ) . getAppId ( ) ) ;
request . setMchId ( this . wxMpService . getWxMpConfigStorage ( ) . getPartnerId ( ) ) ;
request . setAppid ( this . config . getAppId ( ) ) ;
request . setMchId ( this . config . getPartnerId ( ) ) ;
request . setNonceStr ( System . currentTimeMillis ( ) + " " ) ;
String sign = this . createSign ( BeanUtils . xmlBean2Map ( request ) ,
this . wxMpService . getWxMpConfigStorage ( ) . getPartnerKey ( ) ) ;
request . setSign ( sign ) ;
request . setSign ( this . createSign ( request ) ) ;
String url = PAY_BASE_URL + " /pay/orderquery " ;
@@ -276,13 +328,10 @@ public class WxMpPayServiceImpl implements WxMpPayService {
WxPayOrderCloseRequest request = new WxPayOrderCloseRequest ( ) ;
request . setOutTradeNo ( StringUtils . trimToNull ( outTradeNo ) ) ;
request . setAppid ( this . wxMpService . getWxMpConfigStorage ( ) . getAppId ( ) ) ;
request . setMchId ( this . wxMpService . getWxMpConfigStorage ( ) . getPartnerId ( ) ) ;
request . setAppid ( this . config . getAppId ( ) ) ;
request . setMchId ( this . config . getPartnerId ( ) ) ;
request . setNonceStr ( System . currentTimeMillis ( ) + " " ) ;
String sign = this . createSign ( BeanUtils . xmlBean2Map ( request ) ,
this . wxMpService . getWxMpConfigStorage ( ) . getPartnerKey ( ) ) ;
request . setSign ( sign ) ;
request . setSign ( this . createSign ( request ) ) ;
String url = PAY_BASE_URL + " /pay/closeorder " ;
@@ -302,13 +351,25 @@ public class WxMpPayServiceImpl implements WxMpPayService {
xstream . processAnnotations ( WxPayUnifiedOrderRequest . class ) ;
xstream . processAnnotations ( WxPayUnifiedOrderResult . class ) ;
request . setAppid ( this . wxMpService . getWxMpConfigStorage ( ) . getAppId ( ) ) ;
request . setMchId ( this . wxMpService . getWxMpConfigStorage ( ) . getPartnerId ( ) ) ;
request . setNonceStr ( System . currentTimeMillis ( ) + " " ) ;
String sign = this . createSign ( BeanUtils . xmlBean2Map ( request ) ,
this . wxMpService . getWxMpConfigStorage ( ) . getPartnerKey ( ) ) ;
request . s etSign ( sign ) ;
WxMpConfigStorage config = this . config ;
//如果没有设置,则使用配置中默认值
if ( StringUtils . isBlank ( request . getAppid ( ) ) ) {
request . setAppid ( config . getAppId ( ) ) ;
}
if ( StringUtils . isBlank ( request . g etMchId ( ) ) ) {
request . setMchId ( config . getPartnerId ( ) ) ;
}
if ( StringUtils . isBlank ( request . getNotifyURL ( ) ) ) {
request . setNotifyURL ( config . getNotifyURL ( ) ) ;
}
if ( StringUtils . isBlank ( request . getTradeType ( ) ) ) {
request . setTradeType ( config . getTradeType ( ) ) ;
}
if ( StringUtils . isBlank ( request . getNonceStr ( ) ) ) {
request . setNonceStr ( System . currentTimeMillis ( ) + " " ) ;
}
request . setSign ( this . createSign ( request ) ) ;
String url = PAY_BASE_URL + " /pay/unifiedorder " ;
@@ -345,7 +406,7 @@ public class WxMpPayServiceImpl implements WxMpPayService {
}
Map < String , String > payInfo = new HashMap < > ( ) ;
payInfo . put ( " appId " , this . wxMpService . getWxMpConfigStorage ( ) . getAppId ( ) ) ;
payInfo . put ( " appId " , this . config . getAppId ( ) ) ;
// 支付签名时间戳, 注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
payInfo . put ( " timeStamp " , String . valueOf ( System . currentTimeMillis ( ) / 1000 ) ) ;
payInfo . put ( " nonceStr " , System . currentTimeMillis ( ) + " " ) ;
@@ -354,9 +415,7 @@ public class WxMpPayServiceImpl implements WxMpPayService {
if ( " NATIVE " . equals ( request . getTradeType ( ) ) ) {
payInfo . put ( " codeUrl " , unifiedOrderResult . getCodeURL ( ) ) ;
}
String finalSign = this . createSign ( payInfo , this . wxMpService . getWxMpConfigStorage ( ) . getPartnerKey ( ) ) ;
payInfo . put ( " paySign " , finalSign ) ;
payInfo . put ( " paySign " , this . createSign ( payInfo ) ) ;
return payInfo ;
}
@@ -368,12 +427,10 @@ public class WxMpPayServiceImpl implements WxMpPayService {
xstream . processAnnotations ( WxEntPayRequest . class ) ;
xstream . processAnnotations ( WxEntPayResult . class ) ;
request . setMchAppid ( this . wxMpService . getWxMpConfigStorage ( ) . getAppId ( ) ) ;
request . setMchId ( this . wxMpService . getWxMpConfigStorage ( ) . getPartnerId ( ) ) ;
request . setMchAppid ( this . config . getAppId ( ) ) ;
request . setMchId ( this . config . getPartnerId ( ) ) ;
request . setNonceStr ( System . currentTimeMillis ( ) + " " ) ;
String sign = this . createSign ( BeanUtils . xmlBean2Map ( request ) , this . wxMpService . getWxMpConfigStorage ( ) . getPartnerKey ( ) ) ;
request . setSign ( sign ) ;
request . setSign ( this . createSign ( request ) ) ;
String url = PAY_BASE_URL + " /mmpaymkttransfers/promotion/transfers " ;
@@ -390,12 +447,10 @@ public class WxMpPayServiceImpl implements WxMpPayService {
xstream . processAnnotations ( WxEntPayQueryResult . class ) ;
WxEntPayQueryRequest request = new WxEntPayQueryRequest ( ) ;
request . setAppid ( this . wxMpService . getWxMpConfigStorage ( ) . getAppId ( ) ) ;
request . setMchId ( this . wxMpService . getWxMpConfigStorage ( ) . getPartnerId ( ) ) ;
request . setAppid ( this . config . getAppId ( ) ) ;
request . setMchId ( this . config . getPartnerId ( ) ) ;
request . setNonceStr ( System . currentTimeMillis ( ) + " " ) ;
String sign = this . createSign ( BeanUtils . xmlBean2Map ( request ) , this . wxMpService . getWxMpConfigStorage ( ) . getPartnerKey ( ) ) ;
request . setSign ( sign ) ;
request . setSign ( this . createSign ( request ) ) ;
String url = PAY_BASE_URL + " /mmpaymkttransfers/gettransferinfo " ;
@@ -456,5 +511,4 @@ public class WxMpPayServiceImpl implements WxMpPayService {
throw new WxErrorException ( WxError . newBuilder ( ) . setErrorCode ( - 1 ) . setErrorMsg ( e . getMessage ( ) ) . build ( ) , e ) ;
}
}
}