🆕 #3238 【视频号】新增会员功能相关API和消息处理 !122

This commit is contained in:
asushiye 2024-03-02 10:02:05 +00:00 committed by Binary Wang
parent 2ec6a0fe11
commit 149080058e
31 changed files with 1151 additions and 59 deletions

View File

@ -21,6 +21,8 @@ import me.chanjar.weixin.channel.bean.message.product.BrandMessage;
import me.chanjar.weixin.channel.bean.message.product.CategoryAuditMessage; import me.chanjar.weixin.channel.bean.message.product.CategoryAuditMessage;
import me.chanjar.weixin.channel.bean.message.product.SpuAuditMessage; import me.chanjar.weixin.channel.bean.message.product.SpuAuditMessage;
import me.chanjar.weixin.channel.bean.message.supplier.SupplierItemMessage; import me.chanjar.weixin.channel.bean.message.supplier.SupplierItemMessage;
import me.chanjar.weixin.channel.bean.message.vip.ExchangeInfoMessage;
import me.chanjar.weixin.channel.bean.message.vip.UserInfoMessage;
import me.chanjar.weixin.channel.message.WxChannelMessage; import me.chanjar.weixin.channel.message.WxChannelMessage;
import me.chanjar.weixin.channel.message.WxChannelMessageRouterRule; import me.chanjar.weixin.channel.message.WxChannelMessageRouterRule;
import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.common.session.WxSessionManager;
@ -357,6 +359,68 @@ public interface BaseWxChannelMessageService {
void supplierItemUpdate(SupplierItemMessage message, final String content, final String appId, void supplierItemUpdate(SupplierItemMessage message, final String content, final String appId,
final Map<String, Object> context, final WxSessionManager sessionManager); final Map<String, Object> context, final WxSessionManager sessionManager);
/**
* 用户加入会员.
*
* @param message the message
* @param content the content
* @param appId the app id
* @param context the context
* @param sessionManager the session manager
*/
public void vipJoin(UserInfoMessage message, final String content, final String appId,
final Map<String, Object> context, final WxSessionManager sessionManager);
/**
* 用户注销会员.
*
* @param message the message
* @param content the content
* @param appId the app id
* @param context the context
* @param sessionManager the session manager
*/
void vipClose(UserInfoMessage message, final String content, final String appId,
final Map<String, Object> context, final WxSessionManager sessionManager);
/**
* 用户等级更新.
*
* @param message the message
* @param content the content
* @param appId the app id
* @param context the context
* @param sessionManager the session manager
*/
void vipGradeUpdate(UserInfoMessage message, final String content, final String appId,
final Map<String, Object> context, final WxSessionManager sessionManager);
/**
* 用户积分更新.
*
* @param message the message
* @param content the content
* @param appId the app id
* @param context the context
* @param sessionManager the session manager
*/
void vipScoreUpdate(UserInfoMessage message, final String content, final String appId,
final Map<String, Object> context, final WxSessionManager sessionManager);
/**
* 用户积分兑换
*
* @param message the message
* @param content the content
* @param appId the app id
* @param context the context
* @param sessionManager the session manager
*/
void vipScoreExchange(ExchangeInfoMessage message, final String content, final String appId,
final Map<String, Object> context, final WxSessionManager sessionManager);
/** /**
* 默认消息处理 * 默认消息处理
* *

View File

@ -140,4 +140,11 @@ public interface WxChannelService extends BaseWxChannelService {
*/ */
WxAssistantService getAssistantService(); WxAssistantService getAssistantService();
/**
* 会员功能
*
* @return 会员服务
*/
WxChannelVipService getVipService();
} }

View File

@ -0,0 +1,97 @@
package me.chanjar.weixin.channel.api;
import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
import me.chanjar.weixin.channel.bean.vip.VipInfoResponse;
import me.chanjar.weixin.channel.bean.vip.VipListResponse;
import me.chanjar.weixin.channel.bean.vip.VipScoreResponse;
import me.chanjar.weixin.common.error.WxErrorException;
/**
* 视频号小店 会员功能接口
*
* @author <a href="https://github.com/asushiye">aushiye</a>
* @link <a href="https://developers.weixin.qq.com/doc/channels/API/vip/access_guide.html">会员功能接口文档</a>
*/
public interface WxChannelVipService {
/** 拉取用户详情 */
// String VIP_USER_INFO_URL = "https://api.weixin.qq.com/channels/ec/vip/user/info/get";
// /** 拉取用户列表 */
// String VIP_USER_LIST_URL = "https://api.weixin.qq.com/channels/ec/vip/user/list/get";
//
// /** 获取用户积分 */
// String VIP_SCORE_URL = "https://api.weixin.qq.com/channels/ec/vip/user/score/get";
// /** 增加用户积分 */
// String SCORE_INCREASE_URL = "https://api.weixin.qq.com/channels/ec/vip/user/score/increase";
// /** 减少用户积分 */
// String SCORE_DECREASE_URL = "https://api.weixin.qq.com/channels/ec/vip/user/score/decrease";
//
// /** 更新用户等级 */
// String GRADE_UPDATE_URL = "https://api.weixin.qq.com/channels/ec/vip/user/grade/update";
/**
* 获取用户详情
*
* @param openId the open id
* @param needPhoneNumber the need phone number
* @return the vip info
* @throws WxErrorException the wx error exception
*/
VipInfoResponse getVipInfo(String openId, Boolean needPhoneNumber) throws WxErrorException;
/**
* 获取用户积分
*
* @param needPhoneNumber the need phone number
* @param pageNum the page num
* @param PageSize the page size
* @return the vip list
* @throws WxErrorException the wx error exception
*/
VipListResponse getVipList(Boolean needPhoneNumber, Integer pageNum, Integer PageSize) throws WxErrorException;
/**
* 获取用户积分
*
* @param openId the open id
* @return the vip score
* @throws WxErrorException the wx error exception
*/
VipScoreResponse getVipScore(String openId) throws WxErrorException;
/**
* 增加用户积分
*
* @param openId the open id
* @param score the score
* @param remark the remark
* @param requestId the request id
* @return the wx channel base response
* @throws WxErrorException the wx error exception
*/
WxChannelBaseResponse increaseVipScore(String openId, String score, String remark, String requestId) throws WxErrorException;
/**
* 减少用户积分
*
* @param openId the open id
* @param score the score
* @param remark the remark
* @param requestId the request id
* @return the wx channel base response
* @throws WxErrorException the wx error exception
*/
WxChannelBaseResponse decreaseVipScore(String openId, String score, String remark, String requestId) throws WxErrorException;
/**
* 更新用户等级
*
* @param openId the open id
* @param score the score
* @return the wx channel base response
* @throws WxErrorException the wx error exception
*/
WxChannelBaseResponse updateVipGrade(String openId, Integer score) throws WxErrorException;
}

