Skip to content

Commit 058ce62

Browse files
authored
🐛 #1546 修复WxRedisOps问题, #1548 修复WxOpenInMemoryConfigStorage锁问题,#1305 增加商户电子发票功能
1 parent 609b38a commit 058ce62

25 files changed

+1078
-14
lines changed

weixin-java-common/src/main/java/me/chanjar/weixin/common/redis/JedisWxRedisOps.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ public String getValue(String key) {
2323
@Override
2424
public void setValue(String key, String value, int expire, TimeUnit timeUnit) {
2525
try (Jedis jedis = this.jedisPool.getResource()) {
26-
jedis.psetex(key, timeUnit.toMillis(expire), value);
26+
if (expire <= 0) {
27+
jedis.set(key, value);
28+
} else {
29+
jedis.psetex(key, timeUnit.toMillis(expire), value);
30+
}
2731
}
2832
}
2933

weixin-java-common/src/main/java/me/chanjar/weixin/common/redis/RedisTemplateWxRedisOps.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@ public String getValue(String key) {
1919

2020
@Override
2121
public void setValue(String key, String value, int expire, TimeUnit timeUnit) {
22-
redisTemplate.opsForValue().set(key, value, expire, timeUnit);
22+
if (expire <= 0) {
23+
redisTemplate.opsForValue().set(key, value);
24+
} else {
25+
redisTemplate.opsForValue().set(key, value, expire, timeUnit);
26+
}
2327
}
2428

2529
@Override

weixin-java-common/src/main/java/me/chanjar/weixin/common/redis/RedissonWxRedisOps.java

+10-2
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,20 @@ public String getValue(String key) {
1919

2020
@Override
2121
public void setValue(String key, String value, int expire, TimeUnit timeUnit) {
22-
redissonClient.getBucket(key).set(value, expire, timeUnit);
22+
if (expire <= 0) {
23+
redissonClient.getBucket(key).set(value);
24+
} else {
25+
redissonClient.getBucket(key).set(value, expire, timeUnit);
26+
}
2327
}
2428

2529
@Override
2630
public Long getExpire(String key) {
27-
return redissonClient.getBucket(key).remainTimeToLive();
31+
long expire = redissonClient.getBucket(key).remainTimeToLive();
32+
if (expire > 0) {
33+
expire = expire / 1000;
34+
}
35+
return expire;
2836
}
2937

3038
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package me.chanjar.weixin.common.redis;
2+
3+
import org.testng.Assert;
4+
import org.testng.annotations.Test;
5+
6+
import java.util.concurrent.TimeUnit;
7+
8+
public class CommonWxRedisOpsTest {
9+
10+
protected WxRedisOps wxRedisOps;
11+
private String key = "access_token";
12+
private String value = String.valueOf(System.currentTimeMillis());
13+
14+
@Test
15+
public void testGetValue() {
16+
wxRedisOps.setValue(key, value, 3, TimeUnit.SECONDS);
17+
Assert.assertEquals(wxRedisOps.getValue(key), value);
18+
}
19+
20+
@Test
21+
public void testSetValue() {
22+
String key = "access_token", value = String.valueOf(System.currentTimeMillis());
23+
wxRedisOps.setValue(key, value, -1, TimeUnit.SECONDS);
24+
wxRedisOps.setValue(key, value, 0, TimeUnit.SECONDS);
25+
wxRedisOps.setValue(key, value, 1, TimeUnit.SECONDS);
26+
}
27+
28+
@Test
29+
public void testGetExpire() {
30+
String key = "access_token", value = String.valueOf(System.currentTimeMillis());
31+
wxRedisOps.setValue(key, value, -1, TimeUnit.SECONDS);
32+
Assert.assertTrue(wxRedisOps.getExpire(key) < 0);
33+
wxRedisOps.setValue(key, value, 4, TimeUnit.SECONDS);
34+
Long expireSeconds = wxRedisOps.getExpire(key);
35+
Assert.assertTrue(expireSeconds <= 4 && expireSeconds >= 0);
36+
}
37+
38+
@Test
39+
public void testExpire() {
40+
String key = "access_token", value = String.valueOf(System.currentTimeMillis());
41+
wxRedisOps.setValue(key, value, -1, TimeUnit.SECONDS);
42+
wxRedisOps.expire(key, 4, TimeUnit.SECONDS);
43+
Long expireSeconds = wxRedisOps.getExpire(key);
44+
Assert.assertTrue(expireSeconds <= 4 && expireSeconds >= 0);
45+
}
46+
47+
@Test
48+
public void testGetLock() {
49+
Assert.assertNotNull(wxRedisOps.getLock("access_token_lock"));
50+
}
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package me.chanjar.weixin.common.redis;
2+
3+
import org.testng.annotations.AfterTest;
4+
import org.testng.annotations.BeforeTest;
5+
import redis.clients.jedis.JedisPool;
6+
7+
public class JedisWxRedisOpsTest extends CommonWxRedisOpsTest {
8+
9+
JedisPool jedisPool;
10+
11+
@BeforeTest
12+
public void init() {
13+
this.jedisPool = new JedisPool("127.0.0.1", 6379);
14+
this.wxRedisOps = new JedisWxRedisOps(jedisPool);
15+
}
16+
17+
@AfterTest
18+
public void destroy() {
19+
this.jedisPool.close();
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package me.chanjar.weixin.common.redis;
2+
3+
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
4+
import org.springframework.data.redis.core.StringRedisTemplate;
5+
import org.testng.annotations.AfterTest;
6+
import org.testng.annotations.BeforeTest;
7+
8+
public class RedisTemplateWxRedisOpsTest extends CommonWxRedisOpsTest {
9+
10+
StringRedisTemplate redisTemplate;
11+
12+
@BeforeTest
13+
public void init() {
14+
JedisConnectionFactory connectionFactory = new JedisConnectionFactory();
15+
connectionFactory.setHostName("127.0.0.1");
16+
connectionFactory.setPort(6379);
17+
connectionFactory.afterPropertiesSet();
18+
StringRedisTemplate redisTemplate = new StringRedisTemplate(connectionFactory);
19+
this.redisTemplate = redisTemplate;
20+
this.wxRedisOps = new RedisTemplateWxRedisOps(this.redisTemplate);
21+
}
22+
23+
@AfterTest
24+
public void destroy() {
25+
}
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package me.chanjar.weixin.common.redis;
2+
3+
import org.redisson.Redisson;
4+
import org.redisson.api.RedissonClient;
5+
import org.redisson.config.Config;
6+
import org.redisson.config.TransportMode;
7+
import org.testng.annotations.AfterTest;
8+
import org.testng.annotations.BeforeTest;
9+
10+
public class RedissonWxRedisOpsTest extends CommonWxRedisOpsTest {
11+
12+
RedissonClient redissonClient;
13+
14+
@BeforeTest
15+
public void init() {
16+
Config config = new Config();
17+
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
18+
config.setTransportMode(TransportMode.NIO);
19+
this.redissonClient = Redisson.create(config);
20+
this.wxRedisOps = new RedissonWxRedisOps(this.redissonClient);
21+
}
22+
23+
@AfterTest
24+
public void destroy() {
25+
this.redissonClient.shutdown();
26+
}
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package me.chanjar.weixin.mp.api;
2+
3+
4+
import me.chanjar.weixin.common.error.WxErrorException;
5+
import me.chanjar.weixin.mp.bean.invoice.merchant.*;
6+
7+
/**
8+
* 商户电子发票相关的接口
9+
* <p>
10+
* 重要!!!, 根据不同开票平台, 以下错误码可能开票成功(开票,冲红), 内部暂时未处理:
11+
* 73105: 开票平台开票中,请使用相同的发票请求流水号重试开票
12+
* 73107: 发票请求流水正在被处理,请通过查询接口获取结果
13+
* 73100: 开票平台错误
14+
* <p>
15+
* 流程文档: https://developers.weixin.qq.com/doc/offiaccount/WeChat_Invoice/E_Invoice/Vendor_and_Invoicing_Platform_Mode_Instruction.html
16+
* 接口文档: https://developers.weixin.qq.com/doc/offiaccount/WeChat_Invoice/E_Invoice/Vendor_API_List.html
17+
*/
18+
public interface WxMpMerchantInvoiceService {
19+
20+
/**
21+
* 获取开票授权页链接
22+
*/
23+
InvoiceAuthPageResult getAuthPageUrl(InvoiceAuthPageRequest params) throws WxErrorException;
24+
25+
/**
26+
* 获得用户授权数据
27+
*/
28+
InvoiceAuthDataResult getAuthData(InvoiceAuthDataRequest params) throws WxErrorException;
29+
30+
/**
31+
* 拒绝开票
32+
* <p>
33+
* 场景: 用户授权填写数据无效
34+
* 结果: 用户会收到一条开票失败提示
35+
*/
36+
void rejectInvoice(InvoiceRejectRequest params) throws WxErrorException;
37+
38+
/**
39+
* 开具电子发票
40+
*/
41+
void makeOutInvoice(MakeOutInvoiceRequest params) throws WxErrorException;
42+
43+
/**
44+
* 发票冲红
45+
*/
46+
void clearOutInvoice(ClearOutInvoiceRequest params) throws WxErrorException;
47+
48+
/**
49+
* 查询发票信息
50+
*
51+
* @param fpqqlsh 发票请求流水号
52+
* @param nsrsbh 纳税人识别号
53+
*/
54+
InvoiceResult queryInvoiceInfo(String fpqqlsh, String nsrsbh) throws WxErrorException;
55+
56+
/**
57+
* 设置商户联系方式, 获取授权链接前需要设置商户联系信息
58+
*/
59+
void setMerchantContactInfo(MerchantContactInfo contact) throws WxErrorException;
60+
61+
/**
62+
* 获取商户联系方式
63+
*/
64+
MerchantContactInfo getMerchantContactInfo() throws WxErrorException;
65+
66+
/**
67+
* 配置授权页面字段
68+
*/
69+
void setAuthPageSetting(InvoiceAuthPageSetting authPageSetting) throws WxErrorException;
70+
71+
/**
72+
* 获取授权页面配置
73+
*/
74+
InvoiceAuthPageSetting getAuthPageSetting() throws WxErrorException;
75+
76+
/**
77+
* 设置商户开票平台信息
78+
*/
79+
void setMerchantInvoicePlatform(MerchantInvoicePlatformInfo merchantInvoicePlatformInfo) throws WxErrorException;
80+
81+
/**
82+
* 获取商户开票平台信息
83+
*/
84+
MerchantInvoicePlatformInfo getMerchantInvoicePlatform(MerchantInvoicePlatformInfo merchantInvoicePlatformInfo) throws WxErrorException;
85+
}

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

+10-4
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@
66
import com.google.gson.JsonElement;
77
import com.google.gson.JsonObject;
88
import com.google.gson.JsonParser;
9+
import lombok.Getter;
10+
import lombok.Setter;
911
import lombok.extern.slf4j.Slf4j;
1012
import me.chanjar.weixin.common.WxType;
1113
import me.chanjar.weixin.common.bean.WxJsapiSignature;
1214
import me.chanjar.weixin.common.bean.WxNetCheckResult;
15+
import me.chanjar.weixin.common.enums.TicketType;
1316
import me.chanjar.weixin.common.error.WxError;
1417
import me.chanjar.weixin.common.error.WxErrorException;
1518
import me.chanjar.weixin.common.session.StandardSessionManager;
@@ -26,7 +29,6 @@
2629
import me.chanjar.weixin.mp.bean.result.WxMpSemanticQueryResult;
2730
import me.chanjar.weixin.mp.bean.result.WxMpUser;
2831
import me.chanjar.weixin.mp.config.WxMpConfigStorage;
29-
import me.chanjar.weixin.common.enums.TicketType;
3032
import me.chanjar.weixin.mp.enums.WxMpApiUrl;
3133
import me.chanjar.weixin.mp.util.WxMpConfigStorageHolder;
3234
import org.apache.commons.lang3.StringUtils;
@@ -70,6 +72,10 @@ public abstract class BaseWxMpServiceImpl<H, P> implements WxMpService, RequestH
7072
private WxMpOcrService ocrService = new WxMpOcrServiceImpl(this);
7173
private WxMpImgProcService imgProcService = new WxMpImgProcServiceImpl(this);
7274

75+
@Getter
76+
@Setter
77+
private WxMpMerchantInvoiceService merchantInvoiceService = new WxMpMerchantInvoiceServiceImpl(this, this.cardService);
78+
7379
private Map<String, WxMpConfigStorage> configStorageMap;
7480

7581
private int retrySleepMillis = 1000;
@@ -359,11 +365,11 @@ protected <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E
359365
// 强制设置wxMpConfigStorage它的access token过期了,这样在下一次请求里就会刷新access token
360366
Lock lock = this.getWxMpConfigStorage().getAccessTokenLock();
361367
lock.lock();
362-
try{
363-
if(StringUtils.equals(this.getWxMpConfigStorage().getAccessToken(), accessToken)){
368+
try {
369+
if (StringUtils.equals(this.getWxMpConfigStorage().getAccessToken(), accessToken)) {
364370
this.getWxMpConfigStorage().expireAccessToken();
365371
}
366-
} catch (Exception ex){
372+
} catch (Exception ex) {
367373
this.getWxMpConfigStorage().expireAccessToken();
368374
} finally {
369375
lock.unlock();

0 commit comments

Comments
 (0)