Java企业微信开发_05_消息推送之发送消息(主动)

  • Post author:
  • Post category:java


一、本节要点

1.发送消息与被动回复消息

(1)流程不同:发送消息是第三方服务器主动通知微信服务器向用户发消息。而被动回复消息是 用户发送消息之后,微信服务器将消息传递给 第三方服务器,第三方服务器接收到消息后,再对消息做出相应的回复消息。

(2)消息是否加密:在发送消息的流程中,对封装好的回复消息(json字符串)是不进行AES加密的。

而在被动回复消息的流程中,第三方服务器接收消息时,需要先解密微信发过来的消息,在最后发送回复消息前,需要先加密(AES)回复消息。

(3)数据交换的格式不同:在发送消息的流程中,第三方服务器将消息(json字符串格式)发送给微信服务器

而在被动回复消息的过程中,第三方服务器接收的消息和被动回复的消息都是以xml字符串格式的。

二、代码实现

1.实体类

1.1 消息基类(企业号 -> 普通用户) ——BaseMessage


package com.ray.pojo.message.send;  
  
/**
 * 消息基类(企业号 -> 普通用户) 
 * @author shirayner
 *
 */
public class BaseMessage {  
    // 否 成员ID列表(消息接收者,多个接收者用‘|’分隔,最多支持1000个)。特殊情况:指定为@all,则向该企业应用的全部成员发送
    private String touser;  
    // 否 部门ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
    private String toparty;  
    // 否 标签ID列表,多个接收者用‘|’分隔,最多支持100个。当touser为@all时忽略本参数
    private String totag;  
    // 是 消息类型 
    private String msgtype; 
    // 是 企业应用的id,整型。可在应用的设置页面查看
    private int agentid;
    
    
    public String getTouser() {
        return touser;
    }
    public void setTouser(String touser) {
        this.touser = touser;
    }
    public String getToparty() {
        return toparty;
    }
    public void setToparty(String toparty) {
        this.toparty = toparty;
    }
    public String getTotag() {
        return totag;
    }
    public void setTotag(String totag) {
        this.totag = totag;
    }
    public String getMsgtype() {
        return msgtype;
    }
    public void setMsgtype(String msgtype) {
        this.msgtype = msgtype;
    }
    public int getAgentid() {
        return agentid;
    }
    public void setAgentid(int agentid) {
        this.agentid = agentid;
    }

    
 
    
    
}  


View Code

1.2 文本消息——Text、TextMessage

企业微信官方文档中关于文本消息请求包的说明

{
   "touser" : "UserID1|UserID2|UserID3",
   "toparty" : " PartyID1|PartyID2 ",
   "totag" : " TagID1 | TagID2 ",
   "msgtype" : "text",
   "agentid" : 1,
   "text" : {
       "content" : "你的快递已到,请携带工卡前往邮件中心领取。\n出发前可查看<a href=\"http://work.weixin.qq.com\">邮件中心视频实况</a>,聪明避开排队。"
   },
   "safe":0
}

可把整个json对象看做一个java对象,而在这个json对象中又包含一个text对象。(

json中的对象用{ }包裹起来,json中的数组用[  ] 包裹起来

需注意agentid、safe为int型。于是可以把text看做一个java对象,这样TextMessage类组合了Text类,转json字符串的时候,就可以直接使用 String jsonTextMessage=gson.toJson(textMessage).

于是,我们开始对文本消息进行封装

Text.java


package com.ray.pojo.message.send;

/**
 * 文本
 * @author shirayner
 *
 */
public class Text {
    //是    消息内容,最长不超过2048个字节
    private String content;

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }



}


View Code

TextMessage.java


package com.ray.pojo.message.send;  
  
/**
 * 文本消息
 * @author shirayner
 *
 */
public class TextMessage extends BaseMessage {  
    //文本
    private Text text;
    //否     表示是否是保密消息,0表示否,1表示是,默认0
    private int safe;
    
    public Text getText() {
        return text;
    }
    public void setText(Text text) {
        this.text = text;
    }
    public int getSafe() {
        return safe;
    }
    public void setSafe(int safe) {
        this.safe = safe;
    }
    
    
  
   
}  