View File

@ -1,34 +1,5 @@
package me.chanjar.weixin.channel.api.impl; package me.chanjar.weixin.channel.api.impl;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.ACCOUNT_NOTIFY;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.AFTER_SALE_UPDATE;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.BRAND;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.COMPLAINT_NOTIFY;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.CREATE_COUPON;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.DELETE_COUPON;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.EXPIRE_COUPON;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.INVALID_COUPON;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.ORDER_CANCEL;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.ORDER_CONFIRM;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.ORDER_DELIVER;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.ORDER_EXT_INFO_UPDATE;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.ORDER_NEW;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.ORDER_PAY;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.ORDER_SETTLE;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.ORDER_STATUS_UPDATE;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.PRODUCT_CATEGORY_AUDIT;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.PRODUCT_SPU_AUDIT;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.PRODUCT_SPU_STATUS_UPDATE;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.PRODUCT_SPU_UPDATE;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.QRCODE_STATUS;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.RECEIVE_COUPON;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.SUPPLIER_ITEM_UPDATE;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.UPDATE_COUPON_INFO;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.USER_COUPON_EXPIRE;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.USER_COUPON_UNUSE;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.USER_COUPON_USE;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.WITHDRAW_NOTIFY;
import java.util.Map; import java.util.Map;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.channel.api.BaseWxChannelMessageService; import me.chanjar.weixin.channel.api.BaseWxChannelMessageService;
@ -53,6 +24,8 @@ import me.chanjar.weixin.channel.bean.message.product.BrandMessage;
import me.chanjar.weixin.channel.bean.message.product.CategoryAuditMessage; import me.chanjar.weixin.channel.bean.message.product.CategoryAuditMessage;
import me.chanjar.weixin.channel.bean.message.product.SpuAuditMessage; import me.chanjar.weixin.channel.bean.message.product.SpuAuditMessage;
import me.chanjar.weixin.channel.bean.message.supplier.SupplierItemMessage; import me.chanjar.weixin.channel.bean.message.supplier.SupplierItemMessage;
import me.chanjar.weixin.channel.bean.message.vip.ExchangeInfoMessage;
import me.chanjar.weixin.channel.bean.message.vip.UserInfoMessage;
import me.chanjar.weixin.channel.message.WxChannelMessage; import me.chanjar.weixin.channel.message.WxChannelMessage;
import me.chanjar.weixin.channel.message.WxChannelMessageRouter; import me.chanjar.weixin.channel.message.WxChannelMessageRouter;
import me.chanjar.weixin.channel.message.WxChannelMessageRouterRule; import me.chanjar.weixin.channel.message.WxChannelMessageRouterRule;
@ -60,11 +33,13 @@ import me.chanjar.weixin.channel.message.rule.HandlerConsumer;
import me.chanjar.weixin.channel.util.JsonUtils; import me.chanjar.weixin.channel.util.JsonUtils;
import me.chanjar.weixin.common.session.WxSessionManager; import me.chanjar.weixin.common.session.WxSessionManager;
import static me.chanjar.weixin.channel.constant.MessageEventConstants.*;
/** /**
* @author <a href="https://github.com/lixize">Zeyes</a> * @author <a href="https://github.com/lixize">Zeyes</a>
*/ */
@Slf4j @Slf4j
public class BaseWxChannelMessageServiceImpl implements BaseWxChannelMessageService { public abstract class BaseWxChannelMessageServiceImpl implements BaseWxChannelMessageService {
/** 消息路由器 */ /** 消息路由器 */
protected WxChannelMessageRouter router; protected WxChannelMessageRouter router;
@ -134,6 +109,18 @@ public class BaseWxChannelMessageServiceImpl implements BaseWxChannelMessageServ
this.addRule(QrNotifyMessage.class, QRCODE_STATUS, this::qrNotify); this.addRule(QrNotifyMessage.class, QRCODE_STATUS, this::qrNotify);
/* 团长 */ /* 团长 */
this.addRule(SupplierItemMessage.class, SUPPLIER_ITEM_UPDATE, this::supplierItemUpdate); this.addRule(SupplierItemMessage.class, SUPPLIER_ITEM_UPDATE, this::supplierItemUpdate);
/* 用户加入会员 */
this.addRule(UserInfoMessage.class, USER_VIP_JOIN, false, this::vipJoin);
/* 用户注销会员 */
this.addRule(UserInfoMessage.class, USER_VIP_CLOSE,false, this::vipClose);
/* 用户等级信息更新 */
this.addRule(UserInfoMessage.class, USER_VIP_GRADE_INFO_UPDATE, false, this::vipGradeUpdate);
/* 用户积分更新 */
this.addRule(UserInfoMessage.class, USER_VIP_SCORE_UPDATE, false, this::vipScoreUpdate);
/* 用户积分兑换 */
this.addRule(ExchangeInfoMessage.class, USER_VIP_SCORE_EXCHANGE, false, this::vipScoreExchange);
} }
/** /**
@ -144,10 +131,10 @@ public class BaseWxChannelMessageServiceImpl implements BaseWxChannelMessageServ
* @param consumer 处理器 * @param consumer 处理器
* @param <T> 消息类型 * @param <T> 消息类型
*/ */
protected <T extends WxChannelMessage> void addRule(Class<T> clazz, String event, protected <T extends WxChannelMessage> void addRule(Class<T> clazz, String event, Boolean async,
HandlerConsumer<T, String, String, Map<String, Object>, WxSessionManager> consumer) { HandlerConsumer<T, String, String, Map<String, Object>, WxSessionManager> consumer) {
WxChannelMessageRouterRule<T> rule = new WxChannelMessageRouterRule<>(); WxChannelMessageRouterRule<T> rule = new WxChannelMessageRouterRule<>();
rule.setMessageClass(clazz).setEvent(event).setAsync(true); rule.setMessageClass(clazz).setEvent(event).setAsync(async);
rule.getHandlers().add((message, content, appId, context, sessionManager) -> { rule.getHandlers().add((message, content, appId, context, sessionManager) -> {
consumer.accept(message, content, appId, context, sessionManager); consumer.accept(message, content, appId, context, sessionManager);
return "success"; return "success";
@ -155,6 +142,11 @@ public class BaseWxChannelMessageServiceImpl implements BaseWxChannelMessageServ
this.addRule(rule); this.addRule(rule);
} }
protected <T extends WxChannelMessage> void addRule(Class<T> clazz, String event,
HandlerConsumer<T, String, String, Map<String, Object>, WxSessionManager> consumer) {
this.addRule(clazz, event, true, consumer);
}
@Override @Override
public void addRule(WxChannelMessageRouterRule<? extends WxChannelMessage> rule) { public void addRule(WxChannelMessageRouterRule<? extends WxChannelMessage> rule) {
router.getRules().add(rule); router.getRules().add(rule);
@ -340,4 +332,25 @@ public class BaseWxChannelMessageServiceImpl implements BaseWxChannelMessageServ
log.info("默认消息处理:{}", JsonUtils.encode(message)); log.info("默认消息处理:{}", JsonUtils.encode(message));
return null; return null;
} }
@Override
public abstract void vipJoin(UserInfoMessage message, String content, String appId,
Map<String, Object> context, WxSessionManager sessionManager);
@Override
public abstract void vipClose(UserInfoMessage message, String content, String appId,
Map<String, Object> context, WxSessionManager sessionManager);
@Override
public abstract void vipGradeUpdate(UserInfoMessage message, String content, String appId,
Map<String, Object> context, WxSessionManager sessionManager);
@Override
public abstract void vipScoreUpdate(UserInfoMessage message, String content, String appId,
Map<String, Object> context, WxSessionManager sessionManager);
@Override
public abstract void vipScoreExchange(ExchangeInfoMessage message, String content, String appId,
Map<String, Object> context, WxSessionManager sessionManager);
} }

View File

@ -3,26 +3,7 @@ package me.chanjar.weixin.channel.api.impl;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.channel.api.WxAssistantService; import me.chanjar.weixin.channel.api.*;
import me.chanjar.weixin.channel.api.WxChannelAddressService;
import me.chanjar.weixin.channel.api.WxChannelAfterSaleService;
import me.chanjar.weixin.channel.api.WxChannelBasicService;
import me.chanjar.weixin.channel.api.WxChannelBrandService;
import me.chanjar.weixin.channel.api.WxChannelCategoryService;
import me.chanjar.weixin.channel.api.WxChannelCouponService;
import me.chanjar.weixin.channel.api.WxChannelFreightTemplateService;
import me.chanjar.weixin.channel.api.WxChannelFundService;
import me.chanjar.weixin.channel.api.WxChannelOrderService;
import me.chanjar.weixin.channel.api.WxChannelProductService;
import me.chanjar.weixin.channel.api.WxChannelService;
import me.chanjar.weixin.channel.api.WxChannelSharerService;
import me.chanjar.weixin.channel.api.WxChannelWarehouseService;
import me.chanjar.weixin.channel.api.WxFinderLiveService;
import me.chanjar.weixin.channel.api.WxLeadComponentService;
import me.chanjar.weixin.channel.api.WxLeagueProductService;
import me.chanjar.weixin.channel.api.WxLeaguePromoterService;
import me.chanjar.weixin.channel.api.WxLeagueSupplierService;
import me.chanjar.weixin.channel.api.WxLeagueWindowService;
import me.chanjar.weixin.channel.config.WxChannelConfig; import me.chanjar.weixin.channel.config.WxChannelConfig;
import me.chanjar.weixin.channel.util.JsonUtils; import me.chanjar.weixin.channel.util.JsonUtils;
import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.api.WxConsts;
@ -73,6 +54,7 @@ public abstract class BaseWxChannelServiceImpl<H, P> implements WxChannelService
private WxLeadComponentService leadComponentService = null; private WxLeadComponentService leadComponentService = null;
private WxFinderLiveService finderLiveService = null; private WxFinderLiveService finderLiveService = null;
private WxAssistantService assistantService = null; private WxAssistantService assistantService = null;
private WxChannelVipService vipService = new WxChannelVipServiceImpl(this);
protected WxChannelConfig config; protected WxChannelConfig config;
private int retrySleepMillis = 1000; private int retrySleepMillis = 1000;
@ -115,7 +97,7 @@ public abstract class BaseWxChannelServiceImpl<H, P> implements WxChannelService
} while (!locked); } while (!locked);
String response = doGetAccessTokenRequest(); String response = doGetAccessTokenRequest();
return extractAccessToken(response); return extractAccessToken(response);
} catch (IOException | InterruptedException e) { } catch (WxErrorException | InterruptedException e) {
throw new WxRuntimeException(e); throw new WxRuntimeException(e);
} finally { } finally {
if (locked) { if (locked) {
@ -130,7 +112,7 @@ public abstract class BaseWxChannelServiceImpl<H, P> implements WxChannelService
* @return . * @return .
* @throws IOException . * @throws IOException .
*/ */
protected abstract String doGetAccessTokenRequest() throws IOException; protected abstract String doGetAccessTokenRequest() throws WxErrorException;
@Override @Override
public String get(String url, String queryParam) throws WxErrorException { public String get(String url, String queryParam) throws WxErrorException {
@ -425,4 +407,8 @@ public abstract class BaseWxChannelServiceImpl<H, P> implements WxChannelService
return assistantService; return assistantService;
} }
@Override
public WxChannelVipService getVipService() {
return vipService;
}
} }

View File

@ -1,19 +1,27 @@
package me.chanjar.weixin.channel.api.impl; package me.chanjar.weixin.channel.api.impl;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.GET_ACCESS_TOKEN_URL; import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.GET_ACCESS_TOKEN_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.GET_STABLE_ACCESS_TOKEN_URL;
import java.io.IOException; import java.io.IOException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.channel.api.WxChannelVipService;
import me.chanjar.weixin.channel.bean.token.StableToken;
import me.chanjar.weixin.channel.config.WxChannelConfig; import me.chanjar.weixin.channel.config.WxChannelConfig;
import me.chanjar.weixin.channel.util.JsonUtils;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.http.HttpType; 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.ApacheHttpClientBuilder;
import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder; import me.chanjar.weixin.common.util.http.apache.DefaultApacheHttpClientBuilder;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpHost; import org.apache.http.HttpHost;
import org.apache.http.client.HttpClient; import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig; import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicResponseHandler; import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
@ -25,9 +33,18 @@ public class WxChannelServiceHttpClientImpl extends BaseWxChannelServiceImpl<Htt
private CloseableHttpClient httpClient; private CloseableHttpClient httpClient;
private HttpHost httpProxy; private HttpHost httpProxy;
private Boolean stabled = false;
private Boolean forceRefresh = false;
public WxChannelServiceHttpClientImpl() { /**
* 设置调用接口参数.
*
* @param stabled false 表示调用AccessToken接口 true调用稳定版接口
* @param forceRefresh stabled=true使用 true表示强制刷新模式
*/
public WxChannelServiceHttpClientImpl(Boolean stabled, Boolean forceRefresh) {
this.stabled = stabled;
this.forceRefresh = forceRefresh;
} }
@Override @Override
@ -66,7 +83,26 @@ public class WxChannelServiceHttpClientImpl extends BaseWxChannelServiceImpl<Htt
} }
@Override @Override
protected String doGetAccessTokenRequest() throws IOException { protected String doGetAccessTokenRequest() throws WxErrorException {
try {
if (stabled) {
return internalGetStableAccessToken(this.forceRefresh);
} else{
return internalGetAccessToken();
}
} catch(Exception e) {
throw new WxErrorException(e);
}
}
/**
* 获取access_token
*
* @return 返回json的字符串
* @throws IOException the io exception
*/
protected String internalGetAccessToken() throws IOException {
WxChannelConfig config = this.getConfig(); WxChannelConfig config = this.getConfig();
String url = StringUtils.isNotEmpty(config.getAccessTokenUrl()) ? config.getAccessTokenUrl() : String url = StringUtils.isNotEmpty(config.getAccessTokenUrl()) ? config.getAccessTokenUrl() :
StringUtils.isNotEmpty(config.getApiHostUrl()) ? StringUtils.isNotEmpty(config.getApiHostUrl()) ?
@ -97,4 +133,36 @@ public class WxChannelServiceHttpClientImpl extends BaseWxChannelServiceImpl<Htt
} }
} }
/**
* 获取稳定版接口调用凭据
*
* @param forceRefresh false 为普通模式 true为强制刷新模式
* @return 返回json的字符串
* @throws IOException the io exception
*/
protected String internalGetStableAccessToken(Boolean forceRefresh) throws IOException {
WxChannelConfig config = this.getConfig();
String url = GET_STABLE_ACCESS_TOKEN_URL;
HttpPost httpPost = new HttpPost(url);
if (this.getRequestHttpProxy() != null) {
RequestConfig requestConfig = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
httpPost.setConfig(requestConfig);
}
StableToken stableToken = new StableToken("client_credential", config.getAppid(),config.getSecret(), forceRefresh);
StringEntity entity = new StringEntity(JsonUtils.encode(stableToken), Consts.UTF_8);
entity.setContentType("application/json; charset=utf-8");
httpPost.setEntity(entity);
try (CloseableHttpResponse response = getRequestHttpClient().execute(httpPost)) {
return new BasicResponseHandler().handleResponse(response);
} finally {
httpPost.releaseConnection();
}
}
} }

