1
1
package me .chanjar .weixin .mp .api .impl ;
2
2
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 .*;
16
14
import org .apache .commons .codec .digest .DigestUtils ;
15
+ import org .apache .commons .lang3 .ArrayUtils ;
17
16
import org .apache .commons .lang3 .StringUtils ;
18
17
import org .apache .http .client .methods .CloseableHttpResponse ;
19
18
import org .apache .http .client .methods .HttpPost ;
26
25
import org .apache .http .util .EntityUtils ;
27
26
import org .joor .Reflect ;
28
27
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 ;
49
35
50
36
/**
51
37
* Created by Binary Wang on 2016/7/28.
55
41
public class WxMpPayServiceImpl implements WxMpPayService {
56
42
57
43
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
+
60
48
private WxMpService wxMpService ;
61
49
62
50
public WxMpPayServiceImpl (WxMpService wxMpService ) {
@@ -115,33 +103,25 @@ public WxMpPayCallback getJSSDKCallbackData(String xmlData) {
115
103
}
116
104
117
105
@ Override
118
- public WxMpPayRefundResult refundPay ( Map < String , String > parameters )
106
+ public WxMpPayRefundResult refund ( WxMpPayRefundRequest request , File keyFile )
119
107
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 );
138
109
139
- String url = PAY_BASE_URL + "/secapi/pay/refund" ;
140
- String responseContent = this .wxMpService .post (url , request .toString ());
141
110
XStream xstream = XStreamInitializer .getInstance ();
142
111
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 );
145
125
146
126
if (!"SUCCESS" .equalsIgnoreCase (wxMpPayRefundResult .getResultCode ())
147
127
|| !"SUCCESS" .equalsIgnoreCase (wxMpPayRefundResult .getReturnCode ())) {
@@ -158,6 +138,20 @@ public WxMpPayRefundResult refundPay(Map<String, String> parameters)
158
138
return wxMpPayRefundResult ;
159
139
}
160
140
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
+
161
155
@ Override
162
156
public boolean checkJSSDKCallbackDataSignature (Map <String , String > kvm ,
163
157
String signature ) {
@@ -176,7 +170,7 @@ public WxRedpackResult sendRedpack(WxSendRedpackRequest request)
176
170
request .setMchId (this .wxMpService .getWxMpConfigStorage ().getPartnerId ());
177
171
request .setNonceStr (System .currentTimeMillis () + "" );
178
172
179
- String sign = this .createSign (xmlBean2Map (request ),
173
+ String sign = this .createSign (this . xmlBean2Map (request ),
180
174
this .wxMpService .getWxMpConfigStorage ().getPartnerKey ());
181
175
request .setSign (sign );
182
176
@@ -258,7 +252,7 @@ public WxUnifiedOrderResult unifiedOrder(WxUnifiedOrderRequest request)
258
252
request .setMchId (this .wxMpService .getWxMpConfigStorage ().getPartnerId ());
259
253
request .setNonceStr (System .currentTimeMillis () + "" );
260
254
261
- String sign = this .createSign (xmlBean2Map (request ),
255
+ String sign = this .createSign (this . xmlBean2Map (request ),
262
256
this .wxMpService .getWxMpConfigStorage ().getPartnerKey ());
263
257
request .setSign (sign );
264
258
@@ -274,16 +268,13 @@ public WxUnifiedOrderResult unifiedOrder(WxUnifiedOrderRequest request)
274
268
}
275
269
276
270
return result ;
277
-
278
271
}
279
272
280
273
private void checkParameters (WxUnifiedOrderRequest request ) {
281
-
282
274
checkNotNullParams (request );
283
275
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 ) + "其中之一" );
287
278
}
288
279
289
280
if ("JSAPI" .equals (request .getTradeType ()) && request .getOpenid () == null ) {
@@ -368,28 +359,30 @@ public WxEntPayResult entPay(WxEntPayRequest request, File keyFile) throws WxErr
368
359
369
360
String url = PAY_BASE_URL + "/mmpaymkttransfers/promotion/transfers" ;
370
361
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 )) {
373
373
KeyStore keyStore = KeyStore .getInstance ("PKCS12" );
374
- keyStore .load (instream , mchId .toCharArray ());
374
+ keyStore .load (inputStream , mchId .toCharArray ());
375
375
376
376
SSLContext sslcontext = SSLContexts .custom ().loadKeyMaterial (keyStore , mchId .toCharArray ()).build ();
377
377
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory (sslcontext , new String [] { "TLSv1" }, null ,
378
378
new DefaultHostnameVerifier ());
379
379
380
380
try (CloseableHttpClient httpclient = HttpClients .custom ().setSSLSocketFactory (sslsf ).build ()) {
381
381
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" )));
383
383
384
384
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 ());
393
386
}
394
387
}
395
388
} catch (Exception e ) {
0 commit comments