diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpLivingService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpLivingService.java new file mode 100644 index 000000000..4b417e90f --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpLivingService.java @@ -0,0 +1,125 @@ +package me.chanjar.weixin.cp.api; + +import lombok.NonNull; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.cp.bean.living.*; + +/** + * 企业微信直播接口. + * 官方文档:https://work.weixin.qq.com/api/doc/90000/90135/93633 + * + * @author Wang_Wong + * @date 2021-12-21 + */ +public interface WxCpLivingService { + + /** + * 获取微信观看直播凭证 + * 请求方式: POST(HTTPS) + * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/living/get_living_code?access_token=ACCESS_TOKEN + * + * @param openId 用户openid + * @param livingId 直播id + * @return living_code 微信观看直播凭证 + * @throws WxErrorException the wx error exception + */ + String getLivingCode(@NonNull String openId, @NonNull String livingId) throws WxErrorException; + + /** + * 获取直播详情 + * 请求方式:GET(HTTPS) + * 请求地址:https://qyapi.weixin.qq.com/cgi-bin/living/get_living_info?access_token=ACCESS_TOKEN&livingid=LIVINGID + * + * @param livingId 直播id + * @return 获取的直播详情 + * @throws WxErrorException the wx error exception + */ + WxCpLivingInfo getLivingInfo(@NonNull String livingId) throws WxErrorException; + + /** + * 获取直播观看明细 + * 通过该接口可以获取所有观看直播的人员统计 + * + * 请求方式:POST(HTTPS) + * 请求地址:https://qyapi.weixin.qq.com/cgi-bin/living/get_watch_stat?access_token=ACCESS_TOKEN + * + * @param livingId 直播id + * @param nextKey 上一次调用时返回的next_key,初次调用可以填”0” + * @return + * @throws WxErrorException + */ + WxCpWatchStat getWatchStat(@NonNull String livingId, Integer nextKey) throws WxErrorException; + + /** + * 获取成员直播ID列表 + * 通过此接口可以获取指定成员的所有直播ID + * + * 请求方式:POST(HTTPS) + * 请求地址:https://qyapi.weixin.qq.com/cgi-bin/living/get_user_all_livingid?access_token=ACCESS_TOKEN + * + * @param userId 企业成员的userid + * @param cursor 上一次调用时返回的next_cursor,第一次拉取可以不填 + * @param limit 每次拉取的数据量,默认值和最大值都为100 + * @return + * @throws WxErrorException + */ + WxCpLivingResult.LivingIdResult getUserAllLivingId(@NonNull String userId, String cursor, Integer limit) throws WxErrorException; + + /** + * 获取跳转小程序商城的直播观众信息 + * 通过此接口,开发者可获取跳转小程序商城的直播间(“推广产品”直播)观众id、邀请人id及对应直播间id,以打通卖货直播的“人货场”信息闭环。 + * + * 请求方式:POST(HTTPS) + * 请求地址:https://qyapi.weixin.qq.com/cgi-bin/living/get_living_share_info?access_token=ACCESS_TOKEN + * + * @param wwShareCode "推广产品"直播观众跳转小程序商城时会在小程序path中带上ww_share_code=xxxxx参数 + * @return + * @throws WxErrorException + */ + WxCpLivingShareInfo getLivingShareInfo(@NonNull String wwShareCode) throws WxErrorException; + + /** + * 创建预约直播 + * 请求方式: POST(HTTPS) + * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/living/create?access_token=ACCESS_TOKEN + * + * @param request 创建预约直播请求参数. + * @return + * @throws WxErrorException + */ + String livingCreate(WxCpLivingCreateRequest request) throws WxErrorException; + + /** + * 修改预约直播 + * 请求方式: POST(HTTPS) + * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/living/modify?access_token=ACCESS_TOKEN + * + * @param request 修改预约直播请求参数. + * @return + * @throws WxErrorException + */ + WxCpLivingResult livingModify(WxCpLivingModifyRequest request) throws WxErrorException; + + /** + * 取消预约直播 + * 请求方式: POST(HTTPS) + * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/living/cancel?access_token=ACCESS_TOKEN + * + * @param livingId 直播id,仅允许取消预约状态下的直播id + * @return + * @throws WxErrorException + */ + WxCpLivingResult livingCancel(@NonNull String livingId) throws WxErrorException; + + /** + * 删除直播回放 + * 请求方式: POST(HTTPS) + * 请求地址: https://qyapi.weixin.qq.com/cgi-bin/living/delete_replay_data?access_token=ACCESS_TOKEN + * + * @param livingId 直播id + * @return + * @throws WxErrorException + */ + WxCpLivingResult deleteReplayData(@NonNull String livingId) throws WxErrorException; + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java index 94cd21263..123697b8e 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpService.java @@ -392,6 +392,13 @@ public interface WxCpService extends WxService { */ WxCpOaService getOaService(); + /** + * 获取直播相关接口的服务类对象 + * + * @return the Living service + */ + WxCpLivingService getLivingService(); + /** * 获取日历相关接口的服务类对象 * diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java index 89221f1a1..210d54f54 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/BaseWxCpServiceImpl.java @@ -49,6 +49,7 @@ public abstract class BaseWxCpServiceImpl implements WxCpService, RequestH private WxCpTagService tagService = new WxCpTagServiceImpl(this); private WxCpAgentService agentService = new WxCpAgentServiceImpl(this); private WxCpOaService oaService = new WxCpOaServiceImpl(this); + private WxCpLivingService livingService = new WxCpLivingServiceImpl(this); private WxCpTaskCardService taskCardService = new WxCpTaskCardServiceImpl(this); private WxCpExternalContactService externalContactService = new WxCpExternalContactServiceImpl(this); private WxCpGroupRobotService groupRobotService = new WxCpGroupRobotServiceImpl(this); @@ -477,6 +478,11 @@ public abstract class BaseWxCpServiceImpl implements WxCpService, RequestH return oaService; } + @Override + public WxCpLivingService getLivingService() { + return livingService; + } + @Override public WxCpOaCalendarService getOaCalendarService() { return this.oaCalendarService; diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpLivingServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpLivingServiceImpl.java new file mode 100644 index 000000000..5fdf18cf8 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpLivingServiceImpl.java @@ -0,0 +1,118 @@ +package me.chanjar.weixin.cp.api.impl; + +import com.google.gson.JsonObject; +import com.google.gson.reflect.TypeToken; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.common.util.json.GsonHelper; +import me.chanjar.weixin.common.util.json.GsonParser; +import me.chanjar.weixin.cp.api.WxCpLivingService; +import me.chanjar.weixin.cp.api.WxCpService; +import me.chanjar.weixin.cp.bean.living.*; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Living.*; + +/** + * 企业微信直播接口实现类. + * + * @author Wang_Wong + * @date 2021-12-21 + */ +@Slf4j +@RequiredArgsConstructor +public class WxCpLivingServiceImpl implements WxCpLivingService { + private final WxCpService cpService; + + @Override + public String getLivingCode(String openId, String livingId) throws WxErrorException { + final String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(GET_LIVING_CODE); + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("openid", openId); + jsonObject.addProperty("livingid", livingId); + String responseContent = this.cpService.post(apiUrl, jsonObject.toString()); + return GsonHelper.getString(GsonParser.parse(responseContent), "living_code"); + } + + @Override + public WxCpLivingInfo getLivingInfo(String livingId) throws WxErrorException { + String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(GET_LIVING_INFO) + livingId; + String responseContent = this.cpService.get(apiUrl, null); + return WxCpGsonBuilder.create() + .fromJson(GsonParser.parse(responseContent).get("living_info"), + new TypeToken() { + }.getType() + ); + } + + @Override + public WxCpWatchStat getWatchStat(String livingId, Integer nextKey) throws WxErrorException { + String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(GET_WATCH_STAT); + JsonObject jsonObject = new JsonObject(); + if (nextKey != null) { + jsonObject.addProperty("next_key", String.valueOf(nextKey)); + } + jsonObject.addProperty("livingid", livingId); + String responseContent = this.cpService.post(apiUrl, jsonObject.toString()); + return WxCpWatchStat.fromJson(responseContent); + } + + @Override + public WxCpLivingResult.LivingIdResult getUserAllLivingId(String userId, String cursor, Integer limit) throws WxErrorException { + String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(GET_USER_ALL_LIVINGID); + JsonObject jsonObject = new JsonObject(); + if (cursor != null) { + jsonObject.addProperty("cursor", cursor); + } + if (limit != null) { + jsonObject.addProperty("limit", limit); + } + jsonObject.addProperty("userid", userId); + String responseContent = this.cpService.post(apiUrl, jsonObject.toString()); + return WxCpLivingResult.LivingIdResult.fromJson(responseContent); + } + + @Override + public WxCpLivingShareInfo getLivingShareInfo(String wwShareCode) throws WxErrorException { + String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(GET_LIVING_SHARE_INFO); + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("ww_share_code", wwShareCode); + String responseContent = this.cpService.post(apiUrl, jsonObject.toString()); + return WxCpLivingShareInfo.fromJson(responseContent); + } + + @Override + public String livingCreate(WxCpLivingCreateRequest request) throws WxErrorException { + String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(CREATE); + String responseContent = this.cpService.post(apiUrl, request.toJson()); + return GsonHelper.getString(GsonParser.parse(responseContent), "livingid"); + } + + @Override + public WxCpLivingResult livingModify(WxCpLivingModifyRequest request) throws WxErrorException { + String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(MODIFY); + String responseContent = this.cpService.post(apiUrl, request.toJson()); + return WxCpLivingResult.fromJson(responseContent); + } + + @Override + public WxCpLivingResult livingCancel(@NonNull String livingId) throws WxErrorException { + String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(CANCEL); + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("livingid", livingId); + String responseContent = this.cpService.post(apiUrl, jsonObject.toString()); + return WxCpLivingResult.fromJson(responseContent); + } + + @Override + public WxCpLivingResult deleteReplayData(@NonNull String livingId) throws WxErrorException { + String apiUrl = this.cpService.getWxCpConfigStorage().getApiUrl(DELETE_REPLAY_DATA); + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("livingid", livingId); + String responseContent = this.cpService.post(apiUrl, jsonObject.toString()); + return WxCpLivingResult.fromJson(responseContent); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/living/WxCpLivingCreateRequest.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/living/WxCpLivingCreateRequest.java new file mode 100644 index 000000000..6da6b81e5 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/living/WxCpLivingCreateRequest.java @@ -0,0 +1,86 @@ +package me.chanjar.weixin.cp.bean.living; + +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.io.Serializable; + +/** + * 创建预约直播请求. + * + * @author Wang_Wong + * @date 2021-12-23 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Accessors(chain = true) +public class WxCpLivingCreateRequest implements Serializable { + private static final long serialVersionUID = -4960239393895754138L; + + @SerializedName("anchor_userid") + private String anchorUserid; + + @SerializedName("theme") + private String theme; + + @SerializedName("living_start") + private Long livingStart; + + @SerializedName("living_duration") + private Long livingDuration; + + @SerializedName("remind_time") + private Long remindTime; + + @SerializedName("description") + private String description; + + @SerializedName("type") + private Integer type; + + @SerializedName("agentid") + private Integer agentId; + + @SerializedName("activity_cover_mediaid") + private String activityCoverMediaid; + + @SerializedName("activity_share_mediaid") + private String activityShareMediaid; + + @SerializedName("activity_detail") + private ActivityDetail activityDetail; + + public static class ActivityDetail implements Serializable { + + @SerializedName("image_list") + private String[] imageList; + + @SerializedName("description") + private String description; + + public static ActivityDetail fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, ActivityDetail.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + public static WxCpLivingCreateRequest fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpLivingCreateRequest.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/living/WxCpLivingInfo.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/living/WxCpLivingInfo.java new file mode 100644 index 000000000..b7010e57e --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/living/WxCpLivingInfo.java @@ -0,0 +1,80 @@ +package me.chanjar.weixin.cp.bean.living; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.io.Serializable; + +/** + * 直播详情信息. + * + * @author Wang_Wong + */ +@Data +public class WxCpLivingInfo implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("theme") + private String theme; + + @SerializedName("living_start") + private Long livingStart; + + @SerializedName("living_duration") + private Long livingDurationme; + + @SerializedName("status") + private Integer status; + + @SerializedName("reserve_living_duration") + private Long reserveLivingDuration; + + @SerializedName("reserve_start") + private Long reserveStart; + + @SerializedName("description") + private String description; + + @SerializedName("anchor_userid") + private String anchorUserid; + + @SerializedName("main_department") + private Long mainDepartment; + + @SerializedName("viewer_num") + private Integer viewerNum; + + @SerializedName("comment_num") + private Integer commentNum; + + @SerializedName("mic_num") + private Integer micNum; + + @SerializedName("open_replay") + private Integer openReplay; + + @SerializedName("replay_status") + private Integer replayStatus; + + @SerializedName("type") + private Integer type; + + @SerializedName("push_stream_url") + private String pushStreamUrl; + + @SerializedName("online_count") + private Integer onlineCount; + + @SerializedName("subscribe_count") + private Integer subscribeCount; + + public static WxCpLivingInfo fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpLivingInfo.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/living/WxCpLivingModifyRequest.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/living/WxCpLivingModifyRequest.java new file mode 100644 index 000000000..00d193820 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/living/WxCpLivingModifyRequest.java @@ -0,0 +1,56 @@ +package me.chanjar.weixin.cp.bean.living; + +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.io.Serializable; + +/** + * 创建预约直播请求. + * + * @author Wang_Wong + * @date 2021-12-23 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Accessors(chain = true) +public class WxCpLivingModifyRequest implements Serializable { + private static final long serialVersionUID = -4960239393895754138L; + + @SerializedName("livingid") + private String livingId; + + @SerializedName("theme") + private String theme; + + @SerializedName("living_start") + private Long livingStart; + + @SerializedName("living_duration") + private Long livingDuration; + + @SerializedName("remind_time") + private Long remindTime; + + @SerializedName("description") + private String description; + + @SerializedName("type") + private Integer type; + + public static WxCpLivingModifyRequest fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpLivingModifyRequest.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/living/WxCpLivingResult.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/living/WxCpLivingResult.java new file mode 100644 index 000000000..3312eec77 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/living/WxCpLivingResult.java @@ -0,0 +1,55 @@ +package me.chanjar.weixin.cp.bean.living; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.Getter; +import lombok.Setter; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.io.Serializable; + +/** + * 直播返回对象. + * + * @author Wang_Wong + */ +@Data +public class WxCpLivingResult implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + @SerializedName("errcode") + private Integer errcode; + + @SerializedName("errmsg") + private String errmsg; + + @Getter + @Setter + public static class LivingIdResult implements Serializable { + private static final long serialVersionUID = -5696099236344075582L; + + @SerializedName("next_cursor") + private String nextCursor; + + @SerializedName("livingid_list") + private String[] livingidList; + + public static LivingIdResult fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, LivingIdResult.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + + } + + public static WxCpLivingResult fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpLivingResult.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/living/WxCpLivingShareInfo.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/living/WxCpLivingShareInfo.java new file mode 100644 index 000000000..f0b96cc96 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/living/WxCpLivingShareInfo.java @@ -0,0 +1,40 @@ +package me.chanjar.weixin.cp.bean.living; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.io.Serializable; + +/** + * 跳转小程序商城的直播观众信息. + * + * @author Wang_Wong + */ +@Data +public class WxCpLivingShareInfo implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + private String livingid; + + @SerializedName("viewer_userid") + private String viewerUserid; + + @SerializedName("viewer_external_userid") + private String viewerExternalUserid; + + @SerializedName("invitor_userid") + private String invitorUserid; + + @SerializedName("invitor_external_userid") + private String invitorExternalUserid; + + public static WxCpLivingShareInfo fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpLivingShareInfo.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/living/WxCpWatchStat.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/living/WxCpWatchStat.java new file mode 100644 index 000000000..4a77bdd45 --- /dev/null +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/bean/living/WxCpWatchStat.java @@ -0,0 +1,90 @@ +package me.chanjar.weixin.cp.bean.living; + +import com.google.gson.annotations.SerializedName; +import lombok.Data; +import lombok.Getter; +import lombok.Setter; +import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; + +import java.io.Serializable; +import java.util.List; + +/** + * 直播观看明细. + * + * @author Wang_Wong + */ +@Data +public class WxCpWatchStat implements Serializable { + private static final long serialVersionUID = -5028321625140879571L; + + private Integer ending; + + @SerializedName("next_key") + private String nextKey; + + @SerializedName("stat_info") + private StatInfo statInfo; + + @Getter + @Setter + public static class StatInfo implements Serializable { + private static final long serialVersionUID = -5696099236344075582L; + + @SerializedName("users") + private List users; + + @SerializedName("external_users") + private List externalUsers; + + } + + @Getter + @Setter + public static class User implements Serializable { + private static final long serialVersionUID = -5696099236344075582L; + + private String userid; + + @SerializedName("watch_time") + private Long watchTime; + + @SerializedName("is_comment") + private Integer isComment; + + @SerializedName("is_mic") + private Integer isMic; + + } + + @Getter + @Setter + public static class ExternalUser implements Serializable { + private static final long serialVersionUID = -5696099236344075582L; + + private String name; + private Integer type; + + @SerializedName("external_userid") + private String externalUserid; + + @SerializedName("watch_time") + private Long watchTime; + + @SerializedName("is_comment") + private Integer isComment; + + @SerializedName("is_mic") + private Integer isMic; + + } + + public static WxCpWatchStat fromJson(String json) { + return WxCpGsonBuilder.create().fromJson(json, WxCpWatchStat.class); + } + + public String toJson() { + return WxCpGsonBuilder.create().toJson(this); + } + +} diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java index 710f7f6a7..c807b0f04 100644 --- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java +++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/constant/WxCpApiPathConsts.java @@ -1,8 +1,6 @@ package me.chanjar.weixin.cp.constant; -import lombok.experimental.UtilityClass; - /** *
  *  企业微信api地址常量类
@@ -118,6 +116,19 @@ public interface WxCpApiPathConsts {
     String COPY_TEMPLATE = "/cgi-bin/oa/approval/copytemplate";
   }
 
+  interface Living {
+    String GET_LIVING_CODE = "/cgi-bin/living/get_living_code";
+    String GET_LIVING_INFO = "/cgi-bin/living/get_living_info?livingid=";
+    String GET_WATCH_STAT = "/cgi-bin/living/get_watch_stat";
+    String GET_LIVING_SHARE_INFO = "/cgi-bin/living/get_living_share_info";
+    String GET_USER_ALL_LIVINGID = "/cgi-bin/living/get_user_all_livingid";
+
+    String CREATE = "/cgi-bin/living/create";
+    String MODIFY = "/cgi-bin/living/modify";
+    String CANCEL = "/cgi-bin/living/cancel";
+    String DELETE_REPLAY_DATA = "/cgi-bin/living/delete_replay_data";
+  }
+
   interface Tag {
     String TAG_CREATE = "/cgi-bin/tag/create";
     String TAG_UPDATE = "/cgi-bin/tag/update";
diff --git a/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpLivingTest.java b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpLivingTest.java
new file mode 100644
index 000000000..295f0497f
--- /dev/null
+++ b/weixin-java-cp/src/test/java/me/chanjar/weixin/cp/api/WxCpLivingTest.java
@@ -0,0 +1,99 @@
+package me.chanjar.weixin.cp.api;
+
+import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
+import me.chanjar.weixin.cp.bean.living.*;
+import me.chanjar.weixin.cp.config.WxCpConfigStorage;
+import me.chanjar.weixin.cp.demo.WxCpDemoInMemoryConfigStorage;
+import org.eclipse.jetty.util.ajax.JSON;
+import org.testng.annotations.Test;
+
+import java.io.InputStream;
+import java.util.Date;
+
+/**
+ * 企业微信直播测试类.
+ * 官方文档:https://open.work.weixin.qq.com/api/doc/90000/90135/93632
+ *
+ * @author Wang_Wong
+ */
+@Slf4j
+public class WxCpLivingTest {
+
+  private static WxCpConfigStorage wxCpConfigStorage;
+  private static WxCpService wxCpService;
+
+  @Test
+  public void test() throws WxErrorException {
+
+    InputStream inputStream = ClassLoader.getSystemResourceAsStream("test-config.xml");
+    WxCpDemoInMemoryConfigStorage config = WxCpDemoInMemoryConfigStorage.fromXml(inputStream);
+
+    wxCpConfigStorage = config;
+    wxCpService = new WxCpServiceImpl();
+    wxCpService.setWxCpConfigStorage(config);
+
+    String livingCode = wxCpService.getLivingService().getLivingCode("o50by5NezHciWnoexJsrI49ILNqI", "lvOQpTDwAAD2MYuOq9y_bmLNMJfbbdGw");
+    log.info(JSON.toString(livingCode));
+
+    // 直播详情
+    WxCpLivingInfo livingInfo = wxCpService.getLivingService().getLivingInfo("lvOQpTDwAAcP9wNOSSxTwpbni-TMPNSg");
+    log.info(livingInfo.toJson());
+
+    // 直播观看明细
+    WxCpWatchStat watchStat = wxCpService.getLivingService().getWatchStat("lvOQpTDwAAcP9wNOSSxTwpbni-TMPNSg", 0);
+    log.info(watchStat.toJson());
+
+    final String watchStateJson = "{\"errcode\":0,\"errmsg\":\"ok\",\"ending\":1,\"next_key\":\"NEXT_KEY\",\"stat_info\":{\"users\":[{\"userid\":\"userid\",\"watch_time\":30,\"is_comment\":1,\"is_mic\":1}],\"external_users\":[{\"external_userid\":\"external_userid1\",\"type\":1,\"name\":\"user name\",\"watch_time\":30,\"is_comment\":1,\"is_mic\":1},{\"external_userid\":\"external_userid2\",\"type\":2,\"name\":\"user_name\",\"watch_time\":30,\"is_comment\":1,\"is_mic\":1}]}}";
+
+    WxCpWatchStat wxCpWatchStat = WxCpWatchStat.fromJson(watchStateJson);
+    log.info(wxCpWatchStat.toJson());
+
+    // 直播观众信息
+    final String livingShareInfo = "{\"errcode\":0,\"errmsg\":\"ok\",\"livingid\":\"livingid\",\"viewer_userid\":\"viewer_userid\",\"viewer_external_userid\":\"viewer_external_userid\",\"invitor_userid\":\"invitor_userid\",\"invitor_external_userid\":\"invitor_external_userid\"}";
+
+    WxCpLivingShareInfo wxCpLivingShareInfo = WxCpLivingShareInfo.fromJson(livingShareInfo);
+    log.info(wxCpLivingShareInfo.toJson());
+
+    // 获取成员直播ID列表
+    WxCpLivingResult.LivingIdResult livingResult = wxCpService.getLivingService().getUserAllLivingId("ChenHu", null, null);
+    log.info(livingResult.toJson());
+
+    String livinglist = "{\"errcode\":0,\"errmsg\":\"ok\",\"next_cursor\":\"next_cursor\",\"livingid_list\":[\"livingid1\",\"livingid2\"]}";
+    WxCpLivingResult.LivingIdResult livingIdResult = WxCpLivingResult.LivingIdResult.fromJson(livinglist);
+    log.info(livingIdResult.toJson());
+
+
+    log.info("{}", new Date().getTime());
+    // 创建预约直播
+    String create = "{\"anchor_userid\":\"ChenHu\",\"theme\":\"theme\",\"living_start\":164037820420,\"living_duration\":3600,\"description\":\"test description\",\"type\":4,\"remind_time\":60,\"activity_cover_mediaid\":\"MEDIA_ID\",\"activity_share_mediaid\":\"MEDIA_ID\",\"activity_detail\":{\"description\":\"活动描述,非活动类型的直播不用传\",\"image_list\":[\"xxxx1\",\"xxxx1\"]}}";
+    WxCpLivingCreateRequest request = WxCpLivingCreateRequest.fromJson(create);
+    String livingId = wxCpService.getLivingService().livingCreate(request);
+    log.info("livingId为:{}", livingId);
+
+
+    String modify = "{\"livingid\": \""+ livingId +"\",\"theme\":\"theme\",\"living_start\":164047820420,\"living_duration\":3600,\"description\":\"描述:description\",\"type\":1,\"remind_time\":60}";
+    WxCpLivingModifyRequest modifyReq = WxCpLivingModifyRequest.fromJson(modify);
+    WxCpLivingResult result = wxCpService.getLivingService().livingModify(modifyReq);
+    log.info("result:{}", result.toJson());
+
+
+    // 取消预约直播
+//    WxCpLivingResult result2 = wxCpService.getLivingService().livingCancel("lvOQpTDwAA0KyLmWZhf_LIENzYIBVD2g");
+    WxCpLivingResult result2 = wxCpService.getLivingService().livingCancel(livingId);
+    log.info("取消预约直播为:{}", result2.toJson());
+
+
+    // 删除直播回放
+//    WxCpLivingResult response = wxCpService.getLivingService().deleteReplayData("lvOQpTDwAAVdCHyXMgSK63TKPfKDII7w");
+//    log.info(response.toJson());
+
+
+  }
+
+  public static void main(String[] args){
+    log.info("{}", new Date().getTime());
+  }
+
+}