View File

@ -10,4 +10,20 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
public class WxChannelServiceImpl extends WxChannelServiceHttpClientImpl { public class WxChannelServiceImpl extends WxChannelServiceHttpClientImpl {
/**
* 设置普通模式access_token接口参数
*/
public WxChannelServiceImpl() {
super(false, false);
}
/**
* 设置获取access_token接口参数.
*
* @param stabled false 表示调用普通模式AccessToken接口 true调用稳定模式接口
* @param forceRefresh stabled=true使用 true表示强制刷新模式
*/
public WxChannelServiceImpl(Boolean stabled, Boolean forceRefresh) {
super(stabled, forceRefresh);
}
} }

View File

@ -0,0 +1,154 @@
package me.chanjar.weixin.channel.api.impl;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.channel.bean.token.StableToken;
import me.chanjar.weixin.channel.util.JsonUtils;
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.util.http.HttpType;
import me.chanjar.weixin.common.util.http.okhttp.DefaultOkHttpClientBuilder;
import me.chanjar.weixin.common.util.http.okhttp.OkHttpProxyInfo;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.entity.StringEntity;
import java.io.IOException;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.GET_ACCESS_TOKEN_URL;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.GET_STABLE_ACCESS_TOKEN_URL;
/**
* @author : zhenyun.su
* @since : 2024/2/27
*/
@Slf4j
public class WxChannelServiceOkHttpImpl extends BaseWxChannelServiceImpl<OkHttpClient, OkHttpProxyInfo> {
private OkHttpClient httpClient;
private OkHttpProxyInfo httpProxy;
private Boolean stabled = false;
private Boolean forceRefresh = false;
protected final Object globalAccessTokenRefreshLock = new Object();
/**
* 设置调用接口参数.
*
* @param stabled false 表示调用AccessToken接口 true调用稳定版接口
* @param forceRefresh stabled=true使用 true表示强制刷新模式
*/
public WxChannelServiceOkHttpImpl(Boolean stabled, Boolean forceRefresh) {
this.stabled = stabled;
this.forceRefresh = forceRefresh;
}
@Override
public void initHttp() {
log.debug("WxChannelServiceOkHttpImpl initHttp");
if (this.config.getHttpProxyHost() != null && this.config.getHttpProxyPort() > 0) {
this.httpProxy = OkHttpProxyInfo.httpProxy(this.config.getHttpProxyHost(), this.config.getHttpProxyPort(), this.config.getHttpProxyUsername(), this.config.getHttpProxyPassword());
okhttp3.OkHttpClient.Builder clientBuilder = new okhttp3.OkHttpClient.Builder();
clientBuilder.proxy(this.getRequestHttpProxy().getProxy());
clientBuilder.authenticator(new Authenticator() {
@Override
public Request authenticate(Route route, Response response) throws IOException {
String credential = Credentials.basic(WxChannelServiceOkHttpImpl.this.httpProxy.getProxyUsername(), WxChannelServiceOkHttpImpl.this.httpProxy.getProxyPassword());
return response.request().newBuilder().header("Authorization", credential).build();
}
});
this.httpClient = clientBuilder.build();
} else {
this.httpClient = DefaultOkHttpClientBuilder.get().build();
}
}
@Override
public OkHttpClient getRequestHttpClient() {
return this.httpClient;
}
@Override
public OkHttpProxyInfo getRequestHttpProxy() {
return this.httpProxy;
}
@Override
public HttpType getRequestType() {
return HttpType.OK_HTTP;
}
@Override
protected String doGetAccessTokenRequest() throws WxErrorException {
if (stabled) {
return internalGetStableAccessToken(this.forceRefresh);
} else{
return internalGetAccessToken(forceRefresh);
}
}
public String internalGetStableAccessToken(boolean forceRefresh) throws WxErrorException {
if (!this.config.isAccessTokenExpired() && !forceRefresh) {
return this.config.getAccessToken();
} else {
synchronized(this.globalAccessTokenRefreshLock) {
OkHttpClient client = this.getRequestHttpClient();
String url = String.format(GET_STABLE_ACCESS_TOKEN_URL, config.getAppid(), config.getSecret());
StableToken stableToken = new StableToken("client_credential", config.getAppid(),config.getSecret(), forceRefresh);
RequestBody body = RequestBody.Companion.create(JsonUtils.encode(stableToken), MediaType.parse("application/json; charset=utf-8"));
Request request = (new Request.Builder()).url(url).post(body).build();
String resultContent = null;
try {
Response response = client.newCall(request).execute();
resultContent = response.body().string();
} catch (IOException var9) {
log.error(var9.getMessage(), var9);
}
WxError error = WxError.fromJson(resultContent, WxType.CP);
if (error.getErrorCode() != 0) {
throw new WxErrorException(error);
}
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
this.config.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
}
return this.config.getAccessToken();
}
}
public String internalGetAccessToken(boolean forceRefresh) throws WxErrorException {
if (!this.config.isAccessTokenExpired() && !forceRefresh) {
return this.config.getAccessToken();
} else {
synchronized(this.globalAccessTokenRefreshLock) {
OkHttpClient client = this.getRequestHttpClient();
String url = String.format(GET_ACCESS_TOKEN_URL, config.getAppid(), config.getSecret());
Request request = (new Request.Builder()).url(url).get().build();
String resultContent = null;
try {
Response response = client.newCall(request).execute();
resultContent = response.body().string();
} catch (IOException var9) {
log.error(var9.getMessage(), var9);
}
WxError error = WxError.fromJson(resultContent, WxType.CP);
if (error.getErrorCode() != 0) {
throw new WxErrorException(error);
}
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
this.config.updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
}
return this.config.getAccessToken();
}
}
}

