![JAR search and dependency download from the Maven repository](/logo.png)
me.chanjar.weixin.channel.api.impl.BaseWxChannelServiceImpl Maven / Gradle / Ivy
package me.chanjar.weixin.channel.api.impl;
import com.google.gson.JsonObject;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.channel.api.*;
import me.chanjar.weixin.channel.config.WxChannelConfig;
import me.chanjar.weixin.channel.util.JsonUtils;
import me.chanjar.weixin.common.api.WxConsts;
import me.chanjar.weixin.common.bean.CommonUploadParam;
import me.chanjar.weixin.common.bean.ToJson;
import me.chanjar.weixin.common.bean.WxAccessToken;
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.error.WxRuntimeException;
import me.chanjar.weixin.common.executor.CommonUploadRequestExecutor;
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 org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
/**
* @author Zeyes
* @see #doGetAccessTokenRequest
*/
@Slf4j
public abstract class BaseWxChannelServiceImpl implements WxChannelService, RequestHttp {
private final WxChannelBasicService basicService = new WxChannelBasicServiceImpl(this);
private final WxChannelCategoryService categoryService = new WxChannelCategoryServiceImpl(this);
private final WxChannelBrandService brandService = new WxChannelBrandServiceImpl(this);
private final WxChannelProductService productService = new WxChannelProductServiceImpl(this);
private final WxChannelWarehouseService warehouseService = new WxChannelWarehouseServiceImpl(this);
private final WxChannelOrderService orderService = new WxChannelOrderServiceImpl(this);
private final WxChannelAfterSaleService afterSaleService = new WxChannelAfterSaleServiceImpl(this);
private final WxChannelFreightTemplateService freightTemplateService =
new WxChannelFreightTemplateServiceImpl(this);
private final WxChannelAddressService addressService = new WxChannelAddressServiceImpl(this);
private final WxChannelCouponService couponService = new WxChannelCouponServiceImpl(this);
private final WxChannelSharerService sharerService = new WxChannelSharerServiceImpl(this);
private final WxChannelFundService fundService = new WxChannelFundServiceImpl(this);
private WxLeagueWindowService leagueWindowService = null;
private WxLeagueSupplierService leagueSupplierService = null;
private WxLeaguePromoterService leaguePromoterService = null;
private WxLeagueProductService leagueProductService = null;
private WxLeadComponentService leadComponentService = null;
private WxFinderLiveService finderLiveService = null;
private WxAssistantService assistantService = null;
private WxChannelVipService vipService = new WxChannelVipServiceImpl(this);
private final WxChannelCompassFinderService compassFinderService =
new WxChannelCompassFinderServiceImpl(this);
private final WxChannelLiveDashboardService liveDashboardService =
new WxChannelLiveDashboardServiceImpl(this);
protected WxChannelConfig config;
private int retrySleepMillis = 1000;
private int maxRetryTimes = 5;
@Override
public RequestHttp getRequestHttp() {
return this;
}
@Override
public boolean checkSignature(String timestamp, String nonce, String signature) {
try {
return SHA1.gen(this.getConfig().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.getConfig().isAccessTokenExpired()) {
return this.getConfig().getAccessToken();
}
Lock lock = this.getConfig().getAccessTokenLock();
boolean locked = false;
try {
do {
locked = lock.tryLock(100, TimeUnit.MILLISECONDS);
if (!forceRefresh && !this.getConfig().isAccessTokenExpired()) {
return this.getConfig().getAccessToken();
}
} while (!locked);
String response = doGetAccessTokenRequest();
return extractAccessToken(response);
} catch (WxErrorException | InterruptedException e) {
throw new WxRuntimeException(e);
} finally {
if (locked) {
lock.unlock();
}
}
}
/**
* 通过网络请求获取AccessToken
*
* @return .
* @throws IOException .
*/
protected abstract String doGetAccessTokenRequest() throws WxErrorException;
@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 {
// 此处用JsonUtils.encode, 不用Gson
return this.execute(SimplePostRequestExecutor.create(this), url, JsonUtils.encode(obj));
}
@Override
public String post(String url, ToJson obj) throws WxErrorException {
return this.post(url, obj.toJson());
}
@Override
public String upload(String url, CommonUploadParam param) throws WxErrorException {
RequestExecutor executor = CommonUploadRequestExecutor.create(getRequestHttp());
return this.execute(executor, url, param);
}
@Override
public String post(String url, JsonObject jsonObject) throws WxErrorException {
return this.post(url, jsonObject.toString());
}
/**
* 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求
*/
@Override
public T execute(RequestExecutor executor, String uri, E data) throws WxErrorException {
return execute0(executor, uri, data, true);
}
@Override
public T executeWithoutLog(RequestExecutor executor, String uri, E data) throws WxErrorException {
return execute0(executor, uri, data, false);
}
protected T execute0(RequestExecutor executor, String uri, E data, boolean printResult)
throws WxErrorException {
int retryTimes = 0;
do {
try {
return this.executeInternal(executor, uri, data, false, printResult);
} 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 WxRuntimeException("微信服务端异常,超出重试次数");
}
protected T executeInternal(RequestExecutor executor, String uri, E data, boolean doNotAutoRefreshToken,
boolean printResult) throws WxErrorException {
E dataForLog = DataUtils.handleDataWithSecret(data);
if (uri.contains("access_token=")) {
throw new IllegalArgumentException("uri参数中不允许有access_token: " + uri);
}
String accessToken = getAccessToken(false);
WxChannelConfig config = this.getConfig();
if (StringUtils.isNotEmpty(config.getApiHostUrl())) {
uri = uri.replace("https://api.weixin.qq.com", config.getApiHostUrl());
}
String uriWithAccessToken = uri + (uri.contains("?") ? "&" : "?") + "access_token=" + accessToken;
try {
T result = executor.execute(uriWithAccessToken, data, WxType.Channel);
log.debug("\n【请求地址】: {}\n【请求参数】:{}\n【响应数据】:{}", uriWithAccessToken, dataForLog,
printResult ? result : "...");
return result;
} catch (WxErrorException e) {
WxError error = e.getError();
if (WxConsts.ACCESS_TOKEN_ERROR_CODES.contains(error.getErrorCode())) {
// 强制设置WxMaConfig的access token过期了,这样在下一次请求里就会刷新access token
Lock lock = config.getAccessTokenLock();
lock.lock();
try {
if (StringUtils.equals(config.getAccessToken(), accessToken)) {
config.expireAccessToken();
}
} catch (Exception ex) {
config.expireAccessToken();
} finally {
lock.unlock();
}
if (config.autoRefreshToken() && !doNotAutoRefreshToken) {
log.warn("即将重新获取新的access_token,错误代码:{},错误信息:{}", error.getErrorCode(), error.getErrorMsg());
//下一次不再自动重试
//当小程序误调用第三方平台专属接口时,第三方无法使用小程序的access token,如果可以继续自动获取token会导致无限循环重试,直到栈溢出
return this.executeInternal(executor, uri, data, true, printResult);
}
}
if (error.getErrorCode() != 0) {
log.warn("\n【请求地址】: {}\n【请求参数】:{}\n【错误信息】:{}", uriWithAccessToken, dataForLog, error);
throw new WxErrorException(error, e);
}
return null;
} catch (IOException e) {
log.warn("\n【请求地址】: {}\n【请求参数】:{}\n【异常信息】:{}", uriWithAccessToken, dataForLog, e.getMessage());
throw new WxRuntimeException(e);
}
}
/**
* 设置当前的AccessToken
*
* @param resultContent 响应内容
* @return access token
* @throws WxErrorException 异常
*/
protected String extractAccessToken(String resultContent) throws WxErrorException {
log.info("resultContent: " + resultContent);
WxChannelConfig config = this.getConfig();
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 WxChannelConfig getConfig() {
return config;
}
@Override
public void setConfig(WxChannelConfig config) {
this.config = config;
initHttp();
}
@Override
public void setRetrySleepMillis(int retrySleepMillis) {
this.retrySleepMillis = retrySleepMillis;
}
@Override
public void setMaxRetryTimes(int maxRetryTimes) {
this.maxRetryTimes = maxRetryTimes;
}
@Override
public WxChannelBasicService getBasicService() {
return basicService;
}
@Override
public WxChannelCategoryService getCategoryService() {
return categoryService;
}
@Override
public WxChannelBrandService getBrandService() {
return brandService;
}
@Override
public WxChannelProductService getProductService() {
return productService;
}
@Override
public WxChannelWarehouseService getWarehouseService() {
return warehouseService;
}
@Override
public WxChannelOrderService getOrderService() {
return orderService;
}
@Override
public WxChannelAfterSaleService getAfterSaleService() {
return afterSaleService;
}
@Override
public WxChannelFreightTemplateService getFreightTemplateService() {
return freightTemplateService;
}
@Override
public WxChannelAddressService getAddressService() {
return addressService;
}
@Override
public WxChannelCouponService getCouponService() {
return couponService;
}
@Override
public WxChannelSharerService getSharerService() {
return sharerService;
}
@Override
public WxChannelFundService getFundService() {
return fundService;
}
@Override
public synchronized WxLeagueWindowService getLeagueWindowService() {
if (leagueWindowService == null) {
leagueWindowService = new WxLeagueWindowServiceImpl(this);
}
return leagueWindowService;
}
@Override
public synchronized WxLeagueSupplierService getLeagueSupplierService() {
if (leagueSupplierService == null) {
leagueSupplierService = new WxLeagueSupplierServiceImpl(this);
}
return leagueSupplierService;
}
@Override
public synchronized WxLeaguePromoterService getLeaguePromoterService() {
if (leaguePromoterService == null) {
leaguePromoterService = new WxLeaguePromoterServiceImpl(this);
}
return leaguePromoterService;
}
@Override
public synchronized WxLeagueProductService getLeagueProductService() {
if (leagueProductService == null) {
leagueProductService = new WxLeagueProductServiceImpl(this);
}
return leagueProductService;
}
@Override
public WxLeadComponentService getLeadComponentService() {
if (leadComponentService == null) {
leadComponentService = new WxLeadComponentServiceImpl(this);
}
return leadComponentService;
}
@Override
public WxFinderLiveService getFinderLiveService() {
if (finderLiveService == null) {
finderLiveService = new WxFinderLiveServiceImpl(this);
}
return finderLiveService;
}
@Override
public WxAssistantService getAssistantService() {
if (assistantService == null) {
assistantService = new WxAssistantServiceImpl(this) {
};
}
return assistantService;
}
@Override
public WxChannelVipService getVipService() {
return vipService;
}
@Override
public WxChannelCompassFinderService getCompassFinderService() { return compassFinderService; }
@Override
public WxChannelLiveDashboardService getLiveDashboardService() { return liveDashboardService; }
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy