Java微信公众平台开发之素材管理(Spring Boot 2.X)
微信素材管理和群发这块文档对Java很不友好。本文只对新增临时素材,新增永久素材做介绍,其余获取、删除、修改自行补充
公众号经常有需要用到一些临时性的多媒体素材的场景,例如在使用接口特别是发送消息时,对多媒体文件、多媒体消息的获取和调用等操作,是通过media_id来进行的。素材管理接口对所有认证的订阅号和服务号开放。
素材的限制
图片(image): 2M,支持PNG\JPEG\JPG\GIF格式
语音(voice):2M,播放长度不超过60s,支持AMR\MP3格式
视频(video):10MB,支持MP4格式
缩略图(thumb):64KB,支持JPG格式
一、新增临时素材
接口:https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE,再传一个媒体文件类型,可以是图片(image)、语音(voice)、视频(video)和缩略图(thumb)。
1、订阅号和服务号要通过认证
2、临时素材media_id是可复用的
3、媒体文件在微信后台保存时间为3天,即3天后media_id失效。
/** * 新增临时素材(本地) * * @param accessToken * @param type 媒体文件类型,分别有图片(image)、语音(voice)、(video)和缩略图(thumb) * @param filePath 本地路径 * @return */ @Override public MaterialResult uploadTempMediaFile(String accessToken, String type, String filePath) { Map<String, String> params = new HashMap<>(); params.put("access_token", accessToken); params.put("type", type); try { String result = MaterialUtil.uploadMediaFile(wechatMaterialConfig.getUploadTempMediaUrl(), params, filePath); return JsonUtil.fromJson(result, MaterialResult.class); } catch (Exception e) { log.error(e.getMessage()); } return null; } /** * 新增临时素材(网络) * * @param accessToken * @param type 媒体文件类型,分别有图片(image)、语音(voice)、(video)和缩略图(thumb) * @param url 网络路径 * @return */ @Override public MaterialResult uploadTempMediaUrl(String accessToken, String type, String url) { Map<String, String> params = new HashMap<>(); params.put("access_token", accessToken); params.put("type", type); try { String result = MaterialUtil.uploadMediaUrl(wechatMaterialConfig.getUploadTempMediaUrl(), params, url); return JsonUtil.fromJson(result, MaterialResult.class); } catch (Exception e) { log.error(e.getMessage()); } return null; }
二、新增永久素材
接口:https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=ACCESS_TOKEN&type=TYPE,媒体文件类型,分别有图片(image)、语音(voice)、视频(video,例外)和缩略图(thumb)
/** * 新增永久素材(本地) * * @param accessToken * @param type 媒体文件类型,分别有图片(image)、语音(voice)和缩略图(thumb) * @param filePath 本地路径 * @return */ @Override public MaterialResult uploadForeverMediaFile(String accessToken, String type, String filePath) { Map<String, String> params = new HashMap<>(); params.put("access_token", accessToken); params.put("type", type); try { String result = MaterialUtil.uploadMediaFile(wechatMaterialConfig.getUploadForeverMediaUrl(), params, filePath); return JsonUtil.fromJson(result, MaterialResult.class); } catch (Exception e) { log.error(e.getMessage()); } return null; } /** * 新增永久素材(网络) * * @param accessToken * @param type 媒体文件类型,分别有图片(image)、语音(voice)和缩略图(thumb) * @param url 网络路径 * @return */ @Override public MaterialResult uploadForeverMediaUrl(String accessToken, String type, String url) { Map<String, String> params = new HashMap<>(); params.put("access_token", accessToken); params.put("type", type); try { String result = MaterialUtil.uploadMediaUrl(wechatMaterialConfig.getUploadForeverMediaUrl(), params, url); return JsonUtil.fromJson(result, MaterialResult.class); } catch (Exception e) { log.error(e.getMessage()); } return null; }
新增永久视频素材需特别注意,在上传视频素材时需要POST另一个表单,id为description,包含素材的描述信息title和introduction,内容格式为JSON
/** * 上传本地video永久素材 * 返回格式 * { * "media_id":MEDIA_ID * } * * @param accessToken * @param title 视频素材的标题 * @param introduction 视频素材的描述 * @param filePath 本地路径 * @return */ @Override public String uploadForeverMediaFile(String accessToken, String title, String introduction, String filePath) { //只能是mp4的 Map<String, String> params = new HashMap<>(); params.put("access_token", accessToken); params.put("type", WechatMaterialConstant.MATERIAL_UPLOAD_TYPE_VIDEO); try { String result = MaterialUtil.uploadVideoMediaFile(wechatMaterialConfig.getUploadForeverMediaUrl(), params, filePath, title, introduction); return JsonUtil.fromJson(result, MaterialResult.class).getMediaId(); } catch (Exception e) { log.error(e.getMessage()); } return null; } /** * 上传网络video永久素材 * 返回格式 * { * "media_id":MEDIA_ID * } * * @param accessToken * @param title 视频素材的标题 * @param introduction 视频素材的描述 * @param url 网络路径 * @return */ @Override public String uploadForeverMediaUrl(String accessToken, String title, String introduction, String url) { //只能是mp4的 Map<String, String> params = new HashMap<>(); params.put("access_token", accessToken); params.put("type", WechatMaterialConstant.MATERIAL_UPLOAD_TYPE_VIDEO); try { String result = MaterialUtil.uploadVideoMediaUrl(wechatMaterialConfig.getUploadForeverMediaUrl(), params, url, title, introduction); // log.error(result); return JsonUtil.fromJson(result, MaterialResult.class).getMediaId(); } catch (Exception e) { log.error(e.getMessage()); } return null; }
三、新增永久图文素材
接口:https://api.weixin.qq.com/cgi-bin/material/add_news?access_token=ACCESS_TOKEN
对于常用的素材,开发者可通过本接口上传到微信服务器,永久使用.
1、永久图片素材新增后,将带有URL返回给开发者,开发者可以在腾讯系域名内使用(腾讯系域名外使用,图片将被屏蔽)。
2、公众号的素材库保存总数量有上限:图文消息素材、图片素材上限为5000,其他类型为1000。
3、图文消息的具体内容中,微信后台将过滤外部的图片链接,图片url需通过"上传图文消息内的图片获取URL"接口上传图片获取。
4、"上传图文消息内的图片获取URL"接口所上传的图片,不占用公众号的素材库中图片数量的5000个的限制,图片仅支持jpg/png格式,大小必须在1MB以下。
5、图文消息支持正文中插入自己帐号和其他公众号已群发文章链接的能力。
/** * 新增永久图文素材 * 返回示例 * { * "media_id":MEDIA_ID * } * 活得新增的图文消息素材的media_id * * @param accessToken * @param entity 图文消息article组合的data * @return * @see WechatMassService#uploadForMassNewsFile */ @Override public String uploadNewsMedia(String accessToken, UploadNewsEntity entity) { Map<String, String> params = new HashMap<>(); params.put("access_token", accessToken); String data = JsonUtil.toJson(entity); String result = HttpUtil.doPost(wechatMaterialConfig.getAddNewsUrl(), params, data); return JsonUtil.fromJson(result, MassNewsResult.class).getMediaId(); }
四、上传图文消息内的图片获取URL
接口:https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token=ACCESS_TOKEN
本接口所上传的图片不占用公众号的素材库中图片数量的5000个的限制。图片仅支持jpg/png格式,大小必须在1MB以下,此接口返回的url就是上传图片的URL,可放置图文消息中使用。
/** * { * "url": "http://mmbiz.qpic.cn/mmbiz/gLO17UPS6FS2xsypf378iaNhWacZ1G1UplZYWEYfwvuU6Ont96b1roYs CNFwaRrSaKTPCUdBK9DgEHicsKwWCBRQ/0" * } * 图文消息的具体内容中,微信后台将过滤外部的图片链接,图片url需通过"上传图文消息内的图片获取URL"接口上传图片获取 * 获取 * * @param accessToken * @param filePath 本地路径 * @return */ @Override public String uploadFileForNewsMedia(String accessToken, String filePath) { Map<String, String> params = new HashMap<>(); params.put("access_token", accessToken); try { String result = MaterialUtil.uploadMediaFile(wechatMaterialConfig.getUploadimgMediaUrl(), params, filePath); return JsonUtil.fromJson(result, MaterialResult.class).getUrl(); } catch (Exception e) { log.error(e.getMessage()); } return null; } /** * { * "url": "http://mmbiz.qpic.cn/mmbiz/gLO17UPS6FS2xsypf378iaNhWacZ1G1UplZYWEYfwvuU6Ont96b1roYs CNFwaRrSaKTPCUdBK9DgEHicsKwWCBRQ/0" * } * 图文消息的具体内容中,微信后台将过滤外部的图片链接,图片url需通过"上传图文消息内的图片获取URL"接口上传图片获取 * 获取 * * @param accessToken * @param url 网络路径 * @return */ @Override public String uploadUrlForNewsMedia(String accessToken, String url) { Map<String, String> params = new HashMap<>(); params.put("access_token", accessToken); try { String result = MaterialUtil.uploadMediaUrl(wechatMaterialConfig.getUploadimgMediaUrl(), params, url); return JsonUtil.fromJson(result, MaterialResult.class).getUrl(); } catch (Exception e) { log.error(e.getMessage()); } return null; }
五、Junit测试
@RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = WechatMainApplication.class) @ActiveProfiles("dev") public class WechatMaterialServiceImplTest { @Autowired private WechatAuthService wechatAuthService; @Autowired private WechatMaterialService wechatMaterialService; @Test public void uploadTempMediaFile() { String filePath = "C:/Users/Phil/Pictures/cc0a42661f668d17e18d0a0f3a699909.jpeg"; String accessToken = wechatAuthService.getAccessToken(); System.out.println("新增临时本地图片素材,返回" + wechatMaterialService.uploadTempMediaFile(accessToken, WechatMaterialConstant.MATERIAL_UPLOAD_TYPE_IMAGE, filePath)); //新增临时本地图片素材,返回MassNewsResult(type=image, mediaId=rh0D9L_B5Ty_-EcwIFULGjb57eCGAbQZRz8bNrWnfcLMiMz2Pm7vIQCdUKzC8C_8, createdAt=1543648966, url=null) } @Test public void uploadTempMediaUrl() { String url = "http://b-ssl.duitang.com/uploads/item/201503/14/20150314212812_kCLmy.jpeg"; String accessToken = wechatAuthService.getAccessToken(); System.out.println("新增临时网络图片素材,返回 " + wechatMaterialService.uploadTempMediaUrl(accessToken, WechatMaterialConstant.MATERIAL_UPLOAD_TYPE_IMAGE, url)); //新增临时网络图片素材,返回 MassNewsResult(type=image, mediaId=lgbD-K0ltDTmsW2dSxus6sFxqqFc3mU_NiIAOev_U_mU2Yqa6iSv8KPF5e5WE7yC, createdAt=1543648973, url=null) } @Test public void uploadForeverMediaFile() { String filePath = "C:/Users/Phil/Pictures/cc0a42661f668d17e18d0a0f3a699909.jpeg"; String accessToken = wechatAuthService.getAccessToken(); System.out.println("新增永久本地图片素材,返回" + wechatMaterialService.uploadForeverMediaFile(accessToken, WechatMaterialConstant.MATERIAL_UPLOAD_TYPE_IMAGE, filePath)); //新增永久本地图片素材,返回MassNewsResult(type=null, mediaId=tbP52CbH1vuCLlyUAt2rlUEZKK230SjWIaB9xablAPw, createdAt=0, url=http://mmbiz.qpic.cn/mmbiz_jpg/L8zibbZGicwDyd6CV9JpbEe6T7rjqK2fBibCrZAxEvwDCJKHAgtfUialcnNlcjxTsAmycHSKjrO6KzdDUMeDwhYsIA/0?wx_fmt=jpeg) } @Test public void uploadForeverMediaUrl() { String url = "http://www.59xihuan.cn/uploads/allimg/201309/9181378183464-lp.jpg"; // String url = "http://b-ssl.duitang.com/uploads/item/201503/14/20150314212812_kCLmy.jpeg"; String accessToken = wechatAuthService.getAccessToken(); System.out.println("新增永久网络图片素材, 返回" + wechatMaterialService.uploadForeverMediaUrl(accessToken, WechatMaterialConstant.MATERIAL_UPLOAD_TYPE_IMAGE, url)); //新增永久网络图片素材, 返回MassNewsResult(type=null, mediaId=GG16CzQSj3di2OTScAcNAzmoxg_5_KTyxsJ6uEEBpiM, createdAt=0, url=http://mmbiz.qpic.cn/mmbiz_jpg/3WjFdhSpzNwwEwTpWMU4j8UVddOSDGR2zRuJsQZXaRYnsIB3g4yESBqjxkf1e7ruIWYfUO5FtRWIibaVwt6icOHw/0?wx_fmt=jpeg) } @Test public void uploadNewsMedia() { String accessToken = wechatAuthService.getAccessToken(); UploadNewsEntity entity = new UploadNewsEntity(); UploadNewsEntity.UploadNewsArticle article1 = new UploadNewsEntity.UploadNewsArticle(); article1.setThumbMediaId("tbP52CbH1vuCLlyUAt2rlWEIB6qGsfypnI01Jwwonjg"); article1.setAuthor("article1"); article1.setTitle("article1"); article1.setContentSourceUrl(""); article1.setContent("article1"); article1.setDigest("article1"); article1.setShowConverPic(1); entity.addArticle(article1); UploadNewsEntity.UploadNewsArticle article2 = new UploadNewsEntity.UploadNewsArticle(); article2.setThumbMediaId("tbP52CbH1vuCLlyUAt2rlRjbl4sO2dPYqvCLZNwIorg"); article2.setAuthor("article2"); article2.setTitle("article2"); article2.setContentSourceUrl(""); article2.setContent("article2"); article2.setDigest("article2"); article2.setShowConverPic(0); entity.addArticle(article2); System.out.println("新增永久图文素材, 返回" + wechatMaterialService.uploadNewsMedia(accessToken, entity)); //新增永久图文素材, 返回tbP52CbH1vuCLlyUAt2rlVvIMceFKJmY663R_urJAYc } @Test public void uploadFileForNewsMedia() { String accessToken = wechatAuthService.getAccessToken(); String filePath = "D:\\Project\\Phil\\Wechat\\phil_new_wechat\\src\\main\\webapp\\image\\00_01.jpeg"; System.out.println(wechatMaterialService.uploadFileForNewsMedia(accessToken, filePath)); //http://mmbiz.qpic.cn/mmbiz_jpg/L8zibbZGicwDw6sv1WWkFK1nCUDY9bJrHiaEbJuTS37XbJR3hEiblAkibzjdTHdHKqXb6Ij53CDfNwztRsOwljibEp8A/0 } @Test public void uploadUrlForNewsMedia() { String accessToken = wechatAuthService.getAccessToken(); String url = "http://www.59xihuan.cn//uploads/allimg/20130728/64511374987081-lp.jpg"; System.out.println(wechatMaterialService.uploadUrlForNewsMedia(accessToken, url)); //http://mmbiz.qpic.cn/mmbiz_jpg/L8zibbZGicwDw6sv1WWkFK1nCUDY9bJrHiaQXwtf52SyM4ftxVeuickvh1rDLPMaeE1jDxgpWice9TgJOzYPIRAy8uA/0 } @Test public void uploadForeverVideoMediaFile() { String filePath = "D:/Project/Phil/Wechat/phil_new_wechat/src/main/webapp/video/1539717180390.mp4"; String accessToken = wechatAuthService.getAccessToken(); System.out.println("新增永久本地视频素材, 返回" + wechatMaterialService.uploadForeverMediaFile(accessToken, "title", "test", filePath)); //新增永久本地视频素材, 返回GG16CzQSj3di2OTScAcNA-LTwMdsrKszM7M677NJyic } @Test public void uploadForeverVideoMediaUrl() { //String url = "http://vs6.bdstatic.com/browse_static/v3/common/widget/global/player/newPlayer_e2332cd1.swf"; //转换 String url = "http://xiaozhaozhao.nat300.top/video/1539717180390.mp4"; String accessToken = wechatAuthService.getAccessToken(); System.out.println("新增永久网络视频素材, 返回" + wechatMaterialService.uploadForeverMediaUrl(accessToken, "title", "test", url)); // 新增永久网络视频素材, 返回GG16CzQSj3di2OTScAcNA6OWJlBHKk8sXSmbgPzxEQo } @Test public void getTempMaterial() { String accessToken = wechatAuthService.getAccessToken(); String mediaId = "c985PlW3avLd3w9gUclA75geC9PFFozfX6-Jn6s9kRWwV2gu0KHSaBEDJu0Eugno"; System.out.println(wechatMaterialService.getTempMaterial(accessToken, mediaId)); } @Test public void getMaterial() { String accessToken = wechatAuthService.getAccessToken(); // String mediaId = "tbP52CbH1vuCLlyUAt2rlUEZKK230SjWIaB9xablAPw"; //图片 String mediaId = "tbP52CbH1vuCLlyUAt2rlVvIMceFKJmY663R_urJAYc"; //图文 System.out.println(wechatMaterialService.getMaterial(accessToken, mediaId)); } @Test public void deleteMaterial() { String mediaId = "tbP52CbH1vuCLlyUAt2rlYaBvU3BHrs8g0-XxdnNILY"; //tbP52CbH1vuCLlyUAt2rlfnoE7EJNJvPvEv0nFkezsw //tbP52CbH1vuCLlyUAt2rlYUYsAvjhY7UmdgQ_8qnip4 String accessToken = wechatAuthService.getAccessToken(); System.out.println(wechatMaterialService.deleteMaterial(accessToken, mediaId)); //ResultState(errcode=0, errmsg=ok) } @Test public void geMaterialCount() { String accessToken = wechatAuthService.getAccessToken(); System.out.println(wechatMaterialService.geMaterialCount(accessToken)); //MaterialCountResult(voiceCount=0, videoCount=5, imageCount=15, newsCount=2) } }