最近的在项目里要集成微信公众号的群发消息,研究了微信公众号的开发文档,这里要吐槽下微信,他是真的坑啊,对我们开发人员真的是很不友好,弄个测试账号还有接口调用的次数限制。看过开发文档,在看百度查资料,期间遇到了无数的坑,终于算是圆满完成了开发需求。现在将它记录下来,供自己及他人后期研究。开始我们的正文。
首先介绍下微信公众号群发消息的流程:
- 获取token令牌。你的公众号会有两个值:一个是appID;另一个是appsecret;这两个很重要。他们的主要作用是生成令牌,用于后期的操作。注意:在部署正规的公众号上时,微信公众号的IP白名单要设置。否则你将不会获取到令牌token的值,导致后面的所有操作都出错。
- 将你要发送的图文消息内容中的图片的链接地址转换成微信服务器上的微信地址。
- 将要发送的图文消息封装,上传至微信服务器,拿到media_id.
- 开始发送。
下面具体的讲解各步的操作:
- 获取token令牌:
token令牌是由appID和appsecret生成的,先定义一个Token令牌类
/**
* @ClassName: TokenEntity
* @Author: lizn
* @Desprication:
* @Date: Created in 15:42 2018/11/20
* @Version 1.0
*/
public class TokenEntity {
// 接口访问凭证
private String accessToken;
// 凭证有效期,单位:秒
private int expiresIn;
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public int getExpiresIn() {
return expiresIn;
}
public void setExpiresIn(int expiresIn) {
this.expiresIn = expiresIn;
}
}
token令牌是由appID和appsecret参数去GET请求,由微信接口返回的,微信接口的地址URL是:
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
注意这里的访问接口是HTTPS,不是HTTP.
/**
* 获取接口访问凭证高级
*
* @param appid 凭证
* @param appsecret 密钥
* @return
*/
public static TokenEntity getTokenByOauth(String appid, String appsecret) {
TokenEntity token = null;
//将URL中的appID和appsecret替换成我们自己的变量值
String requestUrl = token_url.replace("APPID", appid).replace("APPSECRET", appsecret);
// 发起GET请求获取凭证
JsonNode rootNode = httpsRequest(requestUrl, "GET", null);
if (null != rootNode) {
token = new TokenEntity();
token.setAccessToken(rootNode.get("access_token").textValue());
token.setExpiresIn(toInt(rootNode.get("expires_in").toString()));
}
return token;
}
JsonNode是导入com.fasterxml.jackson.databind.JsonNode下的。方法httpsRequest()方法代码如下
/**
* 发送https请求
*
* @param requestUrl 请求地址
* @param requestMethod 请求方式(GET、POST)
* @param outputStr 提交的数据
* @return rootNode(通过rootNode.get(key)的方式获取json对象的属性值)
*/
public static JsonNode httpsRequest(String requestUrl, String requestMethod, String outputStr) {
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = null;
StringBuffer buffer = new StringBuffer();
InputStream inputStream = null;
BufferedReader bufferedReader = null;
InputStreamReader inputStreamReader = null;
HttpsURLConnection conn = null;
try {
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = { new MyX509TrustManager() };
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(ssf);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
// 设置请求方式(GET/POST)
conn.setRequestMethod(requestMethod);
if("GET".equalsIgnoreCase(requestMethod)) {
conn.connect();
}
// 当outputStr不为null时向输出流写数据
if (null != outputStr) {
OutputStream outputStream = conn.getOutputStream();
// 注意编码格式
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 从输入流读取返回内容
inputStream = conn.getInputStream();
inputStreamReader = new InputStreamReader(inputStream, "utf-8");
bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
rootNode = mapper.readTree(buffer.toString());
} catch (ConnectException ce) {
ce.getMessage();
} catch (Exception e) {
e.getMessage();
}finally {
try {
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
inputStream = null;
conn.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
return rootNode;
}
https的请求方式这里就详细解读了,只是把必要的代码贴出来:
import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* @ClassName: MyX509TrustManager
* @Author: lizn
* @Desprication:
* @Date: Created in 15:46 2018/11/20
* @Version 1.0
*/
public class MyX509TrustManager implements X509TrustManager {
// 检查客户端证书
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
// 检查服务器端证书
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
// 返回受信任的X509证书数组
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
import org.apache.commons.httpclient.methods.PostMethod;
/**
* @ClassName: UTF8PostMethod
* @Author: lizn
* @Desprication:
* @Date: Created in 16:56 2018/11/19
* @Version 1.0
*/
public class UTF8PostMethod extends PostMethod {
public UTF8PostMethod(String url) {
super(url);
}
@Override
public String getRequestCharSet() {//文本编码格式
return "UTF-8";
}
}
通过上面一系列的操作,获取了Token令牌。