Skip to content

Commit c142daa

Browse files
committed
添加扫码支付生成二维码的接口及其单元测试,binarywang#113
1 parent 2d072e9 commit c142daa

File tree

5 files changed

+115
-14
lines changed

5 files changed

+115
-14
lines changed

weixin-java-mp/pom.xml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,11 @@
5959
<artifactId>xml-path</artifactId>
6060
<version>3.0.1</version>
6161
</dependency>
62-
62+
<dependency>
63+
<groupId>com.github.binarywang</groupId>
64+
<artifactId>qrcode-utils</artifactId>
65+
<version>1.0</version>
66+
</dependency>
6367
</dependencies>
6468

6569
<build>

weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpPayService.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import me.chanjar.weixin.mp.bean.pay.request.WxPayUnifiedOrderRequest;
88
import me.chanjar.weixin.mp.bean.pay.result.*;
99

10+
import java.io.File;
1011
import java.util.Map;
1112

1213
/**
@@ -235,4 +236,32 @@ public interface WxMpPayService {
235236
*/
236237
WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxErrorException;
237238

239+
/**
240+
* <pre>
241+
* 扫码支付模式一生成二维码的方法
242+
* 二维码中的内容为链接,形式为:
243+
* weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX
244+
* 其中XXXXX为商户需要填写的内容,商户将该链接生成二维码,如需要打印发布二维码,需要采用此格式。商户可调用第三方库生成二维码图片。
245+
* 文档详见: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4
246+
* </pre>
247+
* @param productId 产品Id
248+
* @param sideLength 要生成的二维码的边长,如果为空,则取默认值400
249+
* @param logoFile 商户logo图片的文件对象,可以为空
250+
* @return 生成的二维码的字节数组
251+
*/
252+
byte[] createScanPayQrcodeMode1(String productId, File logoFile, Integer sideLength);
253+
254+
/**
255+
* <pre>
256+
* 扫码支付模式二生成二维码的方法
257+
* 对应链接格式:weixin://wxpay/bizpayurl?sr=XXXXX。请商户调用第三方库将code_url生成二维码图片。
258+
* 该模式链接较短,生成的二维码打印到结账小票上的识别率较高。
259+
* 文档详见: https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_5
260+
* </pre>
261+
* @param codeUrl 微信返回的交易会话的二维码链接
262+
* @param logoFile 商户logo图片的文件对象,可以为空
263+
* @param sideLength 要生成的二维码的边长,如果为空,则取默认值400
264+
* @return 生成的二维码的字节数组
265+
*/
266+
byte[] createScanPayQrcodeMode2(String codeUrl, File logoFile, Integer sideLength);
238267
}

weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImpl.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package me.chanjar.weixin.mp.api.impl;
22

3+
import com.github.binarywang.utils.qrcode.QrcodeUtils;
4+
import com.google.common.collect.Maps;
35
import me.chanjar.weixin.common.bean.result.WxError;
46
import me.chanjar.weixin.common.exception.WxErrorException;
57
import me.chanjar.weixin.common.util.BeanUtils;
@@ -25,6 +27,7 @@
2527
import org.slf4j.LoggerFactory;
2628

2729
import javax.net.ssl.SSLContext;
30+
import java.io.File;
2831
import java.io.IOException;
2932
import java.util.*;
3033

@@ -316,6 +319,41 @@ public WxEntPayQueryResult queryEntPay(String partnerTradeNo) throws WxErrorExce
316319
return result;
317320
}
318321