View File

@ -0,0 +1,68 @@
package me.chanjar.weixin.channel.api.impl;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.channel.api.WxChannelVipService;
import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
import me.chanjar.weixin.channel.bean.vip.*;
import me.chanjar.weixin.channel.util.ResponseUtils;
import me.chanjar.weixin.common.error.WxErrorException;
import static me.chanjar.weixin.channel.constant.WxChannelApiUrlConstants.Vip.*;
/**
* 视频号小店 会员功能接口
*
* @author <a href="https://github.com/asushiye">aushiye</a>
* @link <a href="https://developers.weixin.qq.com/doc/channels/API/vip/access_guide.html">会员功能接口文档</a>
*/
@Slf4j
public class WxChannelVipServiceImpl implements WxChannelVipService {
private BaseWxChannelServiceImpl vipHttpService;
public WxChannelVipServiceImpl(BaseWxChannelServiceImpl vipHttpService) {
this.vipHttpService = vipHttpService;
}
@Override
public VipInfoResponse getVipInfo(String openId, Boolean needPhoneNumber) throws WxErrorException {
VipInfoParam param = new VipInfoParam(openId, needPhoneNumber);
String respJson = vipHttpService.post(VIP_USER_INFO_URL, param);
return ResponseUtils.decode(respJson, VipInfoResponse.class);
}
@Override
public VipListResponse getVipList(Boolean needPhoneNumber, Integer pageNum, Integer PageSize) throws WxErrorException {
VipListParam param = new VipListParam(needPhoneNumber, pageNum, PageSize);
String respJson = vipHttpService.post(VIP_USER_LIST_URL, param);
return ResponseUtils.decode(respJson, VipListResponse.class);
}
@Override
public VipScoreResponse getVipScore(String openId) throws WxErrorException {
VipParam param = new VipParam(openId);
String respJson = vipHttpService.post(VIP_SCORE_URL, param);
return ResponseUtils.decode(respJson, VipScoreResponse.class);
}
@Override
public WxChannelBaseResponse increaseVipScore(String openId, String score, String remark, String requestId) throws WxErrorException {
VipScoreParam param = new VipScoreParam(openId, score, remark, requestId);
String respJson = vipHttpService.post(SCORE_INCREASE_URL, param);
return ResponseUtils.decode(respJson, WxChannelBaseResponse.class);
}
@Override
public WxChannelBaseResponse decreaseVipScore(String openId, String score, String remark, String requestId) throws WxErrorException {
VipScoreParam param = new VipScoreParam(openId, score, remark, requestId);
String respJson = vipHttpService.post(SCORE_DECREASE_URL, param);
return ResponseUtils.decode(respJson, WxChannelBaseResponse.class);
}
@Override
public WxChannelBaseResponse updateVipGrade(String openId, Integer score) throws WxErrorException {
VipGradeParam param = new VipGradeParam(openId, score);
String respJson = vipHttpService.post(GRADE_UPDATE_URL, param);
return ResponseUtils.decode(respJson, WxChannelBaseResponse.class);
}
}

