300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > 微信公众号开发--群发图文消息 消息体包含图片地址

微信公众号开发--群发图文消息 消息体包含图片地址

时间:2018-11-19 17:31:09

相关推荐

微信公众号开发--群发图文消息 消息体包含图片地址

今天实现了一下微信公众号的消息群发功能,整个过程还是比较麻烦的,而且有些坑。记录一下。

微信官方文档–高级群发接口

在公众平台网站上,为订阅号提供了每天一条的群发权限,为服务号提供每月(自然月)4条的群发权限。而对于某些具备开发能力的公众号运营者,可以通过高级群发接口,实现更灵活的群发能力。

由于群发的次数非常有限。这里是以预览的方式发送给自己。

先看效果

效果

发送成功的返回结果

{"errcode":0,"errmsg":"preview success"}

这个是预览,群发和预览差不多。

正式环境的效果(9月21日补图)

思路

微信的正确思路

我的具体做法

一些代码

接口地址

// 图文内的图片地址获取接口地址private String uploadImageUrl = "https://api./cgi-bin/media/uploadimg?access_token=ACCESS_TOKEN";// 图文封面图片获取接口地址private String postImageMediaUrl = "http://file.api./cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=image";// 图文素材上传接口地址private String postNewsUrl = "https://api./cgi-bin/media/uploadnews?access_token=ACCESS_TOKEN";// 群发接口地址private String sendToAllUrl = "https://api./cgi-bin/message/mass/sendall?access_token=ACCESS_TOKEN";// 预览接口地址private String sendToPreviewUrl = "https://api./cgi-bin/message/mass/preview?access_token=ACCESS_TOKEN";

关键代码

