mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2026-03-10 00:13:40 +08:00
新增卡券相关接口6个
1. getCardApiTicket获得卡券的api_ticket 2. createCardApiSignature创建调用卡券api时的签名 3. decryptCardCode卡券code解码 4. queryCardCode卡券code查询 5. consumeCardCode卡券核销 6. markCardCode卡券mark接口
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package me.chanjar.weixin.mp.api;
|
||||
|
||||
import me.chanjar.weixin.common.bean.WxCardApiSignature;
|
||||
import me.chanjar.weixin.common.bean.WxMenu;
|
||||
import me.chanjar.weixin.common.bean.WxJsapiSignature;
|
||||
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
|
||||
@@ -770,7 +771,7 @@ public interface WxMpService {
|
||||
* @return
|
||||
*/
|
||||
public boolean checkJSSDKCallbackDataSignature(Map<String, String> kvm, String signature);
|
||||
|
||||
|
||||
/**
|
||||
* 发送微信红包给个人用户
|
||||
* @param parameters
|
||||
@@ -778,4 +779,81 @@ public interface WxMpService {
|
||||
* @throws WxErrorException
|
||||
*/
|
||||
public WxRedpackResult sendRedpack(Map<String, String> parameters) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 获得卡券api_ticket,不强制刷新卡券api_ticket
|
||||
* @see #getCardApiTicket(boolean)
|
||||
* @return 卡券api_ticket
|
||||
* @throws WxErrorException
|
||||
*/
|
||||
public String getCardApiTicket() throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 获得卡券api_ticket
|
||||
* 获得时会检查卡券apiToken是否过期,如果过期了,那么就刷新一下,否则就什么都不干
|
||||
*
|
||||
* 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD.954-.E5.8D.A1.E5.88.B8.E6.89.A9.E5.B1.95.E5.AD.97.E6.AE.B5.E5.8F.8A.E7.AD.BE.E5.90.8D.E7.94.9F.E6.88.90.E7.AE.97.E6.B3.95
|
||||
* </pre>
|
||||
* @param forceRefresh 强制刷新
|
||||
* @return 卡券api_ticket
|
||||
* @throws WxErrorException
|
||||
*/
|
||||
public String getCardApiTicket(boolean forceRefresh) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 创建调用卡券api时所需要的签名
|
||||
*
|
||||
* 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD
|
||||
* .954-.E5.8D.A1.E5.88.B8.E6.89.A9.E5.B1.95.E5.AD.97.E6.AE.B5.E5.8F.8A.E7.AD.BE.E5.90.8D.E7.94
|
||||
* .9F.E6.88.90.E7.AE.97.E6.B3.95
|
||||
* </pre>
|
||||
*
|
||||
* @param optionalSignParam 参与签名的参数数组。
|
||||
* 可以为下列字段:app_id, card_id, card_type, code, openid, location_id
|
||||
* @return 卡券Api签名对象
|
||||
*/
|
||||
public WxCardApiSignature createCardApiSignature(String... optionalSignParam) throws
|
||||
WxErrorException;
|
||||
|
||||
/**
|
||||
* 卡券Code解码
|
||||
* @param encryptCode 加密Code,通过JSSDK的chooseCard接口获得
|
||||
* @return 解密后的Code
|
||||
* @throws WxErrorException
|
||||
*/
|
||||
public String decryptCardCode(String encryptCode) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 卡券Code查询
|
||||
* @param cardId 卡券ID代表一类卡券
|
||||
* @param code 单张卡券的唯一标准
|
||||
* @param checkConsume 是否校验code核销状态,填入true和false时的code异常状态返回数据不同
|
||||
* @return WxMpCardResult对象
|
||||
* @throws WxErrorException
|
||||
*/
|
||||
public WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume)
|
||||
throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 卡券Code核销。核销失败会抛出异常
|
||||
* @param code 单张卡券的唯一标准
|
||||
* @return
|
||||
* @throws WxErrorException
|
||||
*/
|
||||
public void consumeCardCode(String code) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 卡券Mark接口。
|
||||
* 开发者在帮助消费者核销卡券之前,必须帮助先将此code(卡券串码)与一个openid绑定(即mark住),
|
||||
* 才能进一步调用核销接口,否则报错。
|
||||
* @param code 卡券的code码
|
||||
* @param cardId 卡券的ID
|
||||
* @param openId 用券用户的openid
|
||||
* @param isMark 是否要mark(占用)这个code,填写true或者false,表示占用或解除占用
|
||||
* @throws WxErrorException
|
||||
*/
|
||||
public void markCardCode(String code, String cardId, String openId, boolean isMark) throws
|
||||
WxErrorException;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -14,8 +15,10 @@ import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import me.chanjar.weixin.common.api.WxConsts;
|
||||
import me.chanjar.weixin.common.bean.WxAccessToken;
|
||||
import me.chanjar.weixin.common.bean.WxCardApiSignature;
|
||||
import me.chanjar.weixin.common.bean.WxJsapiSignature;
|
||||
import me.chanjar.weixin.common.bean.WxMenu;
|
||||
import me.chanjar.weixin.common.bean.result.WxError;
|
||||
@@ -43,6 +46,7 @@ import me.chanjar.weixin.mp.bean.WxMpMaterialArticleUpdate;
|
||||
import me.chanjar.weixin.mp.bean.WxMpMaterialNews;
|
||||
import me.chanjar.weixin.mp.bean.WxMpSemanticQuery;
|
||||
import me.chanjar.weixin.mp.bean.WxMpTemplateMessage;
|
||||
import me.chanjar.weixin.mp.bean.result.WxMpCardResult;
|
||||
import me.chanjar.weixin.mp.bean.result.WxMpMassSendResult;
|
||||
import me.chanjar.weixin.mp.bean.result.WxMpMassUploadResult;
|
||||
import me.chanjar.weixin.mp.bean.result.WxMpMaterialCountResult;
|
||||
@@ -112,6 +116,11 @@ public class WxMpServiceImpl implements WxMpService {
|
||||
*/
|
||||
protected final Object globalJsapiTicketRefreshLock = new Object();
|
||||
|
||||
/**
|
||||
* 全局的是否正在刷新卡券api_ticket的锁
|
||||
*/
|
||||
protected final Object globalCardApiTicketRefreshLock = new Object();
|
||||
|
||||
protected WxMpConfigStorage wxMpConfigStorage;
|
||||
|
||||
protected CloseableHttpClient httpClient;
|
||||
@@ -1006,4 +1015,172 @@ public class WxMpServiceImpl implements WxMpService {
|
||||
throw new WxErrorException(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得卡券api_ticket,不强制刷新卡券api_ticket
|
||||
*
|
||||
* @return 卡券api_ticket
|
||||
* @throws WxErrorException
|
||||
* @see #getCardApiTicket(boolean)
|
||||
*/
|
||||
@Override
|
||||
public String getCardApiTicket() throws WxErrorException {
|
||||
return getCardApiTicket(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 获得卡券api_ticket
|
||||
* 获得时会检查卡券apiToken是否过期,如果过期了,那么就刷新一下,否则就什么都不干
|
||||
*
|
||||
* 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD
|
||||
* .954-.E5.8D.A1.E5.88.B8.E6.89.A9.E5.B1.95.E5.AD.97.E6.AE.B5.E5.8F.8A.E7.AD.BE.E5.90.8D.E7.94
|
||||
* .9F.E6.88.90.E7.AE.97.E6.B3.95
|
||||
* </pre>
|
||||
*
|
||||
* @param forceRefresh 强制刷新
|
||||
* @return 卡券api_ticket
|
||||
* @throws WxErrorException
|
||||
*/
|
||||
@Override
|
||||
public String getCardApiTicket(boolean forceRefresh) throws WxErrorException {
|
||||
if (forceRefresh) {
|
||||
wxMpConfigStorage.expireCardApiTicket();
|
||||
}
|
||||
if (wxMpConfigStorage.isCardApiTicketExpired()) {
|
||||
synchronized (globalCardApiTicketRefreshLock) {
|
||||
if (wxMpConfigStorage.isCardApiTicketExpired()) {
|
||||
String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=wx_card";
|
||||
String responseContent = execute(new SimpleGetRequestExecutor(), url, null);
|
||||
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
|
||||
JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
|
||||
String cardApiTicket = tmpJsonObject.get("ticket").getAsString();
|
||||
int expiresInSeconds = tmpJsonObject.get("expires_in").getAsInt();
|
||||
wxMpConfigStorage.updateCardApiTicket(cardApiTicket, expiresInSeconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
return wxMpConfigStorage.getCardApiTicket();
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 创建调用卡券api时所需要的签名
|
||||
*
|
||||
* 详情请见:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#.E9.99.84.E5.BD
|
||||
* .954-.E5.8D.A1.E5.88.B8.E6.89.A9.E5.B1.95.E5.AD.97.E6.AE.B5.E5.8F.8A.E7.AD.BE.E5.90.8D.E7.94
|
||||
* .9F.E6.88.90.E7.AE.97.E6.B3.95
|
||||
* </pre>
|
||||
*
|
||||
* @param optionalSignParam 参与签名的参数数组。
|
||||
* 可以为下列字段:app_id, card_id, card_type, code, openid, location_id
|
||||
* @return 卡券Api签名对象
|
||||
*/
|
||||
@Override
|
||||
public WxCardApiSignature createCardApiSignature(String... optionalSignParam) throws
|
||||
WxErrorException {
|
||||
long timestamp = System.currentTimeMillis() / 1000;
|
||||
String nonceStr = RandomUtils.getRandomStr();
|
||||
String cardApiTicket = getCardApiTicket(false);
|
||||
|
||||
String[] signParam = Arrays.copyOf(optionalSignParam, optionalSignParam.length + 3);
|
||||
signParam[optionalSignParam.length] = String.valueOf(timestamp);
|
||||
signParam[optionalSignParam.length + 1] = nonceStr;
|
||||
signParam[optionalSignParam.length + 2] = cardApiTicket;
|
||||
try {
|
||||
String signature = SHA1.gen(signParam);
|
||||
WxCardApiSignature cardApiSignature = new WxCardApiSignature();
|
||||
cardApiSignature.setTimestamp(timestamp);
|
||||
cardApiSignature.setNonceStr(nonceStr);
|
||||
cardApiSignature.setSignature(signature);
|
||||
return cardApiSignature;
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 卡券Code解码
|
||||
*
|
||||
* @param encryptCode 加密Code,通过JSSDK的chooseCard接口获得
|
||||
* @return 解密后的Code
|
||||
* @throws WxErrorException
|
||||
*/
|
||||
@Override
|
||||
public String decryptCardCode(String encryptCode) throws WxErrorException {
|
||||
String url = "https://api.weixin.qq.com/card/code/decrypt";
|
||||
JsonObject param = new JsonObject();
|
||||
param.addProperty("encrypt_code", encryptCode);
|
||||
String responseContent = post(url, param.toString());
|
||||
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
|
||||
JsonObject tmpJsonObject = tmpJsonElement.getAsJsonObject();
|
||||
JsonPrimitive jsonPrimitive = tmpJsonObject.getAsJsonPrimitive("code");
|
||||
return jsonPrimitive.getAsString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 卡券Code查询
|
||||
*
|
||||
* @param cardId 卡券ID代表一类卡券
|
||||
* @param code 单张卡券的唯一标准
|
||||
* @param checkConsume 是否校验code核销状态,填入true和false时的code异常状态返回数据不同
|
||||
* @return WxMpCardResult对象
|
||||
* @throws WxErrorException
|
||||
*/
|
||||
@Override
|
||||
public WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) throws WxErrorException {
|
||||
String url = "https://api.weixin.qq.com/card/code/get";
|
||||
JsonObject param = new JsonObject();
|
||||
param.addProperty("card_id", cardId);
|
||||
param.addProperty("code", code);
|
||||
param.addProperty("check_consume", checkConsume);
|
||||
String responseContent = post(url, param.toString());
|
||||
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
|
||||
return WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement,
|
||||
new TypeToken<WxMpCardResult>() {
|
||||
}.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* 卡券Code核销。核销失败会抛出异常
|
||||
*
|
||||
* @param code 单张卡券的唯一标准
|
||||
* @throws WxErrorException
|
||||
*/
|
||||
@Override
|
||||
public void consumeCardCode(String code) throws WxErrorException {
|
||||
String url = "https://api.weixin.qq.com/card/code/consume";
|
||||
JsonObject param = new JsonObject();
|
||||
param.addProperty("code", code);
|
||||
post(url, param.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 卡券Mark接口。
|
||||
* 开发者在帮助消费者核销卡券之前,必须帮助先将此code(卡券串码)与一个openid绑定(即mark住),
|
||||
* 才能进一步调用核销接口,否则报错。
|
||||
*
|
||||
* @param code 卡券的code码
|
||||
* @param cardId 卡券的ID
|
||||
* @param openId 用券用户的openid
|
||||
* @param isMark 是否要mark(占用)这个code,填写true或者false,表示占用或解除占用
|
||||
* @throws WxErrorException
|
||||
*/
|
||||
@Override
|
||||
public void markCardCode(String code, String cardId, String openId, boolean isMark) throws
|
||||
WxErrorException {
|
||||
String url = "https://api.weixin.qq.com/card/code/mark";
|
||||
JsonObject param = new JsonObject();
|
||||
param.addProperty("code", code);
|
||||
param.addProperty("card_id", cardId);
|
||||
param.addProperty("openid", openId);
|
||||
param.addProperty("is_mark", isMark);
|
||||
String responseContent = post(url, param.toString());
|
||||
JsonElement tmpJsonElement = Streams.parse(new JsonReader(new StringReader(responseContent)));
|
||||
WxMpCardResult cardResult = WxMpGsonBuilder.INSTANCE.create().fromJson(tmpJsonElement,
|
||||
new TypeToken<WxMpCardResult>() { }.getType());
|
||||
if (!cardResult.getErrorCode().equals("0")) {
|
||||
log.warn("朋友的券mark失败:{}", cardResult.getErrorMsg());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user