View File

@ -0,0 +1,27 @@
package me.chanjar.weixin.channel.bean.message.vip;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 优惠券信息
*
* @author <a href="https://github.com/asushiye">asushiye</a>
*/
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
public class CouponInfo implements Serializable {
private static final long serialVersionUID = -3659710836197413932L;
/** 兑换的优惠券ID**/
@JsonProperty("related_coupon_id")
@JacksonXmlProperty(localName = "related_coupon_id")
private Long relatedCouponId;
}

View File

@ -0,0 +1,42 @@
package me.chanjar.weixin.channel.bean.message.vip;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 积分兑换
*
* @author <a href="https://github.com/asushiye">asushiye</a>
*/
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
public class ExchangeInfo implements Serializable {
private static final long serialVersionUID = -5692646625631036694L;
/** 入会时间 **/
@JsonProperty("pay_score")
@JacksonXmlProperty(localName = "pay_score")
private Long pay_score;
/** 兑换类型 1.优惠券 2商品 **/
@JsonProperty("score_item_type")
@JacksonXmlProperty(localName = "score_item_type")
private Long score_item_type;
/** 优惠券信息 **/
@JsonProperty("coupon_info")
@JacksonXmlProperty(localName = "coupon_info")
private CouponInfo couponInfo;
/** 商品信息 **/
@JsonProperty("product_info")
@JacksonXmlProperty(localName = "product_info")
private ProductInfo productInfo;
}