@Testpublic void testSendToAll() {String accessToken = accessTokenUtil.getAccessToken();// 获取详情的新闻列表List<NewsArticle> articleList = new ArrayList<>();// 1.原始的新闻列表List<NewsArticle> newsList = getArticleList();if(newsList.size()==0){logger.info("----------今天没有发文章,任务结束----------");return;}// 2.封装新闻详情,并得到新闻列表for (NewsArticle article : newsList) {NewsArticle articleNew = getArticleDetial(article.getUrl());try {// 下载封面String localImage = imageService.saveImageToDisk(articleNew.getImagUrl(), imageSavePath);// 上传封面String jsonStr = HttpUtil.sendPost(postImageMediaUrl.replace("ACCESS_TOKEN", accessToken),new File(localImage));JSONObject object = new JSONObject();logger.info("----------上传封面返回结果:{}----------" + jsonStr);try {object = new JSONObject(jsonStr);logger.info("----------得到的图片media_id:{}----------", object.get("media_id"));articleNew.setImageMediaId((String) object.get("media_id"));} catch (Exception e) {logger.error("----------上传封面发生错误:{}", e.getMessage());}} catch (Exception e) {logger.error("----------下载封面上传封面过程发生错误:{}", e.getMessage());}articleList.add(articleNew);}logger.info("----------最终图文列表:{}----------", articleList);// 3.群发图文消息封装List<GroupActicle> articles = new ArrayList<>();for (NewsArticle NewsArticle : articleList) {GroupActicle article = new GroupActicle();article.setThumb_media_id(NewsArticle.getImageMediaId());article.setAuthor(NewsArticle.getAuthor());article.setTitle(NewsArticle.getTitle());article.setContent_source_url(NewsArticle.getUrl());article.setContent(NewsArticle.getContent());article.setShow_cover_pic(0);articles.add(article);}logger.info("----------图文消息:{}----------", articles);Map<String, Object> jsonMap = new HashMap<>();jsonMap.put("articles", articles);logger.info("----------最终的图文消息json:{}----------", gson.toJson(jsonMap));// 4.上传群发图文素材String postNewsResult = HttpUtil.sendPost(postNewsUrl.replace("ACCESS_TOKEN", accessToken),gson.toJson(jsonMap));logger.info("----------上传图文素材的返回结果:{}----------", postNewsResult);JSONObject object = new JSONObject();String mediaId = "";try {object = new JSONObject(postNewsResult);logger.info("----------得到的media_id:{}----------", object.get("media_id"));mediaId = (String) object.get("media_id");} catch (Exception e) {logger.error("----------上传图文消息发生错误:{}----------", e.getMessage());}// 5.选择发送的用户并发送if (StringUtils.isNotEmpty(mediaId)) {Filter filter = new Filter(true);Mpnews mpnews = new Mpnews(mediaId);SendToAllNews sendAll = new SendToAllNews();sendAll.setFilter(filter);sendAll.setMpnews(mpnews);sendAll.setMsgtype("mpnews");// TODO 正式环境用sendToAllSendToOpenIdPreview sendToPreview = new SendToOpenIdPreview("omSsruLEtGPgxjaJTyurGQwQNh8Q");sendToPreview.setMpnews(mpnews);sendToPreview.setMsgtype("mpnews");logger.info("----------预览的json:{}----------", gson.toJson(sendToPreview));// TODO 正式环境换成sendToAllUrlString sentAllResult = HttpUtil.sendPost(sendToPreviewUrl.replace("ACCESS_TOKEN", accessToken),gson.toJson(sendToPreview));logger.info("----------预览结果:{}----------", sentAllResult);}}

注意

微信群发接口图文消息里面包含图片地址,群发之后图文消息内图片无法显示

官方解释

请注意,在图文消息的具体内容中,将过滤外部的图片链接,开发者可以通过下述接口上传图片得到URL,放到图文内容中使用。

上传图文消息内的图片获取URL 请注意,本接口所上传的图片不占用公众号的素材库中图片数量的5000个的限制。图片仅支持jpg/png格式,大小必须在1MB以下。

所以图文消息中图片的src属性必须是腾讯的域名

也就是说必须是以

/

开头的,这个需要我们调用如下接口地址

// 图文内的图片上传接口地址private String uploadImageUrl = "https://api./cgi-bin/media/uploadimg?access_token=ACCESS_TOKEN";

如果遇到如下错误

{"errcode":40007,"errmsg":"invalid media_id hint: [51TBDa0350sz63]"}

上传图片的接口地址为下面的

// 图文封面图片上传接口地址private String postImageMediaUrl = "http://file.api./cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=image";

参考下面的文章

微信上传图文消息invalid media_id hint,thumb_media_id怎么获取

7月23日更新

今天我的群发消息遇到问题了,好久没有整理了,好多人都说群发消息有问题,我今天把我的代码贴出来供大家参考,敏感信息我已经屏蔽,有些实体类也没给出,只是一个思路,仅供参考

package com.jrbac.service.wechat;import java.io.File;import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.regex.Matcher;import java.util.regex.Pattern;import mons.lang3.StringUtils;import org.json.JSONException;import org.json.JSONObject;import org.jsoup.Jsoup;import org.jsoup.nodes.Document;import org.jsoup.nodes.Element;import org.jsoup.select.Elements;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import com.google.gson.Gson;import com.google.gson.GsonBuilder;import com.jrbac.dao.MessagePushDao;import com.jrbac.model.wechat.message.GroupSendMessage;import com.jrbac.model.wechat.messsend.CdptsArticle;import com.jrbac.model.wechat.messsend.SendToAllNews;import com.jrbac.model.wechat.messsend.SendToOpenIdPreview;import com.jrbac.util.HttpUtil;import com.jrbac.util.ImageUtil;import com.jrbac.util.PropertiesUtil;import com.jrbac.util.wechat.AccessTokenUtil;@Servicepublic class SendToAllService {// 获取accessToken的@Autowiredprivate AccessTokenUtil accessTokenUtil;// 读取配置文件的@Autowiredprivate PropertiesUtil prop;// 将图片下载到本地的@Autowiredprivate WechatImageDownloadService imageService;// 已群发的消息@Autowiredprivate MessagePushDao messagePush;private final Logger logger = LoggerFactory.getLogger(this.getClass());private final Gson gson = new GsonBuilder().disableHtmlEscaping().create();// 图文内的图片上传接口地址private String uploadImageUrl = "https://api./cgi-bin/media/uploadimg?access_token=ACCESS_TOKEN";// 图文封面图片上传接口地址private String postImageMediaUrl = "http://file.api./cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=image";// 图文素材上传接口地址private String postNewsUrl = "https://api./cgi-bin/media/uploadnews?access_token=ACCESS_TOKEN";// 群发接口地址private String sendToAllUrl = "https://api./cgi-bin/message/mass/sendall?access_token=ACCESS_TOKEN";// 群发预览接口地址private String sendToPreviewUrl = "https://api./cgi-bin/message/mass/preview?access_token=ACCESS_TOKEN";// 照片下载路径private String imageSavePath = "/usr/tmp/images/";public void doSend() {List<CdptsArticle> toSendNewsList = new ArrayList<>();// 1.获取新闻列表toSendNewsList = getArticleListFromCdpts();// 再去获取一次,有时候第一次获取不到,不知道为什么if (toSendNewsList.size() == 0) {toSendNewsList = getArticleListFromCdpts();}// 2.移除已发送的新闻toSendNewsList = removeAlreadySentArticle(toSendNewsList);if (toSendNewsList.size() == 0) {logger.info("----------没有文章需要群发----------");return;}// 最多群发8条消息if (toSendNewsList.size() > 8) {toSendNewsList = toSendNewsList.subList(0, 8);}logger.info("----------群发的消息----------");for (CdptsArticle article : toSendNewsList) {logger.info("----------{}----------", article.getTitle());}// 3.上传并设置封面图片toSendNewsList = setCoverImage(toSendNewsList);// 4.群发图文消息json封装String groupSendMessageJsonStr = getGroupSendMessageJsonStr(toSendNewsList);// 5.上传群发图文消息String mediaId = uploadGroupSendMessage(groupSendMessageJsonStr);// 5.群发if (StringUtils.isNotEmpty(mediaId)) {String mode = prop.get("active");if (StringUtils.isNotBlank(mode) && mode.equals("dev")) {logger.info("测试环境,预览");String openId = "你的测试openid";sendToPreview(toSendNewsList, openId, mediaId);} else {logger.info("正式环境,群发");sendToAll(toSendNewsList, mediaId);}}}public void sendToPreview(List<CdptsArticle> toSendNewsList, String openId, String mediaId) {String accessToken = accessTokenUtil.getAccessToken();SendToOpenIdPreview sendToPreview = new SendToOpenIdPreview(openId, mediaId);String sendToPreviewJsonStr = gson.toJson(sendToPreview);logger.info("----------预览的的json:{}----------", sendToPreviewJsonStr);String sentToPreviewResult = HttpUtil.sendPost(sendToPreviewUrl.replace("ACCESS_TOKEN", accessToken),sendToPreviewJsonStr);logger.info("----------预览发送结果:{}----------", sentToPreviewResult);checkSendResult(toSendNewsList, sentToPreviewResult);}public void sendToAll(List<CdptsArticle> toSendNewsList, String mediaId) {String accessToken = accessTokenUtil.getAccessToken();SendToAllNews sendToAll = new SendToAllNews(mediaId);String sendToAllJsonStr = gson.toJson(sendToAll);logger.info("----------群发的json数据:{}----------", sendToAllJsonStr);String sentToAllResult = HttpUtil.sendPost(sendToAllUrl.replace("ACCESS_TOKEN", accessToken), sendToAllJsonStr);logger.info("----------群发结果:{}----------", sentToAllResult);checkSendResult(toSendNewsList, sentToAllResult);}/*** 查看消息群发结果,并保存群发数据* * @param toSendNewsList* @param sentToAllResult*/private void checkSendResult(List<CdptsArticle> toSendNewsList, String sentToAllResult) {try {JSONObject object = new JSONObject(sentToAllResult);int errorCode = (Integer) object.get("errcode");if (errorCode == 0) {for (CdptsArticle articleSend : toSendNewsList) {messagePush.addArticleToPushed(articleSend);}} else {logger.error("---------群发发生了异常{},---------", sentToAllResult);}} catch (JSONException e) {logger.error("---------群发结果json解析异常:{}\n----------jsonStr:{}---------", e.getMessage(), sentToAllResult);}}private String uploadGroupSendMessage(String groupSendMessageJsonStr) {String accessToken = accessTokenUtil.getAccessToken();String postNewsResult = HttpUtil.sendPost(postNewsUrl.replace("ACCESS_TOKEN", accessToken),groupSendMessageJsonStr);logger.info("----------上传群发图文消息的返回结果:{}----------", postNewsResult);String mediaId = "";try {JSONObject object = new JSONObject(postNewsResult);mediaId = (String) object.get("media_id");} catch (JSONException e) {logger.error("上传群发图文消息发生错误{}", postNewsResult);}return mediaId;}private String getGroupSendMessageJsonStr(List<CdptsArticle> toSendNewsList) {List<GroupSendMessage> groupSendMessageList = new ArrayList<>();for (CdptsArticle cdptsArticle : toSendNewsList) {GroupSendMessage groupSendMessage = new GroupSendMessage();groupSendMessage.setThumb_media_id(cdptsArticle.getImageMediaId());groupSendMessage.setAuthor(cdptsArticle.getAuthor());groupSendMessage.setTitle(cdptsArticle.getTitle());groupSendMessage.setContent_source_url(cdptsArticle.getUrl());groupSendMessage.setContent(cdptsArticle.getContent());groupSendMessage.setShow_cover_pic(0);groupSendMessageList.add(groupSendMessage);}logger.info("----------最终封装的图文消息列表:{}----------", groupSendMessageList);Map<String, Object> jsonMap = new HashMap<>();jsonMap.put("articles", groupSendMessageList);String groupSendMessageJsonStr = gson.toJson(jsonMap);logger.info("----------最终要发送的图文消息json数据:{}----------", groupSendMessageJsonStr);return groupSendMessageJsonStr;}/*** 设置图文消息的封面图片* * @param newsList* @return*/private List<CdptsArticle> setCoverImage(List<CdptsArticle> newsList) {String accessToken = accessTokenUtil.getAccessToken();// 3.将待发送的新闻填充List<CdptsArticle> detialArticleList = new ArrayList<>();// 4.封装新闻详情,并得到新闻列表for (CdptsArticle article : newsList) {CdptsArticle articleWithDetial = getArticleDetialAndReplaceImage(article.getUrl());try {// 下载封面图片到本地String localImage = imageService.saveImageToDisk(articleWithDetial.getImageUrl(), imageSavePath);ImageUtil.thumbImage(localImage);// 上传封面到微信String jsonStr = HttpUtil.sendPost(postImageMediaUrl.replace("ACCESS_TOKEN", accessToken),new File(localImage));logger.info("----------上传封面图片返回结果:{}----------" + jsonStr);try {JSONObject object = new JSONObject(jsonStr);logger.info("----------得到的封面图片media_id:{}----------", object.get("media_id"));articleWithDetial.setImageMediaId((String) object.get("media_id"));} catch (Exception e) {logger.error("----------上传封面发生错误:{}", e.getMessage());}} catch (Exception e) {logger.error("----------下载封面,上传封面到微信过程发生错误:{}", e.getMessage());}detialArticleList.add(articleWithDetial);}logger.info("----------最终群发图文列表:{}----------", detialArticleList);return detialArticleList;}/*** 从新闻列表中删除已发送的文章* * @return*/public List<CdptsArticle> removeAlreadySentArticle(List<CdptsArticle> articleList) {List<CdptsArticle> messagePushed = messagePush.queryMessagePushed();// 已发送的List<String> urlPushedList = new ArrayList<>();for (CdptsArticle article : messagePushed) {urlPushedList.add(article.getUrl());}// 删除已发送的Iterator<CdptsArticle> iterator = articleList.iterator();while (iterator.hasNext()) {CdptsArticle article = iterator.next();if (urlPushedList.contains(article.getUrl())) {iterator.remove();}}return articleList;}/*** 官网获取新闻列表* * @return*/public List<CdptsArticle> getArticleListFromCdpts() {// 新闻列表地址String url = prop.get("allNewsHome");logger.info("----------获取群发消息列表地址:{}----------", url);List<CdptsArticle> articleList = new ArrayList<>();// 得到页面String result = HttpUtil.sendGet(url);Document doc = Jsoup.parse(result);String weiSchoolPrefix = prop.get("weischool");// 内容页面Elements elements = doc.select("div.m_right");for (Element element : elements) {Elements contentElements = element.getElementsByTag("ul");for (Element contents : contentElements) {// System.out.println("内容:");Elements liContent = contents.getElementsByTag("li");for (Element content : liContent) {CdptsArticle article = new CdptsArticle();// System.out.println(content);String time = content.getElementsByTag("span").first().text();// System.out.println(content.getElementsByTag("span").first().text());article.setTime(time);String title = content.getElementsByTag("a").first().text();article.setTitle(title);String originalUrl = content.select("a[href]").attr("href");article.setUrl(weiSchoolPrefix + originalUrl);articleList.add(article);}}}logger.info("----------获取到的新闻列表:{}----------", articleList);return articleList;}// 图片校验private static boolean isImage(String imageSrc) {String reg = ".+(.JPEG|.jpeg|.JPG|.jpg|.GIF|.gif|.BMP|.bmp|.PNG|.png)$";Pattern pattern = pile(reg);Matcher matcher = pattern.matcher(imageSrc.toLowerCase());return (matcher.find());}/*** 获取新闻详情并替换图片为微信的* * @param articleUrl* @return*/private CdptsArticle getArticleDetialAndReplaceImage(String articleUrl) {String accessToken = accessTokenUtil.getAccessToken();CdptsArticle article = new CdptsArticle();article.setUrl(articleUrl);// 具体页面String remoteUrl = prop.get("remoteDomain") + "/Article/Index/" + articleUrl.split("/Article/Index/")[1];logger.info("----------获取页面详情url:{}----------", remoteUrl);// 得到页面String result = HttpUtil.sendGet(remoteUrl);Document doc = Jsoup.parse(result);// 内容页面Elements elements = doc.select("div.m_right");for (Element element : elements) {// System.out.println("原始内容:\n" + element);// 作者信息Element pageInfo = element.select("p.D_infor").remove(0);// 标题Element titleInfo = element.select("h1.D_title").remove(0);article.setTitle(titleInfo.text());String page = pageInfo.toString();// System.out.println("作者相关信息:\n" + page);// 所在板块String module = element.getElementsByTag("h2").first().select("a[href]").text();// 页面内容String content = element.select("div.r_cont").html();// 替换所有的图片路径Elements images = element.select("div.r_cont").select("img");for (Element image : images) {String imageUrl = image.attr("src");if(!isImage(imageUrl)){// 不是图片格式,直接删掉// image.attr("src", prop.get("localhost") + "/assets/image/school/bg.jpg");image.remove();continue;}else{if (imageUrl.startsWith("http://")) {continue;} else if (imageUrl.startsWith("/Upload")) {image.attr("src", prop.get("remoteDomain") + image.attr("src"));} else {image.attr("src", prop.get("localhost") + "/assets/image/school/bg.jpg");}}// if (!image.attr("src").startsWith("http://")) {// image.attr("src", prop.get("remoteDomain") +// image.attr("src"));// }}content = element.select("div.r_cont").html();// 作者相关// 作者相关Elements info = element.getElementsByTag("p").first().getElementsByTag("span");article.setTime(info.get(0).text().replace("发表时间: ", ""));article.setAuthor(info.get(1).text().replace("发布人:", ""));article.setCount(info.get(2).text().replace("点击率:", ""));article.setModule(module);// System.out.println("[所在板块]\t" + module);String contents = content.replace(page, "").replace(titleInfo.toString(), "");// System.out.println("[页面内容]\t" + contents);Document docImage = Jsoup.parse(contents);Elements elementImage = docImage.select("img");if (elementImage.size() == 0) {article.setImageUrl(prop.get("localhost") + "/assets/image/school/bg.jpg");} else {article.setImageUrl(elementImage.get(0).attr("src"));}for (Element imageElement : elementImage) {try {// 下载文件logger.info("----------下载页面中的图片src:{}----------", imageElement.attr("src"));String imageRealPath = imageService.saveImageToDisk(imageElement.attr("src"), imageSavePath);logger.info("----------图片保存路径:{}----------", imageRealPath);// 压缩处理ImageUtil.thumbImage(imageRealPath);// 上传到微信logger.info("----------上传到微信----------");String responseStr = HttpUtil.sendPost(uploadImageUrl.replace("ACCESS_TOKEN", accessToken),new File(imageRealPath));logger.info("----------上传结果:{}----------", responseStr);JSONObject object = new JSONObject();try {object = new JSONObject(responseStr);logger.info("----------得到上传图片的url:{}----------", object.get("url"));imageElement.attr("src", (String) object.get("url"));} catch (Exception e) {logger.error("----------上传图片到微信发生了错误:{}" + responseStr);}} catch (Exception e) {logger.error("----------下载图片并上传到微信过程发生了错误:{}" + e.getMessage());}}String contentFinal = docImage.select("div.D_cont").html();article.setContent(contentFinal);}logger.info("----------获取页面详情返回结果:{}----------", article);return article;}}

参考文献

微信开发文档–群发接口

微信上传图文消息invalid media_id hint,thumb_media_id怎么获取

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。