微信公众平台开发之Java实现群发消息

首先贴上官方文档:
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432
私以为这份文档写的还是很不错的,在开发的时候没有给我造成多大的困扰,比微信支付的文档好的不要太多。当然也可能是因为我调用的功能太少,没有碰上坑。
接下来进入正题。


这里会分步介绍代码所实现的功能,在文章最后会附上完整的类以及用到的其他类。

1. 获取AccessToken

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,在文章最后会贴出该类的完整代码

2. 群发消息

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;
    }
}

如有疑问,烦请留言。

你可能感兴趣的:(Java)