JAVA微信公众号网页开发——将文章群发到微信公众号中(文章使用富文本,包含图片)
阅读原文时间:2022年05月12日阅读:1

SendTextToAllUserAct.java

package com.weixin.sendmessage;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.HttpResponseException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.net.URI;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* 控制器
*/
public class SendTextToAllUserAct {

/\*\*  
 \* 群发文章微信  
 \*  
 \* @param ids 内容id  
 \* @return  
 \*/  
@RequestMapping("/content/o\_sendToWeixin.do")  
public String sendToWeixin(Integer\[\] ids) {

    Content\[\] beans = new Content\[ids.length\];  
    for (int i = 0; i < ids.length; i++) {  
        beans\[i\] = contentMng.findById(ids\[i\]); //查询所有要发送的内容  
    }  
    sendTextToAllUser(beans);  
    return null;  
}

/\*\*  
 \* 群发  
 \*/  
public void sendTextToAllUser(Content\[\] beans) {  
    String access\_token = getToken();  
    //上传内容到微信  
    /\*\*  
     \* 上传图文消息素材  
     \* 官方接口文档:https://developers.weixin.qq.com/doc/offiaccount/Message\_Management/Batch\_Sends\_and\_Originality\_Checks.html#%E4%B8%8A%E4%BC%A0%E5%9B%BE%E6%96%87%E6%B6%88%E6%81%AF%E7%B4%A0%E6%9D%90%E3%80%90%E8%AE%A2%E9%98%85%E5%8F%B7%E4%B8%8E%E6%9C%8D%E5%8A%A1%E5%8F%B7%E8%AE%A4%E8%AF%81%E5%90%8E%E5%9D%87%E5%8F%AF%E7%94%A8%E3%80%91  
     \*/  
    String articalUploadUrl = "https://api.weixin.qq.com/cgi-bin/media/uploadnews";  
    String url = articalUploadUrl + "?access\_token=" + access\_token;

    String\[\] str = articalUpload(access\_token, beans);  
    Integer contentCount = 0;  
    contentCount = Integer.parseInt(str\[1\]);  
    if (contentCount > 0) {  
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();  
        //HttpClient  
        CloseableHttpClient client = httpClientBuilder.build();  
        client = (CloseableHttpClient) wrapClient(client);  
        HttpPost post = new HttpPost(url);  
        try {  
            System.out.println("str\[0\]:" + str\[0\]);  
            StringEntity s = new StringEntity(str\[0\], "utf-8");  
            s.setContentType("application/json");  
            post.setEntity(s);  
            HttpResponse res = client.execute(post);  
            HttpEntity entity = res.getEntity();  
            String contentString = EntityUtils.toString(entity, "utf-8");  
            System.out.println("contentString:" + contentString);  
            JSONObject json = new JSONObject(contentString);  
            //输出返回消息  
            String media\_id = "";  
            media\_id = json.getString("media\_id");  
            if (StringUtils.isNotBlank(media\_id)) {  
                /\*\*  
                 \*图文消息群发  
                 \* 官方接口文档:https://developers.weixin.qq.com/doc/offiaccount/Message\_Management/Batch\_Sends\_and\_Originality\_Checks.html  
                 \*/  
                String sendAllMessageUrl = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall";  
                String url\_send = sendAllMessageUrl + "?access\_token=" + token;  
                String str\_send = "{\\"filter\\":{\\"is\_to\_all\\":true},\\"mpnews\\":{\\"media\_id\\":\\"" + media\_id + "\\"},\\"msgtype\\":\\"mpnews\\"}";  
                post(url\_send, str\_send, "application/json");  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
}

private String post(String url, String json, String contentType) {  
    HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();  
    //HttpClient  
    CloseableHttpClient client = httpClientBuilder.build();  
    client = (CloseableHttpClient) wrapClient(client);  
    HttpPost post = new HttpPost(url);  
    try {  
        StringEntity s = new StringEntity(json, "utf-8");  
        if (StringUtils.isBlank(contentType)) {  
            s.setContentType("application/json");  
        }  
        s.setContentType(contentType);  
        post.setEntity(s);  
        HttpResponse res = client.execute(post);  
        HttpEntity entity = res.getEntity();  
        String str = EntityUtils.toString(entity, "utf-8");  
        return str;  
    } catch (Exception e) {  
        e.printStackTrace();  
    }  
    return null;  
}

/\*\*  
 \* @param token  
 \* @param beans  
 \* @return  
 \*/  
private String\[\] articalUpload(String token, Content\[\] beans) {  
    Integer count = 0;  
    String str = "{\\"articles\\":\[";  
    for (int i = 0; i < beans.length; i++) {  
        //将富文本图片先上传到微信服务器上  
        String txt = contentHtmlProc(token, beans\[i\].getHtml());  
        String mediaId = "";  
        if (!StringUtils.isBlank("文章类型图")) {  
            String typeImg = "文章类型图";  
            mediaId = uploadFile(token, typeImg, "image");  
            System.out.println("typeImg:" + typeImg);  
            str = str + "{" +  
                    "\\"thumb\_media\_id\\":\\"" + mediaId + "\\"," +  
                    "\\"author\\":\\"" + beans\[i\].getAuthor() + "\\"," +  
                    "\\"title\\":\\"" + beans\[i\].getTitle() + "\\"," +  
                    "\\"content\_source\_url\\":\\"" + beans\[i\].getSourceUrl() + "\\"," +  
                    "\\"content\\":\\"" + txt + "\\"," +  
                    "\\"digest\\":\\"" + beans\[i\].getDescription() + "\\","  
                    + "\\"show\_cover\_pic\\":\\"0\\"" + "}";  
            if (i != beans.length - 1) {  
                str = str + ",";  
            }  
            count++;  
        }  
    }  
    str = str + "\]}";  
    String\[\] result = new String\[2\];  
    result\[0\] = str;  
    result\[1\] = count.toString();  
    return result;  
}

/\*\*  
 \* 把内容中的图片先上传到微信服务器  
 \*  
 \* @param access\_token 微信的access\_token  
 \* @param txt          富文本内容 html代码  
 \* @return  
 \*/  
private String contentHtmlProc(String access\_token, String txt) {  
    if (StringUtils.isBlank(txt)) {  
        return "";  
    }

    //从富文本的html中提取img图片路径  
    List<String> imgUrls = getImageSrc(txt);  
    for (String img : imgUrls) {  
        //img路径为图片的绝对路径  
        //上传图片到微信  
        String imgRealUrl = uploadImg(access\_token, img);  
        if (StringUtils.isNotBlank(imgRealUrl)) {  
            txt = txt.replace(img, imgRealUrl);  
        }  
    }  
    //html标签双引号需要注意  
    txt = txt.replaceAll("\\"", "\\'");  
    return txt;  
}

/\*\*  
 \* 文件上传到微信服务器  
 \* 官方接口文档:https://developers.weixin.qq.com/doc/offiaccount/Asset\_Management/New\_temporary\_materials.html  
 \*  
 \* @param access\_token  
 \* @param filePath     文件路径 ,绝对地址  
 \* @param type         文件类型  
 \* @return  
 \*/  
public String uploadFile(String access\_token, String filePath, String type) {  
    String sendGetUrl = "https://api.weixin.qq.com/cgi-bin/media/upload";  
    String url = sendGetUrl + "?access\_token=" + access\_token;  
    String result = null;  
    String mediaId = "";  
    FileUpload fileUpload = new FileUpload();  
    try {  
        result = fileUpload.uploadFile(url, filePath, type);  
        System.out.println("result:" + result);  
        if (result.startsWith("{") && result.contains("media\_id")) {  
            JSONObject json = new JSONObject(result);  
            mediaId = json.getString("media\_id");  
        }  
    } catch (Exception e) {  
        e.printStackTrace();  
    }  
    return mediaId;  
}

/\*\*  
 \* 把本地图片先上传到服务器 ,上传图文消息内的图片获取URL  
 \* 官网接口地址 :https://developers.weixin.qq.com/doc/offiaccount/Asset\_Management/Adding\_Permanent\_Assets.html  
 \*  
 \* @param access\_token  
 \* @param filePath     图片路径  
 \* @return  
 \*/  
private String uploadImg(String access\_token, String filePath) {  
    String sendGetUrl = "https://api.weixin.qq.com/cgi-bin/media/uploadimg";  
    String url = sendGetUrl + "?access\_token=" + access\_token;  
    String result = null;  
    String mediaId = "";  
    FileUpload fileUpload = new FileUpload();  
    try {  
        result = fileUpload.uploadFile(url, filePath, null);  
        if (result.startsWith("{")) {  
            JSONObject json = new JSONObject(result);  
            mediaId = json.getString("url");  
        }  
    } catch (Exception e) {  
        e.printStackTrace();  
    }  
    return mediaId;  
}

/\*\*  
 \* 提取img图片路径  
 \*  
 \* @param htmlCode html代码  
 \* @return  
 \*/  
public static List<String> getImageSrc(String htmlCode) {  
    List<String> imageSrcList = new ArrayList<String>();  
    String regular = "<img(.\*?)src=\\"(.\*?)\\"";  
    String img\_pre = "(?i)<img(.\*?)src=\\"";  
    String img\_sub = "\\"";  
    Pattern p = Pattern.compile(regular, Pattern.CASE\_INSENSITIVE);  
    Matcher m = p.matcher(htmlCode);  
    String src = null;  
    while (m.find()) {  
        src = m.group();  
        src = src.replaceAll(img\_pre, "").replaceAll(img\_sub, "").trim();  
        imageSrcList.add(src);  
    }  
    return imageSrcList;  
}

/\*\*  
 \* 获取access\_token  
 \*  
 \* @return  
 \*/  
public String getToken() {  
    String tokenGetUrl = "https://api.weixin.qq.com/cgi-bin/token?grant\_type=client\_credential";//微信提供获取access\_token接口地址  
    String appid = "";  
    String secret = "";

    System.out.println("~~~~~appid:" + appid);  
    System.out.println("~~~~~secret:" + secret);  
    JSONObject tokenJson = new JSONObject();  
    if (StringUtils.isNotBlank(appid) && StringUtils.isNotBlank(secret)) {  
        tokenGetUrl += "&appid=" + appid + "&secret=" + secret;  
        tokenJson = getUrlResponse(tokenGetUrl);  
        System.out.println("~~~~~tokenJson:" + tokenJson.toString());  
        try {  
            return (String) tokenJson.get("access\_token");  
        } catch (JSONException e) {  
            System.out.println("报错了");  
            return null;  
        }  
    } else {  
        System.out.println("appid和secret为空");  
        return null;  
    }  
}

private JSONObject getUrlResponse(String url) {  
    CharsetHandler handler = new CharsetHandler("UTF-8");  
    try {  
        HttpGet httpget = new HttpGet(new URI(url));  
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();  
        //HttpClient  
        CloseableHttpClient client = httpClientBuilder.build();  
        client = (CloseableHttpClient) wrapClient(client);  
        return new JSONObject(client.execute(httpget, handler));  
    } catch (Exception e) {  
        e.printStackTrace();  
        return null;  
    }  
}

private static HttpClient wrapClient(HttpClient base) {  
    try {  
        SSLContext ctx = SSLContext.getInstance("TLSv1");  
        X509TrustManager tm = new X509TrustManager() {  
            public void checkClientTrusted(X509Certificate\[\] xcs,  
                                           String string) throws CertificateException {  
            }

            public void checkServerTrusted(X509Certificate\[\] xcs,  
                                           String string) throws CertificateException {  
            }

            public X509Certificate\[\] getAcceptedIssuers() {  
                return null;  
            }  
        };  
        ctx.init(null, new TrustManager\[\]{tm}, null);  
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(ctx, new String\[\]{"TLSv1"}, null,  
                SSLConnectionSocketFactory.BROWSER\_COMPATIBLE\_HOSTNAME\_VERIFIER);  
        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();  
        return httpclient;

    } catch (Exception ex) {  
        return null;  
    }  
}

private class CharsetHandler implements ResponseHandler<String> {  
    private String charset;

    public CharsetHandler(String charset) {  
        this.charset = charset;  
    }

    public String handleResponse(HttpResponse response)  
            throws ClientProtocolException, IOException {  
        StatusLine statusLine = response.getStatusLine();  
        if (statusLine.getStatusCode() >= 300) {  
            throw new HttpResponseException(statusLine.getStatusCode(),  
                    statusLine.getReasonPhrase());  
        }  
        HttpEntity entity = response.getEntity();  
        if (entity != null) {  
            if (!StringUtils.isBlank(charset)) {  
                return EntityUtils.toString(entity, charset);  
            } else {  
                return EntityUtils.toString(entity);  
            }  
        } else {  
            return null;  
        }  
    }

}  

}

Content.java

package com.weixin.sendmessage;

/**
* 内容实体类
*/
public class Content {

private Integer id;

private String author;

private String html;

private String title;

private String description;

private String sourceUrl;

public String getSourceUrl() {  
    return sourceUrl;  
}

public void setSourceUrl(String sourceUrl) {  
    this.sourceUrl = sourceUrl;  
}

public Integer getId() {  
    return id;  
}

public void setId(Integer id) {  
    this.id = id;  
}

public String getAuthor() {  
    return author;  
}

public void setAuthor(String author) {  
    this.author = author;  
}

public String getHtml() {  
    return html;  
}

public void setHtml(String html) {  
    this.html = html;  
}

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

}

FileUpload.java

package com.weixin.sendmessage;

import org.apache.commons.lang.StringUtils;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;

public class FileUpload {
/**
* 模拟form表单的形式 ,上传文件 以输出流的形式把文件写入到url中,然后用输入流来获取url的响应
*
* @param url 请求地址 form表单url地址
* @param filePath 文件在服务器保存路径
* @return String 正确上传返回media_id
* @throws IOException
*/

/\*\* 微信上传文件接口  \*/  
public String uploadFile(String url, String filePath, String type) throws Exception {  
     File file = new File(filePath);  
     String result = null;  
        if (!file.exists() || !file.isFile()) {  
            return "文件路径错误";  
        }  
        /\*\*  
         \* 第一部分  
         \*/  
        if(StringUtils.isNotBlank(type)){  
            url = url+"&type="+type;  
        }  
        URL urlObj = new URL(url);  
        HttpURLConnection con = null;

        //解决HTTPS  
        trustAllHttpsCertificates();  
        HostnameVerifier hv = new HostnameVerifier() {  
            public boolean verify(String urlHostName, SSLSession session) {  
                System.out.println("Warning: URL Host: " + urlHostName + " vs. "  
                                   + session.getPeerHost());  
                return true;  
            }  
        };  
        HttpsURLConnection.setDefaultHostnameVerifier(hv);  
        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);

        //con.setRequestProperty("Content-Type", "multipart/mixed; boundary=" + BOUNDARY);  
        //con.setRequestProperty("content-type", "text/html");  
        // 请求正文信息

        // 第一部分:  
        StringBuilder sb = new StringBuilder();  
        sb.append("--"); // ////////必须多两道线  
        sb.append(BOUNDARY);  
        sb.append("\\r\\n");  
        sb.append("Content-Disposition: form-data;name=\\"file\\";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);

        // 文件正文部分  
        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();  
        /\*\*  
         \* 读取服务器响应,必须读取,否则提交不成功  
         \*/  
       // con.getResponseCode();

        /\*\*  
         \* 下面的方式读取也是可以的  
         \*/

         try {

         // 定义BufferedReader输入流来读取URL的响应  
             StringBuffer buffer = new StringBuffer();  
             BufferedReader reader = new BufferedReader(new InputStreamReader(  
             con.getInputStream(),"UTF-8"));  
             String line = null;  
             while ((line = reader.readLine()) != null) {  
                //System.out.println(line);  
                buffer.append(line);  
             }  
             if(result==null){  
                result = buffer.toString();  
            }  
             return buffer.toString();  
         } catch (Exception e) {  
             System.out.println("发送POST请求出现异常!" + e);  
             e.printStackTrace();  
         }  
         return result;  
}

private static void trustAllHttpsCertificates() throws Exception {  
    javax.net.ssl.TrustManager\[\] trustAllCerts = new javax.net.ssl.TrustManager\[1\];  
    javax.net.ssl.TrustManager tm = new miTM();  
    trustAllCerts\[0\] = tm;  
    javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext  
            .getInstance("SSL");  
    sc.init(null, trustAllCerts, null);  
    HttpsURLConnection.setDefaultSSLSocketFactory(sc  
            .getSocketFactory());  
}

static class miTM implements javax.net.ssl.TrustManager,  
    javax.net.ssl.X509TrustManager {  
    public java.security.cert.X509Certificate\[\] getAcceptedIssuers() {  
        return null;  
    }

    public boolean isServerTrusted(  
            java.security.cert.X509Certificate\[\] certs) {  
        return true;  
    }

    public boolean isClientTrusted(  
            java.security.cert.X509Certificate\[\] certs) {  
        return true;  
    }

    public void checkServerTrusted(  
            java.security.cert.X509Certificate\[\] certs, String authType)  
            throws java.security.cert.CertificateException {  
        return;  
    }

    public void checkClientTrusted(  
            java.security.cert.X509Certificate\[\] certs, String authType)  
            throws java.security.cert.CertificateException {  
        return;  
    }  
}

public static void main(String\[\] args) throws Exception {  
    String filePath = "d:/mv1.jpg";  
    String token="Jdr\_B5dQzbWlmmTAlMxbpOZiUfe100laWKeNjRgqfYAJ2GkgCdbQCQO4gAA6e0qd7uYM8fhhzx9ehQBCHlQvKQ";  
    String result = null;  
    FileUpload fileUpload = new FileUpload();  
    result = fileUpload.uploadFile(token, filePath, "image");  
    System.out.println(result);  
}  

}