首先贴上官方文档:
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432
私以为这份文档写的还是很不错的,在开发的时候没有给我造成多大的困扰,比微信支付的文档好的不要太多。当然也可能是因为我调用的功能太少,没有碰上坑。
接下来进入正题。
这里会分步介绍代码所实现的功能,在文章最后会附上完整的类以及用到的其他类。
access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。
HttpConnection conn = new HttpConnection();
StringBuilder sb = new StringBuilder("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential");
sb.append("&appid="+PropertiesUtil.getInstance().getPropMap().get("wx.AppKey"));
sb.append("&secret="+PropertiesUtil.getInstance().getPropMap().get("wx.AppSecret"));
String result = conn.get(sb.toString());
System.out.println(result);
JSONObject obj = new JSONObject(result);
String accessToken = obj.getString("access_token");
Instance.ACCESS_TOKEN = accessToken;
System.out.println(accessToken);
这里用到了HttpConnection类和PropertiesUtil,在文章最后会贴出该类的完整代码
String resp = "";//响应
String reqUrl = "https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token="+Instance.ACCESS_TOKEN;
try {
// 构造httprequest设置
HttpClient client = new HttpClient();
PostMethod request = new PostMethod(reqUrl);
// 添加request headers
request.addRequestHeader("Content-type", "application/json");
request.addRequestHeader("Accept", "application/json");
Map<String, Object> param = new HashMap<String, Object>();
param.put("touser", openId);
param.put("msgtype", "text");
Map<String, Object> content = new HashMap<String, Object>();
content.put("content", text);
param.put("text",content);
String json = new Gson().toJson(param);
request.setRequestEntity(new ByteArrayRequestEntity(json.getBytes("UTF-8")));
client.executeMethod(request);
resp = request.getResponseBodyAsString();
System.out.println(resp);
} catch (Exception e) {
System.out.println("发送POST请求出现异常!" + e);
e.printStackTrace();
}
该方法参数中的openId为用户在微信的唯一标识,text为需要发送的消息内容。
需要注意的两点,
1.群发接口的openId数组必须包含2个及以上,如果只传一个openid会发送失败,这是我所不能理解的。
2.如果返回code为48003,这个返回码在官方文档中没有说明,出现的原因可能是你的微信公众号没有开通群发功能,需要登录微信公众号,在首页点击“新建群发”按钮,同意之后就可以了。
最后贴上完整的代码,记得把package替换掉:
package com.diecolor.wxpay;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.json.JSONObject;
import com.diecolor.util.HttpConnection;
import com.diecolor.util.PropertiesUtil;
import com.google.gson.Gson;
public class MessageUtil {
/**
* 内部类
* 实例化当前对象
*
*/
private static class Instance{
private static final MessageUtil mu = new MessageUtil();
private static String ACCESS_TOKEN = null;
}
/**
* 暴露在外部的方法
* @return
*/
public static MessageUtil getInstance() {
return Instance.mu;
}
/**
* 获取accessToken
* @return
* @throws Exception
*/
private String getAssessToken() throws Exception {
if (Instance.ACCESS_TOKEN==null) {
HttpConnection conn = new HttpConnection();
StringBuilder sb = new StringBuilder("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential");
sb.append("&appid="+PropertiesUtil.getInstance().getPropMap().get("wx.AppKey"));
sb.append("&secret="+PropertiesUtil.getInstance().getPropMap().get("wx.AppSecret"));
String result = conn.get(sb.toString());
System.out.println(result);
JSONObject obj = new JSONObject(result);
String accessToken = obj.getString("access_token");
Instance.ACCESS_TOKEN = accessToken;
System.out.println(accessToken);
}
return Instance.ACCESS_TOKEN;
}
/**
* 群发文本消息
* @param openId
* @param text
* @return
*/
private boolean messTextMessage(String[] openId,String text) {
try {
String resp = "";//响应
String reqUrl = "https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token="+Instance.ACCESS_TOKEN;
try {
// 构造httprequest设置
HttpClient client = new HttpClient();
PostMethod request = new PostMethod(reqUrl);
// 添加request headers
request.addRequestHeader("Content-type", "application/json");
request.addRequestHeader("Accept", "application/json");
Map param = new HashMap();
param.put("touser", openId);
param.put("msgtype", "text");
Map content = new HashMap();
content.put("content", text);
param.put("text",content);
String json = new Gson().toJson(param);
request.setRequestEntity(new ByteArrayRequestEntity(json.getBytes("UTF-8")));
client.executeMethod(request);
resp = request.getResponseBodyAsString();
System.out.println(resp);
} catch (Exception e) {
System.out.println("发送POST请求出现异常!" + e);
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
public static void main(String[] args) throws Exception {
MessageUtil.getInstance().getAssessToken();
String[] openId = {"oDyjy0pvqxQMV66D7rPzekfxPOUg","oDyjy0hVQSWUU4Np3isCFPy_zC2U"};//
MessageUtil.getInstance().messTextMessage(openId, "测试群发消息");
}
}
package com.diecolor.util;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* 单例模式读取配置文件
* @author 武佳伟丶
*
*/
public class PropertiesUtil {
private static Map proMap = new HashMap();//Maps.newHashMap();//并不知道是干什么用的
private static class PropertiesInstance {
private static final PropertiesUtil props = new PropertiesUtil();
}
public static PropertiesUtil getInstance(){
return PropertiesInstance.props;
}
public Map getPropMap() {
return proMap;
}
/*
* 构造函数
*/
private PropertiesUtil(){
proMap = readProperties();
}
@SuppressWarnings("rawtypes")
private static Map readProperties() {
Properties props = new Properties();
InputStream in = null;
try {
in = PropertiesUtil.class.getClassLoader().getResourceAsStream("upush.properties");
props.load(in);
Enumeration en = props.propertyNames();
while (en.hasMoreElements()) {
String key = (String) en.nextElement();
String value = props.getProperty(key);
proMap.put(key, value);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
return proMap;
}
}
package com.diecolor.util;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Iterator;
import java.util.Map;
import javax.activation.MimetypesFileTypeMap;
import org.springframework.stereotype.Component;
/**
* HTTP通信类
*
*/
@Component
public class HttpConnection {
/**
* 向指定URL发送GET方法的请求
* @param url 发送请求的URL
* @param param 请求参数,请求参数应该是name1=value1&name2=value2的形式。
* @return URL所代表远程资源的响应
*/
public String get(String url, String param) throws Exception {
String urlName = url + "?" + param;
return get(urlName);
}
/**
* 向指定URL发送GET方法的请求
*
* @param url
* 发送请求的URL
* @return URL所代表远程资源的响应
*/
public String get(String url) throws Exception {
String result = "";
BufferedReader in = null;
URL realUrl = new URL(url);
URLConnection conn = realUrl.openConnection();
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.8");
conn.setRequestProperty("Content-Type", "text/xml;charset=utf-8");
conn.setRequestProperty("connection", "keep-alive");
conn.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
// 建立实际的连接
conn.connect();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
in.close();
return result;
}
/**
* 向指定URL发送POST方法的请求
* @param url 发送请求的URL
* @param content 内容
* @return URL所代表远程资源的响应
* @throws Exception
*/
public String post(String url,String content) throws Exception{
String result = "";
URL postUrl = new URL(url);
HttpURLConnection connection = (HttpURLConnection) postUrl
.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestMethod("POST");
connection.setUseCaches(false);
connection.setInstanceFollowRedirects(true);
connection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
connection.connect();
DataOutputStream out = new DataOutputStream(connection
.getOutputStream());
// out.writeBytes(content);
out.write(content.getBytes("UTF-8"));
out.flush();
out.close(); // flush and close
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(),"utf-8"));//设置编码,否则中文乱码
String line="";
while ((line = reader.readLine()) != null){
result += line;
}
reader.close();
connection.disconnect();
return result;
}
/**
* 向指定URL发送POST方法的请求
* @Title: post
* @Description: TODO
* @param @param url
* @param @param textMap
* @param @return
* @return String
* @throws
*/
public String post(String url, Map textMap){
String res = "";
HttpURLConnection conn = null;
String BOUNDARY = "---------------------------123821742118716"; //boundary就是request头和上传文件内容的分隔符
try {
URL postUrl = new URL(url);
conn = (HttpURLConnection) postUrl.openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(30000);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("User-Agent",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");
conn.setRequestProperty("Content-Type",
"multipart/form-data; boundary=" + BOUNDARY);
OutputStream out = new DataOutputStream(conn.getOutputStream());
// text
if (textMap != null) {
StringBuffer strBuf = new StringBuffer();
Iterator iter = textMap.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
String inputName = (String) entry.getKey();
String inputValue = (String) entry.getValue();
if (inputValue == null) {
continue;
}
strBuf.append("\r\n").append("--").append(BOUNDARY).append(
"\r\n");
strBuf.append("Content-Disposition: form-data; name=\""
+ inputName + "\"\r\n\r\n");
strBuf.append(inputValue);
}
out.write(strBuf.toString().getBytes());
}
byte[] endData = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
out.write(endData);
out.flush();
out.close();
// 读取返回数据
StringBuffer strBuf = new StringBuffer();
BufferedReader reader = new BufferedReader(new InputStreamReader(
conn.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null) {
strBuf.append(line).append("\n");
}
res = strBuf.toString();
reader.close();
reader = null;
} catch (Exception e) {
System.out.println("发送POST请求出错。" + url);
e.printStackTrace();
} finally {
if (conn != null) {
conn.disconnect();
conn = null;
}
}
return res;
}
/**
* 向指定URL发送POST方法的请求 (带文件)
* @param url 发送请求的URL
* @param textMap 文本参数键值
* @param fileMap 文件键值
* @return URL所代表远程资源的响应
* @throws Exception
*/
public String filePost(String url, Map textMap,
Map fileMap) {
String res = "";
HttpURLConnection conn = null;
String BOUNDARY = "---------------------------123821742118716"; //boundary就是request头和上传文件内容的分隔符
try {
URL postUrl = new URL(url);
conn = (HttpURLConnection) postUrl.openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(30000);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("User-Agent",
"Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");
conn.setRequestProperty("Content-Type",
"multipart/form-data; boundary=" + BOUNDARY);
OutputStream out = new DataOutputStream(conn.getOutputStream());
// text
if (textMap != null) {
StringBuffer strBuf = new StringBuffer();
Iterator iter = textMap.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
String inputName = (String) entry.getKey();
String inputValue = (String) entry.getValue();
if (inputValue == null) {
continue;
}
strBuf.append("\r\n").append("--").append(BOUNDARY).append(
"\r\n");
strBuf.append("Content-Disposition: form-data; name=\""
+ inputName + "\"\r\n\r\n");
strBuf.append(inputValue);
}
out.write(strBuf.toString().getBytes());
}
// file
if (fileMap != null) {
Iterator iter = fileMap.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
String inputName = (String) entry.getKey();
String inputValue = (String) entry.getValue();
if (inputValue == null) {
continue;
}
File file = new File(inputValue);
String filename = file.getName();
String contentType = new MimetypesFileTypeMap()
.getContentType(file);
if (filename.endsWith(".png")) {
contentType = "image/png";
}
if (contentType == null || contentType.equals("")) {
contentType = "application/octet-stream";
}
StringBuffer strBuf = new StringBuffer();
strBuf.append("\r\n").append("--").append(BOUNDARY).append(
"\r\n");
strBuf.append("Content-Disposition: form-data; name=\""
+ inputName + "\"; filename=\"" + filename
+ "\"\r\n");
strBuf.append("Content-Type:" + contentType + "\r\n\r\n");
out.write(strBuf.toString().getBytes());
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[] endData = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
out.write(endData);
out.flush();
out.close();
// 读取返回数据
StringBuffer strBuf = new StringBuffer();
BufferedReader reader = new BufferedReader(new InputStreamReader(
conn.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null) {
strBuf.append(line).append("\n");
}
res = strBuf.toString();
reader.close();
reader = null;
} catch (Exception e) {
System.out.println("发送POST请求出错。" + url);
e.printStackTrace();
} finally {
if (conn != null) {
conn.disconnect();
conn = null;
}
}
return res;
}
}
如有疑问,烦请留言。