mirror of
				https://gitee.com/binary/weixin-java-tools.git
				synced 2025-11-01 00:46:54 +08:00 
			
		
		
		
	🆕 #2356 【公众号】新增草稿箱和发布相关的接口
This commit is contained in:
		| @@ -0,0 +1,127 @@ | ||||
| package me.chanjar.weixin.mp.api; | ||||
|  | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | ||||
| import me.chanjar.weixin.mp.bean.draft.WxMpAddDraft; | ||||
| import me.chanjar.weixin.mp.bean.draft.WxMpDraftInfo; | ||||
| import me.chanjar.weixin.mp.bean.draft.WxMpDraftList; | ||||
| import me.chanjar.weixin.mp.bean.draft.WxMpUpdateDraft; | ||||
|  | ||||
| /** | ||||
|  * 微信 草稿箱 接口. | ||||
|  * | ||||
|  * @author dragon | ||||
|  * @date 2021-10-22 | ||||
|  */ | ||||
| public interface WxMpDraftService { | ||||
|  | ||||
|   /** | ||||
|    * 新建草稿 - 只有默认必填参数 | ||||
|    * <pre> | ||||
|    * 请求地址:POST https://api.weixin.qq.com/cgi-bin/draft/add?access_token=ACCESS_TOKEN | ||||
|    * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Draft_Box/Add_draft.html | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param title        标题 | ||||
|    * @param content      图文消息的具体内容,支持HTML标签,必须少于2万字符,小于1M,且此处会去除JS,涉及图片url必须来源 "上传图文消息内的图片获取URL"接口获取。外部图片url将被过滤。 | ||||
|    * @param thumbMediaId 图文消息的封面图片素材id(必须是永久MediaID) | ||||
|    * @throws WxErrorException . | ||||
|    */ | ||||
|   String addDraft(String title, String content, String thumbMediaId) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * 新建草稿 - 完整参数 | ||||
|    * <pre> | ||||
|    * 请求地址:POST https://api.weixin.qq.com/cgi-bin/draft/add?access_token=ACCESS_TOKEN | ||||
|    * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Draft_Box/Add_draft.html | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param addDraft 新建草稿信息 | ||||
|    * @throws WxErrorException . | ||||
|    */ | ||||
|   String addDraft(WxMpAddDraft addDraft) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * 修改草稿 - 完整参数 | ||||
|    * 正常情况下调用成功时,errcode将为0。错误时微信会返回错误码等信息,请根据错误码查询错误信息 | ||||
|    * <pre> | ||||
|    * 请求地址: POST https://api.weixin.qq.com/cgi-bin/draft/update?access_token=ACCESS_TOKEN | ||||
|    * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Draft_Box/Update_draft.html | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param updateDraftInfo 修改草稿信息 | ||||
|    * @throws WxErrorException . | ||||
|    */ | ||||
|   Boolean updateDraft(WxMpUpdateDraft updateDraftInfo) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * 获取草稿信息 | ||||
|    * | ||||
|    * <pre> | ||||
|    * 请求地址:POST https://api.weixin.qq.com/cgi-bin/draft/get?access_token=ACCESS_TOKEN | ||||
|    * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Draft_Box/Get_draft.html | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param mediaId 要获取的草稿的media_id | ||||
|    * @return 草稿信息 | ||||
|    * @throws WxErrorException . | ||||
|    */ | ||||
|   WxMpDraftInfo getDraft(String mediaId) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * 删除草稿 | ||||
|    * 正常情况下调用成功时,errcode将为0。错误时微信会返回错误码等信息,请根据错误码查询错误信息。 | ||||
|    * 多次删除同一篇草稿,也返回 0. | ||||
|    * <pre> | ||||
|    * 请求地址:POST https://api.weixin.qq.com/cgi-bin/draft/delete?access_token=ACCESS_TOKEN | ||||
|    * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Draft_Box/Delete_draft.html | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param mediaId 要删除的草稿的media_id | ||||
|    * @throws WxErrorException . | ||||
|    */ | ||||
|   Boolean delDraft(String mediaId) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * 获取草稿列表 | ||||
|    * | ||||
|    * <pre> | ||||
|    * 请求地址:POST https://api.weixin.qq.com/cgi-bin/draft/batchget?access_token=ACCESS_TOKEN | ||||
|    * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Draft_Box/Get_draft_list.html | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param offset    分页页数,从0开始 从全部素材的该偏移位置开始返回,0表示从第一个素材返回 | ||||
|    * @param count     每页数量 返回素材的数量,取值在1到20之间 | ||||
|    * @param noContent 1 表示不返回 content 字段,0 表示正常返回,默认为 0 | ||||
|    * @return 草稿信息列表 | ||||
|    * @throws WxErrorException . | ||||
|    */ | ||||
|   WxMpDraftList listDraft(int offset, int count, int noContent) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * 获取草稿列表 | ||||
|    * <pre> | ||||
|    * 请求地址:POST https://api.weixin.qq.com/cgi-bin/draft/batchget?access_token=ACCESS_TOKEN | ||||
|    * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Draft_Box/Get_draft_list.html | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param offset 分页页数,从0开始 从全部素材的该偏移位置开始返回,0表示从第一个素材返回 | ||||
|    * @param count  每页数量 返回素材的数量,取值在1到20之间 | ||||
|    * @return | ||||
|    * @throws WxErrorException | ||||
|    */ | ||||
|   WxMpDraftList listDraft(int offset, int count) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * 获取草稿数量 | ||||
|    * 开发者可以根据本接口来获取草稿的总数。此接口只统计数量,不返回草稿的具体内容。 | ||||
|    * <pre> | ||||
|    * 请求地址:POST https://api.weixin.qq.com/cgi-bin/draft/count?access_token=ACCESS_TOKEN | ||||
|    * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Draft_Box/Count_drafts.html | ||||
|    * </pre> | ||||
|    * | ||||
|    * @return 草稿的总数 | ||||
|    * @throws WxErrorException . | ||||
|    */ | ||||
|   Long countDraft() throws WxErrorException; | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,113 @@ | ||||
| package me.chanjar.weixin.mp.api; | ||||
|  | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | ||||
| import me.chanjar.weixin.mp.bean.freepublish.WxMpFreePublishInfo; | ||||
| import me.chanjar.weixin.mp.bean.freepublish.WxMpFreePublishList; | ||||
| import me.chanjar.weixin.mp.bean.freepublish.WxMpFreePublishStatus; | ||||
|  | ||||
| /** | ||||
|  * 微信 发布能力 接口. | ||||
|  * | ||||
|  * @author dragon | ||||
|  * @date 2021-10-23 | ||||
|  */ | ||||
| public interface WxMpFreePublishService { | ||||
|  | ||||
|   /** | ||||
|    * 发布接口 - 只有默认必填参数 | ||||
|    * 开发者需要先将图文素材以草稿的形式保存(见“草稿箱/新建草稿”,如需从已保存的草稿中选择,见“草稿箱/获取草稿列表”),选择要发布的草稿 media_id 进行发布 | ||||
|    * <pre> | ||||
|    * 请求地址:POST https://api.weixin.qq.com/cgi-bin/freepublish/submit?access_token=ACCESS_TOKEN | ||||
|    * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Publish/Publish.html | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param mediaId        要发布的草稿的media_id | ||||
|    * @throws WxErrorException . | ||||
|    */ | ||||
|   String submit(String mediaId) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * 发布状态轮询接口 | ||||
|    * 开发者可以尝试通过下面的发布状态轮询接口获知发布情况。 | ||||
|    * <pre> | ||||
|    * 请求地址:POST https://api.weixin.qq.com/cgi-bin/freepublish/get?access_token=ACCESS_TOKEN | ||||
|    * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Publish/Get_status.html | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param publishId 发布任务id | ||||
|    * @throws WxErrorException . | ||||
|    */ | ||||
|   WxMpFreePublishStatus getPushStatus(String publishId) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * 删除发布 | ||||
|    * 发布成功之后,随时可以通过该接口删除。此操作不可逆,请谨慎操作。 | ||||
|    * <pre> | ||||
|    * 请求地址:POST https://api.weixin.qq.com/cgi-bin/freepublish/delete?access_token=ACCESS_TOKEN | ||||
|    * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Publish/Delete_posts.html | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param articleId 成功发布时返回的 article_id | ||||
|    * @param index 要删除的文章在图文消息中的位置,第一篇编号为1,该字段不填或填0会删除全部文章 | ||||
|    * @throws WxErrorException . | ||||
|    */ | ||||
|   Boolean deletePush(String articleId, Integer index) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * 删除发布 - 此条发布的所有内容,不指定文章编号 | ||||
|    * 发布成功之后,随时可以通过该接口删除。此操作不可逆,请谨慎操作。 | ||||
|    * <pre> | ||||
|    * 请求地址:POST https://api.weixin.qq.com/cgi-bin/freepublish/delete?access_token=ACCESS_TOKEN | ||||
|    * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Publish/Delete_posts.html | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param articleId 成功发布时返回的 article_id | ||||
|    * @throws WxErrorException . | ||||
|    */ | ||||
|   Boolean deletePushAllArticle(String articleId) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * 通过 article_id 获取已发布文章 | ||||
|    * 开发者可以通过 article_id 获取已发布的图文信息。 | ||||
|    * <pre> | ||||
|    * 请求地址:POST https://api.weixin.qq.com/cgi-bin/freepublish/getarticle?access_token=ACCESS_TOKEN | ||||
|    * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Publish/Get_article_from_id.html | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param articleId 要获取的草稿的article_id | ||||
|    * @return 已发布文章信息 | ||||
|    * @throws WxErrorException . | ||||
|    */ | ||||
|   WxMpFreePublishInfo getArticleFromId(String articleId) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * 获取成功发布列表 - 支持选择是否返回:图文消息的具体内容 | ||||
|    * | ||||
|    * <pre> | ||||
|    * 请求地址:POST https://api.weixin.qq.com/cgi-bin/draft/batchget?access_token=ACCESS_TOKEN | ||||
|    * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Publish/Get_publication_records.html | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param offset    分页页数,从0开始 从全部素材的该偏移位置开始返回,0表示从第一个素材返回 | ||||
|    * @param count     每页数量 返回素材的数量,取值在1到20之间 | ||||
|    * @param noContent 1 表示不返回 content 字段,0 表示正常返回,默认为 0 | ||||
|    * @return 草稿信息列表 | ||||
|    * @throws WxErrorException . | ||||
|    */ | ||||
|   WxMpFreePublishList getPublicationRecords(int offset, int count, int noContent) throws WxErrorException; | ||||
|  | ||||
|   /** | ||||
|    * 获取成功发布列表 - 默认返回 图文消息的具体内容 | ||||
|    * <pre> | ||||
|    * 请求地址:POST https://api.weixin.qq.com/cgi-bin/draft/batchget?access_token=ACCESS_TOKEN | ||||
|    * 文档地址:https://developers.weixin.qq.com/doc/offiaccount/Publish/Get_publication_records.html | ||||
|    * </pre> | ||||
|    * | ||||
|    * @param offset 分页页数,从0开始 从全部素材的该偏移位置开始返回,0表示从第一个素材返回 | ||||
|    * @param count  每页数量 返回素材的数量,取值在1到20之间 | ||||
|    * @return | ||||
|    * @throws WxErrorException | ||||
|    */ | ||||
|   WxMpFreePublishList getPublicationRecords(int offset, int count) throws WxErrorException; | ||||
|  | ||||
| } | ||||
| @@ -567,6 +567,20 @@ public interface WxMpService extends WxService { | ||||
|    */ | ||||
|   WxMpReimburseInvoiceService getReimburseInvoiceService(); | ||||
|  | ||||
|   /** | ||||
|    * 返回草稿箱相关接口 | ||||
|    * | ||||
|    * @return WxMpDraftService | ||||
|    */ | ||||
|   WxMpDraftService getDraftService(); | ||||
|  | ||||
|   /** | ||||
|    * 返回发布能力接口 | ||||
|    * | ||||
|    * @return WxMpFreePublishService | ||||
|    */ | ||||
|   WxMpFreePublishService getFreePublishService(); | ||||
|  | ||||
|   /** | ||||
|    * . | ||||
|    * | ||||
| @@ -818,4 +832,18 @@ public interface WxMpService extends WxService { | ||||
|    * @param merchantInvoiceService the merchant invoice service | ||||
|    */ | ||||
|   void setMerchantInvoiceService(WxMpMerchantInvoiceService merchantInvoiceService); | ||||
|  | ||||
|   /** | ||||
|    * Sets draft service. | ||||
|    * | ||||
|    * @param draftService the draft service | ||||
|    */ | ||||
|   void setDraftService(WxMpDraftService draftService); | ||||
|  | ||||
|   /** | ||||
|    * Sets free publish service. | ||||
|    * | ||||
|    * @param freePublishService the free publish service | ||||
|    */ | ||||
|   void setFreePublishService(WxMpFreePublishService freePublishService); | ||||
| } | ||||
|   | ||||
| @@ -25,7 +25,11 @@ import me.chanjar.weixin.common.session.WxSessionManager; | ||||
| import me.chanjar.weixin.common.util.DataUtils; | ||||
| import me.chanjar.weixin.common.util.RandomUtils; | ||||
| import me.chanjar.weixin.common.util.crypto.SHA1; | ||||
| import me.chanjar.weixin.common.util.http.*; | ||||
| 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.http.URIUtil; | ||||
| import me.chanjar.weixin.common.util.json.GsonParser; | ||||
| import me.chanjar.weixin.common.util.json.WxGsonBuilder; | ||||
| import me.chanjar.weixin.mp.api.*; | ||||
| @@ -42,7 +46,16 @@ import java.io.IOException; | ||||
| import java.util.Map; | ||||
| import java.util.concurrent.locks.Lock; | ||||
|  | ||||
| import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.*; | ||||
| import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.CLEAR_QUOTA_URL; | ||||
| import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.FETCH_SHORTEN_URL; | ||||
| import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.GEN_SHORTEN_URL; | ||||
| import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.GET_CALLBACK_IP_URL; | ||||
| import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.GET_CURRENT_AUTOREPLY_INFO_URL; | ||||
| import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.GET_TICKET_URL; | ||||
| import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.NETCHECK_URL; | ||||
| import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.QRCONNECT_URL; | ||||
| import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.SEMANTIC_SEMPROXY_SEARCH_URL; | ||||
| import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Other.SHORTURL_API_URL; | ||||
|  | ||||
| /** | ||||
|  * 基础实现类. | ||||
| @@ -146,6 +159,14 @@ public abstract class BaseWxMpServiceImpl<H, P> implements WxMpService, RequestH | ||||
|   @Setter | ||||
|   private WxMpReimburseInvoiceService reimburseInvoiceService = new WxMpReimburseInvoiceServiceImpl(this); | ||||
|  | ||||
|   @Getter | ||||
|   @Setter | ||||
|   private WxMpDraftService draftService = new WxMpDraftServiceImpl(this); | ||||
|  | ||||
|   @Getter | ||||
|   @Setter | ||||
|   private WxMpFreePublishService freePublishService = new WxMpFreePublishServiceImpl(this); | ||||
|  | ||||
|   private Map<String, WxMpConfigStorage> configStorageMap; | ||||
|  | ||||
|   private int retrySleepMillis = 1000; | ||||
|   | ||||
| @@ -0,0 +1,84 @@ | ||||
| package me.chanjar.weixin.mp.api.impl; | ||||
|  | ||||
| import lombok.AllArgsConstructor; | ||||
| 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.mp.api.WxMpDraftService; | ||||
| import me.chanjar.weixin.mp.api.WxMpService; | ||||
| import me.chanjar.weixin.mp.bean.draft.WxMpAddDraft; | ||||
| import me.chanjar.weixin.mp.bean.draft.WxMpDraftArticles; | ||||
| import me.chanjar.weixin.mp.bean.draft.WxMpDraftInfo; | ||||
| import me.chanjar.weixin.mp.bean.draft.WxMpDraftList; | ||||
| import me.chanjar.weixin.mp.bean.draft.WxMpUpdateDraft; | ||||
| import me.chanjar.weixin.mp.enums.WxMpApiUrl; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 草稿箱能力-service实现类. | ||||
|  * | ||||
|  * @author dragon | ||||
|  * @date 2021-10-22 | ||||
|  */ | ||||
| @AllArgsConstructor | ||||
| public class WxMpDraftServiceImpl implements WxMpDraftService { | ||||
|  | ||||
|   private static final String MEDIA_ID = "media_id"; | ||||
|   private static final String ERRCODE_SUCCESS = "0"; | ||||
|   private static final String ERRCODE = "errcode"; | ||||
|   private final WxMpService mpService; | ||||
|  | ||||
|   @Override | ||||
|   public String addDraft(String title, String content, String thumbMediaId) throws WxErrorException { | ||||
|     List<WxMpDraftArticles> draftArticleList = new ArrayList<>(); | ||||
|     WxMpDraftArticles draftArticle = WxMpDraftArticles.builder() | ||||
|       .title(title).content(content).thumbMediaId(thumbMediaId).build(); | ||||
|     WxMpAddDraft addDraft = WxMpAddDraft.builder().articles(draftArticleList).build(); | ||||
|     draftArticleList.add(draftArticle); | ||||
|     return addDraft(addDraft); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public String addDraft(WxMpAddDraft addDraft) throws WxErrorException { | ||||
|     String json = this.mpService.post(WxMpApiUrl.Draft.ADD_DRAFT, addDraft); | ||||
|     return GsonParser.parse(json).get(MEDIA_ID).toString(); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public Boolean updateDraft(WxMpUpdateDraft updateDraftInfo) throws WxErrorException { | ||||
|     String json = this.mpService.post(WxMpApiUrl.Draft.UPDATE_DRAFT, updateDraftInfo); | ||||
|     return GsonParser.parse(json).get(ERRCODE).toString().equals(ERRCODE_SUCCESS); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public WxMpDraftInfo getDraft(String mediaId) throws WxErrorException { | ||||
|     return WxMpDraftInfo.fromJson(this.mpService.post(WxMpApiUrl.Draft.GET_DRAFT, | ||||
|       GsonHelper.buildJsonObject(MEDIA_ID, mediaId))); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public Boolean delDraft(String mediaId) throws WxErrorException { | ||||
|     String json = this.mpService.post(WxMpApiUrl.Draft.DEL_DRAFT, | ||||
|       GsonHelper.buildJsonObject(MEDIA_ID, mediaId)); | ||||
|     return GsonParser.parse(json).get(ERRCODE).toString().equals(ERRCODE_SUCCESS); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public WxMpDraftList listDraft(int offset, int count, int noContent) throws WxErrorException { | ||||
|     return WxMpDraftList.fromJson(this.mpService.post(WxMpApiUrl.Draft.LIST_DRAFT, | ||||
|       GsonHelper.buildJsonObject("offset", offset, "count", count, "no_content", noContent))); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public WxMpDraftList listDraft(int offset, int count) throws WxErrorException { | ||||
|     return listDraft(offset, count, 0); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public Long countDraft() throws WxErrorException { | ||||
|     String json = this.mpService.get(WxMpApiUrl.Draft.COUNT_DRAFT, null); | ||||
|     return Long.valueOf(GsonParser.parse(json).get("total_count").toString()); | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,72 @@ | ||||
| package me.chanjar.weixin.mp.api.impl; | ||||
|  | ||||
| import lombok.AllArgsConstructor; | ||||
| 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.mp.api.WxMpFreePublishService; | ||||
| import me.chanjar.weixin.mp.api.WxMpService; | ||||
| import me.chanjar.weixin.mp.bean.freepublish.WxMpFreePublishInfo; | ||||
| import me.chanjar.weixin.mp.bean.freepublish.WxMpFreePublishList; | ||||
| import me.chanjar.weixin.mp.bean.freepublish.WxMpFreePublishStatus; | ||||
| import me.chanjar.weixin.mp.enums.WxMpApiUrl; | ||||
|  | ||||
| /** | ||||
|  * 发布能力-service实现类. | ||||
|  * | ||||
|  * @author dragon | ||||
|  * @date 2021-10-23 | ||||
|  */ | ||||
| @AllArgsConstructor | ||||
| public class WxMpFreePublishServiceImpl implements WxMpFreePublishService { | ||||
|  | ||||
|   private static final String MEDIA_ID = "media_id"; | ||||
|   private static final String PUBLISH_ID = "publish_id"; | ||||
|   private static final String ARTICLE_ID = "article_id"; | ||||
|   private static final String ERRCODE_SUCCESS = "0"; | ||||
|   private static final String ERRCODE = "errcode"; | ||||
|   private final WxMpService mpService; | ||||
|  | ||||
|   @Override | ||||
|   public String submit(String mediaId) throws WxErrorException { | ||||
|     String json = this.mpService.post(WxMpApiUrl.FreePublish.SUBMIT, | ||||
|       GsonHelper.buildJsonObject(MEDIA_ID, mediaId)); | ||||
|     return GsonParser.parse(json).get(PUBLISH_ID).toString(); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public WxMpFreePublishStatus getPushStatus(String publishId) throws WxErrorException { | ||||
|     return WxMpFreePublishStatus.fromJson(this.mpService.post(WxMpApiUrl.FreePublish.GET_PUSH_STATUS, | ||||
|       GsonHelper.buildJsonObject(PUBLISH_ID, publishId))); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public Boolean deletePush(String articleId, Integer index) throws WxErrorException { | ||||
|     String json = this.mpService.post(WxMpApiUrl.FreePublish.DEL_PUSH, | ||||
|       GsonHelper.buildJsonObject(ARTICLE_ID, articleId, "index", index)); | ||||
|     return GsonParser.parse(json).get(ERRCODE).toString().equals(ERRCODE_SUCCESS); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public Boolean deletePushAllArticle(String articleId) throws WxErrorException { | ||||
|     // index字段不填或填0会删除全部文章 | ||||
|     return deletePush(articleId, 0); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public WxMpFreePublishInfo getArticleFromId(String articleId) throws WxErrorException { | ||||
|     return WxMpFreePublishInfo.fromJson(this.mpService.post(WxMpApiUrl.FreePublish.GET_ARTICLE, | ||||
|       GsonHelper.buildJsonObject(ARTICLE_ID, articleId))); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public WxMpFreePublishList getPublicationRecords(int offset, int count, int noContent) throws WxErrorException { | ||||
|     return WxMpFreePublishList.fromJson(this.mpService.post(WxMpApiUrl.FreePublish.BATCH_GET, | ||||
|       GsonHelper.buildJsonObject("offset", offset, "count", count, "no_content", noContent))); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public WxMpFreePublishList getPublicationRecords(int offset, int count) throws WxErrorException { | ||||
|     return getPublicationRecords(offset, count, 0); | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,44 @@ | ||||
| package me.chanjar.weixin.mp.bean.draft; | ||||
|  | ||||
| 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.common.bean.ToJson; | ||||
| import me.chanjar.weixin.common.util.json.WxGsonBuilder; | ||||
|  | ||||
| import java.io.Serializable; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 草稿箱能力-新建草稿. | ||||
|  * | ||||
|  * @author dragon | ||||
|  * @date 2021-10-22 | ||||
|  */ | ||||
| @Data | ||||
| @Builder | ||||
| @Accessors(chain = true) | ||||
| @NoArgsConstructor | ||||
| @AllArgsConstructor | ||||
| public class WxMpAddDraft implements ToJson, Serializable { | ||||
|   private static final long serialVersionUID = 2481699972367293721L; | ||||
|  | ||||
|   /** | ||||
|    * 图文素材列表 | ||||
|    */ | ||||
|   @SerializedName("articles") | ||||
|   private List<WxMpDraftArticles> articles; | ||||
|  | ||||
|   public static WxMpAddDraft fromJson(String json) { | ||||
|     return WxGsonBuilder.create().fromJson(json, WxMpAddDraft.class); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public String toJson() { | ||||
|     return WxGsonBuilder.create().toJson(this); | ||||
|   } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,81 @@ | ||||
| package me.chanjar.weixin.mp.bean.draft; | ||||
|  | ||||
| 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.common.bean.ToJson; | ||||
| import me.chanjar.weixin.common.util.json.WxGsonBuilder; | ||||
|  | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * 草稿箱能力-图文素材文章实体. | ||||
|  * | ||||
|  * @author dragon | ||||
|  * @date 2021-10-22 | ||||
|  */ | ||||
| @Data | ||||
| @Builder | ||||
| @Accessors(chain = true) | ||||
| @NoArgsConstructor | ||||
| @AllArgsConstructor | ||||
| public class WxMpDraftArticles implements ToJson, Serializable { | ||||
|   /** | ||||
|    * 标题 | ||||
|    */ | ||||
|   @SerializedName("title") | ||||
|   private String title; | ||||
|   /** | ||||
|    * 作者 | ||||
|    */ | ||||
|   @SerializedName("author") | ||||
|   private String author; | ||||
|   /** | ||||
|    * 图文消息的摘要,仅有单图文消息才有摘要,多图文此处为空。如果本字段为没有填写,则默认抓取正文前54个字。 | ||||
|    */ | ||||
|   @SerializedName("digest") | ||||
|   private String digest; | ||||
|   /** | ||||
|    * 图文消息的具体内容,支持HTML标签,必须少于2万字符,小于1M,且此处会去除JS,涉及图片url必须来源 "上传图文消息内的图片获取URL"接口获取。外部图片url将被过滤。 | ||||
|    */ | ||||
|   @SerializedName("content") | ||||
|   private String content; | ||||
|   /** | ||||
|    * 图文消息的原文地址,即点击“阅读原文”后的URL | ||||
|    */ | ||||
|   @SerializedName("content_source_url") | ||||
|   private String contentSourceUrl; | ||||
|   /** | ||||
|    * 图文消息的封面图片素材id(必须是永久MediaID) | ||||
|    */ | ||||
|   @SerializedName("thumb_media_id") | ||||
|   private String thumbMediaId; | ||||
|   /** | ||||
|    * 是否显示封面,0为false,即不显示,1为true,即显示(默认) | ||||
|    */ | ||||
|   @SerializedName("show_cover_pic") | ||||
|   private Integer showCoverPic; | ||||
|   /** | ||||
|    * 是否打开评论,0不打开(默认),1打开 | ||||
|    */ | ||||
|   @SerializedName("need_open_comment") | ||||
|   private Integer needOpenComment; | ||||
|   /** | ||||
|    * 是否粉丝才可评论,0所有人可评论(默认),1粉丝才可评论 | ||||
|    */ | ||||
|   @SerializedName("only_fans_can_comment") | ||||
|   private Integer onlyFansCanComment; | ||||
|  | ||||
|   public static WxMpDraftArticles fromJson(String json) { | ||||
|     return WxGsonBuilder.create().fromJson(json, WxMpDraftArticles.class); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public String toJson() { | ||||
|     return WxGsonBuilder.create().toJson(this); | ||||
|   } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,44 @@ | ||||
| package me.chanjar.weixin.mp.bean.draft; | ||||
|  | ||||
| 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.common.bean.ToJson; | ||||
| import me.chanjar.weixin.common.util.json.WxGsonBuilder; | ||||
|  | ||||
| import java.io.Serializable; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 草稿箱能力-获取草稿详情. | ||||
|  * | ||||
|  * @author dragon | ||||
|  * @date 2021-10-22 | ||||
|  */ | ||||
| @Data | ||||
| @Builder | ||||
| @Accessors(chain = true) | ||||
| @NoArgsConstructor | ||||
| @AllArgsConstructor | ||||
| public class WxMpDraftInfo implements ToJson, Serializable { | ||||
|   private static final long serialVersionUID = 6111694033486314392L; | ||||
|  | ||||
|   /** | ||||
|    * 文章列表 | ||||
|    */ | ||||
|   @SerializedName("news_item") | ||||
|   private List<WxMpDraftArticles> newsItem; | ||||
|  | ||||
|   public static WxMpDraftInfo fromJson(String json) { | ||||
|     return WxGsonBuilder.create().fromJson(json, WxMpDraftInfo.class); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public String toJson() { | ||||
|     return WxGsonBuilder.create().toJson(this); | ||||
|   } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,33 @@ | ||||
| package me.chanjar.weixin.mp.bean.draft; | ||||
|  | ||||
| import com.google.gson.annotations.SerializedName; | ||||
| import lombok.Data; | ||||
| import me.chanjar.weixin.common.util.json.WxGsonBuilder; | ||||
|  | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * 一条草稿 | ||||
|  * | ||||
|  * @author dragon | ||||
|  * @date 2021-10-22 | ||||
|  */ | ||||
| @Data | ||||
| public class WxMpDraftItem implements Serializable { | ||||
|   private static final long serialVersionUID = 214696458030935146L; | ||||
|  | ||||
|   /** | ||||
|    * 图文消息的id | ||||
|    */ | ||||
|   @SerializedName("media_id") | ||||
|   private String mediaId; | ||||
|   /** | ||||
|    * 图文消息的具体内容,支持HTML标签,必须少于2万字符,小于1M,且此处会去除JS。 | ||||
|    */ | ||||
|   @SerializedName("content") | ||||
|   private WxMpDraftInfo content; | ||||
|  | ||||
|   public static WxMpDraftItem fromJson(String json) { | ||||
|     return WxGsonBuilder.create().fromJson(json, WxMpDraftItem.class); | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,41 @@ | ||||
| package me.chanjar.weixin.mp.bean.draft; | ||||
|  | ||||
| import com.google.gson.annotations.SerializedName; | ||||
| import lombok.Data; | ||||
| import me.chanjar.weixin.common.util.json.WxGsonBuilder; | ||||
|  | ||||
| import java.io.Serializable; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 草稿箱能力-获取草稿列表. | ||||
|  * | ||||
|  * @author dragon | ||||
|  * @date 2021-10-22 | ||||
|  */ | ||||
| @Data | ||||
| public class WxMpDraftList implements Serializable { | ||||
|   private static final long serialVersionUID = 7216822694952035295L; | ||||
|  | ||||
|   /** | ||||
|    * 草稿素材的总数 | ||||
|    */ | ||||
|   @SerializedName("total_count") | ||||
|   private Integer totalCount; | ||||
|  | ||||
|   /** | ||||
|    * 本次调用获取的素材的数量 | ||||
|    */ | ||||
|   @SerializedName("item_count") | ||||
|   private Integer itemCount; | ||||
|  | ||||
|   /** | ||||
|    * 所有草稿列表 | ||||
|    */ | ||||
|   @SerializedName("item") | ||||
|   private List<WxMpDraftItem> items; | ||||
|  | ||||
|   public static WxMpDraftList fromJson(String json) { | ||||
|     return WxGsonBuilder.create().fromJson(json, WxMpDraftList.class); | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,55 @@ | ||||
| package me.chanjar.weixin.mp.bean.draft; | ||||
|  | ||||
| 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.common.bean.ToJson; | ||||
| import me.chanjar.weixin.common.util.json.WxGsonBuilder; | ||||
|  | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * 草稿箱能力-修改草稿. | ||||
|  * | ||||
|  * @author dragon | ||||
|  * @date 2021-10-22 | ||||
|  */ | ||||
| @Data | ||||
| @Builder | ||||
| @Accessors(chain = true) | ||||
| @NoArgsConstructor | ||||
| @AllArgsConstructor | ||||
| public class WxMpUpdateDraft implements ToJson, Serializable { | ||||
|  | ||||
|   private static final long serialVersionUID = -8564521168423899915L; | ||||
|   /** | ||||
|    * 要修改的图文消息的id | ||||
|    */ | ||||
|   @SerializedName("media_id") | ||||
|   private String mediaId; | ||||
|  | ||||
|   /** | ||||
|    * 要更新的文章在图文消息中的位置(多图文消息时,此字段才有意义),第一篇为0 | ||||
|    */ | ||||
|   @SerializedName("index") | ||||
|   private Integer index; | ||||
|  | ||||
|   /** | ||||
|    * 图文素材列表 | ||||
|    */ | ||||
|   @SerializedName("articles") | ||||
|   private WxMpDraftArticles articles; | ||||
|  | ||||
|   public static WxMpUpdateDraft fromJson(String json) { | ||||
|     return WxGsonBuilder.create().fromJson(json, WxMpUpdateDraft.class); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public String toJson() { | ||||
|     return WxGsonBuilder.create().toJson(this); | ||||
|   } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,85 @@ | ||||
| package me.chanjar.weixin.mp.bean.freepublish; | ||||
|  | ||||
| import com.google.gson.annotations.SerializedName; | ||||
| import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | ||||
| import me.chanjar.weixin.common.util.json.WxGsonBuilder; | ||||
|  | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * 一条发布的图文记录 | ||||
|  * | ||||
|  * @author dragon | ||||
|  * @date 2021-10-23 | ||||
|  */ | ||||
| @NoArgsConstructor | ||||
| @Data | ||||
| public class WxMpFreePublishArticles implements Serializable { | ||||
|   private static final long serialVersionUID = -6435229818150835883L; | ||||
|  | ||||
|   /** | ||||
|    * 标题 | ||||
|    */ | ||||
|   @SerializedName("title") | ||||
|   private String title; | ||||
|   /** | ||||
|    * 作者 | ||||
|    */ | ||||
|   @SerializedName("author") | ||||
|   private String author; | ||||
|   /** | ||||
|    * 图文消息的摘要,仅有单图文消息才有摘要,多图文此处为空。 | ||||
|    */ | ||||
|   @SerializedName("digest") | ||||
|   private String digest; | ||||
|   /** | ||||
|    * 图文消息的具体内容,支持HTML标签,必须少于2万字符,小于1M,且此处会去除JS | ||||
|    */ | ||||
|   @SerializedName("content") | ||||
|   private String content; | ||||
|   /** | ||||
|    * 图文消息的原文地址,即点击“阅读原文”后的URL | ||||
|    */ | ||||
|   @SerializedName("content_source_url") | ||||
|   private String contentSourceUrl; | ||||
|   /** | ||||
|    * 图文消息的封面图片素材id(一定是永久MediaID) | ||||
|    */ | ||||
|   @SerializedName("thumb_media_id") | ||||
|   private String thumbMediaId; | ||||
|   /** | ||||
|    * 是否显示封面,0为false,即不显示,1为true,即显示(默认) | ||||
|    */ | ||||
|   @SerializedName("show_cover_pic") | ||||
|   private Integer showCoverPic; | ||||
|   /** | ||||
|    * 是否打开评论,0不打开(默认),1打开 | ||||
|    */ | ||||
|   @SerializedName("need_open_comment") | ||||
|   private Integer needOpenComment; | ||||
|   /** | ||||
|    * 是否粉丝才可评论,0所有人可评论(默认),1粉丝才可评论 | ||||
|    */ | ||||
|   @SerializedName("only_fans_can_comment") | ||||
|   private Integer onlyFansCanComment; | ||||
|  | ||||
|   /* | ||||
|    * ===== 上面的参数,就是草稿箱的内容的字段,为了后续扩展,单独写一份==== | ||||
|    */ | ||||
|  | ||||
|   /** | ||||
|    * 草稿的临时链接 | ||||
|    */ | ||||
|   @SerializedName("url") | ||||
|   private String url; | ||||
|   /** | ||||
|    * 该图文是否被删除 | ||||
|    */ | ||||
|   @SerializedName("is_deleted") | ||||
|   private Boolean isDeleted; | ||||
|  | ||||
|   public static WxMpFreePublishArticles fromJson(String json) { | ||||
|     return WxGsonBuilder.create().fromJson(json, WxMpFreePublishArticles.class); | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,44 @@ | ||||
| package me.chanjar.weixin.mp.bean.freepublish; | ||||
|  | ||||
| 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.common.bean.ToJson; | ||||
| import me.chanjar.weixin.common.util.json.WxGsonBuilder; | ||||
|  | ||||
| import java.io.Serializable; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 发布能力-通过 article_id 获取已发布文章. | ||||
|  * | ||||
|  * @author dragon | ||||
|  * @date 2021-10-23 | ||||
|  */ | ||||
| @Data | ||||
| @Builder | ||||
| @Accessors(chain = true) | ||||
| @NoArgsConstructor | ||||
| @AllArgsConstructor | ||||
| public class WxMpFreePublishInfo implements ToJson, Serializable { | ||||
|   private static final long serialVersionUID = 3331288672996730705L; | ||||
|  | ||||
|   /** | ||||
|    * 文章列表 | ||||
|    */ | ||||
|   @SerializedName("news_item") | ||||
|   private List<WxMpFreePublishArticles> newsItem; | ||||
|  | ||||
|   public static WxMpFreePublishInfo fromJson(String json) { | ||||
|     return WxGsonBuilder.create().fromJson(json, WxMpFreePublishInfo.class); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public String toJson() { | ||||
|     return WxGsonBuilder.create().toJson(this); | ||||
|   } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,35 @@ | ||||
| package me.chanjar.weixin.mp.bean.freepublish; | ||||
|  | ||||
| import com.google.gson.annotations.SerializedName; | ||||
| import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | ||||
| import me.chanjar.weixin.common.util.json.WxGsonBuilder; | ||||
|  | ||||
| import java.io.Serializable; | ||||
|  | ||||
| /** | ||||
|  * 发布列表的一条记录 | ||||
|  * | ||||
|  * @author dragon | ||||
|  * @date 2021-10-23 | ||||
|  */ | ||||
| @NoArgsConstructor | ||||
| @Data | ||||
| public class WxMpFreePublishItem implements Serializable { | ||||
|   private static final long serialVersionUID = -6435229818150835883L; | ||||
|  | ||||
|   /** | ||||
|    * 成功发布的图文消息id | ||||
|    */ | ||||
|   @SerializedName("article_id") | ||||
|   private String articleId; | ||||
|   /** | ||||
|    * 图文消息的具体内容,支持HTML标签,必须少于2万字符,小于1M,且此处会去除JS。 | ||||
|    */ | ||||
|   @SerializedName("content") | ||||
|   private WxMpFreePublishInfo content; | ||||
|  | ||||
|   public static WxMpFreePublishItem fromJson(String json) { | ||||
|     return WxGsonBuilder.create().fromJson(json, WxMpFreePublishItem.class); | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,41 @@ | ||||
| package me.chanjar.weixin.mp.bean.freepublish; | ||||
|  | ||||
| import com.google.gson.annotations.SerializedName; | ||||
| import lombok.Data; | ||||
| import me.chanjar.weixin.common.util.json.WxGsonBuilder; | ||||
|  | ||||
| import java.io.Serializable; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 发布能力-获取成功发布列表. | ||||
|  * | ||||
|  * @author dragon | ||||
|  * @date 2021-10-22 | ||||
|  */ | ||||
| @Data | ||||
| public class WxMpFreePublishList implements Serializable { | ||||
|   private static final long serialVersionUID = 764054773431665250L; | ||||
|  | ||||
|   /** | ||||
|    * 成功发布素材的总数 | ||||
|    */ | ||||
|   @SerializedName("total_count") | ||||
|   private Integer totalCount; | ||||
|  | ||||
|   /** | ||||
|    * 本次调用获取的素材的数量 | ||||
|    */ | ||||
|   @SerializedName("item_count") | ||||
|   private Integer itemCount; | ||||
|  | ||||
|   /** | ||||
|    * 所有成功发布列表 | ||||
|    */ | ||||
|   @SerializedName("item") | ||||
|   private List<WxMpFreePublishItem> items; | ||||
|  | ||||
|   public static WxMpFreePublishList fromJson(String json) { | ||||
|     return WxGsonBuilder.create().fromJson(json, WxMpFreePublishList.class); | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,56 @@ | ||||
| package me.chanjar.weixin.mp.bean.freepublish; | ||||
|  | ||||
| import lombok.AllArgsConstructor; | ||||
| import lombok.Builder; | ||||
| import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | ||||
| import lombok.experimental.Accessors; | ||||
| import me.chanjar.weixin.common.bean.ToJson; | ||||
| import me.chanjar.weixin.common.util.json.WxGsonBuilder; | ||||
|  | ||||
| import java.io.Serializable; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 发布能力-发布状态轮询接口,通过publishId返回 article_id(删除发布时需要用到). | ||||
|  * | ||||
|  * @author dragon | ||||
|  * @date 2021-10-23 | ||||
|  */ | ||||
| @Data | ||||
| @Builder | ||||
| @Accessors(chain = true) | ||||
| @NoArgsConstructor | ||||
| @AllArgsConstructor | ||||
| public class WxMpFreePublishStatus implements ToJson, Serializable { | ||||
|  | ||||
|   private static final long serialVersionUID = -7526369389476785732L; | ||||
|   private String publish_id; | ||||
|   private Integer publish_status; | ||||
|   private String article_id; | ||||
|   private ArticleDetail article_detail; | ||||
|   private List<Integer> fail_idx; | ||||
|  | ||||
|   public static WxMpFreePublishStatus fromJson(String json) { | ||||
|     return WxGsonBuilder.create().fromJson(json, WxMpFreePublishStatus.class); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public String toJson() { | ||||
|     return WxGsonBuilder.create().toJson(this); | ||||
|   } | ||||
|  | ||||
|   @NoArgsConstructor | ||||
|   @Data | ||||
|   public static class ArticleDetail { | ||||
|     private Integer count; | ||||
|     private List<Item> item; | ||||
|  | ||||
|     @NoArgsConstructor | ||||
|     @Data | ||||
|     public static class Item { | ||||
|       private Integer idx; | ||||
|       private String article_url; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @@ -5,7 +5,10 @@ import lombok.Getter; | ||||
| import me.chanjar.weixin.mp.config.WxMpConfigStorage; | ||||
| import me.chanjar.weixin.mp.config.WxMpHostConfig; | ||||
|  | ||||
| import static me.chanjar.weixin.mp.config.WxMpHostConfig.*; | ||||
| import static me.chanjar.weixin.mp.config.WxMpHostConfig.API_DEFAULT_HOST_URL; | ||||
| import static me.chanjar.weixin.mp.config.WxMpHostConfig.MP_DEFAULT_HOST_URL; | ||||
| import static me.chanjar.weixin.mp.config.WxMpHostConfig.OPEN_DEFAULT_HOST_URL; | ||||
| import static me.chanjar.weixin.mp.config.WxMpHostConfig.buildUrl; | ||||
|  | ||||
| /** | ||||
|  * <pre> | ||||
| @@ -1374,6 +1377,90 @@ public interface WxMpApiUrl { | ||||
|     ; | ||||
|  | ||||
|  | ||||
|     private final String prefix; | ||||
|     private final String path; | ||||
|  | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 草稿箱 能力: | ||||
|    * 新建草稿 | ||||
|    * 获取草稿 | ||||
|    * 删除草稿 | ||||
|    * 修改草稿 | ||||
|    * 获取草稿总数 | ||||
|    * 获取草稿列表 | ||||
|    * MP端开关(仅内测期间使用)- 上线后废弃,没实现,可以自己去公众号后台开启草稿箱 | ||||
|    */ | ||||
|   @AllArgsConstructor | ||||
|   @Getter | ||||
|   enum Draft implements WxMpApiUrl { | ||||
|  | ||||
|     /** | ||||
|      * 新建草稿 | ||||
|      */ | ||||
|     ADD_DRAFT(API_DEFAULT_HOST_URL, "/cgi-bin/draft/add"), | ||||
|     /** | ||||
|      * 修改草稿 | ||||
|      */ | ||||
|     UPDATE_DRAFT(API_DEFAULT_HOST_URL, "/cgi-bin/draft/update"), | ||||
|     /** | ||||
|      * 获取草稿 | ||||
|      */ | ||||
|     GET_DRAFT(API_DEFAULT_HOST_URL, "/cgi-bin/draft/get"), | ||||
|     /** | ||||
|      * 删除草稿 | ||||
|      */ | ||||
|     DEL_DRAFT(API_DEFAULT_HOST_URL, "/cgi-bin/draft/delete"), | ||||
|     /** | ||||
|      * 获取草稿列表 | ||||
|      */ | ||||
|     LIST_DRAFT(API_DEFAULT_HOST_URL, "/cgi-bin/draft/batchget"), | ||||
|     /** | ||||
|      * 获取草稿总数 | ||||
|      */ | ||||
|     COUNT_DRAFT(API_DEFAULT_HOST_URL, "/cgi-bin/draft/count"); | ||||
|  | ||||
|     private final String prefix; | ||||
|     private final String path; | ||||
|  | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * 发布能力: | ||||
|    * 发布接口 | ||||
|    * 发布状态轮询接口 | ||||
|    * 事件推送发布结果 -- 是回调,没实现 | ||||
|    * 删除发布 | ||||
|    * 通过 article_id 获取已发布文章 | ||||
|    * 获取成功发布列表 | ||||
|    */ | ||||
|   @AllArgsConstructor | ||||
|   @Getter | ||||
|   enum FreePublish implements WxMpApiUrl { | ||||
|  | ||||
|     /** | ||||
|      * 发布接口 | ||||
|      */ | ||||
|     SUBMIT(API_DEFAULT_HOST_URL, "/cgi-bin/freepublish/submit"), | ||||
|     /** | ||||
|      * 通过 article_id 获取已发布文章 | ||||
|      */ | ||||
|     GET_ARTICLE(API_DEFAULT_HOST_URL, "/cgi-bin/freepublish/getarticle"), | ||||
|     /** | ||||
|      * 发布状态轮询接口 | ||||
|      */ | ||||
|     GET_PUSH_STATUS(API_DEFAULT_HOST_URL, "/cgi-bin/freepublish/get"), | ||||
|     /** | ||||
|      * 删除发布 | ||||
|      */ | ||||
|     DEL_PUSH(API_DEFAULT_HOST_URL, "/cgi-bin/freepublish/delete"), | ||||
|     /** | ||||
|      * 获取成功发布列表 | ||||
|      */ | ||||
|     BATCH_GET(API_DEFAULT_HOST_URL, "/cgi-bin/freepublish/batchget") | ||||
|     ; | ||||
|  | ||||
|     private final String prefix; | ||||
|     private final String path; | ||||
|  | ||||
|   | ||||
| @@ -0,0 +1,127 @@ | ||||
| package me.chanjar.weixin.mp.api.impl; | ||||
|  | ||||
| import com.google.inject.Inject; | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | ||||
| import me.chanjar.weixin.mp.api.WxMpService; | ||||
| import me.chanjar.weixin.mp.api.test.ApiTestModule; | ||||
| import me.chanjar.weixin.mp.bean.draft.WxMpAddDraft; | ||||
| import me.chanjar.weixin.mp.bean.draft.WxMpDraftArticles; | ||||
| import me.chanjar.weixin.mp.bean.draft.WxMpDraftInfo; | ||||
| import me.chanjar.weixin.mp.bean.draft.WxMpDraftList; | ||||
| import me.chanjar.weixin.mp.bean.draft.WxMpUpdateDraft; | ||||
| import org.testng.annotations.Guice; | ||||
| import org.testng.annotations.Test; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
|  | ||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||
|  | ||||
| /** | ||||
|  * 草稿箱单元测试. | ||||
|  * | ||||
|  * @author dragon | ||||
|  * @date 2021-10-22 | ||||
|  */ | ||||
| @Guice(modules = ApiTestModule.class) | ||||
| public class WxMpDraftServiceImplTest { | ||||
|  | ||||
|   /** | ||||
|    * 1.先上传一个永久图片素材:me.chanjar.weixin.mp.api.impl.WxMpMaterialServiceImplTest.testUploadMaterial | ||||
|    * 2.后续图文需要设置一个永久素材id | ||||
|    */ | ||||
|   final String thumbMediaId = "zUUtT8ZYeXzZ4slFbtnAkh7Yd-f45DbFoF9ERzVC6s4"; | ||||
|  | ||||
|   /** | ||||
|    * 新增草稿后返回的id,后续查询、修改、删除,获取等需要使用 | ||||
|    */ | ||||
|   final String mediaId = "zUUtT8ZYeXzZ4slFbtnAkpgGKyqnTsjtUvMdVBRWJVk"; | ||||
|  | ||||
|   @Inject | ||||
|   protected WxMpService wxService; | ||||
|  | ||||
|   @Test | ||||
|   public void testAddDraft() throws WxErrorException { | ||||
|     // {"mediaId":"zUUtT8ZYeXzZ4slFbtnAkh7Yd-f45DbFoF9ERzVC6s4","url":"http://mmbiz.qpic.cn/mmbiz_jpg/fLtyChQRfH84IyicNUbGt3l3IlHxJRibSFz7Tky0ibmzKykzVbo9tZGYhXQGJ2npFtDPbvPhKYxBz6JxkYIibTmUicQ/0?wx_fmt=jpeg"} | ||||
|     this.wxService.getDraftService().addDraft("标题", "图文消息的具体内容", thumbMediaId); | ||||
|     // 【响应数据】:{"media_id":"zUUtT8ZYeXzZ4slFbtnAks-nZeGiPQmwvhShTh72CqM","item":[]} | ||||
|   } | ||||
|  | ||||
|   @Test | ||||
|   public void testAddGuide_another() throws WxErrorException { | ||||
|     List<WxMpDraftArticles> draftArticleList = new ArrayList<>(); | ||||
|     WxMpDraftArticles draftArticle = WxMpDraftArticles.builder() | ||||
|       .title("新建草稿-对象形式") | ||||
|       .author("dragon") | ||||
|       .digest("图文消息的摘要,仅有单图文消息才有摘要,多图文此处为空") | ||||
|       .content("图文消息的具体内容,支持HTML标签,必须少于2万字符,小于1M,且此处会去除JS") | ||||
|       .contentSourceUrl("https://github.com/Wechat-Group/WxJava") | ||||
|       .thumbMediaId(thumbMediaId) | ||||
|       // 显示封面、打开评论、所有人可评论 | ||||
|       .showCoverPic(1).needOpenComment(1).onlyFansCanComment(0) | ||||
|       .build(); | ||||
|     draftArticleList.add(draftArticle); | ||||
|  | ||||
|     WxMpAddDraft addDraft = WxMpAddDraft.builder().articles(draftArticleList).build(); | ||||
|     String mediaId = this.wxService.getDraftService().addDraft(addDraft); | ||||
|     // 【响应数据】:{"media_id":"zUUtT8ZYeXzZ4slFbtnAkpgGKyqnTsjtUvMdVBRWJVk","item":[]} | ||||
|     assertThat(mediaId).isNotNull(); | ||||
|   } | ||||
|  | ||||
|   @Test | ||||
|   public void testGetDraft() throws WxErrorException { | ||||
|     final WxMpDraftInfo draftInfo = this.wxService.getDraftService().getDraft(mediaId); | ||||
|     assertThat(draftInfo).isNotNull(); | ||||
|     // 【响应数据】:{"news_item":[{"title":"标题","author":"","digest":"图文消息的具体内容","content":"图文消息的具体内容","content_source_url":"","thumb_media_id":"zUUtT8ZYeXzZ4slFbtnAkh7Yd-f45DbFoF9ERzVC6s4","show_cover_pic":1,"url":"http:\/\/mp.weixin.qq.com\/s?__biz=Mzk0OTI5MzM1OQ==&mid=100000006&idx=1&sn=89903965ae5ebd6014903c7c5ca34daa&chksm=435bd946742c5050d18da32289904db5ede8bbd157d181438231a1762b85030419b3c0ed4c00#rd","thumb_url":"http:\/\/mmbiz.qpic.cn\/mmbiz_jpg\/fLtyChQRfH84IyicNUbGt3l3IlHxJRibSFz7Tky0ibmzKykzVbo9tZGYhXQGJ2npFtDPbvPhKYxBz6JxkYIibTmUicQ\/0?wx_fmt=jpeg","need_open_comment":0,"only_fans_can_comment":0}],"create_time":1634886802,"update_time":1634886802} | ||||
|   } | ||||
|  | ||||
|   @Test | ||||
|   public void testUpdateDraft() throws WxErrorException { | ||||
|     WxMpDraftArticles draftArticles = WxMpDraftArticles.builder() | ||||
|       .title("新标题").content("新图文消息的具体内容").thumbMediaId(thumbMediaId).build(); | ||||
|     WxMpUpdateDraft updateDraft = WxMpUpdateDraft.builder() | ||||
|       .mediaId(mediaId) | ||||
|       .index(0) | ||||
|       .articles(draftArticles) | ||||
|       .build(); | ||||
|     Boolean updateDraftResult = this.wxService.getDraftService().updateDraft(updateDraft); | ||||
|     // assertThat(updateDraftResult).isTrue(); | ||||
|     assertThat(updateDraftResult).isTrue(); | ||||
|   } | ||||
|  | ||||
|   @Test | ||||
|   public void testDelDraft() throws WxErrorException { | ||||
|     Boolean delDraftResult = this.wxService.getDraftService().delDraft(mediaId); | ||||
|     // 【响应数据】:{"errcode":0,"errmsg":"ok"} | ||||
|     assertThat(delDraftResult).isTrue(); | ||||
|   } | ||||
|  | ||||
|   @Test | ||||
|   public void testListDraft() throws WxErrorException { | ||||
|     WxMpDraftList draftList = this.wxService.getDraftService().listDraft(0, 10); | ||||
|     /* | ||||
|     【响应数据】:{"item":[{"media_id":"zUUtT8ZYeXzZ4slFbtnAks-nZeGiPQmwvhShTh72CqM", | ||||
|     "content":{ | ||||
|       "news_item": | ||||
|       [ | ||||
|         {"title":"标题","author":"","digest":"图文消息的具体内容","content":"图文消息的具体内容", | ||||
|         "content_source_url":"","thumb_media_id":"zUUtT8ZYeXzZ4slFbtnAkh7Yd-f45DbFoF9ERzVC6s4", | ||||
|         "show_cover_pic":1,"url":"http:\/\/mp.weixin.qq.com\/s?__biz=Mzk0OTI5MzM1?wx_fmt=jpeg", | ||||
|         "need_open_comment":0,"only_fans_can_comment":0}], | ||||
|         "create_time":1634886802,"update_time":1634886802},"update_time":1634886802} | ||||
|       ] | ||||
|     ,"total_count":1,"item_count":1} | ||||
|  | ||||
|     */ | ||||
|     assertThat(draftList).isNotNull(); | ||||
|   } | ||||
|  | ||||
|   @Test | ||||
|   public void testCountDraft() throws WxErrorException { | ||||
|     Long countDraft = this.wxService.getDraftService().countDraft(); | ||||
|     // 【响应数据】:{"total_count":1} | ||||
|     assertThat(countDraft).isNotNull(); | ||||
|   } | ||||
|  | ||||
| } | ||||
|  | ||||
| @@ -0,0 +1,109 @@ | ||||
| package me.chanjar.weixin.mp.api.impl; | ||||
|  | ||||
| import com.google.inject.Inject; | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | ||||
| import me.chanjar.weixin.mp.api.WxMpService; | ||||
| import me.chanjar.weixin.mp.api.test.ApiTestModule; | ||||
| import me.chanjar.weixin.mp.bean.freepublish.WxMpFreePublishInfo; | ||||
| import me.chanjar.weixin.mp.bean.freepublish.WxMpFreePublishList; | ||||
| import me.chanjar.weixin.mp.bean.freepublish.WxMpFreePublishStatus; | ||||
| import org.testng.annotations.Guice; | ||||
| import org.testng.annotations.Test; | ||||
|  | ||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||
|  | ||||
| /** | ||||
|  * 发布能力-单元测试. | ||||
|  * | ||||
|  * @author dragon | ||||
|  * @date 2021-10-23 | ||||
|  */ | ||||
| @Guice(modules = ApiTestModule.class) | ||||
| public class WxMpFreePublishServiceImplTest { | ||||
|  | ||||
|   /** | ||||
|    * 新增草稿后返回的id,发布需要使用 | ||||
|    */ | ||||
|   final String mediaId = "HKVdzjkDfooMqBqJtvSs2EEeRAJaM33gJgkii_JDOHg"; | ||||
|  | ||||
|   /** | ||||
|    * 发布后的id,后续查询等需要使用 | ||||
|    */ | ||||
|   final String publishId = "2650177669"; | ||||
|  | ||||
|   /** | ||||
|    * 图文的 article_id,后续查询图文详情、删除发布内容 需要使用 | ||||
|    * 要根据 publishId 来获取 article_id | ||||
|    * | ||||
|    * @see this.testGetPushStatus | ||||
|    */ | ||||
|   final String articleId = "zjMKVd1g66BkEkpetwml4ElbDdniE8JeI2Ec324Sjqg"; | ||||
|  | ||||
|   @Inject | ||||
|   protected WxMpService wxService; | ||||
|  | ||||
|   @Test | ||||
|   public void testSubmit() throws WxErrorException { | ||||
|     String submit = this.wxService.getFreePublishService().submit(mediaId); | ||||
|     assertThat(submit).isNotBlank(); | ||||
|     // 【响应数据】:{"errcode":0,"errmsg":"ok","publish_id":2650177668} | ||||
|   } | ||||
|  | ||||
|   @Test | ||||
|   public void testGetPushStatus() throws WxErrorException { | ||||
|     WxMpFreePublishStatus pushStatus = this.wxService.getFreePublishService().getPushStatus(publishId); | ||||
|     assertThat(pushStatus).isNotNull(); | ||||
|     // 【响应数据】:{"publish_id":2650177668,"publish_status":0,"article_id":"zjMKVd1g66BkEkpetwml4J-4gNf4I1nsh-B-r_inemw", | ||||
|     // "article_detail":{"count":1,"item": | ||||
|     // [{"idx":1,"article_url": | ||||
|     // "https://mp.weixin.qq.com/s?__biz=MzAwMTE2MzA1xxxxxxxxxx" | ||||
|     // }]},"fail_idx":[]} | ||||
|     // article_url -> 已发布内容可被自定义菜单、自动回复、话题引用,也可用于公开传播 | ||||
|   } | ||||
|  | ||||
|   @Test | ||||
|   public void testGetArticleFromId() throws WxErrorException { | ||||
|     WxMpFreePublishInfo articleFromId = this.wxService.getFreePublishService().getArticleFromId(articleId); | ||||
|     assertThat(articleFromId).isNotNull(); | ||||
|     /* 【响应数据】:{"news_item":[{"title":"欢迎你加入啊~ 这是我的第一条文字消息草稿","author":"","digest":"","content":"欢迎你加入啊~ 这是我的第一条文字消息草稿", | ||||
|     "content_source_url":"","thumb_media_id":"","show_cover_pic":0,"url":"http:\/\/mp.weixin.qq | ||||
|     .com\/s?__biz=MzAwMTE2MzA1Mg==&mid=2650177668","thumb_url":"","need_open_comment":1,"only_fans_can_comment":1,"is_deleted":false}], | ||||
|     "create_time":1634961670,"update_time":1634961672} | ||||
|      */ | ||||
|   } | ||||
|  | ||||
|   @Test | ||||
|   public void testDelPush() throws WxErrorException { | ||||
|     Boolean deletePush = this.wxService.getFreePublishService().deletePush(articleId, 0); | ||||
|     // 【响应数据】:{"errcode":0,"errmsg":"ok"} | ||||
|     assertThat(deletePush).isTrue(); | ||||
|   } | ||||
|  | ||||
|   @Test | ||||
|   public void testDeletePushAllArticle() throws WxErrorException { | ||||
|     Boolean deletePush = this.wxService.getFreePublishService().deletePushAllArticle(articleId); | ||||
|     // 【响应数据】:{"errcode":0,"errmsg":"ok"} | ||||
|     assertThat(deletePush).isTrue(); | ||||
|   } | ||||
|  | ||||
|   @Test | ||||
|   public void testGetPublicationRecords() throws WxErrorException { | ||||
|     WxMpFreePublishList publicationRecords = this.wxService.getFreePublishService().getPublicationRecords(0, 10, 0); | ||||
|     /* | ||||
|     【响应数据】: | ||||
|     {"item":[{"article_id":"zjMKVd1g66BkEkpetwml4BOSzatuEYNY3TFhCc0kSIE","content":{"news_item":[ | ||||
|     {"title":"新建草稿-对象形式","author":"dragon","digest":"图文消息的摘要,仅有单图文消息才有摘要,多图文此处为空", | ||||
|     "content":"图文消息的具体内容,支持HTML标签,必须少于2万字符,小于1M,且此处会去除JS", | ||||
|     "content_source_url":"https:\/\/github.com\/Wechat-Group\/WxJava","thumb_media_id":"HKVdzjkDfooMqBqJtvSs2Ajz2v6L_vtGhyyr_mqKcPU", | ||||
|     "show_cover_pic":1,"url":"http:\/\/mp.weixin.qq.com\/s?__biz=MzAwMTE2MzA1Mg==&mid=26501776710e5adb91#rd", | ||||
|     "thumb_url":"http:\/\/mmbiz.qpic.cn\/mmbiz_jpg\/0QSAUfroWrUmxHthQ\/0?wx_fmt=jpeg", | ||||
|     "need_open_comment":1,"only_fans_can_comment":0,"is_deleted":false}], | ||||
|     "create_time":1634976306,"update_time":1634976318}} | ||||
|     ] | ||||
|     ,"total_count":1,"item_count":1} | ||||
|     */ | ||||
|     assertThat(publicationRecords).isNotNull(); | ||||
|   } | ||||
|  | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 dragon
					dragon