View File

@ -0,0 +1,28 @@
package me.chanjar.weixin.channel.bean.message.vip;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import me.chanjar.weixin.channel.message.WxChannelMessage;
/**
* 积分兑换消息
*
* @author <a href="https://github.com/asushiye">asushiye</a>
*/
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@JacksonXmlRootElement(localName = "xml")
public class ExchangeInfoMessage extends WxChannelMessage {
private static final long serialVersionUID = 2926346100146724110L;
/** 积分兑换信息 */
@JsonProperty("exchange_info")
@JacksonXmlProperty(localName = "exchange_info")
private ExchangeInfo exchangeInfo;
}

View File

@ -0,0 +1,27 @@
package me.chanjar.weixin.channel.bean.message.vip;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 商品信息
*
* @author <a href="https://github.com/asushiye">asushiye</a>
*/
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
public class ProductInfo implements Serializable {
private static final long serialVersionUID = -3037180342360944232L;
/** 兑换的商品ID**/
@JsonProperty("related_product_id")
@JacksonXmlProperty(localName = "related_product_id")
private Long relatedProductId;
}

View File

@ -0,0 +1,59 @@
package me.chanjar.weixin.channel.bean.message.vip;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 用户信息
*
* @author <a href="https://github.com/asushiye">asushiye</a>
*/
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
@NoArgsConstructor
public class UserInfo implements Serializable {
private static final long serialVersionUID = 1239486732464880985L;
/** 入会时间 **/
@JsonProperty("join_time")
@JacksonXmlProperty(localName = "join_time")
private Long joinTime;
/** 注销时间 **/
@JsonProperty("close_time")
@JacksonXmlProperty(localName = "close_time")
private Long closeTime;
/** 手机号 **/
@JsonProperty("phone_number")
@JacksonXmlProperty(localName = "phone_number")
private String phoneNumber;
/** 等级 **/
@JsonProperty("grade")
@JacksonXmlProperty(localName = "grade")
private Integer grade;
/** 当前等级经验值 **/
@JsonProperty("experience_value")
@JacksonXmlProperty(localName = "experience_value")
private Long experienceValue;
/** 当前积分 **/
@JsonProperty("score")
@JacksonXmlProperty(localName = "score")
private Long score;
/** 本次改动积分,负数减少,正数新增 **/
@JsonProperty("delta_score")
@JacksonXmlProperty(localName = "delta_score")
private Long deltaScore;
}