View Code

1.3 图片类、语音类、文件类——Media

通过对微信官方文档的仔细阅读,可以看到图片消息、语音消息、文件消息中的的json对象都内含同一个Jason对象(media_id),于是我们根据这个对象封装Media.java


package com.ray.pojo.message.send;

/**
 * 图片、语音、文件
 * @author shirayner
 *
 */
public class Media {
    //是     图片/语音/文件 媒体文件id,可以调用上传临时素材接口获取
    private String media_id;

    public String getMedia_id() {
        return media_id;
    }

    public void setMedia_id(String media_id) {
        this.media_id = media_id;
    }    
    
    
}


View Code

1.3.1 图片消息——ImgMessage


package com.ray.pojo.message.send;  
  
/**
 * 图片消息
 * @author shirayner
 *
 */
public class ImgMessage extends BaseMessage {  
    //图片
    private Media image ;
    //否     表示是否是保密消息,0表示否,1表示是,默认0
    private int safe;
    
    public Media getImage() {
        return image;
    }
    public void setImage(Media image) {
        this.image = image;
    }
    public int getSafe() {
        return safe;
    }
    public void setSafe(int safe) {
        this.safe = safe;
    }

   
}  


View Code

1.3.2 语音消息——VoiceMessage


package com.ray.pojo.message.send;  
  
/**
 * 语音消息
 * @author shirayner
 *
 */
public class VoiceMessage extends BaseMessage {  
    //语音
    private Media voice ;
    //否     表示是否是保密消息,0表示否,1表示是,默认0
    private int safe;
    
    public Media getVoice() {
        return voice;
    }
    public void setVoice(Media voice) {
        this.voice = voice;
    }
    public int getSafe() {
        return safe;
    }
    public void setSafe(int safe) {
        this.safe = safe;
    }
   
    

   
}  


View Code

1.3.3 文件消息——FileMessage


package com.ray.pojo.message.send;  
  
/**
 * 文件消息
 * @author shirayner
 *
 */
public class FileMessage extends BaseMessage {  
    //文件
    private Media file ;
    //否     表示是否是保密消息,0表示否,1表示是,默认0
    private int safe;
   
    public Media getFile() {
        return file;
    }
    public void setFile(Media file) {
        this.file = file;
    }
    public int getSafe() {
        return safe;
    }
    public void setSafe(int safe) {
        this.safe = safe;
    }
   
    

   
}  


View Code

1.4  视频消息——Video、VideoMessage

Video.java


package com.ray.pojo.message.send;

/**
 * 视频
 * @author shirayner
 *
 */
public class Video {
    //是     视频媒体文件id,可以调用上传临时素材接口获取
    private String media_id;    
    //否     视频消息的标题,不超过128个字节,超过会自动截断
    private String title;
    //否     视频消息的描述,不超过512个字节,超过会自动截断
    private String description;
    
    public String getMedia_id() {
        return media_id;
    }
    public void setMedia_id(String media_id) {
        this.media_id = media_id;
    }
    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;
    }    
    
    
}


View Code

VideoMessage.java


package com.ray.pojo.message.send;  
  
/**
 * 视频消息
 * @author shirayner
 *
 */
public class VideoMessage extends BaseMessage {  
    //视频
    private Video video ;
    //否     表示是否是保密消息,0表示否,1表示是,默认0
    private int safe;
    
    public Video getVideo() {
        return video;
    }
    public void setVideo(Video video) {
        this.video = video;
    }
    public int getSafe() {
        return safe;
    }
    public void setSafe(int safe) {
        this.safe = safe;
    }

}  


View Code

1.5 文本卡片消息——Textcard、TextcardMessage

Textcard.java


package com.ray.pojo.message.send;

/**
 * 文本卡片
 * @author shirayner
 *
 */
public class Textcard {
    //是 标题,不超过128个字节,超过会自动截断
    private String title;    
    //是    描述,不超过512个字节,超过会自动截断
    private String description;    
    //是    点击后跳转的链接。
    private String url;
    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;
    }
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }    
    
    
}


View Code

TextcardMessage.java


