🆕 #2356 【公众号】新增草稿箱和发布相关的接口

This commit is contained in:
dragon
2021-10-23 23:23:18 +08:00
committed by GitHub
parent 8c787d1638
commit 5755c293df
20 changed files with 1330 additions and 3 deletions

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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());
}
}

View File

@@ -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);
}
}