View File

@ -0,0 +1,28 @@
package me.chanjar.weixin.channel.bean.message.vip;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import me.chanjar.weixin.channel.message.WxChannelMessage;
/**
* 用户信息消息
*
* @author <a href="https://github.com/asushiye">asushiye</a>
*/
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@JacksonXmlRootElement(localName = "xml")
public class UserInfoMessage extends WxChannelMessage {
private static final long serialVersionUID = 6926608689621530622L;
/** 用户信息 */
@JsonProperty("user_info")
@JacksonXmlProperty(localName = "order_info")
private UserInfo userInfo;
}

View File

@ -0,0 +1,34 @@
package me.chanjar.weixin.channel.bean.token;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 稳定版access_token,请求参数
*
* @author <a href="https://github.com/asushiye">asushiye</a>
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class StableToken implements Serializable {
private static final long serialVersionUID = 6849364823232834171L;
@JsonProperty("grant_type")
private String grantType;
@JsonProperty("appid")
private String appId;
@JsonProperty("secret")
private String secret;
@JsonProperty("force_refresh")
private Boolean forceRefresh;
}

View File

@ -0,0 +1,23 @@
package me.chanjar.weixin.channel.bean.vip;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 视频号小店-会员功能 - 订单详情
*
* @author <a href="https://github.com/asushiye">asushiye</a>
*
*/
@Data
@NoArgsConstructor
public class ScoreInfo implements Serializable {
private static final long serialVersionUID = -3290653233070826576L;
/** 积分 */
@JsonProperty("score")
protected String score;
}

View File

@ -0,0 +1,27 @@
package me.chanjar.weixin.channel.bean.vip;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 视频号小店-会员功能 - 用户等级信息
*
* @author <a href="https://github.com/asushiye">asushiye</a>
*
*/
@Data
@NoArgsConstructor
public class UserGradeInfo implements Serializable {
private static final long serialVersionUID = -8040963202754069865L;
/** 等级编号 */
@JsonProperty("grade")
protected Integer grade;
/** 用户经验值 */
@JsonProperty("experience_value")
protected String experienceValue;
}

View File

@ -0,0 +1,23 @@
package me.chanjar.weixin.channel.bean.vip;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 视频号小店-会员功能 - 订单详情
*
* @author <a href="https://github.com/asushiye">asushiye</a>
*
*/
@Data
@NoArgsConstructor
public class UserInfo implements Serializable {
private static final long serialVersionUID = 8523354700203385190L;
/** 手机号 */
@JsonProperty("phone_number")
protected String phoneNumber;
}

View File

@ -0,0 +1,31 @@
package me.chanjar.weixin.channel.bean.vip;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @author : zhenyun.su
* @since : 2023/10/8
*/
@Data
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
@AllArgsConstructor
public class VipGradeParam implements Serializable {
private static final long serialVersionUID = 8672089025435220864L;
@JsonProperty("openid")
private String openId;
@JsonProperty("grade")
private Integer grade;
}

View File

@ -0,0 +1,47 @@
package me.chanjar.weixin.channel.bean.vip;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* 视频号小店-会员功能 - 订单详情
*
* @author <a href="https://github.com/asushiye">asushiye</a>
*
* "info": {
* "openid": "OPENID",
* "unionid": "UNIONID",
* "user_info": {
* "phone_number": "123456789"
* },
* "user_grade_info": {
* "grade": 1,
* "experience_value": "100"
* }
* }
*/
@Data
@NoArgsConstructor
public class VipInfo implements Serializable {
private static final long serialVersionUID = -215590991862774701L;
/** 视频号openid */
@JsonProperty("openid")
protected String openId;
/** 视频号union_id */
@JsonProperty("union_id")
protected String unionId;
/** 用户信息 */
@JsonProperty("user_info")
protected UserInfo userInfo;
/** 用户等级信息 */
@JsonProperty("user_grade_info")
protected UserGradeInfo userGradeInfo;
}

View File

@ -0,0 +1,27 @@
package me.chanjar.weixin.channel.bean.vip;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @author : zhenyun.su
* @since : 2023/10/8
*/
@Data
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
@AllArgsConstructor
public class VipInfoParam implements Serializable {
private static final long serialVersionUID = -4196252299609288196L;
@JsonProperty("openid")
private String openId;
@JsonProperty("need_phone_number")
private Boolean needPhoneNumber;
}

View File

