Skip to content

Commit ec5cc69

Browse files
authored
binarywang#776 开放平台增加获取会员卡开卡插件参数和手机端预授权等接口
1、增加卡券的api_ticket,区分jsapi_ticket,二者的获取逻辑不同; 2、增加小程序审核事件及审核事件推送消息SuccTime和Reason两个字段; 3、增加开放平台获取会员卡开卡插件参数接口。 4、增加开放平台手机端预授权接口实现;
2 parents 9fcb433 + 34eb2f6 commit ec5cc69

File tree

15 files changed

+353
-27
lines changed

15 files changed

+353
-27
lines changed

weixin-java-common/src/main/java/me/chanjar/weixin/common/api/WxConsts.java

+9
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,15 @@ public static class EventType {
250250
*/
251251
public static final String CARD_PAY_ORDER = "card_pay_order";
252252

253+
/**
254+
* 小程序审核事件:审核通过
255+
*/
256+
public static final String WEAPP_AUDIT_SUCCESS = "weapp_audit_success";
257+
258+
/**
259+
* 小程序审核事件:审核不通过
260+
*/
261+
public static final String WEAPP_AUDIT_FAIL = "weapp_audit_fail";
253262

254263
}
255264

weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/WxMaJsapiService.java

+20-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,26 @@ public interface WxMaJsapiService {
1515
/**
1616
* 获得jsapi_ticket的url
1717
*/
18-
String GET_JSAPI_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi";
18+
String GET_JSAPI_TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket";
19+
20+
/**
21+
* 获得卡券api_ticket,不强制刷新api_ticket
22+
*
23+
* @see #getJsapiTicket(boolean)
24+
*/
25+
String getCardApiTicket() throws WxErrorException;
26+
27+
/**
28+
* <pre>
29+
* 获得卡券api_ticket
30+
* 获得时会检查apiToken是否过期,如果过期了,那么就刷新一下,否则就什么都不干
31+
*
32+
* 详情请见:http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN
33+
* </pre>
34+
*
35+
* @param forceRefresh 强制刷新
36+
*/
37+
String getCardApiTicket(boolean forceRefresh) throws WxErrorException;
1938

2039
/**
2140
* 获得jsapi_ticket,不强制刷新jsapi_ticket

weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/api/impl/WxMaJsapiServiceImpl.java

+27-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,32 @@ public WxMaJsapiServiceImpl(WxMaService wxMaService) {
2828
this.wxMaService = wxMaService;
2929
}
3030

31+
public String getCardApiTicket() throws WxErrorException {
32+
return getCardApiTicket(false);
33+
}
34+
35+
public String getCardApiTicket(boolean forceRefresh) throws WxErrorException {
36+
Lock lock = this.wxMaService.getWxMaConfig().getCardApiTicketLock();
37+
try {
38+
lock.lock();
39+
if (forceRefresh) {
40+
this.wxMaService.getWxMaConfig().expireCardApiTicket();
41+
}
42+
43+
if (this.wxMaService.getWxMaConfig().isCardApiTicketExpired()) {
44+
String responseContent = this.wxMaService.get(GET_JSAPI_TICKET_URL + "?type=wx_card", null);
45+
JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent);
46+
JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
47+
String jsapiTicket = tmpJsonObject.get("ticket").getAsString();
48+
int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
49+
this.wxMaService.getWxMaConfig().updateCardApiTicket(jsapiTicket, expiresInSeconds);
50+
}
51+
} finally {
52+
lock.unlock();
53+
}
54+
return this.wxMaService.getWxMaConfig().getJsapiTicket();
55+
}
56+
3157
@Override
3258
public String getJsapiTicket() throws WxErrorException {
3359
return getJsapiTicket(false);
@@ -43,7 +69,7 @@ public String getJsapiTicket(boolean forceRefresh) throws WxErrorException {
4369
}
4470

4571
if (this.wxMaService.getWxMaConfig().isJsapiTicketExpired()) {
46-
String responseContent = this.wxMaService.get(GET_JSAPI_TICKET_URL, null);
72+
String responseContent = this.wxMaService.get(GET_JSAPI_TICKET_URL + "?type=jsapi", null);
4773
JsonElement tmpJsonElement = JSON_PARSER.parse(responseContent);
4874
JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
4975
String jsapiTicket = tmpJsonObject.get("ticket").getAsString();

weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java

+19
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,25 @@ public interface WxMaConfig {
5757
*/
5858
void updateJsapiTicket(String jsapiTicket, int expiresInSeconds);
5959

60+
String getCardApiTicket();
61+
62+
Lock getCardApiTicketLock();
63+
64+
boolean isCardApiTicketExpired();
65+
66+
/**
67+
* 强制将卡券api ticket过期掉
68+
*/
69+
void expireCardApiTicket();
70+
71+
/**
72+
* 应该是线程安全的
73+
*
74+
* @param 卡券apiTicket 新的卡券api ticket值
75+
* @param expiresInSeconds 过期时间,以秒为单位
76+
*/
77+
void updateCardApiTicket(String apiTicket, int expiresInSeconds);
78+
6079
String getAppid();
6180

6281
String getSecret();

weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/config/WxMaInMemoryConfig.java

+39-6
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
package cn.binarywang.wx.miniapp.config;
22

3-
import java.io.File;
4-
import java.util.concurrent.locks.Lock;
5-
import java.util.concurrent.locks.ReentrantLock;
6-
3+
import me.chanjar.weixin.common.bean.WxAccessToken;
4+
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
75
import org.apache.commons.lang3.builder.ToStringBuilder;
86
import org.apache.commons.lang3.builder.ToStringStyle;
97

10-
import me.chanjar.weixin.common.bean.WxAccessToken;
11-
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
8+
import java.io.File;
9+
import java.util.concurrent.locks.Lock;
10+
import java.util.concurrent.locks.ReentrantLock;
1211

1312
/**
1413
* 基于内存的微信配置provider,在实际生产环境中应该将这些配置持久化
@@ -32,8 +31,14 @@ public class WxMaInMemoryConfig implements WxMaConfig {
3231
protected volatile String jsapiTicket;
3332
protected volatile long jsapiTicketExpiresTime;
3433

34+
//微信卡券的ticket单独缓存
35+
protected volatile String cardApiTicket;
36+
protected volatile long cardApiTicketExpiresTime;
37+
38+
3539
protected Lock accessTokenLock = new ReentrantLock();
3640
protected Lock jsapiTicketLock = new ReentrantLock();
41+
protected Lock cardApiTicketLock = new ReentrantLock();
3742

3843
/**
3944
* 临时文件目录
@@ -103,6 +108,34 @@ public void updateJsapiTicket(String jsapiTicket, int expiresInSeconds) {
103108
this.jsapiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
104109
}
105110

111+
112+
@Override
113+
public String getCardApiTicket() {
114+
return this.cardApiTicket;
115+
}
116+
117+
@Override
118+
public Lock getCardApiTicketLock() {
119+
return this.cardApiTicketLock;
120+
}
121+
122+
@Override
123+
public boolean isCardApiTicketExpired() {
124+
return System.currentTimeMillis() > this.cardApiTicketExpiresTime;
125+
}
126+
127+
@Override
128+
public void expireCardApiTicket() {
129+
this.cardApiTicketExpiresTime = 0;
130+
}
131+
132+
@Override
133+
public void updateCardApiTicket(String cardApiTicket, int expiresInSeconds) {
134+
this.cardApiTicket = cardApiTicket;
135+
// 预留200秒的时间
136+
this.cardApiTicketExpiresTime = System.currentTimeMillis() + (expiresInSeconds - 200) * 1000L;
137+
}
138+
106139
@Override
107140
public void expireAccessToken() {
108141
this.expiresTime = 0;

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

+14
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ public interface WxMpMemberCardService {
2424
*/
2525
String MEMBER_CARD_ACTIVATEUSERFORM = "https://api.weixin.qq.com/card/membercard/activateuserform/set";
2626

27+
/**
28+
* 获取会员卡开卡插件参数
29+
*/
30+
String MEMBER_CARD_ACTIVATE_URL = "https://api.weixin.qq.com/card/membercard/activate/geturl";
31+
2732
/**
2833
* 得到WxMpService
2934
*/
@@ -88,4 +93,13 @@ public interface WxMpMemberCardService {
8893
*/
8994
MemberCardActivateUserFormResult setActivateUserForm(MemberCardActivateUserFormRequest userFormRequest) throws WxErrorException;
9095

96+
/**
97+
* 获取会员卡开卡插件参数(跳转型开卡组件需要参数)
98+
*
99+
* @param cardId
100+
* @param outStr
101+
* @return
102+
* @throws WxErrorException
103+
*/
104+
ActivatePluginParam getActivatePluginParam(String cardId, String outStr) throws WxErrorException;
91105
}

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

+93-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919
import org.slf4j.Logger;
2020
import org.slf4j.LoggerFactory;
2121

22+
import java.io.UnsupportedEncodingException;
23+
import java.net.URLDecoder;
24+
import java.util.HashMap;
25+
import java.util.Map;
26+
2227
/**
2328
* 会员卡相关接口的实现类
2429
*
@@ -237,7 +242,7 @@ public WxMpMemberCardUserInfoResult getUserInfo(String cardId, String code) thro
237242
jsonObject.addProperty("code", code);
238243

239244
String responseContent = this.getWxMpService().post(MEMBER_CARD_USER_INFO_GET, jsonObject.toString());
240-
log.debug("{}",responseContent);
245+
log.debug("{}", responseContent);
241246
JsonElement tmpJsonElement = new JsonParser().parse(responseContent);
242247
return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement,
243248
new TypeToken<WxMpMemberCardUserInfoResult>() {
@@ -280,4 +285,91 @@ public MemberCardActivateUserFormResult setActivateUserForm(MemberCardActivateUs
280285
return MemberCardActivateUserFormResult.fromJson(responseContent);
281286
}
282287

288+
/**
289+
* 获取会员卡开卡插件参数(跳转型开卡组件需要参数)
290+
*
291+
* @param outStr
292+
* @return
293+
* @throws WxErrorException
294+
*/
295+
public ActivatePluginParam getActivatePluginParam(String cardId, String outStr) throws WxErrorException {
296+
JsonObject params = new JsonObject();
297+
params.addProperty("card_id", cardId);
298+
params.addProperty("outer_str", outStr);
299+
String response = this.wxMpService.post(MEMBER_CARD_ACTIVATE_URL, GSON.toJson(params));
300+
ActivatePluginParamResult result = GSON.fromJson(response, ActivatePluginParamResult.class);
301+
if (0 == result.getErrcode()) {
302+
String url = result.getUrl();
303+
try {
304+
String decodedUrl = URLDecoder.decode(url, "UTF-8");
305+
Map<String, String> resultMap = parseRequestUrl(decodedUrl);
306+
ActivatePluginParam activatePluginParam = new ActivatePluginParam();
307+
activatePluginParam.setEncryptCardId(resultMap.get("encrypt_card_id"));
308+
activatePluginParam.setOuterStr(resultMap.get("outer_str"));
309+
activatePluginParam.setBiz(resultMap.get("biz")+"==");
310+
return activatePluginParam;
311+
} catch (UnsupportedEncodingException e) {
312+
e.printStackTrace();
313+
}
314+
}
315+
return null;
316+
}
317+
318+
/**
319+
* 去掉url中的路径,留下请求参数部分
320+
*
321+
* @param strURL url地址
322+
* @return url请求参数部分
323+
*/
324+
private static String truncateUrlPage(String strURL) {
325+
String strAllParam = null;
326+
String[] arrSplit = null;
327+
arrSplit = strURL.split("[?]");
328+
if (strURL.length() > 1) {
329+
if (arrSplit.length > 1) {
330+
if (arrSplit[1] != null) {
331+
strAllParam = arrSplit[1];
332+
}
333+
}
334+
}
335+
336+
return strAllParam;
337+
}
338+
339+
/**
340+
* 解析出url参数中的键值对
341+
* 如 "index.jsp?Action=del&id=123",解析出Action:del,id:123存入map中
342+
*
343+
* @param URL url地址
344+
* @return url请求参数部分
345+
*/
346+
public static Map<String, String> parseRequestUrl(String URL) {
347+
Map<String, String> mapRequest = new HashMap<String, String>();
348+
349+
String[] arrSplit = null;
350+
351+
String strUrlParam = truncateUrlPage(URL);
352+
if (strUrlParam == null) {
353+
return mapRequest;
354+
}
355+
arrSplit = strUrlParam.split("[&]");
356+
for (String strSplit : arrSplit) {
357+
String[] arrSplitEqual = null;
358+
arrSplitEqual = strSplit.split("[=]");
359+
360+
//解析出键值
361+
if (arrSplitEqual.length > 1) {
362+
//正确解析
363+
mapRequest.put(arrSplitEqual[0], arrSplitEqual[1]);
364+
365+
} else {
366+
if (arrSplitEqual[0] != "") {
367+
//只有参数没有值,不加入
368+
mapRequest.put(arrSplitEqual[0], "");
369+
}
370+
}
371+
}
372+
return mapRequest;
373+
}
374+
283375
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package me.chanjar.weixin.mp.bean.membercard;
2+
3+
import com.google.gson.annotations.SerializedName;
4+
import lombok.Data;
5+
6+
/**
7+
* @author yqx
8+
* @date 2018/9/19
9+
*/
10+
@Data
11+
public class ActivatePluginParam {
12+
13+
@SerializedName("encrypt_card_id")
14+
String encryptCardId;
15+
16+
@SerializedName("outer_str")
17+
String outerStr;
18+
19+
@SerializedName("biz")
20+
String biz;
21+
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package me.chanjar.weixin.mp.bean.membercard;
2+
3+
import lombok.Data;
4+
5+
/**
6+
* @author yqx
7+
* @date 2018/9/19
8+
*/
9+
@Data
10+
public class ActivatePluginParamResult {
11+
12+
private int errcode;
13+
14+
private String errmsg;
15+
16+
private String url;
17+
18+
}

weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/message/WxMpXmlMessage.java

+15
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,21 @@ public class WxMpXmlMessage implements Serializable {
541541
@XStreamAlias("DeviceStatus")
542542
private Integer deviceStatus;
543543

544+
///////////////////////////////////////
545+
// 小程序 审核事件
546+
///////////////////////////////////////
547+
/**
548+
* 审核成功时的时间(整形),时间戳
549+
*/
550+
@XStreamAlias("SuccTime")
551+
private Long succTime;
552+
553+
/**
554+
* 审核失败的原因
555+
*/
556+
@XStreamAlias("Reason")
557+
private String reason;
558+
544559
public static WxMpXmlMessage fromXml(String xml) {
545560
//修改微信变态的消息内容格式,方便解析
546561
xml = xml.replace("</PicList><PicList>", "");

0 commit comments

Comments
 (0)