前言:最近做微信开发,弄了一个群发接口,本着不记录肯定会忘记的本事,在这里整理一下。多学习多进步。本文比较啰嗦,可以查看参考文章,我就是从那位大神那里学习到的。本片文章基于Spring开发,Spring提供的用于访问Rest服务的客户端。
这篇文章解决的问题:
1.上传图文消息素材
2.根据openid列表群发
官方技术文档:微信公众平台技术文档
我想说明一下这里,因为本人是技术菜鸟,学习的时候查看文档,发现会多都是直接把代码一粘贴一复制就算OK,以前我也是这样,后来自己再去用的时候发现根本看不懂了,所以以后整理每一篇博客我都会很上心,把一些自己注意到的细节问题写出了方便自己以后的使用。
(1)发送消息-群发接口
群发消息,我们首先要上传消息,再群发。按照目录的第一点是上传图文消息内的图片获取URL,但是第二点上传图文消息素材。我们查看上传图文消息素材接口会发现,我们上传资源的参数是thumb_media_id。如图:
而上传图文消息内的图片获取URL返回的是url,如图:
所以我们这里要使用素材管理接口
这里有两种素材,一种是临时素材,一种是永久素材,区别自己查看接口就能知道,这里讲解上传临时素材,毕竟永久素材上传是有个数的。
调用临时素材接口就可以返回media_id,就是我们上传图文消息素材需要的thumb_media_id参数数据了。
现在开始正式java接口开发。
参考柳峰文章:
微信公众平台开发教程第22篇-如何保证access_token长期有效
public final class MediaType {
public static final String APPLICATION_XML = "application/xml;charset=UTF-8";
public static final String APPLICATION_JSON = "application/json;charset=UTF-8";
public static final String APPLICATION_X_WWW_F_U = "application/x-www-form-urlencoded;charset=UTF-8";
}
GroupSendMessageApi接口
package com.weixin.message.api;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import com.basic.protocol.MediaType;
import com.weixin.message.model.Articles;
import com.weixin.message.model.FilePathData;
import com.weixin.message.model.GroupSendResponse;
import com.weixin.message.model.MessageData;
import com.weixin.message.model.UploadResponse;
/**
* 接口名:群发消息接口
* 创建时间:2017-05-26
* 开发者: wangql
*/
@Path("/groupSendMessage")
public interface GroupSendMessageApi {
/**
* 上传临时素材
* @param filePath
* @return
*/
@POST
@Path("/uploadMatter")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON })
public UploadResponse fileUpload(FilePathData filePath);
}
FilePathData请求数据
package com.weixin.message.model;
public class FilePathData {
private String filePath;//文件路径
private String type;//文件类型 默认image
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
GroupSendMessageApiImpl实现类
package com.weixin.message.api.impl;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.client.RestTemplate;
import com.basic.factory.RestTemplateFactory;
import com.basic.utils.JsonUtil;
import com.basic.utils.TokenUtil;
import com.weixin.message.api.GroupSendMessageApi;
import com.weixin.message.model.Articles;
import com.weixin.message.model.FilePathData;
import com.weixin.message.model.GroupSendResponse;
import com.weixin.message.model.MessageData;
import com.weixin.message.model.UploadResponse;
/**
* 接口名:群发消息实现类
* 创建时间:2017-05-26
* 开发者: wangqiulin
*/
public class GroupSendMessageApiImpl implements GroupSendMessageApi {
private static Log logger = LogFactory.getLog(GroupSendMessageApiImpl.class);
private RestTemplate restTemplate;
public GroupSendMessageApiImpl() {
restTemplate = RestTemplateFactory.makeRestTemplate();
}
@Override
public UploadResponse fileUpload(FilePathData filePath) {
UploadResponse response = new UploadResponse();
if(filePath != null){
String type = filePath.getType()==null?"image":filePath.getType();//文件类型
String url = new StringBuffer("http://file.api.weixin.qq.com/cgi-bin/media/upload?access_token=")
.append(AccessToken).append("&type="+type).toString();
logger.info("文件路径:"+filePath.getFilePath());
GroupSendMessageApiImpl groupSendMessageApiImpl = new GroupSendMessageApiImpl();
try {
String result = groupSendMessageApiImpl.send(url, filePath.getFilePath());
logger.info(result);
if(result != null){
response = JsonUtil.jsonToObject(result, response.getClass());
}
} catch (IOException e) {
e.printStackTrace();
}
}else {
response.setErrcode(1);
response.setErrmsg("上传图片路径为空");
}
return response;
}
/**
* 上传文件
* @param url
* @param filePath
* @return
* @throws IOException
*/
public String send(String url, String filePath) throws IOException {
String result = null;
File file = new File(filePath);
if (!file.exists() || !file.isFile()) {
throw new IOException("文件不存在");
}
/**
* 第一部分
*/
URL urlObj = new URL(url);
// 连接
HttpURLConnection con = (HttpURLConnection) urlObj.openConnection();
/**
* 设置关键值
*/
con.setRequestMethod("POST"); // 以Post方式提交表单,默认get方式
con.setDoInput(true);
con.setDoOutput(true);
con.setUseCaches(false); // post方式不能使用缓存
// 设置请求头信息
con.setRequestProperty("Connection", "Keep-Alive");
con.setRequestProperty("Charset", "UTF-8");
// 设置边界
String BOUNDARY = "---------------------------" + System.currentTimeMillis();
con.setRequestProperty("Content-Type", "multipart/form-data; boundary="
+ BOUNDARY);
// 请求正文信息
// 第一部分:
StringBuilder sb = new StringBuilder();
sb.append("--"); // 必须多两道线
sb.append(BOUNDARY);
sb.append("\r\n");
sb.append("Content-Disposition: form-data;name=\"media\";filename=\""
+ file.getName() + "\"\r\n");
sb.append("Content-Type:application/octet-stream\r\n\r\n");
byte[] head = sb.toString().getBytes("utf-8");
// 获得输出流
OutputStream out = new DataOutputStream(con.getOutputStream());
// 输出表头
out.write(head);
// 文件正文部分
// 把文件已流文件的方式 推入到url中
DataInputStream in = new DataInputStream(new FileInputStream(file));
int bytes = 0;
byte[] bufferOut = new byte[1024];
while ((bytes = in.read(bufferOut)) != -1) {
out.write(bufferOut, 0, bytes);
}
in.close();
// 结尾部分
byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");// 定义最后数据分隔线
out.write(foot);
out.flush();
out.close();
StringBuffer buffer = new StringBuffer();
BufferedReader reader = null;
try {
// 定义BufferedReader输入流来读取URL的响应
reader = new BufferedReader(new InputStreamReader(
con.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
if (result == null) {
result = buffer.toString();
}
} catch (IOException e) {
System.out.println("发送POST请求出现异常!" + e);
e.printStackTrace();
throw new IOException("数据读取异常");
} finally {
if (reader != null) {
reader.close();
}
}
return result;
}
}
UploadResponse响应数据
/**
* 上传图文或者素材响应
* @author wangqiulin
*/
public class UploadResponse {
private int errcode;
private String errmsg;
private String type;
private String media_id;
private Long created_at;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getMedia_id() {
return media_id;
}
public void setMedia_id(String media_id) {
this.media_id = media_id;
}
public Long getCreated_at() {
return created_at;
}
public void setCreated_at(Long created_at) {
this.created_at = created_at;
}
public int getErrcode() {
return errcode;
}
public void setErrcode(int errcode) {
this.errcode = errcode;
}
public String getErrmsg() {
return errmsg;
}
public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}
}
如果自己测试的话直接写一个main方法就可以解决,使用接口主要是让功能更加清晰。主要的核心代码是实现类,其他的请求和响应都是辅助存在。
(3)请求接口参数
返回参数:
请求接口:
这样我们就生成了media_id。这个media_id就是上传图文消息素材的thumb_media_id。
http请求方式: POST
https://api.weixin.qq.com/cgi-bin/media/uploadnews?access_token=ACCESS_TOKEN
(1)Articles请求参数
package com.weixin.message.model;
public class Articles {
private Article[] articles;
public Article[] getArticles() {
return articles;
}
public void setArticles(Article[] articles) {
this.articles = articles;
}
}
package com.plateno.weixin.message.model;
public class Article {
private String title;
private String description;
private String url;
private String picurl;
private String thumb_media_id;
private String author;
private String content_source_url;
private String content;
private String digest;
private Integer show_cover_pic;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getPicurl() {
return picurl;
}
public void setPicurl(String picurl) {
this.picurl = picurl;
}
public String getThumb_media_id() {
return thumb_media_id;
}
public void setThumb_media_id(String thumb_media_id) {
this.thumb_media_id = thumb_media_id;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getContent_source_url() {
return content_source_url;
}
public void setContent_source_url(String content_source_url) {
this.content_source_url = content_source_url;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getDigest() {
return digest;
}
public void setDigest(String digest) {
this.digest = digest;
}
public Integer getShow_cover_pic() {
return show_cover_pic;
}
public void setShow_cover_pic(Integer show_cover_pic) {
this.show_cover_pic = show_cover_pic;
}
}
(2)uploadFile接口
package com.weixin.message.api;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import com.basic.protocol.MediaType;
import com.weixin.message.model.Articles;
import com.weixin.message.model.FilePathData;
import com.weixin.message.model.GroupSendResponse;
import com.weixin.message.model.MessageData;
import com.weixin.message.model.UploadResponse;
/**
* 接口名:群发消息接口
* 创建时间:2017-05-26
* 开发者: wangqiulin
*/
@Path("/groupSendMessage")
public interface GroupSendMessageApi {
/**
* 上传临时素材
* @param filePath
* @return
*/
@POST
@Path("/uploadMatter")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON })
public UploadResponse fileUpload(FilePathData filePath);
/**
* 上传图文消息
* @param articles
* @return
*/
@POST
@Path("/uploadFile")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON })
public UploadResponse uploadFile(Articles articles);
}
(3)uploadFile实现方法
@Override
public UploadResponse uploadFile(Articles articles) {
UploadResponse response = null;
if(articles != null){
String url = new StringBuffer("https://api.weixin.qq.com/cgi-bin/media/uploadnews?access_token=").append(TokenUtil.getAccessToken()).toString();
response = restTemplate.postForObject(url, articles, UploadResponse.class);
logger.info("Errcode:"+response.getErrcode());
logger.info("Errmsg:"+response.getErrmsg());
logger.info("Type:"+response.getType());
logger.info("Created_at"+response.getCreated_at());
}else {
response.setErrcode(1);
response.setErrmsg("上传图文消息素材为空");
}
return response;
}
参数示例:
{"articles": [{"thumb_media_id":"DphGJnvnYMeU3QGVmr8rXdb4wLn0dz96Uin4GpwFrAdjTkVmoIgs8zhKdjKGS2ML","author":"wql","title":"Happy Day","content_source_url":"www.platone.com","content":"content","digest":"digest"}]}
参数示例:
{
"type":"news",
"media_id":"CsEf3ldqkAYJAU6EJeIkStVDSvffUJ54vqbThMgplD-VJXXof6ctX5fI6-aYyUiQ",
"created_at":1391857799
}
http请求方式: POST
https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token=ACCESS_TOKEN
图文消息(注意图文消息的media_id需要通过上述方法来得到):
{
"touser":[
"OPENID1",
"OPENID2"
],
"mpnews":{
"media_id":"123dsdajkasd231jhksad"
},
"msgtype":"mpnews",
"send_ignore_reprint":0
}
(1)请求参数
package com.weixin.message.model;
public class MessageData {
private String[] touser;
private String msgtype;
private MediaContent mpnews;
private Integer send_ignore_reprint;
public String[] getTouser() {
return touser;
}
public void setTouser(String[] touser) {
this.touser = touser;
}
public String getMsgtype() {
return msgtype;
}
public void setMsgtype(String msgtype) {
this.msgtype = msgtype;
}
public MediaContent getMpnews() {
return mpnews;
}
public void setMpnews(MediaContent mpnews) {
this.mpnews = mpnews;
}
public Integer getSend_ignore_reprint() {
return send_ignore_reprint;
}
public void setSend_ignore_reprint(Integer send_ignore_reprint) {
this.send_ignore_reprint = send_ignore_reprint;
}
}
(2)sendMsg接口
/**
* 根据openid群发消息接口
* @param message
* @return
*/
@POST
@Path("/sendMsg")
@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public GroupSendResponse sendMsg(MessageData message);
(3)sendMsg实现方法
@Override
public GroupSendResponse sendMsg(MessageData message) {
GroupSendResponse response = null;
if(message != null){
String url = new StringBuffer("https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token=").append(TokenUtil.getAccessToken()).toString();
response = restTemplate.postForObject(url, message, GroupSendResponse.class);
logger.info("Errcode:"+response.getErrcode());
logger.info("Errmsg:"+response.getErrmsg());
logger.info("Msg_id:"+response.getMsg_id());
logger.info("Msg_data_id:"+response.getMsg_data_id());
}else {
response.setErrcode(1);
response.setErrmsg("图文消息为空");
}
return response;
}
(1)参数示例:
{
"errcode":0,
"errmsg":"send job submission success",
"msg_id":34182,
"msg_data_id": 206227730
}
java微信开发高级接口—-群发功能