322+
@Override
323+
public byte[] createScanPayQrcodeMode1(String productId, File logoFile, Integer sideLength) {
324+
//weixin://wxpay/bizpayurl?sign=XXXXX&appid=XXXXX&mch_id=XXXXX&product_id=XXXXXX&time_stamp=XXXXXX&nonce_str=XXXXX
325+
StringBuilder codeUrl = new StringBuilder("weixin://wxpay/bizpayurl?");
326+
Map<String, String> params = Maps.newHashMap();
327+
params.put("appid", this.getConfig().getAppId());
328+
params.put("mch_id", this.getConfig().getPartnerId());
329+
params.put("product_id", productId);
330+
params.put("time_stamp", String.valueOf(System.currentTimeMillis()));
331+
params.put("nonce_str", String.valueOf(System.currentTimeMillis()));
332+
333+
String sign = this.createSign(params);
334+
params.put("sign", sign);
335+
336+
for (String key : params.keySet()) {
337+
codeUrl.append(key + "=" + params.get(key) + "&");
338+
}
339+
340+
String content = codeUrl.toString().substring(0, codeUrl.length() - 1);
341+
if (sideLength == null || sideLength < 1) {
342+
return QrcodeUtils.createQrcode(content, logoFile);
343+
}
344+
345+
return QrcodeUtils.createQrcode(content, sideLength, logoFile);
346+
}
347+
348+
@Override
349+
public byte[] createScanPayQrcodeMode2(String codeUrl, File logoFile, Integer sideLength) {
350+
if (sideLength == null || sideLength < 1) {
351+
return QrcodeUtils.createQrcode(codeUrl, logoFile);
352+
}
353+
354+
return QrcodeUtils.createQrcode(codeUrl, sideLength, logoFile);
355+
}
356+
319357
private String executeRequest(String url, String requestStr) throws WxErrorException {
320358
HttpPost httpPost = new HttpPost(url);
321359
if (this.wxMpService.getHttpProxy() != null) {

weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/ApiTestModule.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ public void configure(Binder binder) {
1919
WxXmlMpInMemoryConfigStorage config = this
2020
.fromXml(WxXmlMpInMemoryConfigStorage.class, is1);
2121
config.setAccessTokenLock(new ReentrantLock());
22-
config.setSslContextFilePath(config.getKeyPath());
2322
WxMpService wxService = new WxMpServiceImpl();
2423
wxService.setWxMpConfigStorage(config);
2524

weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpPayServiceImplTest.java

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package me.chanjar.weixin.mp.api.impl;
22

3+
import com.github.binarywang.utils.qrcode.QrcodeUtils;
34
import com.google.inject.Inject;
45
import me.chanjar.weixin.common.exception.WxErrorException;
56
import me.chanjar.weixin.mp.api.ApiTestModule;
@@ -10,9 +11,13 @@
1011
import me.chanjar.weixin.mp.bean.pay.request.WxPaySendRedpackRequest;
1112
import me.chanjar.weixin.mp.bean.pay.request.WxPayUnifiedOrderRequest;
1213
import me.chanjar.weixin.mp.bean.pay.result.*;
14+
import org.testng.Assert;
1315
import org.testng.annotations.Guice;
1416
import org.testng.annotations.Test;
1517

18+
import java.nio.file.Files;
19+
import java.nio.file.Path;
20+
1621
/**
1722
* 测试支付相关接口
1823
* Created by Binary Wang on 2016/7/28.
@@ -22,7 +27,6 @@
2227
@Test
2328
@Guice(modules = ApiTestModule.class)
2429
public class WxMpPayServiceImplTest {
25-
2630
@Inject
2731
protected WxMpService wxService;
2832

@@ -32,9 +36,17 @@ public void testGetPayInfo() throws Exception {
3236
}
3337

3438
/**
35-
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#refund(WxPayRefundRequest)} .
39+
* 需要证书的接口需要先执行该方法
3640
*/
3741
@Test
42+
public void setSSLKey(){
43+
WxXmlMpInMemoryConfigStorage config = (WxXmlMpInMemoryConfigStorage) this.wxService.getWxMpConfigStorage();
44+
config.setSslContextFilePath(config.getKeyPath());
45+
}
46+
/**
47+
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#refund(WxPayRefundRequest)} .
48+
*/
49+
@Test(dependsOnMethods = {"setSSLKey"})
3850
public void testRefund() throws Exception {
3951
WxPayRefundRequest request = new WxPayRefundRequest();
4052
request.setOutRefundNo("aaa");
@@ -45,7 +57,6 @@ public void testRefund() throws Exception {
4557
System.err.println(result);
4658
}
4759

48-
4960
/**
5061
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#refundQuery(String, String, String, String)} .
5162
*/
@@ -63,15 +74,10 @@ public void testRefundQuery() throws Exception {
6374
System.err.println(result);
6475
}
6576

66-
@Test
67-
public void testCheckJSSDKCallbackDataSignature() throws Exception {
68-
69-
}
70-
7177
/**
7278
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#sendRedpack(WxPaySendRedpackRequest)} .
7379
*/
74-
@Test
80+
@Test(dependsOnMethods = {"setSSLKey"})
7581
public void testSendRedpack() throws Exception {
7682
WxPaySendRedpackRequest request = new WxPaySendRedpackRequest();
7783
request.setActName("abc");
@@ -86,7 +92,7 @@ public void testSendRedpack() throws Exception {
8692
/**
8793
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#queryRedpack(String)}.
8894
*/
89-
@Test
95+
@Test(dependsOnMethods = {"setSSLKey"})
9096
public void testQueryRedpack() throws Exception {
9197
WxPayRedpackQueryResult redpackResult = this.wxService.getPayService().queryRedpack("aaaa");
9298
System.err.println(redpackResult);
@@ -125,7 +131,7 @@ public final void testCloseOrder() throws WxErrorException {
125131
/**
126132
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#entPay(WxEntPayRequest)}.
127133
*/
128-
@Test
134+
@Test(dependsOnMethods = {"setSSLKey"})
129135
public final void testEntPay() throws WxErrorException {
130136
WxEntPayRequest request = new WxEntPayRequest();
131137
System.err.println(this.wxService.getPayService().entPay(request));
@@ -134,8 +140,33 @@ public final void testEntPay() throws WxErrorException {
134140
/**
135141
* Test method for {@link me.chanjar.weixin.mp.api.impl.WxMpPayServiceImpl#queryEntPay(String)}.
136142
*/
137-
@Test
143+
@Test(dependsOnMethods = {"setSSLKey"})
138144
public final void testQueryEntPay() throws WxErrorException {
139145
System.err.println(this.wxService.getPayService().queryEntPay("11212121"));
140146
}
147+
148+
@Test
149+
public void testCreateScanPayQrcodeMode1() throws Exception {
150+
String productId = "abc";
151+
byte[] bytes = this.wxService.getPayService().createScanPayQrcodeMode1(productId, null, null);
152+
Path qrcodeFilePath = Files.createTempFile("qrcode_", ".jpg");
153+
Files.write(qrcodeFilePath, bytes);
154+
String qrcodeContent = QrcodeUtils.decodeQrcode(qrcodeFilePath.toFile());
155+
System.out.println(qrcodeContent);
156+
157+
Assert.assertTrue(qrcodeContent.startsWith("weixin://wxpay/bizpayurl?"));
158+
Assert.assertTrue(qrcodeContent.contains("product_id=" + productId));
159+
}
160+
161+
@Test
162+
public void testCreateScanPayQrcodeMode2() throws Exception {
163+
String qrcodeContent = "abc";
164+
byte[] bytes = this.wxService.getPayService().createScanPayQrcodeMode2(qrcodeContent, null, null);
165+
Path qrcodeFilePath = Files.createTempFile("qrcode_", ".jpg");
166+
Files.write(qrcodeFilePath, bytes);
167+
168+
Assert.assertEquals(QrcodeUtils.decodeQrcode(qrcodeFilePath.toFile()), qrcodeContent);
169+
}
170+
171+
141172
}

0 commit comments

Comments
 (0)