@ -0,0 +1,20 @@
package me.chanjar.weixin.channel.bean.vip;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
/**
* @author : zhenyun.su
* @since : 2023/10/8
*/
@Data
@NoArgsConstructor
public class VipInfoResponse extends WxChannelBaseResponse {
private static final long serialVersionUID = -2439510304690862381L;
@JsonProperty("info")
private VipInfo vipInfo;
}

View File

@ -0,0 +1,32 @@
package me.chanjar.weixin.channel.bean.vip;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @author : zhenyun.su
* @since : 2023/10/8
*/
@Data
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
@AllArgsConstructor
public class VipListParam implements Serializable {
private static final long serialVersionUID = 7503422865410116202L;
@JsonProperty("need_phone_number")
private Boolean needPhoneNumber;
@JsonProperty("page_num")
private Integer pageNum;
@JsonProperty("page_size")
private Integer pageSize;
}

View File

@ -0,0 +1,25 @@
package me.chanjar.weixin.channel.bean.vip;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
import java.util.List;
/**
* @author : zhenyun.su
* @since : 2023/10/8
*/
@Data
@NoArgsConstructor
public class VipListResponse extends WxChannelBaseResponse {
private static final long serialVersionUID = -8127372979925053579L;
@JsonProperty("list")
private List<VipInfo> vipInfos;
@JsonProperty("total_num")
private Long totalNum;
}

View File

@ -0,0 +1,24 @@
package me.chanjar.weixin.channel.bean.vip;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @author : zhenyun.su
* @since : 2023/10/8
*/
@Data
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
@AllArgsConstructor
public class VipParam implements Serializable {
private static final long serialVersionUID = -7924178026258012317L;
@JsonProperty("openid")
private String openId;
}

View File

@ -0,0 +1,39 @@
package me.chanjar.weixin.channel.bean.vip;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @author : zhenyun.su
* @since : 2023/10/8
* {
* "openid": "OPENID",
* "score": "100",
* "remark": "备注",
* "request_id": "REQUEST_ID"
* }
*/
@Data
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
@AllArgsConstructor
public class VipScoreParam implements Serializable {
private static final long serialVersionUID = -4122983978977407168L;
@JsonProperty("openid")
private String openId;
@JsonProperty("score")
private String score;
@JsonProperty("remark")
private String remark;
@JsonProperty("request_id")
private String requestId;
}

View File

@ -0,0 +1,20 @@
package me.chanjar.weixin.channel.bean.vip;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import me.chanjar.weixin.channel.bean.base.WxChannelBaseResponse;
/**
* @author : zhenyun.su
* @since : 2023/10/8
*/
@Data
@NoArgsConstructor
public class VipScoreResponse extends WxChannelBaseResponse {
private static final long serialVersionUID = -7252972818862693546L;
@JsonProperty("info")
private ScoreInfo scoreInfo;
}

View File

@ -67,4 +67,16 @@ public interface MessageEventConstants {
// 其他 // 其他
/** 进入会话事件 */ /** 进入会话事件 */
String USER_ENTER_TEMP_SESSION = "user_enter_tempsession"; String USER_ENTER_TEMP_SESSION = "user_enter_tempsession";
// 会员相关
/** 用户加入会员 */
String USER_VIP_JOIN = "channels_ec_vip_join";
/** 用户注销会员 */
String USER_VIP_CLOSE = "channels_ec_vip_close";
/** 用户等级更新 */
String USER_VIP_GRADE_INFO_UPDATE = "channels_ec_vip_grade_info_update";
/** 用户积分更新 */
String USER_VIP_SCORE_UPDATE = "channels_ec_vip_score_update";
/** 用户积分兑换 */
String USER_VIP_SCORE_EXCHANGE = "channels_ec_vip_score_exchange";
} }

View File

@ -16,6 +16,11 @@ public class WxChannelApiUrlConstants {
public static final String GET_ACCESS_TOKEN_URL = public static final String GET_ACCESS_TOKEN_URL =
"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"; "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
/**
* 获取Stable access_token.
*/
public static final String GET_STABLE_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/stable_token";
/** 基础接口 */ /** 基础接口 */
public interface Basics { public interface Basics {
@ -400,4 +405,23 @@ public class WxChannelApiUrlConstants {
*/ */
String GET_FINDER_LIVE_LEADS_DATA = "https://api.weixin.qq.com/channels/finderlive/get_finder_live_leads_data"; String GET_FINDER_LIVE_LEADS_DATA = "https://api.weixin.qq.com/channels/finderlive/get_finder_live_leads_data";
} }
/** 会员功能接口 */
public interface Vip {
/** 拉取用户详情 */
String VIP_USER_INFO_URL = "https://api.weixin.qq.com/channels/ec/vip/user/info/get";
/** 拉取用户列表 */
String VIP_USER_LIST_URL = "https://api.weixin.qq.com/channels/ec/vip/user/list/get";
/** 获取用户积分 */
String VIP_SCORE_URL = "https://api.weixin.qq.com/channels/ec/vip/user/score/get";
/** 增加用户积分 */
String SCORE_INCREASE_URL = "https://api.weixin.qq.com/channels/ec/vip/user/score/increase";
/** 减少用户积分 */
String SCORE_DECREASE_URL = "https://api.weixin.qq.com/channels/ec/vip/user/score/decrease";
/** 更新用户等级 */
String GRADE_UPDATE_URL = "https://api.weixin.qq.com/channels/ec/vip/user/grade/update";
}
} }

View File

@ -11,7 +11,7 @@ import okhttp3.Response;
import java.io.IOException; import java.io.IOException;
/** /**
* . *
* *
* @author ecoolper * @author ecoolper
* created on 2017/5/4 * created on 2017/5/4