package com.ray.pojo.message.send;  
  
/**
 * 文本卡片消息
 * @author shirayner
 *
 */
public class TextcardMessage extends BaseMessage {  
    //文本
    private Textcard textcard;
    
    //btntxt    否    按钮文字。 默认为“详情”, 不超过4个文字,超过自动截断。
    
    public Textcard getTextcard() {
        return textcard;
    }

    public void setTextcard(Textcard textcard) {
        this.textcard = textcard;
    }
   

   
}  


View Code

1.6 图文消息——Article、News、NewsMessage

企业微信官方文档中关于图文消息请求包的说明:

{
   "touser" : "UserID1|UserID2|UserID3",
   "toparty" : " PartyID1 | PartyID2 ",
   "totag" : " TagID1 | TagID2 ",
   "msgtype" : "news",
   "agentid" : 1,
   "news" : {
       "articles" : [
           {
               "title" : "中秋节礼品领取",
               "description" : "今年中秋节公司有豪礼相送",
               "url" : "URL",
               "picurl" : "http://res.mail.qq.com/node/ww/wwopenmng/images/independent/doc/test_pic_msg1.png"
           }
        ]
   }
}

可以看到NewsMessage类组合了News类,News类组合了List<Aticle> articles(即Article数组),于是得到以下实体类。

Article.java


package com.ray.pojo.message.send;

/**
 * 文章
 * @author shirayner
 *
 */
public class Article {
    //是    标题,不超过128个字节,超过会自动截断
    private String title;    
    //否    描述,不超过512个字节,超过会自动截断
    private String description;    
    //是    点击后跳转的链接。
    private String url;    
    //否    图文消息的图片链接,支持JPG、PNG格式,较好的效果为大图640320,小图8080。
    private String picurl;
    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;
    }
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    public String getPicurl() {
        return picurl;
    }
    public void setPicurl(String picurl) {
        this.picurl = picurl;
    }    
    
    
}


View Code

News.java


package com.ray.pojo.message.send;

import java.util.List;

/**
 * 图文
 * @author shirayner
 *
 */
public class News {
     //文章列表
     private List<Article> articles;

    public List<Article> getArticles() {
        return articles;
    }

    public void setArticles(List<Article> articles) {
        this.articles = articles;
    }
     
     
}


View Code

NewsMessage.java


package com.ray.pojo.message.send;  

  
/**
 * 图文消息
 * @author shirayner
 *
 */
public class NewsMessage extends BaseMessage {  
    //图文
    private News news;

    public News getNews() {
        return news;
    }

    public void setNews(News news) {
        this.news = news;
    }
    


}  


View Code

2.发送消息业务类——

SendMessageService


package com.ray.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.sf.json.JSONObject;

import com.google.gson.Gson;
import com.ray.pojo.message.send.BaseMessage;

import com.ray.test.UserTest;
import com.ray.util.WeiXinUtil;

/**@desc  : 发送消息
 * 
 * @author: shirayner
 * @date  : 2017-8-18 上午10:06:23
 */
public class SendMessageService {
    private static Logger log = LoggerFactory.getLogger(UserTest.class);  

    private  static  String sendMessage_url="https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=ACCESS_TOKEN";  

