微信开发者模式实现图文消息发送

公众号类型

测试号

测试号现在仅支持使用预览接口,并不能实现群发。

微信开发者模式实现图文消息发送

【图片来源:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1481187827_i0l21截图】

实现

基于springboot

微信开发者模式实现图文消息发送

微信开发者模式实现图文消息发送

前端是自己根据图文消息(Article)的格式设计的,Article的内容如下:

微信开发者模式实现图文消息发送

【图片来源:官方文档截图】

 

1. 上传内容图片获取URL

微信开发者模式实现图文消息发送

【图片来源:官方文档截图】

前端使用bootstrap-fileinput上传图片,传到后台获取URL,然后将URL作为图片链接,放入wangEditor编辑器中。

(此处仅提供图片素材上传功能,暂未考虑视频、音频素材)

微信开发者模式实现图文消息发送

微信开发者模式实现图文消息发送

微信开发者模式实现图文消息发送

【注意:通过获取的微信服务器的URL插入编辑器时,可能会出现”未经允许“的图案,只需在当前html中加入

<meta name="referrer" content="never">

即可】

后台代码如下:

    @PostMapping(value = "/wx/upload/img")
    @ResponseBody
    public String uploadImg(MultipartFile img) throws IOException {
        JsonResult res = ResultUtil.success();
        String url = wxService.postImg(img);
        if (null != url) {
            res.setData(url);
        } else {
            res = ResultUtil.error(ResultEnum.UPLOAD_IMG_FAILURE);
        }
        return res.toString();
    }

     /**
     * 上传图文信息图片
     *
     * @param img 图片
     * @return url
     */
    @Override
    @Nullable
    public String postImg(MultipartFile img) throws IOException {
        // 保存到本地,获取本地图片绝对路径
        String filePath = FileUtil.saveFile("TEMP", img, "TEMP_"+DataUtil.getTimeStringSixBit()+DataUtil.getRandom(6)+".jpg");
        JSONObject res = doPostForm(UPLOAD_IMG_URL.replace("ACCESS_TOKEN", wxTokenHelper.getToken().getToken()), filePath);
        return res.getString("url");
    }

    /**
     * POST请求 - Form格式数据
     *
     * @param url 请求地址
     * @param filePath 文件本地路径
     * @return
     */
    public JSONObject doPostForm(String url, String filePath) throws IOException {
        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");
        con.setDoInput(true);
        con.setDoOutput(true);
        con.setUseCaches(false);

        // 设置请求头信息
        con.setRequestProperty("Connection", "Keep-Alive");
        con.setRequestProperty("Charset", "UTF-8");

        // 设置边界
        String BOUNDARY = "----------" + System.currentTimeMillis();
        con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);

        String sb = "--" +
                BOUNDARY +
                "\r\n" +
                "Content-Disposition: form-data;name=\"file\";filename=\"" + file.getName() + "\"\r\n" +
                "Content-Type:application/octet-stream\r\n\r\n";

        byte[] head = sb.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();

        StringBuilder buffer = new StringBuilder();
        BufferedReader reader = null;
        String result = null;
        try {
            // 定义BufferedReader输入流来读取URL的响应
            reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                buffer.append(line);
            }
            result = buffer.toString();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                reader.close();
            }
        }

        return JSONObject.parseObject(result);
    }

    

 

2. 上传图文消息素材,得到media_id

微信开发者模式实现图文消息发送

【图片来源:官方文档截图】

     /**
     * 上传图文消息素材
     *
     * @param articles 图文消息集合
     * @return media_id
     */
    @Override
    @Nullable
    public String postNews(Article[] articles) {
        JSONObject data = new JSONObject();
        data.put("articles", articles);
        JSONObject res = doPostStr(UPLOAD_NEWS_URL.replace("ACCESS_TOKEN", wxTokenHelper.getToken().getToken()), data.toJSONString());
        return res.getString("media_id");
    }

    /**
     * POST请求 - JSON格式数据
     *
     * @param url
     * @param outStr
     * @return
     */
    public JSONObject doPostStr(String url, String outStr) {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Content-Type", "application/json;charset=UTF-8");// 解决请求乱码问题
        String response = restTemplate.postForEntity(url, new HttpEntity<String>(outStr, headers), String.class)
                .getBody();
        return JSON.parseObject(response);
    }

    /**
 * @author kingsong
 * @create 2018/9/26 9:00
 * @desc 图文消息【推送】实体类
 **/
public class Article {

    private String thumb_media_id;  // 图文消息缩略图media_id

    private String author;  // 图文消息作者

    private String title;  // 图文消息标题

    private String content_source_url;  // “阅读原文”链接,受安全限制,如需跳转Appstore,可以使用itun.es或appsto.re的短链服务,并在短链后增加 #wechat_redirect 后缀。

    private String content;  // 消息内容,支持HTML标签

    private String digest;  // 推送描述,如本字段为空,则默认抓去正文的前64个字

    private int show_cover_pic;  // 是否显示封面

    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 getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    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 int getShow_cover_pic() {
        return show_cover_pic;
    }

    public void setShow_cover_pic(int show_cover_pic) {
        this.show_cover_pic = show_cover_pic;
    }

}

 

3. 发送图文消息

测试号目前仅支持预览接口

微信开发者模式实现图文消息发送

【图片来源:官方文档截图】

后台代码如下:

    @PostMapping(value = "/wx/send/new")
    @ResponseBody
    public String sendNew(String media_id) throws Exception {
        JsonResult res = ResultUtil.success();
        res.setData(wxService.sendNewsByOpenIds(userService.getAllOpenIds(), media_id));
        return res.toString();
    }

    /**
     * 根OpenID群发图文消息
     *
     * @param openIds OpenID集合
     * @param media_id 图文消息媒体编号
     * @return msg_id
     * @throws Exception 发送失败
     */
    @Override
    public String sendNewsByOpenIds(List<String> openIds, String media_id) throws Exception {
        JSONObject data = new JSONObject();
        // 预览接口仅支持一个openID
        data.put("touser", openIds.get(0));
        Map<String, String> npnews = new HashMap<>();
        npnews.put("media_id", media_id);
        data.put("mpnews", npnews);
        data.put("msgtype", "mpnews");
        data.put("send_ignore_reprint", 0);
        JSONObject res = doPostStr(SEND_NEWS_URL.replace("ACCESS_TOKEN", wxTokenHelper.getToken().getToken()), data.toJSONString());
        if(0!=res.getIntValue("errcode")) {
            // 发送失败
            throw new CustomException(ResultEnum.SEND_NEWS_FAILURE);
        } else {
            return res.getString("msg_id");
        }
    }

若出现错误情况,可以查阅微信公众平台技术文档 - 全局返回码说明