mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2025-08-24 16:18:51 +08:00
🆕 #3077【小程序】增加openApi管理的接口支持
This commit is contained in:
parent
9bd7940195
commit
831aac31ba
@ -70,11 +70,10 @@ public enum WxMaErrorMsgEnum {
|
||||
* appid不正确,或者不符合绑定关系要求.
|
||||
* 对应操作:<code>sendUniformMessage</code>
|
||||
* 对应地址:
|
||||
* POST https://api.weixin.qq.com/cgi-bin/message/wxopen/template/uniform_send?access_token=ACCESS_TOKEN
|
||||
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/uniform-message/sendUniformMessage.html
|
||||
* 参考文档地址: https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/openApi-mgnt/clearQuota.html
|
||||
* </pre>
|
||||
*/
|
||||
CODE_40013(40013, "appid不正确,或者不符合绑定关系要求"),
|
||||
CODE_40013(40013, "appid不正确/不合法(避免异常字符,注意大小写),或者不符合绑定关系要求"),
|
||||
/**
|
||||
* <pre>
|
||||
* template_id 不正确.
|
||||
@ -267,6 +266,50 @@ public enum WxMaErrorMsgEnum {
|
||||
* activity_id 过期.
|
||||
*/
|
||||
CODE_47504(47504, "activity_id 过期"),
|
||||
/**
|
||||
* api 禁止清零调用次数,因为清零次数达到上限
|
||||
*
|
||||
* @see <a href="https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/openApi-mgnt/clearQuota.html">参考文档</a>
|
||||
*/
|
||||
CODE_48006(48006, "api 禁止清零调用次数,因为清零次数达到上限"),
|
||||
|
||||
/**
|
||||
* rid不存在
|
||||
*
|
||||
* @see <a href="https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/openApi-mgnt/getRidInfo.html">参考文档</a>
|
||||
*/
|
||||
CODE_76001(76001, "rid不存在"),
|
||||
/**
|
||||
* rid为空或者格式错误
|
||||
*
|
||||
* @see <a href="https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/openApi-mgnt/getRidInfo.html">参考文档</a>
|
||||
*/
|
||||
CODE_76002(76002, "rid为空或者格式错误"),
|
||||
/**
|
||||
* 当前账号无权查询该rid,该rid属于其他账号调用所产生
|
||||
*
|
||||
* @see <a href="https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/openApi-mgnt/getRidInfo.html">参考文档</a>
|
||||
*/
|
||||
CODE_76003(76003, "当前账号无权查询该rid,该rid属于其他账号调用所产生"),
|
||||
/**
|
||||
* rid过期
|
||||
*
|
||||
* @see <a href="https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/openApi-mgnt/getRidInfo.html">参考文档</a>
|
||||
*/
|
||||
CODE_76004(76004, "rid过期,仅支持持续7天内的rid"),
|
||||
/**
|
||||
* cgi_path填错了
|
||||
*
|
||||
* @see <a href="https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/openApi-mgnt/getApiQuota.html">参考文档</a>
|
||||
*/
|
||||
CODE_76021(76021, "cgi_path填错了"),
|
||||
/**
|
||||
* 当前调用接口使用的token与api所属账号不符
|
||||
*
|
||||
* @see <a href="https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/openApi-mgnt/getApiQuota.html">参考文档</a>
|
||||
*/
|
||||
CODE_76022(76022, "当前调用接口使用的token与api所属账号不符,详情可看注意事项的说明"),
|
||||
|
||||
/**
|
||||
* 没有绑定开放平台帐号.
|
||||
*/
|
||||
@ -343,6 +386,17 @@ public enum WxMaErrorMsgEnum {
|
||||
CODE_91017(91017, "+号规则 不同类型关联名主体不一致"),
|
||||
|
||||
CODE_40097(40097, "参数错误"),
|
||||
/**
|
||||
* 缺少 appid 参数
|
||||
* <a href="https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/openApi-mgnt/clearQuotaByAppSecret.html">参考文档</a>
|
||||
*/
|
||||
CODE_41002(41002, "缺少 appid 参数"),
|
||||
/**
|
||||
* 缺少 secret 参数
|
||||
* <a href="https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/openApi-mgnt/clearQuotaByAppSecret.html">参考文档</a>
|
||||
*/
|
||||
CODE_41004(41004, "缺少 secret 参数"),
|
||||
|
||||
|
||||
CODE_41006(41006, "media_id 不能为空"),
|
||||
|
||||
|
@ -0,0 +1,65 @@
|
||||
package cn.binarywang.wx.miniapp.api;
|
||||
|
||||
import cn.binarywang.wx.miniapp.bean.openapi.WxMiniGetApiQuotaResult;
|
||||
import cn.binarywang.wx.miniapp.bean.openapi.WxMiniGetRidInfoResult;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
|
||||
/**
|
||||
* openApi管理
|
||||
*
|
||||
* @author shuiyihan12
|
||||
* @see <a href="https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/openApi-mgnt/clearQuota.html">openApi管理 微信文档</a>
|
||||
* @since 2023/7/7 17:07
|
||||
*/
|
||||
public interface WxMaOpenApiService {
|
||||
|
||||
/**
|
||||
* 本接口用于清空公众号/小程序/第三方平台等接口的每日调用接口次数
|
||||
* HTTP调用:https://api.weixin.qq.com/cgi-bin/clear_quota?access_token=ACCESS_TOKEN
|
||||
*
|
||||
* @return 是否成功
|
||||
* @throws WxErrorException the wx error exception
|
||||
* @apiNote !!! 单小程序直接调用该方法 , 如多个appid调用此方法前请调用 {@link cn.binarywang.wx.miniapp.api.WxMaService#switchoverTo} 切换appid !!!
|
||||
* @code wxMaService.getWxMaOpenApiService().clearQuota() //单个
|
||||
* @code wxMaService.switchoverTo(" appid ").getWxMaOpenApiService().clearQuota() //多个
|
||||
* @see <a href="https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/openApi-mgnt/clearQuota.html">注意事项参考微信文档</a>
|
||||
*/
|
||||
boolean clearQuota() throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 查询API调用额度
|
||||
* HTTP调用:https://api.weixin.qq.com/cgi-bin/openapi/quota/get?access_token=ACCESS_TOKEN
|
||||
*
|
||||
* @param cgiPath api的请求地址,例如"/cgi-bin/message/custom/send";不要前缀“https://api.weixin.qq.com” ,也不要漏了"/",否则都会76003的报错
|
||||
* @return 额度详情
|
||||
* @throws WxErrorException 微信异常
|
||||
* @see <a href="https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/openApi-mgnt/getApiQuota.html">注意事项参考微信文档</a>
|
||||
*/
|
||||
WxMiniGetApiQuotaResult getApiQuota(String cgiPath) throws WxErrorException;
|
||||
|
||||
/**
|
||||
* 查询rid信息
|
||||
* HTTP调用:https://api.weixin.qq.com/cgi-bin/openapi/rid/get?access_token=ACCESS_TOKEN
|
||||
*
|
||||
* @param rid 调用接口报错返回的rid
|
||||
* @return 该rid对应的请求详情
|
||||
* @throws WxErrorException 微信异常
|
||||
* @see <a href="https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/openApi-mgnt/getRidInfo.html">注意事项参考微信文档</a>
|
||||
*/
|
||||
WxMiniGetRidInfoResult getRidInfo(String rid) throws WxErrorException;
|
||||
|
||||
|
||||
/**
|
||||
* 使用AppSecret重置 API 调用次数
|
||||
* HTTP调用:https://api.weixin.qq.com/cgi-bin/clear_quota/v2
|
||||
*
|
||||
* @return 是否成功
|
||||
* @throws WxErrorException 微信异常
|
||||
* @apiNote !!! 单小程序直接调用该方法 , 如多个appid调用此方法前请调用 {@link cn.binarywang.wx.miniapp.api.WxMaService#switchoverTo} 切换appid!!!
|
||||
* 参考示例
|
||||
* @code wxMaService.getWxMaOpenApiService().clearQuotaByAppSecret() //单个
|
||||
* @code wxMaService.switchoverTo(" appid ").getWxMaOpenApiService().clearQuotaByAppSecret() //多个
|
||||
* @see <a href="https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/openApi-mgnt/clearQuotaByAppSecret.html">注意事项参考微信文档</a>
|
||||
*/
|
||||
boolean clearQuotaByAppSecret() throws WxErrorException;
|
||||
}
|
@ -523,4 +523,10 @@ public interface WxMaService extends WxService {
|
||||
* @return getWxMaShopPayService
|
||||
*/
|
||||
WxMaShopPayService getWxMaShopPayService();
|
||||
|
||||
/**
|
||||
* 小程序openApi管理
|
||||
* @return getWxMaOpenApiService
|
||||
*/
|
||||
WxMaOpenApiService getWxMaOpenApiService();
|
||||
}
|
||||
|
@ -85,6 +85,7 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
|
||||
private final WxMaProductOrderService productOrderService = new WxMaProductOrderServiceImpl(this);
|
||||
private final WxMaShopCouponService wxMaShopCouponService = new WxMaShopCouponServiceImpl(this);
|
||||
private final WxMaShopPayService wxMaShopPayService = new WxMaShopPayServiceImpl(this);
|
||||
private final WxMaOpenApiService wxMaOpenApiService = new WxMaOpenApiServiceImpl(this);
|
||||
private Map<String, WxMaConfig> configMap;
|
||||
private int retrySleepMillis = 1000;
|
||||
private int maxRetryTimes = 5;
|
||||
@ -634,4 +635,9 @@ public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestH
|
||||
public WxMaShopPayService getWxMaShopPayService() {
|
||||
return this.wxMaShopPayService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxMaOpenApiService getWxMaOpenApiService() {
|
||||
return this.wxMaOpenApiService;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,81 @@
|
||||
package cn.binarywang.wx.miniapp.api.impl;
|
||||
|
||||
import cn.binarywang.wx.miniapp.api.WxMaOpenApiService;
|
||||
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||
import cn.binarywang.wx.miniapp.bean.openapi.WxMiniGetApiQuotaResult;
|
||||
import cn.binarywang.wx.miniapp.bean.openapi.WxMiniGetRidInfoResult;
|
||||
import cn.binarywang.wx.miniapp.constant.WxMaApiUrlConstants;
|
||||
import cn.binarywang.wx.miniapp.json.WxMaGsonBuilder;
|
||||
import com.google.gson.JsonObject;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.chanjar.weixin.common.enums.WxType;
|
||||
import me.chanjar.weixin.common.error.WxError;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.util.json.GsonParser;
|
||||
|
||||
import static me.chanjar.weixin.common.api.WxConsts.ERR_CODE;
|
||||
|
||||
/**
|
||||
* @author shuiyihan12
|
||||
* @since 2023/7/7 17:08
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class WxMaOpenApiServiceImpl implements WxMaOpenApiService {
|
||||
private final WxMaService wxMaService;
|
||||
|
||||
private static final String QUOTA = "quota";
|
||||
private static final String REQUEST = "request";
|
||||
|
||||
|
||||
@Override
|
||||
public boolean clearQuota() throws WxErrorException {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("appid", this.wxMaService.getWxMaConfig().getAppid());
|
||||
String responseContent = this.wxMaService.post(WxMaApiUrlConstants.OpenApi.CLEAR_QUOTA, params.toString());
|
||||
parseErrorResponse(responseContent);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WxMiniGetApiQuotaResult getApiQuota(String cgiPath) throws WxErrorException {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("cgi_path", cgiPath);
|
||||
String responseContent = this.wxMaService.post(WxMaApiUrlConstants.OpenApi.GET_API_QUOTA, params.toString());
|
||||
parseErrorResponse(responseContent);
|
||||
JsonObject response = GsonParser.parse(responseContent);
|
||||
if (response.has(QUOTA)) {
|
||||
return WxMaGsonBuilder.create().fromJson(response.getAsJsonObject(QUOTA), WxMiniGetApiQuotaResult.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public WxMiniGetRidInfoResult getRidInfo(String rid) throws WxErrorException {
|
||||
JsonObject params = new JsonObject();
|
||||
params.addProperty("rid", rid);
|
||||
String responseContent = this.wxMaService.post(WxMaApiUrlConstants.OpenApi.GET_RID_INFO, params.toString());
|
||||
parseErrorResponse(responseContent);
|
||||
JsonObject response = GsonParser.parse(responseContent);
|
||||
if (response.has(REQUEST)) {
|
||||
return WxMaGsonBuilder.create().fromJson(response.getAsJsonObject(QUOTA), WxMiniGetRidInfoResult.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean clearQuotaByAppSecret() throws WxErrorException {
|
||||
String url = String.format(WxMaApiUrlConstants.OpenApi.CLEAR_QUOTA_BY_APP_SECRET, this.wxMaService.getWxMaConfig().getAppid(), this.wxMaService.getWxMaConfig().getSecret());
|
||||
String responseContent = this.wxMaService.post(url, "");
|
||||
parseErrorResponse(responseContent);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private void parseErrorResponse(String response) throws WxErrorException {
|
||||
JsonObject jsonObject = GsonParser.parse(response);
|
||||
if (jsonObject.get(ERR_CODE).getAsInt() != 0) {
|
||||
throw new WxErrorException(WxError.fromJson(response, WxType.MiniApp));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package cn.binarywang.wx.miniapp.bean.openapi;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 查询API调用额度 返回数据
|
||||
*
|
||||
* @author shuiyihan12
|
||||
* @since 2023/7/10 16:52
|
||||
*/
|
||||
@Data
|
||||
public class WxMiniGetApiQuotaResult {
|
||||
|
||||
/**
|
||||
* 当天该账号可调用该接口的次数
|
||||
*/
|
||||
@SerializedName("daily_limit")
|
||||
private Integer dailyLimit;
|
||||
/**
|
||||
* 当天已经调用的次数
|
||||
*/
|
||||
private Integer used;
|
||||
/**
|
||||
* 当天剩余调用次数
|
||||
*/
|
||||
private Integer remain;
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package cn.binarywang.wx.miniapp.bean.openapi;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 查询rid信息 返回数据
|
||||
* @author shuiyihan12
|
||||
* @since 2023/7/10 16:53
|
||||
*/
|
||||
@Data
|
||||
public class WxMiniGetRidInfoResult {
|
||||
|
||||
/**
|
||||
* 发起请求的时间戳
|
||||
*/
|
||||
@SerializedName("invoke_time")
|
||||
private Integer invokeTime;
|
||||
/**
|
||||
* 请求毫秒级耗时
|
||||
*/
|
||||
@SerializedName("cost_in_ms")
|
||||
private Integer costInMs;
|
||||
/**
|
||||
* 请求的URL参数
|
||||
*/
|
||||
@SerializedName("request_url")
|
||||
private String requestUrl;
|
||||
/**
|
||||
* post请求的请求参数
|
||||
*/
|
||||
@SerializedName("request_body")
|
||||
private String requestBody;
|
||||
/**
|
||||
* 接口请求返回参数
|
||||
*/
|
||||
@SerializedName("response_body")
|
||||
private String responseBody;
|
||||
/**
|
||||
* 接口请求的客户端ip
|
||||
*/
|
||||
@SerializedName("client_ip")
|
||||
private String clientIp;
|
||||
}
|
@ -10,6 +10,30 @@ import lombok.experimental.UtilityClass;
|
||||
*/
|
||||
@UtilityClass
|
||||
public class WxMaApiUrlConstants {
|
||||
|
||||
/**
|
||||
* openApi管理
|
||||
*/
|
||||
public interface OpenApi {
|
||||
/**
|
||||
* 重置API调用次数
|
||||
*/
|
||||
String CLEAR_QUOTA = "https://api.weixin.qq.com/cgi-bin/clear_quota";
|
||||
/**
|
||||
* 查询API调用额度
|
||||
*/
|
||||
String GET_API_QUOTA = "https://api.weixin.qq.com/cgi-bin/openapi/quota/get";
|
||||
/**
|
||||
* 查询rid信息
|
||||
*/
|
||||
String GET_RID_INFO = "https://api.weixin.qq.com/cgi-bin/openapi/rid/get";
|
||||
/**
|
||||
* 使用AppSecret重置 API 调用次数
|
||||
*/
|
||||
String CLEAR_QUOTA_BY_APP_SECRET = "https://api.weixin.qq.com/cgi-bin/clear_quota/v2?appid=%s&appsecret=%s";
|
||||
|
||||
}
|
||||
|
||||
public interface Analysis {
|
||||
String GET_DAILY_SUMMARY_TREND_URL = "https://api.weixin.qq.com/datacube/getweanalysisappiddailysummarytrend";
|
||||
String GET_DAILY_VISIT_TREND_URL = "https://api.weixin.qq.com/datacube/getweanalysisappiddailyvisittrend";
|
||||
|
@ -0,0 +1,48 @@
|
||||
package cn.binarywang.wx.miniapp.api.impl;
|
||||
|
||||
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||
import cn.binarywang.wx.miniapp.bean.openapi.WxMiniGetApiQuotaResult;
|
||||
import cn.binarywang.wx.miniapp.test.ApiTestModule;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.inject.Inject;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import org.testng.annotations.Guice;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
import static org.testng.AssertJUnit.assertTrue;
|
||||
|
||||
/**
|
||||
* openApi管理测试
|
||||
*
|
||||
* @author shuiyihan12
|
||||
* @since 2023/7/7 17:08
|
||||
*/
|
||||
@Test
|
||||
@Guice(modules = ApiTestModule.class)
|
||||
public class WxMaOpenApiServiceImplTest {
|
||||
|
||||
@Inject
|
||||
private WxMaService wxMaService;
|
||||
|
||||
|
||||
@Test
|
||||
public void clearQuota() throws WxErrorException {
|
||||
final boolean result = wxMaService.getWxMaOpenApiService().clearQuota();
|
||||
assertTrue(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getApiQuota() throws WxErrorException {
|
||||
String cgiPath = "/cgi-bin/openapi/quota/get";
|
||||
final WxMiniGetApiQuotaResult apiQuota = wxMaService.getWxMaOpenApiService().getApiQuota(cgiPath);
|
||||
assertNotNull(apiQuota);
|
||||
System.out.println(new Gson().toJson(apiQuota));
|
||||
}
|
||||
@Test
|
||||
public void clearQuotaByAppSecret() throws WxErrorException {
|
||||
final boolean result = wxMaService.getWxMaOpenApiService().clearQuotaByAppSecret();
|
||||
assertTrue(result);
|
||||
}
|
||||
|
||||
}
|
@ -209,9 +209,11 @@ public abstract class BaseWxPayServiceImpl implements WxPayService {
|
||||
@Override
|
||||
public String getPayBaseUrl() {
|
||||
if (this.getConfig().isUseSandboxEnv()) {
|
||||
if (StringUtils.isNotBlank(this.getConfig().getApiV3Key())) {
|
||||
throw new WxRuntimeException("微信支付V3 目前不支持沙箱模式!");
|
||||
}
|
||||
return this.getConfig().getPayBaseUrl() + "/xdc/apiv2sandbox";
|
||||
}
|
||||
|
||||
return this.getConfig().getPayBaseUrl();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user