11package me .chanjar .weixin .mp .api .impl ;
22
3- import java .io .File ;
4- import java .io .FileInputStream ;
5- import java .lang .reflect .Field ;
6- import java .security .KeyStore ;
7- import java .util .HashMap ;
8- import java .util .List ;
9- import java .util .Map ;
10- import java .util .Map .Entry ;
11- import java .util .SortedMap ;
12- import java .util .TreeMap ;
13-
14- import javax .net .ssl .SSLContext ;
15-
3+ import com .google .common .collect .Lists ;
4+ import com .google .common .collect .Maps ;
5+ import com .thoughtworks .xstream .XStream ;
6+ import com .thoughtworks .xstream .annotations .XStreamAlias ;
7+ import me .chanjar .weixin .common .annotation .Required ;
8+ import me .chanjar .weixin .common .bean .result .WxError ;
9+ import me .chanjar .weixin .common .exception .WxErrorException ;
10+ import me .chanjar .weixin .common .util .xml .XStreamInitializer ;
11+ import me .chanjar .weixin .mp .api .WxMpPayService ;
12+ import me .chanjar .weixin .mp .api .WxMpService ;
13+ import me .chanjar .weixin .mp .bean .pay .*;
1614import org .apache .commons .codec .digest .DigestUtils ;
15+ import org .apache .commons .lang3 .ArrayUtils ;
1716import org .apache .commons .lang3 .StringUtils ;
1817import org .apache .http .client .methods .CloseableHttpResponse ;
1918import org .apache .http .client .methods .HttpPost ;
2625import org .apache .http .util .EntityUtils ;
2726import org .joor .Reflect ;
2827
29- import com .google .common .collect .Lists ;
30- import com .google .common .collect .Maps ;
31- import com .thoughtworks .xstream .XStream ;
32- import com .thoughtworks .xstream .annotations .XStreamAlias ;
33-
34- import me .chanjar .weixin .common .annotation .Required ;
35- import me .chanjar .weixin .common .bean .result .WxError ;
36- import me .chanjar .weixin .common .exception .WxErrorException ;
37- import me .chanjar .weixin .common .util .xml .XStreamInitializer ;
38- import me .chanjar .weixin .mp .api .WxMpPayService ;
39- import me .chanjar .weixin .mp .api .WxMpService ;
40- import me .chanjar .weixin .mp .bean .pay .WxEntPayRequest ;
41- import me .chanjar .weixin .mp .bean .pay .WxEntPayResult ;
42- import me .chanjar .weixin .mp .bean .pay .WxMpPayCallback ;
43- import me .chanjar .weixin .mp .bean .pay .WxMpPayRefundResult ;
44- import me .chanjar .weixin .mp .bean .pay .WxMpPayResult ;
45- import me .chanjar .weixin .mp .bean .pay .WxRedpackResult ;
46- import me .chanjar .weixin .mp .bean .pay .WxSendRedpackRequest ;
47- import me .chanjar .weixin .mp .bean .pay .WxUnifiedOrderRequest ;
48- import me .chanjar .weixin .mp .bean .pay .WxUnifiedOrderResult ;
28+ import javax .net .ssl .SSLContext ;
29+ import java .io .File ;
30+ import java .io .FileInputStream ;
31+ import java .lang .reflect .Field ;
32+ import java .security .KeyStore ;
33+ import java .util .*;
34+ import java .util .Map .Entry ;
4935
5036/**
5137 * Created by Binary Wang on 2016/7/28.
5541public class WxMpPayServiceImpl implements WxMpPayService {
5642
5743 private static final String PAY_BASE_URL = "https://api.mch.weixin.qq.com" ;
58- private static final List <String > TRADE_TYPES = Lists .newArrayList ("JSAPI" ,
59- "NATIVE" , "APP" );
44+ private static final String [] TRADE_TYPES = new String []{"JSAPI" ,"NATIVE" , "APP" };
45+ private static final String [] REFUND_ACCOUNT = new String []{"REFUND_SOURCE_RECHARGE_FUNDS" ,
46+ "REFUND_SOURCE_UNSETTLED_FUNDS" };
47+
6048 private WxMpService wxMpService ;
6149
6250 public WxMpPayServiceImpl (WxMpService wxMpService ) {
@@ -115,33 +103,25 @@ public WxMpPayCallback getJSSDKCallbackData(String xmlData) {
115103 }
116104
117105 @ Override
118- public WxMpPayRefundResult refundPay ( Map < String , String > parameters )
106+ public WxMpPayRefundResult refund ( WxMpPayRefundRequest request , File keyFile )
119107 throws WxErrorException {
120- SortedMap <String , String > refundParams = new TreeMap <>(parameters );
121- refundParams .put ("appid" ,
122- this .wxMpService .getWxMpConfigStorage ().getAppId ());
123- refundParams .put ("mch_id" ,
124- this .wxMpService .getWxMpConfigStorage ().getPartnerId ());
125- refundParams .put ("nonce_str" , System .currentTimeMillis () + "" );
126- refundParams .put ("op_user_id" ,
127- this .wxMpService .getWxMpConfigStorage ().getPartnerId ());
128- String sign = this .createSign (refundParams ,
129- this .wxMpService .getWxMpConfigStorage ().getPartnerKey ());
130- refundParams .put ("sign" , sign );
131-
132- StringBuilder request = new StringBuilder ("<xml>" );
133- for (Map .Entry <String , String > para : refundParams .entrySet ()) {
134- request .append (String .format ("<%s>%s</%s>" , para .getKey (),
135- para .getValue (), para .getKey ()));
136- }
137- request .append ("</xml>" );
108+ checkParameters (request );
138109
139- String url = PAY_BASE_URL + "/secapi/pay/refund" ;
140- String responseContent = this .wxMpService .post (url , request .toString ());
141110 XStream xstream = XStreamInitializer .getInstance ();
142111 xstream .processAnnotations (WxMpPayRefundResult .class );
143- WxMpPayRefundResult wxMpPayRefundResult = (WxMpPayRefundResult ) xstream
144- .fromXML (responseContent );
112+ xstream .processAnnotations (WxMpPayRefundRequest .class );
113+
114+ request .setAppid (this .wxMpService .getWxMpConfigStorage ().getAppId ());
115+ String partnerId = this .wxMpService .getWxMpConfigStorage ().getPartnerId ();
116+ request .setMchId (partnerId );
117+ request .setNonceStr ( System .currentTimeMillis () + "" );
118+ request .setOpUserId (partnerId );
119+ String sign = this .createSign (this .xmlBean2Map (request ), this .wxMpService .getWxMpConfigStorage ().getPartnerKey ());
120+ request .setSign (sign );
121+
122+ String url = PAY_BASE_URL + "/secapi/pay/refund" ;
123+ String responseContent = this .executeRequestWithKeyFile (url , xstream .toXML (request ), keyFile , partnerId );
124+ WxMpPayRefundResult wxMpPayRefundResult = (WxMpPayRefundResult ) xstream .fromXML (responseContent );
145125
146126 if (!"SUCCESS" .equalsIgnoreCase (wxMpPayRefundResult .getResultCode ())
147127 || !"SUCCESS" .equalsIgnoreCase (wxMpPayRefundResult .getReturnCode ())) {
@@ -158,6 +138,20 @@ public WxMpPayRefundResult refundPay(Map<String, String> parameters)
158138 return wxMpPayRefundResult ;
159139 }
160140
141+ private void checkParameters (WxMpPayRefundRequest request ) {
142+ checkNotNullParams (request );
143+
144+ if (StringUtils .isNotBlank (request .getRefundAccount ())) {
145+ if (!ArrayUtils .contains (REFUND_ACCOUNT , request .getRefundAccount ())){
146+ throw new IllegalArgumentException ("refund_account目前必须为" + Arrays .toString (REFUND_ACCOUNT ) + "其中之一" );
147+ }
148+ }
149+
150+ if (StringUtils .isBlank (request .getOutTradeNo ()) && StringUtils .isBlank (request .getTransactionId ())) {
151+ throw new IllegalArgumentException ("transaction_id 和 out_trade_no 不能同时为空,必须提供一个" );
152+ }
153+ }
154+
161155 @ Override
162156 public boolean checkJSSDKCallbackDataSignature (Map <String , String > kvm ,
163157 String signature ) {
@@ -176,7 +170,7 @@ public WxRedpackResult sendRedpack(WxSendRedpackRequest request)
176170 request .setMchId (this .wxMpService .getWxMpConfigStorage ().getPartnerId ());
177171 request .setNonceStr (System .currentTimeMillis () + "" );
178172
179- String sign = this .createSign (xmlBean2Map (request ),
173+ String sign = this .createSign (this . xmlBean2Map (request ),
180174 this .wxMpService .getWxMpConfigStorage ().getPartnerKey ());
181175 request .setSign (sign );
182176
@@ -258,7 +252,7 @@ public WxUnifiedOrderResult unifiedOrder(WxUnifiedOrderRequest request)
258252 request .setMchId (this .wxMpService .getWxMpConfigStorage ().getPartnerId ());
259253 request .setNonceStr (System .currentTimeMillis () + "" );
260254
261- String sign = this .createSign (xmlBean2Map (request ),
255+ String sign = this .createSign (this . xmlBean2Map (request ),
262256 this .wxMpService .getWxMpConfigStorage ().getPartnerKey ());
263257 request .setSign (sign );
264258
@@ -274,16 +268,13 @@ public WxUnifiedOrderResult unifiedOrder(WxUnifiedOrderRequest request)
274268 }
275269
276270 return result ;
277-
278271 }
279272
280273 private void checkParameters (WxUnifiedOrderRequest request ) {
281-
282274 checkNotNullParams (request );
283275
284- if (!TRADE_TYPES .contains (request .getTradeType ())) {
285- throw new IllegalArgumentException ("trade_type目前必须为" + TRADE_TYPES + "其中之一" );
286-
276+ if (! ArrayUtils .contains (TRADE_TYPES , request .getTradeType ())) {
277+ throw new IllegalArgumentException ("trade_type目前必须为" + Arrays .toString (TRADE_TYPES ) + "其中之一" );
287278 }
288279
289280 if ("JSAPI" .equals (request .getTradeType ()) && request .getOpenid () == null ) {
@@ -368,28 +359,30 @@ public WxEntPayResult entPay(WxEntPayRequest request, File keyFile) throws WxErr
368359
369360 String url = PAY_BASE_URL + "/mmpaymkttransfers/promotion/transfers" ;
370361
371- try (FileInputStream instream = new FileInputStream (keyFile )) {
372- String mchId = request .getMchId ();
362+ String responseContent = this .executeRequestWithKeyFile (xstream .toXML (request ), url , keyFile , request .getMchId ());
363+ WxEntPayResult result = (WxEntPayResult ) xstream .fromXML (responseContent );
364+ if ("FAIL" .equals (result .getResultCode ())) {
365+ throw new WxErrorException (
366+ WxError .newBuilder ().setErrorMsg (result .getErrCode () + ":" + result .getErrCodeDes ()).build ());
367+ }
368+ return result ;
369+ }
370+
371+ private String executeRequestWithKeyFile ( String requestStr , String url , File keyFile , String mchId ) throws WxErrorException {
372+ try (FileInputStream inputStream = new FileInputStream (keyFile )) {
373373 KeyStore keyStore = KeyStore .getInstance ("PKCS12" );
374- keyStore .load (instream , mchId .toCharArray ());
374+ keyStore .load (inputStream , mchId .toCharArray ());
375375
376376 SSLContext sslcontext = SSLContexts .custom ().loadKeyMaterial (keyStore , mchId .toCharArray ()).build ();
377377 SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory (sslcontext , new String [] { "TLSv1" }, null ,
378378 new DefaultHostnameVerifier ());
379379
380380 try (CloseableHttpClient httpclient = HttpClients .custom ().setSSLSocketFactory (sslsf ).build ()) {
381381 HttpPost httpPost = new HttpPost (url );
382- httpPost .setEntity (new StringEntity (new String (xstream . toXML ( request ) .getBytes ("UTF-8" ), "ISO-8859-1" )));
382+ httpPost .setEntity (new StringEntity (new String (requestStr .getBytes ("UTF-8" ), "ISO-8859-1" )));
383383
384384 try (CloseableHttpResponse response = httpclient .execute (httpPost )) {
385- String responseContent = EntityUtils .toString (response .getEntity ());
386- WxEntPayResult result = (WxEntPayResult ) xstream .fromXML (responseContent );
387- if ("FAIL" .equals (result .getResultCode ())) {
388- throw new WxErrorException (
389- WxError .newBuilder ().setErrorMsg (result .getErrCode () + ":" + result .getErrCodeDes ()).build ());
390- }
391-
392- return result ;
385+ return EntityUtils .toString (response .getEntity ());
393386 }
394387 }
395388 } catch (Exception e ) {
0 commit comments