    /**
     * @desc :0.公共方法:发送消息
     *  
     * @param accessToken
     * @param message void
     */
    public void sendMessage(String accessToken,BaseMessage message){

        //1.获取json字符串:将message对象转换为json字符串    
        Gson gson = new Gson(); 
        String jsonMessage =gson.toJson(message);      //使用gson.toJson(user)即可将user对象顺序转成json
        System.out.println("jsonTextMessage:"+jsonMessage);


        //2.获取请求的url  
        sendMessage_url=sendMessage_url.replace("ACCESS_TOKEN", accessToken);

        //3.调用接口,发送消息
        JSONObject jsonObject = WeiXinUtil.httpRequest(sendMessage_url, "POST", jsonMessage);  
        System.out.println("jsonObject:"+jsonObject.toString());

        //4.错误消息处理
        if (null != jsonObject) {  
            if (0 != jsonObject.getInt("errcode")) {  
                log.error("创建成员失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));  
            }  
        }  
    }
    
    
    
    
}


View Code

3.发送消息测试类——SendMessageTest


package com.ray.test;

import java.util.ArrayList;
import java.util.List;

import org.junit.Test;


import com.ray.pojo.message.send.Article;
import com.ray.pojo.message.send.FileMessage;
import com.ray.pojo.message.send.ImgMessage;
import com.ray.pojo.message.send.Media;
import com.ray.pojo.message.send.News;
import com.ray.pojo.message.send.NewsMessage;
import com.ray.pojo.message.send.Text;
import com.ray.pojo.message.send.TextMessage;
import com.ray.pojo.message.send.Textcard;
import com.ray.pojo.message.send.TextcardMessage;
import com.ray.pojo.message.send.Video;
import com.ray.pojo.message.send.VideoMessage;
import com.ray.pojo.message.send.VoiceMessage;
import com.ray.service.SendMessageService;
import com.ray.util.WeiXinParamesUtil;
import com.ray.util.WeiXinUtil;

/**@desc  : 消息推送之发送消息
 * 
 * @author: shirayner
 * @date  : 2017-8-18 上午10:04:55
 */
public class SendMessageTest {

    //1.发送文本消息
    @Test
    public void testSendTextMessage(){
        //0.设置消息内容
        String content="你的快递已到,请携带工卡前往邮件中心领取。\n出发前可查看" +
                "<a href=\"http://work.weixin.qq.com\">邮件中心视频实况" +
                "</a>,聪明避开排队。";

        //1.创建文本消息对象
        TextMessage message=new TextMessage();
        //1.1非必需
        message.setTouser("@all");  //不区分大小写
        //textMessage.setToparty("1");
        //txtMsg.setTotag(totag);
        //txtMsg.setSafe(0);

        //1.2必需
        message.setMsgtype("text");
        message.setAgentid(WeiXinParamesUtil.agentId);

        Text text=new Text();
        text.setContent(content);
        message.setText(text);

        //2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
        String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
        System.out.println("accessToken:"+accessToken);

        //3.发送消息:调用业务类,发送消息
        SendMessageService sms=new SendMessageService();
        sms.sendMessage(accessToken, message);

    }

    //2.发送文本卡片消息
    @Test
    public void testSendTextcardMessage(){
        //0.设置消息内容
        String title="代办事宜";
        String description="<div class=\"gray\">2017年8月18日</div> <div class=\"normal\">" +
                "恭喜你抽中iPhone 7一台,领奖码:xxxx</div><div class=\"highlight\">" +
                "请于2017年10月10日前联系行政同事领取</div>";
        String url="http://www.cnblogs.com/shirui/p/7297872.html";

        //1.创建文本卡片消息对象
        TextcardMessage message=new TextcardMessage();
        //1.1非必需
        message.setTouser("shirui");  //不区分大小写
        //message.setToparty("1");
        //message.setTotag(totag);
        //message.setSafe(0);

        //1.2必需
        message.setMsgtype("textcard");
        message.setAgentid(WeiXinParamesUtil.agentId);

        Textcard textcard=new Textcard();
        textcard.setTitle(title);
        textcard.setDescription(description);
        textcard.setUrl(url);
        message.setTextcard(textcard);

        //2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
        String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
        System.out.println("accessToken:"+accessToken);

        //3.发送消息:调用业务类,发送消息
        SendMessageService sms=new SendMessageService();
        sms.sendMessage(accessToken, message);

    }

    //3.发送图片消息---无效的media_id
    @Test
    public void testSendImgMessage(){
        //0.设置消息内容
        String media_;
        //1.创建图片消息对象
        ImgMessage message=new ImgMessage();
        //1.1非必需
        message.setTouser("@all");  //不区分大小写
        //textMessage.setToparty("1");
        //txtMsg.setTotag(totag);
        //txtMsg.setSafe(0);

        //1.2必需
        message.setMsgtype("image");
        message.setAgentid(WeiXinParamesUtil.agentId);

        Media image=new Media();
        image.setMedia_id(media_id);
        message.setImage(image);

        //2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
        String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
        System.out.println("accessToken:"+accessToken);

        //3.发送消息:调用业务类,发送消息
        SendMessageService sms=new SendMessageService();
        sms.sendMessage(accessToken, message);

    }


