mirror of
https://gitee.com/binary/weixin-java-tools.git
synced 2025-10-21 11:07:37 +08:00
🎨 #571 微信小程序接口请求增加多种http客户端
This commit is contained in:
@@ -23,7 +23,7 @@
|
|||||||
wx.miniapp.config-storage.redis.host = 127.0.0.1
|
wx.miniapp.config-storage.redis.host = 127.0.0.1
|
||||||
wx.miniapp.config-storage.redis.port = 6379
|
wx.miniapp.config-storage.redis.port = 6379
|
||||||
# http客户端配置
|
# http客户端配置
|
||||||
wx.miniapp.config-storage.http-client-type=HttpClient # http客户端类型: HttpClient(默认)
|
wx.miniapp.config-storage.http-client-type=HttpClient # http客户端类型: HttpClient(默认), OkHttp, JoddHttp
|
||||||
wx.miniapp.config-storage.http-proxy-host=
|
wx.miniapp.config-storage.http-proxy-host=
|
||||||
wx.miniapp.config-storage.http-proxy-port=
|
wx.miniapp.config-storage.http-proxy-port=
|
||||||
wx.miniapp.config-storage.http-proxy-username=
|
wx.miniapp.config-storage.http-proxy-username=
|
||||||
|
@@ -1,11 +1,14 @@
|
|||||||
package com.binarywang.spring.starter.wxjava.miniapp.config;
|
package com.binarywang.spring.starter.wxjava.miniapp.config;
|
||||||
|
|
||||||
import cn.binarywang.wx.miniapp.api.WxMaService;
|
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||||
|
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceHttpClientImpl;
|
||||||
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
|
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
|
||||||
|
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceJoddHttpImpl;
|
||||||
|
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceOkHttpImpl;
|
||||||
import cn.binarywang.wx.miniapp.config.WxMaConfig;
|
import cn.binarywang.wx.miniapp.config.WxMaConfig;
|
||||||
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
|
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
|
||||||
import cn.binarywang.wx.miniapp.config.impl.WxMaRedisBetterConfigImpl;
|
import cn.binarywang.wx.miniapp.config.impl.WxMaRedisBetterConfigImpl;
|
||||||
import com.binarywang.spring.starter.wxjava.miniapp.enums.StorageType;
|
import com.binarywang.spring.starter.wxjava.miniapp.enums.HttpClientType;
|
||||||
import com.binarywang.spring.starter.wxjava.miniapp.properties.ConfigStorage;
|
import com.binarywang.spring.starter.wxjava.miniapp.properties.ConfigStorage;
|
||||||
import com.binarywang.spring.starter.wxjava.miniapp.properties.RedisProperties;
|
import com.binarywang.spring.starter.wxjava.miniapp.properties.RedisProperties;
|
||||||
import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties;
|
import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties;
|
||||||
@@ -49,9 +52,19 @@ public class WxMaAutoConfiguration {
|
|||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean(WxMaService.class)
|
@ConditionalOnMissingBean(WxMaService.class)
|
||||||
public WxMaService service(WxMaConfig wxMaConfig) {
|
public WxMaService service(WxMaConfig wxMaConfig) {
|
||||||
final WxMaServiceImpl service = new WxMaServiceImpl();
|
HttpClientType httpClientType = wxMaProperties.getConfigStorage().getHttpClientType();
|
||||||
service.setWxMaConfig(wxMaConfig);
|
WxMaService wxMaService;
|
||||||
return service;
|
if (httpClientType == HttpClientType.OkHttp) {
|
||||||
|
wxMaService = new WxMaServiceOkHttpImpl();
|
||||||
|
} else if (httpClientType == HttpClientType.JoddHttp) {
|
||||||
|
wxMaService = new WxMaServiceJoddHttpImpl();
|
||||||
|
} else if (httpClientType == HttpClientType.HttpClient) {
|
||||||
|
wxMaService = new WxMaServiceHttpClientImpl();
|
||||||
|
} else {
|
||||||
|
wxMaService = new WxMaServiceImpl();
|
||||||
|
}
|
||||||
|
wxMaService.setWxMaConfig(wxMaConfig);
|
||||||
|
return wxMaService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@@ -10,5 +10,13 @@ public enum HttpClientType {
|
|||||||
/**
|
/**
|
||||||
* HttpClient.
|
* HttpClient.
|
||||||
*/
|
*/
|
||||||
HttpClient
|
HttpClient,
|
||||||
|
/**
|
||||||
|
* OkHttp.
|
||||||
|
*/
|
||||||
|
OkHttp,
|
||||||
|
/**
|
||||||
|
* JoddHttp.
|
||||||
|
*/
|
||||||
|
JoddHttp,
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,397 @@
|
|||||||
|
package cn.binarywang.wx.miniapp.api.impl;
|
||||||
|
|
||||||
|
import cn.binarywang.wx.miniapp.api.*;
|
||||||
|
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
|
||||||
|
import cn.binarywang.wx.miniapp.config.WxMaConfig;
|
||||||
|
import com.google.common.base.Joiner;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import me.chanjar.weixin.common.WxType;
|
||||||
|
import me.chanjar.weixin.common.bean.WxAccessToken;
|
||||||
|
import me.chanjar.weixin.common.error.WxError;
|
||||||
|
import me.chanjar.weixin.common.error.WxErrorException;
|
||||||
|
import me.chanjar.weixin.common.util.DataUtils;
|
||||||
|
import me.chanjar.weixin.common.util.crypto.SHA1;
|
||||||
|
import me.chanjar.weixin.common.util.http.RequestExecutor;
|
||||||
|
import me.chanjar.weixin.common.util.http.RequestHttp;
|
||||||
|
import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor;
|
||||||
|
import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor;
|
||||||
|
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
|
||||||
|
import static cn.binarywang.wx.miniapp.constant.WxMaConstants.ErrorCode.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||||
|
* @see #doGetAccessTokenRequest
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public abstract class BaseWxMaServiceImpl<H, P> implements WxMaService, RequestHttp<H, P> {
|
||||||
|
private static final JsonParser JSON_PARSER = new JsonParser();
|
||||||
|
private WxMaConfig wxMaConfig;
|
||||||
|
|
||||||
|
private final WxMaMsgService kefuService = new WxMaMsgServiceImpl(this);
|
||||||
|
private final WxMaMediaService materialService = new WxMaMediaServiceImpl(this);
|
||||||
|
private final WxMaUserService userService = new WxMaUserServiceImpl(this);
|
||||||
|
private final WxMaQrcodeService qrCodeService = new WxMaQrcodeServiceImpl(this);
|
||||||
|
private final WxMaTemplateService templateService = new WxMaTemplateServiceImpl(this);
|
||||||
|
private final WxMaAnalysisService analysisService = new WxMaAnalysisServiceImpl(this);
|
||||||
|
private final WxMaCodeService codeService = new WxMaCodeServiceImpl(this);
|
||||||
|
private final WxMaSettingService settingService = new WxMaSettingServiceImpl(this);
|
||||||
|
private final WxMaJsapiService jsapiService = new WxMaJsapiServiceImpl(this);
|
||||||
|
private final WxMaShareService shareService = new WxMaShareServiceImpl(this);
|
||||||
|
private final WxMaRunService runService = new WxMaRunServiceImpl(this);
|
||||||
|
private final WxMaSecCheckService secCheckService = new WxMaSecCheckServiceImpl(this);
|
||||||
|
private final WxMaPluginService pluginService = new WxMaPluginServiceImpl(this);
|
||||||
|
private final WxMaExpressService expressService = new WxMaExpressServiceImpl(this);
|
||||||
|
private final WxMaSubscribeService subscribeService = new WxMaSubscribeServiceImpl(this);
|
||||||
|
private final WxMaCloudService cloudService = new WxMaCloudServiceImpl(this);
|
||||||
|
private final WxMaLiveService liveService = new WxMaLiveServiceImpl(this);
|
||||||
|
|
||||||
|
private int retrySleepMillis = 1000;
|
||||||
|
private int maxRetryTimes = 5;
|
||||||
|
|
||||||
|
protected static final Gson GSON = new Gson();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RequestHttp getRequestHttp() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPaidUnionId(String openid, String transactionId, String mchId, String outTradeNo)
|
||||||
|
throws WxErrorException {
|
||||||
|
Map<String, String> params = new HashMap<>(8);
|
||||||
|
params.put("openid", openid);
|
||||||
|
|
||||||
|
if (StringUtils.isNotEmpty(transactionId)) {
|
||||||
|
params.put("transaction_id", transactionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringUtils.isNotEmpty(mchId)) {
|
||||||
|
params.put("mch_id", mchId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringUtils.isNotEmpty(outTradeNo)) {
|
||||||
|
params.put("out_trade_no", outTradeNo);
|
||||||
|
}
|
||||||
|
|
||||||
|
String responseContent = this.get(GET_PAID_UNION_ID_URL, Joiner.on("&").withKeyValueSeparator("=").join(params));
|
||||||
|
WxError error = WxError.fromJson(responseContent, WxType.MiniApp);
|
||||||
|
if (error.getErrorCode() != 0) {
|
||||||
|
throw new WxErrorException(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON_PARSER.parse(responseContent).getAsJsonObject().get("unionid").getAsString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxMaJscode2SessionResult jsCode2SessionInfo(String jsCode) throws WxErrorException {
|
||||||
|
final WxMaConfig config = getWxMaConfig();
|
||||||
|
Map<String, String> params = new HashMap<>(8);
|
||||||
|
params.put("appid", config.getAppid());
|
||||||
|
params.put("secret", config.getSecret());
|
||||||
|
params.put("js_code", jsCode);
|
||||||
|
params.put("grant_type", "authorization_code");
|
||||||
|
|
||||||
|
String result = get(JSCODE_TO_SESSION_URL, Joiner.on("&").withKeyValueSeparator("=").join(params));
|
||||||
|
return WxMaJscode2SessionResult.fromJson(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDynamicData(int lifespan, String type, int scene, String data) throws WxErrorException {
|
||||||
|
JsonObject jsonObject = new JsonObject();
|
||||||
|
jsonObject.addProperty("lifespan", lifespan);
|
||||||
|
jsonObject.addProperty("query", WxGsonBuilder.create().toJson(ImmutableMap.of("type", type)));
|
||||||
|
jsonObject.addProperty("data", data);
|
||||||
|
jsonObject.addProperty("scene", scene);
|
||||||
|
|
||||||
|
this.post(SET_DYNAMIC_DATA_URL, jsonObject.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkSignature(String timestamp, String nonce, String signature) {
|
||||||
|
try {
|
||||||
|
return SHA1.gen(this.getWxMaConfig().getToken(), timestamp, nonce).equals(signature);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Checking signature failed, and the reason is :" + e.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAccessToken() throws WxErrorException {
|
||||||
|
return getAccessToken(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAccessToken(boolean forceRefresh) throws WxErrorException {
|
||||||
|
if (!forceRefresh && !this.getWxMaConfig().isAccessTokenExpired()) {
|
||||||
|
return this.getWxMaConfig().getAccessToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
Lock lock = this.getWxMaConfig().getAccessTokenLock();
|
||||||
|
boolean locked = false;
|
||||||
|
try {
|
||||||
|
do {
|
||||||
|
locked = lock.tryLock(100, TimeUnit.MILLISECONDS);
|
||||||
|
if (!forceRefresh && !this.getWxMaConfig().isAccessTokenExpired()) {
|
||||||
|
return this.getWxMaConfig().getAccessToken();
|
||||||
|
}
|
||||||
|
} while (!locked);
|
||||||
|
String response = doGetAccessTokenRequest();
|
||||||
|
return extractAccessToken(response);
|
||||||
|
} catch (IOException | InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} finally {
|
||||||
|
if (locked) {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过网络请求获取AccessToken
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
protected abstract String doGetAccessTokenRequest() throws IOException;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String get(String url, String queryParam) throws WxErrorException {
|
||||||
|
return execute(SimpleGetRequestExecutor.create(this), url, queryParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String post(String url, String postData) throws WxErrorException {
|
||||||
|
return execute(SimplePostRequestExecutor.create(this), url, postData);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String post(String url, Object obj) throws WxErrorException {
|
||||||
|
return this.execute(SimplePostRequestExecutor.create(this), url, WxGsonBuilder.create().toJson(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {
|
||||||
|
int retryTimes = 0;
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
return this.executeInternal(executor, uri, data);
|
||||||
|
} catch (WxErrorException e) {
|
||||||
|
if (retryTimes + 1 > this.maxRetryTimes) {
|
||||||
|
log.warn("重试达到最大次数【{}】", maxRetryTimes);
|
||||||
|
//最后一次重试失败后,直接抛出异常,不再等待
|
||||||
|
throw new WxErrorException(WxError.builder()
|
||||||
|
.errorCode(e.getError().getErrorCode())
|
||||||
|
.errorMsg("微信服务端异常,超出重试次数!")
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
WxError error = e.getError();
|
||||||
|
// -1 系统繁忙, 1000ms后重试
|
||||||
|
if (error.getErrorCode() == -1) {
|
||||||
|
int sleepMillis = this.retrySleepMillis * (1 << retryTimes);
|
||||||
|
try {
|
||||||
|
log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
|
||||||
|
Thread.sleep(sleepMillis);
|
||||||
|
} catch (InterruptedException e1) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (retryTimes++ < this.maxRetryTimes);
|
||||||
|
|
||||||
|
log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
|
||||||
|
throw new RuntimeException("微信服务端异常,超出重试次数");
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {
|
||||||
|
E dataForLog = DataUtils.handleDataWithSecret(data);
|
||||||
|
|
||||||
|
if (uri.contains("access_token=")) {
|
||||||
|
throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri);
|
||||||
|
}
|
||||||
|
String accessToken = getAccessToken(false);
|
||||||
|
|
||||||
|
String uriWithAccessToken = uri + (uri.contains("?") ? "&" : "?") + "access_token=" + accessToken;
|
||||||
|
|
||||||
|
try {
|
||||||
|
T result = executor.execute(uriWithAccessToken, data, WxType.MiniApp);
|
||||||
|
log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog, result);
|
||||||
|
return result;
|
||||||
|
} catch (WxErrorException e) {
|
||||||
|
WxError error = e.getError();
|
||||||
|
/*
|
||||||
|
* 发生以下情况时尝试刷新access_token
|
||||||
|
*/
|
||||||
|
if (error.getErrorCode() == ERR_40001
|
||||||
|
|| error.getErrorCode() == ERR_42001
|
||||||
|
|| error.getErrorCode() == ERR_40014) {
|
||||||
|
// 强制设置WxMaConfig的access token过期了,这样在下一次请求里就会刷新access token
|
||||||
|
Lock lock = this.getWxMaConfig().getAccessTokenLock();
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
if (StringUtils.equals(this.getWxMaConfig().getAccessToken(), accessToken)) {
|
||||||
|
this.getWxMaConfig().expireAccessToken();
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
this.getWxMaConfig().expireAccessToken();
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
if (this.getWxMaConfig().autoRefreshToken()) {
|
||||||
|
return this.execute(executor, uri, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error.getErrorCode() != 0) {
|
||||||
|
log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error);
|
||||||
|
throw new WxErrorException(error, e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage());
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置当前的AccessToken
|
||||||
|
*
|
||||||
|
* @param resultContent
|
||||||
|
* @return
|
||||||
|
* @throws WxErrorException
|
||||||
|
*/
|
||||||
|
protected String extractAccessToken(String resultContent) throws WxErrorException {
|
||||||
|
WxMaConfig config = this.getWxMaConfig();
|
||||||
|
WxError error = WxError.fromJson(resultContent, WxType.MiniApp);
|
||||||
|
if (error.getErrorCode() != 0) {
|
||||||
|
throw new WxErrorException(error);
|
||||||
|
}
|
||||||
|
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
|
||||||
|
config.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
|
||||||
|
return accessToken.getAccessToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxMaConfig getWxMaConfig() {
|
||||||
|
return this.wxMaConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setWxMaConfig(WxMaConfig wxConfigProvider) {
|
||||||
|
this.wxMaConfig = wxConfigProvider;
|
||||||
|
this.initHttp();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRetrySleepMillis(int retrySleepMillis) {
|
||||||
|
this.retrySleepMillis = retrySleepMillis;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMaxRetryTimes(int maxRetryTimes) {
|
||||||
|
this.maxRetryTimes = maxRetryTimes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxMaMsgService getMsgService() {
|
||||||
|
return this.kefuService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxMaMediaService getMediaService() {
|
||||||
|
return this.materialService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxMaUserService getUserService() {
|
||||||
|
return this.userService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxMaQrcodeService getQrcodeService() {
|
||||||
|
return this.qrCodeService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxMaTemplateService getTemplateService() {
|
||||||
|
return this.templateService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxMaSubscribeService getSubscribeService() {
|
||||||
|
return this.subscribeService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxMaAnalysisService getAnalysisService() {
|
||||||
|
return this.analysisService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxMaCodeService getCodeService() {
|
||||||
|
return this.codeService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxMaJsapiService getJsapiService() {
|
||||||
|
return this.jsapiService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxMaSettingService getSettingService() {
|
||||||
|
return this.settingService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxMaShareService getShareService() {
|
||||||
|
return this.shareService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxMaRunService getRunService() {
|
||||||
|
return this.runService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxMaSecCheckService getSecCheckService() {
|
||||||
|
return this.secCheckService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxMaPluginService getPluginService() {
|
||||||
|
return this.pluginService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxMaExpressService getExpressService() {
|
||||||
|
return this.expressService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxMaCloudService getCloudService() {
|
||||||
|
return this.cloudService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxMaLiveService getLiveService() {
|
||||||
|
return this.liveService;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,88 @@
|
|||||||
|
package cn.binarywang.wx.miniapp.api.impl;
|
||||||
|
|
||||||
|
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||||
|
import cn.binarywang.wx.miniapp.config.WxMaConfig;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import me.chanjar.weixin.common.util.http.HttpType;
|
||||||
|
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
|
||||||
|
import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
|
||||||
|
import org.apache.http.HttpHost;
|
||||||
|
import org.apache.http.client.config.RequestConfig;
|
||||||
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.impl.client.BasicResponseHandler;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class WxMaServiceHttpClientImpl extends BaseWxMaServiceImpl {
|
||||||
|
private CloseableHttpClient httpClient;
|
||||||
|
private HttpHost httpProxy;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initHttp() {
|
||||||
|
WxMaConfig configStorage = this.getWxMaConfig();
|
||||||
|
ApacheHttpClientBuilder apacheHttpClientBuilder = configStorage.getApacheHttpClientBuilder();
|
||||||
|
if (null == apacheHttpClientBuilder) {
|
||||||
|
apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
apacheHttpClientBuilder.httpProxyHost(configStorage.getHttpProxyHost())
|
||||||
|
.httpProxyPort(configStorage.getHttpProxyPort())
|
||||||
|
.httpProxyUsername(configStorage.getHttpProxyUsername())
|
||||||
|
.httpProxyPassword(configStorage.getHttpProxyPassword());
|
||||||
|
|
||||||
|
if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) {
|
||||||
|
this.httpProxy = new HttpHost(configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.httpClient = apacheHttpClientBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CloseableHttpClient getRequestHttpClient() {
|
||||||
|
return httpClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpHost getRequestHttpProxy() {
|
||||||
|
return httpProxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpType getRequestType() {
|
||||||
|
return HttpType.APACHE_HTTP;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String doGetAccessTokenRequest() throws IOException {
|
||||||
|
String url = String.format(WxMaService.GET_ACCESS_TOKEN_URL, this.getWxMaConfig().getAppid(), this.getWxMaConfig().getSecret());
|
||||||
|
|
||||||
|
HttpGet httpGet = null;
|
||||||
|
CloseableHttpResponse response = null;
|
||||||
|
try {
|
||||||
|
httpGet = new HttpGet(url);
|
||||||
|
if (this.getRequestHttpProxy() != null) {
|
||||||
|
RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
|
||||||
|
httpGet.setConfig(config);
|
||||||
|
}
|
||||||
|
response = getRequestHttpClient().execute(httpGet);
|
||||||
|
return new BasicResponseHandler().handleResponse(response);
|
||||||
|
} finally {
|
||||||
|
if (httpGet != null) {
|
||||||
|
httpGet.releaseConnection();
|
||||||
|
}
|
||||||
|
if (response != null) {
|
||||||
|
try {
|
||||||
|
response.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -1,428 +1,11 @@
|
|||||||
package cn.binarywang.wx.miniapp.api.impl;
|
package cn.binarywang.wx.miniapp.api.impl;
|
||||||
|
|
||||||
import cn.binarywang.wx.miniapp.api.*;
|
|
||||||
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
|
|
||||||
import cn.binarywang.wx.miniapp.config.WxMaConfig;
|
|
||||||
import com.google.common.base.Joiner;
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.JsonParser;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import me.chanjar.weixin.common.WxType;
|
|
||||||
import me.chanjar.weixin.common.bean.WxAccessToken;
|
|
||||||
import me.chanjar.weixin.common.error.WxError;
|
|
||||||
import me.chanjar.weixin.common.error.WxErrorException;
|
|
||||||
import me.chanjar.weixin.common.util.DataUtils;
|
|
||||||
import me.chanjar.weixin.common.util.crypto.SHA1;
|
|
||||||
import me.chanjar.weixin.common.util.http.*;
|
|
||||||
import me.chanjar.weixin.common.util.http.apache.ApacheHttpClientBuilder;
|
|
||||||
import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
|
|
||||||
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.http.HttpHost;
|
|
||||||
import org.apache.http.client.config.RequestConfig;
|
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
|
||||||
import org.apache.http.client.methods.HttpGet;
|
|
||||||
import org.apache.http.impl.client.BasicResponseHandler;
|
|
||||||
import org.apache.http.impl.client.CloseableHttpClient;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.locks.Lock;
|
|
||||||
|
|
||||||
import static cn.binarywang.wx.miniapp.constant.WxMaConstants.ErrorCode.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class WxMaServiceImpl implements WxMaService, RequestHttp<CloseableHttpClient, HttpHost> {
|
public class WxMaServiceImpl extends WxMaServiceHttpClientImpl {
|
||||||
private static final JsonParser JSON_PARSER = new JsonParser();
|
|
||||||
private CloseableHttpClient httpClient;
|
|
||||||
private HttpHost httpProxy;
|
|
||||||
private WxMaConfig wxMaConfig;
|
|
||||||
|
|
||||||
private final WxMaMsgService kefuService = new WxMaMsgServiceImpl(this);
|
|
||||||
private final WxMaMediaService materialService = new WxMaMediaServiceImpl(this);
|
|
||||||
private final WxMaUserService userService = new WxMaUserServiceImpl(this);
|
|
||||||
private final WxMaQrcodeService qrCodeService = new WxMaQrcodeServiceImpl(this);
|
|
||||||
private final WxMaTemplateService templateService = new WxMaTemplateServiceImpl(this);
|
|
||||||
private final WxMaAnalysisService analysisService = new WxMaAnalysisServiceImpl(this);
|
|
||||||
private final WxMaCodeService codeService = new WxMaCodeServiceImpl(this);
|
|
||||||
private final WxMaSettingService settingService = new WxMaSettingServiceImpl(this);
|
|
||||||
private final WxMaJsapiService jsapiService = new WxMaJsapiServiceImpl(this);
|
|
||||||
private final WxMaShareService shareService = new WxMaShareServiceImpl(this);
|
|
||||||
private final WxMaRunService runService = new WxMaRunServiceImpl(this);
|
|
||||||
private final WxMaSecCheckService secCheckService = new WxMaSecCheckServiceImpl(this);
|
|
||||||
private final WxMaPluginService pluginService = new WxMaPluginServiceImpl(this);
|
|
||||||
private final WxMaExpressService expressService = new WxMaExpressServiceImpl(this);
|
|
||||||
private final WxMaSubscribeService subscribeService = new WxMaSubscribeServiceImpl(this);
|
|
||||||
private final WxMaCloudService cloudService = new WxMaCloudServiceImpl(this);
|
|
||||||
private final WxMaLiveService liveService = new WxMaLiveServiceImpl(this);
|
|
||||||
|
|
||||||
private int retrySleepMillis = 1000;
|
|
||||||
private int maxRetryTimes = 5;
|
|
||||||
|
|
||||||
protected static final Gson GSON = new Gson();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CloseableHttpClient getRequestHttpClient() {
|
|
||||||
return httpClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HttpHost getRequestHttpProxy() {
|
|
||||||
return httpProxy;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HttpType getRequestType() {
|
|
||||||
return HttpType.APACHE_HTTP;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initHttp() {
|
|
||||||
WxMaConfig configStorage = this.getWxMaConfig();
|
|
||||||
ApacheHttpClientBuilder apacheHttpClientBuilder = configStorage.getApacheHttpClientBuilder();
|
|
||||||
if (null == apacheHttpClientBuilder) {
|
|
||||||
apacheHttpClientBuilder = DefaultApacheHttpClientBuilder.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
apacheHttpClientBuilder.httpProxyHost(configStorage.getHttpProxyHost())
|
|
||||||
.httpProxyPort(configStorage.getHttpProxyPort())
|
|
||||||
.httpProxyUsername(configStorage.getHttpProxyUsername())
|
|
||||||
.httpProxyPassword(configStorage.getHttpProxyPassword());
|
|
||||||
|
|
||||||
if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) {
|
|
||||||
this.httpProxy = new HttpHost(configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort());
|
|
||||||
}
|
|
||||||
|
|
||||||
this.httpClient = apacheHttpClientBuilder.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RequestHttp getRequestHttp() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAccessToken(boolean forceRefresh) throws WxErrorException {
|
|
||||||
if (!this.getWxMaConfig().isAccessTokenExpired() && !forceRefresh) {
|
|
||||||
return this.getWxMaConfig().getAccessToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
Lock lock = this.getWxMaConfig().getAccessTokenLock();
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
if (!this.getWxMaConfig().isAccessTokenExpired() && !forceRefresh) {
|
|
||||||
return this.getWxMaConfig().getAccessToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
String url = String.format(WxMaService.GET_ACCESS_TOKEN_URL, this.getWxMaConfig().getAppid(),
|
|
||||||
this.getWxMaConfig().getSecret());
|
|
||||||
try {
|
|
||||||
HttpGet httpGet = new HttpGet(url);
|
|
||||||
if (this.getRequestHttpProxy() != null) {
|
|
||||||
RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
|
|
||||||
httpGet.setConfig(config);
|
|
||||||
}
|
|
||||||
try (CloseableHttpResponse response = getRequestHttpClient().execute(httpGet)) {
|
|
||||||
String resultContent = new BasicResponseHandler().handleResponse(response);
|
|
||||||
WxError error = WxError.fromJson(resultContent, WxType.MiniApp);
|
|
||||||
if (error.getErrorCode() != 0) {
|
|
||||||
throw new WxErrorException(error);
|
|
||||||
}
|
|
||||||
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
|
|
||||||
this.getWxMaConfig().updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
|
|
||||||
|
|
||||||
return this.getWxMaConfig().getAccessToken();
|
|
||||||
} finally {
|
|
||||||
httpGet.releaseConnection();
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getPaidUnionId(String openid, String transactionId, String mchId, String outTradeNo)
|
|
||||||
throws WxErrorException {
|
|
||||||
Map<String, String> params = new HashMap<>(8);
|
|
||||||
params.put("openid", openid);
|
|
||||||
|
|
||||||
if (StringUtils.isNotEmpty(transactionId)) {
|
|
||||||
params.put("transaction_id", transactionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringUtils.isNotEmpty(mchId)) {
|
|
||||||
params.put("mch_id", mchId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringUtils.isNotEmpty(outTradeNo)) {
|
|
||||||
params.put("out_trade_no", outTradeNo);
|
|
||||||
}
|
|
||||||
|
|
||||||
String responseContent = this.get(GET_PAID_UNION_ID_URL, Joiner.on("&").withKeyValueSeparator("=").join(params));
|
|
||||||
WxError error = WxError.fromJson(responseContent, WxType.MiniApp);
|
|
||||||
if (error.getErrorCode() != 0) {
|
|
||||||
throw new WxErrorException(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return JSON_PARSER.parse(responseContent).getAsJsonObject().get("unionid").getAsString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WxMaJscode2SessionResult jsCode2SessionInfo(String jsCode) throws WxErrorException {
|
|
||||||
final WxMaConfig config = getWxMaConfig();
|
|
||||||
Map<String, String> params = new HashMap<>(8);
|
|
||||||
params.put("appid", config.getAppid());
|
|
||||||
params.put("secret", config.getSecret());
|
|
||||||
params.put("js_code", jsCode);
|
|
||||||
params.put("grant_type", "authorization_code");
|
|
||||||
|
|
||||||
String result = get(JSCODE_TO_SESSION_URL, Joiner.on("&").withKeyValueSeparator("=").join(params));
|
|
||||||
return WxMaJscode2SessionResult.fromJson(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setDynamicData(int lifespan, String type, int scene, String data) throws WxErrorException {
|
|
||||||
JsonObject jsonObject = new JsonObject();
|
|
||||||
jsonObject.addProperty("lifespan", lifespan);
|
|
||||||
jsonObject.addProperty("query", WxGsonBuilder.create().toJson(ImmutableMap.of("type", type)));
|
|
||||||
jsonObject.addProperty("data", data);
|
|
||||||
jsonObject.addProperty("scene", scene);
|
|
||||||
|
|
||||||
this.post(SET_DYNAMIC_DATA_URL, jsonObject.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean checkSignature(String timestamp, String nonce, String signature) {
|
|
||||||
try {
|
|
||||||
return SHA1.gen(this.getWxMaConfig().getToken(), timestamp, nonce).equals(signature);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Checking signature failed, and the reason is :" + e.getMessage());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAccessToken() throws WxErrorException {
|
|
||||||
return getAccessToken(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String get(String url, String queryParam) throws WxErrorException {
|
|
||||||
return execute(SimpleGetRequestExecutor.create(this), url, queryParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String post(String url, String postData) throws WxErrorException {
|
|
||||||
return execute(SimplePostRequestExecutor.create(this), url, postData);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String post(String url, Object obj) throws WxErrorException {
|
|
||||||
return this.execute(SimplePostRequestExecutor.create(this), url, WxGsonBuilder.create().toJson(obj));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {
|
|
||||||
int retryTimes = 0;
|
|
||||||
do {
|
|
||||||
try {
|
|
||||||
return this.executeInternal(executor, uri, data);
|
|
||||||
} catch (WxErrorException e) {
|
|
||||||
if (retryTimes + 1 > this.maxRetryTimes) {
|
|
||||||
log.warn("重试达到最大次数【{}】", maxRetryTimes);
|
|
||||||
//最后一次重试失败后,直接抛出异常,不再等待
|
|
||||||
throw new WxErrorException(WxError.builder()
|
|
||||||
.errorCode(e.getError().getErrorCode())
|
|
||||||
.errorMsg("微信服务端异常,超出重试次数!")
|
|
||||||
.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
WxError error = e.getError();
|
|
||||||
// -1 系统繁忙, 1000ms后重试
|
|
||||||
if (error.getErrorCode() == -1) {
|
|
||||||
int sleepMillis = this.retrySleepMillis * (1 << retryTimes);
|
|
||||||
try {
|
|
||||||
log.warn("微信系统繁忙,{} ms 后重试(第{}次)", sleepMillis, retryTimes + 1);
|
|
||||||
Thread.sleep(sleepMillis);
|
|
||||||
} catch (InterruptedException e1) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (retryTimes++ < this.maxRetryTimes);
|
|
||||||
|
|
||||||
log.warn("重试达到最大次数【{}】", this.maxRetryTimes);
|
|
||||||
throw new RuntimeException("微信服务端异常,超出重试次数");
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T, E> T executeInternal(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException {
|
|
||||||
E dataForLog = DataUtils.handleDataWithSecret(data);
|
|
||||||
|
|
||||||
if (uri.contains("access_token=")) {
|
|
||||||
throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri);
|
|
||||||
}
|
|
||||||
String accessToken = getAccessToken(false);
|
|
||||||
|
|
||||||
String uriWithAccessToken = uri + (uri.contains("?") ? "&" : "?") + "access_token=" + accessToken;
|
|
||||||
|
|
||||||
try {
|
|
||||||
T result = executor.execute(uriWithAccessToken, data, WxType.MiniApp);
|
|
||||||
log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog, result);
|
|
||||||
return result;
|
|
||||||
} catch (WxErrorException e) {
|
|
||||||
WxError error = e.getError();
|
|
||||||
/*
|
|
||||||
* 发生以下情况时尝试刷新access_token
|
|
||||||
*/
|
|
||||||
if (error.getErrorCode() == ERR_40001
|
|
||||||
|| error.getErrorCode() == ERR_42001
|
|
||||||
|| error.getErrorCode() == ERR_40014) {
|
|
||||||
// 强制设置WxMaConfig的access token过期了,这样在下一次请求里就会刷新access token
|
|
||||||
Lock lock = this.getWxMaConfig().getAccessTokenLock();
|
|
||||||
lock.lock();
|
|
||||||
try {
|
|
||||||
if (StringUtils.equals(this.getWxMaConfig().getAccessToken(), accessToken)) {
|
|
||||||
this.getWxMaConfig().expireAccessToken();
|
|
||||||
}
|
|
||||||
} catch (Exception ex) {
|
|
||||||
this.getWxMaConfig().expireAccessToken();
|
|
||||||
} finally {
|
|
||||||
lock.unlock();
|
|
||||||
}
|
|
||||||
if (this.getWxMaConfig().autoRefreshToken()) {
|
|
||||||
return this.execute(executor, uri, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error.getErrorCode() != 0) {
|
|
||||||
log.error("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error);
|
|
||||||
throw new WxErrorException(error, e);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
} catch (IOException e) {
|
|
||||||
log.error("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage());
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WxMaConfig getWxMaConfig() {
|
|
||||||
return this.wxMaConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setWxMaConfig(WxMaConfig wxConfigProvider) {
|
|
||||||
this.wxMaConfig = wxConfigProvider;
|
|
||||||
this.initHttp();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setRetrySleepMillis(int retrySleepMillis) {
|
|
||||||
this.retrySleepMillis = retrySleepMillis;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setMaxRetryTimes(int maxRetryTimes) {
|
|
||||||
this.maxRetryTimes = maxRetryTimes;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WxMaMsgService getMsgService() {
|
|
||||||
return this.kefuService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WxMaMediaService getMediaService() {
|
|
||||||
return this.materialService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WxMaUserService getUserService() {
|
|
||||||
return this.userService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WxMaQrcodeService getQrcodeService() {
|
|
||||||
return this.qrCodeService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WxMaTemplateService getTemplateService() {
|
|
||||||
return this.templateService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WxMaSubscribeService getSubscribeService() {
|
|
||||||
return this.subscribeService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WxMaAnalysisService getAnalysisService() {
|
|
||||||
return this.analysisService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WxMaCodeService getCodeService() {
|
|
||||||
return this.codeService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WxMaJsapiService getJsapiService() {
|
|
||||||
return this.jsapiService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WxMaSettingService getSettingService() {
|
|
||||||
return this.settingService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WxMaShareService getShareService() {
|
|
||||||
return this.shareService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WxMaRunService getRunService() {
|
|
||||||
return this.runService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WxMaSecCheckService getSecCheckService() {
|
|
||||||
return this.secCheckService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WxMaPluginService getPluginService() {
|
|
||||||
return this.pluginService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WxMaExpressService getExpressService() {
|
|
||||||
return this.expressService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WxMaCloudService getCloudService() {
|
|
||||||
return this.cloudService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WxMaLiveService getLiveService() {
|
|
||||||
return this.liveService;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,59 @@
|
|||||||
|
package cn.binarywang.wx.miniapp.api.impl;
|
||||||
|
|
||||||
|
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||||
|
import cn.binarywang.wx.miniapp.config.WxMaConfig;
|
||||||
|
import jodd.http.HttpConnectionProvider;
|
||||||
|
import jodd.http.HttpRequest;
|
||||||
|
import jodd.http.ProxyInfo;
|
||||||
|
import jodd.http.net.SocketHttpConnectionProvider;
|
||||||
|
import me.chanjar.weixin.common.util.http.HttpType;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* jodd-http方式实现.
|
||||||
|
*
|
||||||
|
* @author someone
|
||||||
|
*/
|
||||||
|
public class WxMaServiceJoddHttpImpl extends BaseWxMaServiceImpl<HttpConnectionProvider, ProxyInfo> {
|
||||||
|
private HttpConnectionProvider httpClient;
|
||||||
|
private ProxyInfo httpProxy;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initHttp() {
|
||||||
|
WxMaConfig configStorage = this.getWxMaConfig();
|
||||||
|
if (configStorage.getHttpProxyHost() != null && configStorage.getHttpProxyPort() > 0) {
|
||||||
|
this.httpProxy = new ProxyInfo(ProxyInfo.ProxyType.HTTP, configStorage.getHttpProxyHost(), configStorage.getHttpProxyPort(), configStorage.getHttpProxyUsername(), configStorage.getHttpProxyPassword());
|
||||||
|
}
|
||||||
|
this.httpClient = new SocketHttpConnectionProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpConnectionProvider getRequestHttpClient() {
|
||||||
|
return httpClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProxyInfo getRequestHttpProxy() {
|
||||||
|
return httpProxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpType getRequestType() {
|
||||||
|
return HttpType.JODD_HTTP;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String doGetAccessTokenRequest() throws IOException {
|
||||||
|
String url = String.format(WxMaService.GET_ACCESS_TOKEN_URL, this.getWxMaConfig().getAppid(), this.getWxMaConfig().getSecret());
|
||||||
|
HttpRequest request = HttpRequest.get(url);
|
||||||
|
if (this.getRequestHttpProxy() != null) {
|
||||||
|
SocketHttpConnectionProvider provider = new SocketHttpConnectionProvider();
|
||||||
|
provider.useProxy(getRequestHttpProxy());
|
||||||
|
|
||||||
|
request.withConnectionProvider(provider);
|
||||||
|
}
|
||||||
|
return request.send().bodyText();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,72 @@
|
|||||||
|
package cn.binarywang.wx.miniapp.api.impl;
|
||||||
|
|
||||||
|
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||||
|
import cn.binarywang.wx.miniapp.config.WxMaConfig;
|
||||||
|
import me.chanjar.weixin.common.util.http.HttpType;
|
||||||
|
import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
|
||||||
|
import okhttp3.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* okhttp实现.
|
||||||
|
*/
|
||||||
|
public class WxMaServiceOkHttpImpl extends BaseWxMaServiceImpl<OkHttpClient, OkHttpProxyInfo> {
|
||||||
|
|
||||||
|
private OkHttpClient httpClient;
|
||||||
|
private OkHttpProxyInfo httpProxy;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initHttp() {
|
||||||
|
WxMaConfig wxMpConfigStorage = this.getWxMaConfig();
|
||||||
|
//设置代理
|
||||||
|
if (wxMpConfigStorage.getHttpProxyHost() != null && wxMpConfigStorage.getHttpProxyPort() > 0) {
|
||||||
|
httpProxy = OkHttpProxyInfo.httpProxy(wxMpConfigStorage.getHttpProxyHost(),
|
||||||
|
wxMpConfigStorage.getHttpProxyPort(),
|
||||||
|
wxMpConfigStorage.getHttpProxyUsername(),
|
||||||
|
wxMpConfigStorage.getHttpProxyPassword());
|
||||||
|
}
|
||||||
|
|
||||||
|
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
|
||||||
|
if (httpProxy != null) {
|
||||||
|
clientBuilder.proxy(getRequestHttpProxy().getProxy());
|
||||||
|
|
||||||
|
//设置授权
|
||||||
|
clientBuilder.authenticator(new Authenticator() {
|
||||||
|
@Override
|
||||||
|
public Request authenticate(Route route, Response response) throws IOException {
|
||||||
|
String credential = Credentials.basic(httpProxy.getProxyUsername(), httpProxy.getProxyPassword());
|
||||||
|
return response.request().newBuilder()
|
||||||
|
.header("Authorization", credential)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
httpClient = clientBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OkHttpClient getRequestHttpClient() {
|
||||||
|
return httpClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OkHttpProxyInfo getRequestHttpProxy() {
|
||||||
|
return httpProxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpType getRequestType() {
|
||||||
|
return HttpType.OK_HTTP;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String doGetAccessTokenRequest() throws IOException {
|
||||||
|
String url = String.format(WxMaService.GET_ACCESS_TOKEN_URL, this.getWxMaConfig().getAppid(), this.getWxMaConfig().getSecret());
|
||||||
|
Request request = new Request.Builder().url(url).get().build();
|
||||||
|
try (Response response = getRequestHttpClient().newCall(request).execute()) {
|
||||||
|
return Objects.requireNonNull(response.body()).string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,6 @@
|
|||||||
package me.chanjar.weixin.open.api.impl;
|
package me.chanjar.weixin.open.api.impl;
|
||||||
|
|
||||||
|
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||||
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
|
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
|
||||||
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
|
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
|
||||||
import cn.binarywang.wx.miniapp.config.WxMaConfig;
|
import cn.binarywang.wx.miniapp.config.WxMaConfig;
|
||||||
@@ -196,6 +197,7 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 解除绑定小程序体验者
|
* 解除绑定小程序体验者
|
||||||
|
*
|
||||||
* @param userstr 人员对应的唯一字符串, 可通过获取已绑定的体验者列表获取人员对应的字符串
|
* @param userstr 人员对应的唯一字符串, 可通过获取已绑定的体验者列表获取人员对应的字符串
|
||||||
* @return
|
* @return
|
||||||
* @throws WxErrorException
|
* @throws WxErrorException
|
||||||
@@ -306,7 +308,8 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ
|
|||||||
public File getTestQrcode(String pagePath, Map<String, String> params) throws WxErrorException {
|
public File getTestQrcode(String pagePath, Map<String, String> params) throws WxErrorException {
|
||||||
WxMaQrcodeParam qrcodeParam = WxMaQrcodeParam.create(pagePath);
|
WxMaQrcodeParam qrcodeParam = WxMaQrcodeParam.create(pagePath);
|
||||||
qrcodeParam.addPageParam(params);
|
qrcodeParam.addPageParam(params);
|
||||||
return execute(MaQrCodeRequestExecutor.create(getRequestHttp()), API_TEST_QRCODE, qrcodeParam);
|
WxMaService wxMaService = this;
|
||||||
|
return wxMaService.execute(MaQrCodeRequestExecutor.create(getRequestHttp()), API_TEST_QRCODE, qrcodeParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -547,7 +550,6 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加急审核申请
|
* 加急审核申请
|
||||||
* 有加急次数的第三方可以通过该接口,对已经提审的小程序进行加急操作,加急后的小程序预计2-12小时内审完。
|
* 有加急次数的第三方可以通过该接口,对已经提审的小程序进行加急操作,加急后的小程序预计2-12小时内审完。
|
||||||
@@ -564,6 +566,7 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* (1)增加或修改二维码规则
|
* (1)增加或修改二维码规则
|
||||||
|
*
|
||||||
* @param wxQrcodeJumpRule
|
* @param wxQrcodeJumpRule
|
||||||
* @return
|
* @return
|
||||||
* @throws WxErrorException
|
* @throws WxErrorException
|
||||||
@@ -576,6 +579,7 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* (2)获取已设置的二维码规则
|
* (2)获取已设置的二维码规则
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
* @throws WxErrorException
|
* @throws WxErrorException
|
||||||
*/
|
*/
|
||||||
@@ -587,6 +591,7 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* (3)获取校验文件名称及内容
|
* (3)获取校验文件名称及内容
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
* @throws WxErrorException
|
* @throws WxErrorException
|
||||||
*/
|
*/
|
||||||
@@ -598,6 +603,7 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* (4)删除已设置的二维码规则
|
* (4)删除已设置的二维码规则
|
||||||
|
*
|
||||||
* @param prefix
|
* @param prefix
|
||||||
* @return
|
* @return
|
||||||
* @throws WxErrorException
|
* @throws WxErrorException
|
||||||
@@ -612,6 +618,7 @@ public class WxOpenMaServiceImpl extends WxMaServiceImpl implements WxOpenMaServ
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* (5)发布已设置的二维码规则
|
* (5)发布已设置的二维码规则
|
||||||
|
*
|
||||||
* @param prefix
|
* @param prefix
|
||||||
* @return
|
* @return
|
||||||
* @throws WxErrorException
|
* @throws WxErrorException
|
||||||
|
Reference in New Issue
Block a user