    //4.发送语音消息---无效的media_id
    @Test
    public void testSendVoiceMessage(){
        //0.设置消息内容
        String media_;
        //1.创建语音消息对象
        VoiceMessage message=new VoiceMessage();
        //1.1非必需
        message.setTouser("@all");  //不区分大小写
        //textMessage.setToparty("1");
        //txtMsg.setTotag(totag);
        //txtMsg.setSafe(0);

        //1.2必需
        message.setMsgtype("image");
        message.setAgentid(WeiXinParamesUtil.agentId);

        Media voice=new Media();
        voice.setMedia_id(media_id);
        message.setVoice(voice);

        //2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
        String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
        System.out.println("accessToken:"+accessToken);

        //3.发送消息:调用业务类,发送消息
        SendMessageService sms=new SendMessageService();
        sms.sendMessage(accessToken, message);

    }

    //5.发送视频消息
    @Test
    public void testSendVideoMessage(){
        //0.设置消息内容
        String media_;
        String title="视频示例";
        String description="好看的视频";


        //1.创建视频消息对象
        VideoMessage message=new VideoMessage();
        //1.1非必需
        message.setTouser("@all");  //不区分大小写
        //message.setToparty("1");
        //message.setTotag(totag);
        //message.setSafe(0);

        //1.2必需
        message.setMsgtype("video");
        message.setAgentid(WeiXinParamesUtil.agentId);

        Video video=new Video();
        video.setMedia_id(media_id);
        video.setTitle(title);
        video.setDescription(description);
        message.setVideo(video);

        //2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
        String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
        System.out.println("accessToken:"+accessToken);

        //3.发送消息:调用业务类,发送消息
        SendMessageService sms=new SendMessageService();
        sms.sendMessage(accessToken, message);

    }

    //6.发送文件消息
    @Test
    public void testSendFileMessage(){
        //0.设置消息内容
        String media_;

        //1.创建文件对象
        FileMessage message=new FileMessage();
        //1.1非必需
        message.setTouser("@all");  //不区分大小写
        //textMessage.setToparty("1");
        //txtMsg.setTotag(totag);
        //txtMsg.setSafe(0);

        //1.2必需
        message.setMsgtype("file");
        message.setAgentid(WeiXinParamesUtil.agentId);

        Media file=new Media();
        file.setMedia_id(media_id);
        message.setFile(file);

        //2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
        String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
        System.out.println("accessToken:"+accessToken);

        //3.发送消息:调用业务类,发送消息
        SendMessageService sms=new SendMessageService();
        sms.sendMessage(accessToken, message);

    }

    //7.发送图文消息
    @Test
    public void testSendNewsMessage(){

        //1.创建图文消息对象
        NewsMessage message=new NewsMessage();
        //1.1非必需
        message.setTouser("@all");  //不区分大小写
        //textMessage.setToparty("1");
        //txtMsg.setTotag(totag);
        //txtMsg.setSafe(0);

        //1.2必需
        message.setMsgtype("news");
        message.setAgentid(WeiXinParamesUtil.agentId);
        //设置图文消息
        Article article1=new  Article();
        article1.setTitle("青年文摘");
        article1.setDescription("这是一个很特别的描述");
        article1.setPicurl("http://mat1.gtimg.com/fashion/images/index/2017/08/18/tpzs2.jpg");
        article1.setUrl("http://www.cnblogs.com/shirui/p/7297872.html");
        
        List<Article>  articles=new ArrayList<Article>();
        articles.add(article1);
        
        News news=new News();
        news.setArticles(articles);
        message.setNews(news);

        //2.获取access_token:根据企业id和通讯录密钥获取access_token,并拼接请求url
        String accessToken= WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
        System.out.println("accessToken:"+accessToken);

        //3.发送消息:调用业务类,发送消息
        SendMessageService sms=new SendMessageService();
        sms.sendMessage(accessToken, message);

    }




}


View Code