2017-08-08 17:04:13 somehow1002 阅读数 1658
  • 微信公众平台开发4-消息管理-微信开发php

    微信公众平台开发之消息管理是子恒老师《微信公众平台开发》视频教程的第4部。详细讲解了用php开发微信,对微信公众平台中的消息管理开发。内容包含微信关键字回复,多图文消息回复开发,接收图片消息,视频,小视频消息等等。欢迎反馈,微信/QQ:68183131

    6302 人正在学习 去看看 秦子恒

微信开发中的消息验证与消息回复

处理逻辑

  1. 判断微信服务器传来的数据是否含有名为echostr的GET参数
  2. 有则进行服务器消息验证(valid)
  3. 没有则微信推送过来的是一条消息,需要我们处理。
    消息类型分为
    1)事件类型:用户关注/取消关注事件、扫描二维码事件……
    2)被动回复类型:用户发送过来一条文字、图片、语音……
    然后根据需求回复相应的文字、图片、图文….

代码示例

<?php
define("TOKEN","###your token###");
require_once 'response.class.php';

$res=new response();
if(!isset($_GET['echostr'])){
    responseMsg();
}else{
    valid();
}

function valid(){
    /* @微信服务器消息验证
     *
     * 1)将token、timestamp、nonce三个参数进行字典序排序
     * 2)将三个参数字符串拼接成一个字符串进行sha1加密
     * 3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
     *
     * */
    $echoStr=$_GET['echostr'];
    $signature=$_GET['signature'];
    $timestamp=$_GET['timestamp'];
    $nonce=$_GET['nonce'];
    $token=TOKEN;
    $tmpArr=array($token,$timestamp,$nonce);
    sort($tmpArr,SORT_STRING);
    $tmpStr=implode($tmpArr);
    $tmpStr=sha1($tmpStr);
    if($tmpStr==$signature){
        echo $echoStr;
        exit();
    }
}

function responseMsg(){
    /* @获取微信推送过来的post数据(xml)
     * 
     * 以下旧的提取方式,php高版本已经废弃了
     * $postStr=$GLOBALS['HTTP_RAW_POST_DATA'];
     * 
     * */
    $postStr=file_get_contents("php://input");

    /* @将xml数据转化为obj
     * 
     * */
    $postObj=simplexml_load_string($postStr,'SimpleXMLElement',LIBXML_NOCDATA);

    /* @根据接收到的不同消息,进行相应回复
     * 1.用户关注事件
     * 2.用户发送消息被动回复
     * 
     * */
    if(strtolower($postObj->MsgType)=='event'){
        if(strtolower($postObj->Event)=='subscribe'){//用户关注事件
            $content="欢迎关注XXXX";
            responseText($postObj, $content);
        }
    }else if(strtolower($postObj->MsgType)=='text'){
        switch(trim($postObj->Content)){
            /*被动回复文本信息*/
            case 'test':
                $content="this is test!";
                responseText($postObj, $content);
                break;
            case 'time':
                $content="现在是北京时间:".date("Y-m-d H:i:s",time());
                responseText($postObj, $content);
                break;
            case 'website':
                $content="<a href='http://www.hewie.cn'>乘风破浪</a>";
                responseText($postObj, $content);
                break;
            /*被动回复图文信息*/
            case 'news':
                $arr=array(
                    array(
                    'title'=>'我的csdn博客',
                    'description'=>'欢迎访问我的csdn博客',
                    'picUrl'=>'http://avatar.csdn.net/9/5/4/1_somehow1002.jpg',
                    'url'=>'http://blog.csdn.net/somehow1002',
                    ),
                    array(
                    'title'=>'开源中国',
                    'description'=>'。。。。。',
                    'picUrl'=>'https://www.oschina.net/img/ie/logo_osc.png','',
                    'url'=>'https://www.oschina.net/',
                    ),
                );
                responseNews($postObj, $arr);
                break;
            default:
                $content="sorry, I don't understand!";
                $res->responseText($postObj, $content);
                break;
        }
    }
}

function responseText($postObj,$content){
    /* @文字消息回复格式
     * 
     * <xml>
     * <ToUserName><![CDATA[toUser]]></ToUserName>
     * <FromUserName><![CDATA[fromUser]]></FromUserName>
     * <CreateTime>12345678</CreateTime>
     * <MsgType><![CDATA[text]]></MsgType>
     * <Content><![CDATA[你好]]></Content>
     * </xml>
     * 
     * */
    $fromUserName=$postObj->ToUserName;
    $toUserName=$postObj->FromUserName;
    $time=time();
    $msgType='text';
    $template="<xml>
                    <ToUserName><![CDATA[%s]]></ToUserName>
                    <FromUserName><![CDATA[%s]]></FromUserName>
                    <CreateTime>%s</CreateTime>
                    <MsgType><![CDATA[%s]]></MsgType>
                    <Content><![CDATA[%s]]></Content>
                    </xml>";
    echo sprintf($template,$toUserName,$fromUserName,$time,$msgType,$content);
}

function responseNews($postObj,$arr){
    /* @图文消息回复格式
     * #一个item一则图文消息
     * 
     * <xml>
     * <ToUserName><![CDATA[toUser]]></ToUserName>
     * <FromUserName><![CDATA[fromUser]]></FromUserName>
     * <CreateTime>12345678</CreateTime>
     * <MsgType><![CDATA[news]]></MsgType>
     * <ArticleCount>2</ArticleCount>
     * <Articles>
     * <item>
     * <Title><![CDATA[title1]]></Title>
     * <Description><![CDATA[description1]]></Description>
     * <PicUrl><![CDATA[picurl]]></PicUrl>
     * <Url><![CDATA[url]]></Url>
     * </item>
     * <item>
     * <Title><![CDATA[title]]></Title>
     * <Description><![CDATA[description]]></Description>
     * <PicUrl><![CDATA[picurl]]></PicUrl>
     * <Url><![CDATA[url]]></Url>
     * </item>
     * </Articles>
     * </xml>
     * 
     * */
    $fromUserName=$postObj->ToUserName;
    $toUserName=$postObj->FromUserName;
    $time=time();
    $msgType='text';
    $template="<xml>
                    <ToUserName><![CDATA[%s]]></ToUserName>
                    <FromUserName><![CDATA[%s]]></FromUserName>
                    <CreateTime>%s</CreateTime>
                    <MsgType><![CDATA[news]]></MsgType>
                    <ArticleCount>".count($arr)."</ArticleCount>
                    <Articles>";
    foreach($arr as $v){
        $template.="
                    <item>
                    <Title><![CDATA[".$v[title]."]]></Title>
                    <Description><![CDATA[".$v[description]."]]></Description>
                    <PicUrl><![CDATA[".$v['picUrl']."]]></PicUrl>
                    <Url><![CDATA[".$v[url]."]]></Url>
                    </item>";
    }
    $template.="
                    </Articles>
                    </xml>";
    echo sprintf($template,$toUserName,$fromUserName,time());
}

参考微信开发手册
原文地址:http://blog.csdn.net/somehow1002/article/details/76919270
个人见解,如有错误之处,欢迎指正。

2017-09-19 11:28:26 tanglei6636 阅读数 471
  • 微信公众平台开发4-消息管理-微信开发php

    微信公众平台开发之消息管理是子恒老师《微信公众平台开发》视频教程的第4部。详细讲解了用php开发微信,对微信公众平台中的消息管理开发。内容包含微信关键字回复,多图文消息回复开发,接收图片消息,视频,小视频消息等等。欢迎反馈,微信/QQ:68183131

    6302 人正在学习 去看看 秦子恒

1、简介:
本文以捕捉并回复文本消息以及关注事件为例,介绍微信的消息接受与回复机制;
当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上;

数据交互模型:
1

微信消息接受与回复流程图:
2

2、参数说明:
消息类型
3

事件类型
4

3、代码实现:
5

当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。我们获取POST请求里面的信息,取msgType判断是什么类型的消息,如果是事件(event)类型消息的话就再取其event属性判断是什么类型事件,以此进行相应操作;

2017-04-22 12:10:27 hq0556 阅读数 1399
  • 微信公众平台开发4-消息管理-微信开发php

    微信公众平台开发之消息管理是子恒老师《微信公众平台开发》视频教程的第4部。详细讲解了用php开发微信,对微信公众平台中的消息管理开发。内容包含微信关键字回复,多图文消息回复开发,接收图片消息,视频,小视频消息等等。欢迎反馈,微信/QQ:68183131

    6302 人正在学习 去看看 秦子恒

本例中有些引用的类与方法不做过多介绍,之后会提供完整源码下载,请自行查看。

本篇根据开发者文档-被动回复用户消息编写。请对照查看,一些传入与返回参数就不过多介绍。地址为:https://mp.weixin.qq.com/wiki/18/c66a9f0b5aa952346e46dc39de20f672.html


简述

当用户发送消息给公众号时(或某些特定的用户操作引发的事件推送时),会产生一个POST请求,开发者可以在响应包(Get)中返回特定XML结构,来对该消息进行响应(现支持回复文本、图片、图文、语音、视频、音乐)。严格来说,发送被动响应消息其实并不是一种接口,而是对微信服务器发过来消息的一次回复。

微信服务器在将用户的消息发给公众号的开发者服务器地址(开发者中心处配置)后,微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次,如果在调试中,发现用户无法收到响应的消息,可以检查是否消息处理超时。关于重试的消息排重,有msgid的消息推荐使用msgid排重。事件类型消息推荐使用FromUserName + CreateTime 排重。

如果开发者希望增强安全性,可以在开发者中心处开启消息加密,这样,用户发给公众号的消息以及公众号被动回复用户消息都会继续加密(但),详见被动回复消息加解密说明。

假如服务器无法保证在五秒内处理并回复,必须做出下述回复,这样微信服务器才不会对此作任何处理,并且不会发起重试(这种情况下,可以使用客服消息接口进行异步回复),否则,将出现严重的错误提示。
“`
/*
* 被动回复用户消息
* http://mp.weixin.qq.com/wiki/14/89b871b5466b19b3efa4ada8e577d45e.html
*/
public class BaseRespMsg {

public static XStream xstream = XMLUtil.xstream;

private String ToUserName;          // 开发者微信号
private String FromUserName;        // 发送方帐号(一个OpenID)
private long   CreateTime;          // 消息创建时间 (整型)
private String MsgType;             // 消息类型(text/image/location/link)

public String getToUserName() {
    return ToUserName;
}
public void setToUserName(String toUserName) {
    ToUserName = toUserName;
}

public String getFromUserName() {
    return FromUserName;
}
public void setFromUserName(String fromUserName) {
    FromUserName = fromUserName;
}

public long getCreateTime() {
    return CreateTime;
}
public void setCreateTime(long createTime) {
    CreateTime = createTime;
}

public String getMsgType() {
    return MsgType;
}
public void setMsgType(String msgType) {
    MsgType = msgType;
}   

}

“`

回复消息类型

回复文本消息

/*
 * 被动回复用户消息
 * http://mp.weixin.qq.com/wiki/14/89b871b5466b19b3efa4ada8e577d45e.html
 */
public class BaseRespMsg {

    public static XStream xstream = XMLUtil.xstream;

    private String ToUserName;          // 开发者微信号
    private String FromUserName;        // 发送方帐号(一个OpenID)
    private long   CreateTime;          // 消息创建时间 (整型)
    private String MsgType;             // 消息类型(text/image/location/link)

    public String getToUserName() {
        return ToUserName;
    }
    public void setToUserName(String toUserName) {
        ToUserName = toUserName;
    }

    public String getFromUserName() {
        return FromUserName;
    }
    public void setFromUserName(String fromUserName) {
        FromUserName = fromUserName;
    }

    public long getCreateTime() {
        return CreateTime;
    }
    public void setCreateTime(long createTime) {
        CreateTime = createTime;
    }

    public String getMsgType() {
        return MsgType;
    }
    public void setMsgType(String msgType) {
        MsgType = msgType;
    }   
}

回复图片消息

/*
 * MsgType--->
 * image:图片消息
 */
public class ImageRespMsg extends BaseRespMsg {

    private List<Image> Image;

    public List<Image> getImage() {
        if(Image == null) Image = new ArrayList<Image>();
        return Image;
    }
    public void setImage(List<Image> images) {
        Image = images;
    }

    public class Image {
        private String MediaId;     //是 通过素材管理中的接口上传多媒体文件,得到的id

        public String getMediaId() {
            return MediaId;
        }
        public void setMediaId(String mediaId) {
            MediaId = mediaId;
        }
    }

    /*
     * 返回的文本示例
     * <xml>
     *   <ToUserName><![CDATA[toUser]]></ToUserName>
     *   <FromUserName><![CDATA[fromUser]]></FromUserName>
     *   <CreateTime>12345678</CreateTime>
     *   <MsgType><![CDATA[image]]></MsgType>
     *   <Image>
     *       <MediaId><![CDATA[media_id]]></MediaId>
     *   </Image>
     * </xml>
     */
    public static String responseMessage(ImageRespMsg imageMessage) {
        imageMessage.setCreateTime(new Date().getTime());
      imageMessage.setMsgType(WeChatEntitiesType.RESP_MESSAGE_TYPE_IMAGE);

        xstream.alias("xml", imageMessage.getClass());  
        xstream.addImplicitCollection(imageMessage.getClass(), "Image");  
        xstream.alias("Image", imageMessage.new Image().getClass());
        return xstream.toXML(imageMessage);
    }

    public static String test(String xmlStr) {
        String response = "ImageRespMsg-->error";
        try {
            ImageReqMsg imageReqMsg = ImageReqMsg.requestMessage(xmlStr);
            ImageRespMsg imageRespMsg = new ImageRespMsg();
          imageRespMsg.setToUserName(imageReqMsg.getFromUserName());
          imageRespMsg.setFromUserName(imageReqMsg.getToUserName());
            int images = 1;
            for(int i=0; i<images; i++) {
                ImageRespMsg.Image image = imageRespMsg.new Image();
                image.setMediaId(imageReqMsg.getMediaId());
                imageRespMsg.getImage().add(image);
            }
            response = responseMessage(imageRespMsg);
        } catch(Exception e) {
            e.printStackTrace();
        }
        return response;
    }
}

回复语音消息

/*
 * MsgType--->
 * voice:语音消息
 */
public class VoiceRespMsg extends BaseRespMsg {

    private List<Voice> Voice;

    public List<Voice> getVoice() {
        if(Voice == null) Voice = new ArrayList<Voice>();
        return Voice;
    }
    public void setVoice(List<Voice> voice) {
        Voice = voice;
    }

    public class Voice {
        private String MediaId;     //是 通过素材管理中的接口上传多媒体文件,得到的id

        public String getMediaId() {
            return MediaId;
        }
        public void setMediaId(String mediaId) {
            MediaId = mediaId;
        }
    }

    /*
     * 返回的文本示例
     * <xml>
     *   <ToUserName><![CDATA[toUser]]></ToUserName>
     *   <FromUserName><![CDATA[fromUser]]></FromUserName>
     *   <CreateTime>12345678</CreateTime>
     *   <MsgType><![CDATA[voice]]></MsgType>
     *   <Voice>
     *       <MediaId><![CDATA[media_id]]></MediaId>
     *   </Voice>
     * </xml>
     */
    public static String responseMessage(VoiceRespMsg voiceMessage) {
        voiceMessage.setCreateTime(new Date().getTime());
      voiceMessage.setMsgType(WeChatEntitiesType.RESP_MESSAGE_TYPE_VOICE);

        xstream.alias("xml", voiceMessage.getClass());
        xstream.addImplicitCollection(voiceMessage.getClass(), "Voice");  
        xstream.alias("Voice", voiceMessage.new Voice().getClass());
        return xstream.toXML(voiceMessage);
    }

    public static String test(String xmlStr) {
        String response = "VoiceRespMsg-->error";
        try {
            VoiceReqMsg voiceReqMsg = VoiceReqMsg.requestMessage(xmlStr);
            VoiceRespMsg voiceRespMsg = new VoiceRespMsg();
          voiceRespMsg.setToUserName(voiceReqMsg.getFromUserName());
          voiceRespMsg.setFromUserName(voiceReqMsg.getToUserName());
            int voices = 1;
            for(int i=0; i<voices; i++) {
                VoiceRespMsg.Voice voice = voiceRespMsg.new Voice();
                voice.setMediaId(voiceReqMsg.getMediaID());
                voiceRespMsg.getVoice().add(voice);
            }
            response = responseMessage(voiceRespMsg);
        } catch(Exception e) {
            e.printStackTrace();
        }
        return response;
    }
}

回复视频消息

/*
 * MsgType--->
 * video:视频消息
 */
public class VideoRespMsg extends BaseRespMsg {

    private List<Video> Video;

    public List<Video> getVideo() {
        if(Video == null) Video = new ArrayList<Video>();
        return Video;
    }
    public void setImage(List<Video> video) {
        Video = video;
    }

    public class Video {
        private String MediaId;     //是 通过素材管理中的接口上传多媒体文件,得到的id
        private String Title;       //否 视频消息的标题
        private String Description; //否 视频消息的描述

        public String getMediaId() {
            return MediaId;
        }
        public void setMediaId(String mediaId) {
            MediaId = mediaId;
        }

        public String getTitle() {
            return Title;
        }
        public void setTitle(String title) {
            Title = title;
        }

        public String getDescription() {
            return Description;
        }
        public void setDescription(String description) {
            Description = description;
        }
    }

    /*
     * 返回的文本示例
     * <xml>
     *   <ToUserName><![CDATA[toUser]]></ToUserName>
     *   <FromUserName><![CDATA[fromUser]]></FromUserName>
     *   <CreateTime>12345678</CreateTime>
     *   <MsgType><![CDATA[video]]></MsgType>
     *   <Video>
     *      <MediaId><![CDATA[media_id]]></MediaId>
     *      <Title><![CDATA[title]]></Title>
     *      <Description><![CDATA[description]]></Description>
     *   </Video> 
     * </xml>
     */
    public static String responseMessage(VideoRespMsg videoMessage) {
        videoMessage.setCreateTime(new Date().getTime());
      videoMessage.setMsgType(WeChatEntitiesType.RESP_MESSAGE_TYPE_VIDEO);

        xstream.alias("xml", videoMessage.getClass());  
        xstream.addImplicitCollection(videoMessage.getClass(), "Video");  
        xstream.alias("Video", videoMessage.new Video().getClass());
        return xstream.toXML(videoMessage);
    }

    public static String test(String xmlStr) {
        String response = "VideoRespMsg-->error";
        try {
            VideoReqMsg videoReqMsg = VideoReqMsg.requestMessage(xmlStr);
            VideoRespMsg videoRespMsg = new VideoRespMsg();
          videoRespMsg.setToUserName(videoReqMsg.getFromUserName());
          videoRespMsg.setFromUserName(videoReqMsg.getToUserName());
            int videos = 1;
            for(int i=0; i<videos; i++) {
                VideoRespMsg.Video video = videoRespMsg.new Video();
                video.setMediaId(WeChatCertificate.VIDEO_MEDIAID);
                video.setTitle("title");
                video.setDescription("description");
                videoRespMsg.getVideo().add(video);
            }
            response = responseMessage(videoRespMsg);
        } catch(Exception e) {
            e.printStackTrace();
        }
        return response;
    }
}

回复音乐消息

/*
 * MsgType--->
 * music:音乐消息
 */
public class MusicRespMsg extends BaseRespMsg {

    private List<Music> Music;

    public List<Music> getMusic() {
        if(Music == null) Music = new ArrayList<Music>();
        return Music;
    }
    public void setMusic(List<Music> music) {
        Music = music;
    }

    public class Music {
        private String Title;           //否 音乐标题
        private String Description;     //否 音乐描述
        private String MusicUrl;        //否 音乐链接
        private String HQMusicUrl;      //否 高质量音乐链接,WIFI环境优先使用该链接播放音乐
        private String ThumbMediaId;    //是 缩略图的媒体id,通过素材管理中的接口上传多媒体文件,得到的id

        public String getTitle() {
            return Title;
        }
        public void setTitle(String title) {
            Title = title;
        }

        public String getDescription() {
            return Description;
        }
        public void setDescription(String description) {
            Description = description;
        }

        public String getMusicUrl() {
            return MusicUrl;
        }
        public void setMusicUrl(String musicURL) {
            MusicUrl = musicURL;
        }

        public String getHQMusicUrl() {
            return HQMusicUrl;
        }
        public void setHQMusicUrl(String hQMusicUrl) {
            HQMusicUrl = hQMusicUrl;
        }

        public String getThumbMediaId() {
            return ThumbMediaId;
        }
        public void setThumbMediaId(String thumbMediaId) {
            ThumbMediaId = thumbMediaId;
        }
    }

    /*
     * 返回的文本示例
     * <xml>
     *   <ToUserName><![CDATA[toUser]]></ToUserName>
     *   <FromUserName><![CDATA[fromUser]]></FromUserName>
     *   <CreateTime>12345678</CreateTime>
     *   <MsgType><![CDATA[music]]></MsgType>
     *   <Music>
     *      <Title><![CDATA[TITLE]]></Title>
     *      <Description><![CDATA[DESCRIPTION]]></Description>
     *      <MusicUrl><![CDATA[MUSIC_Url]]></MusicUrl>
     *      <HQMusicUrl><![CDATA[HQ_MUSIC_Url]]></HQMusicUrl>
     *      <ThumbMediaId><![CDATA[media_id]]></ThumbMediaId>
     *   </Music>
     * </xml>
     */
    public static String responseMessage(MusicRespMsg musicMessage) {
        musicMessage.setCreateTime(new Date().getTime());
      musicMessage.setMsgType(WeChatEntitiesType.RESP_MESSAGE_TYPE_MUSIC);

        xstream.alias("xml", musicMessage.getClass());
        xstream.addImplicitCollection(musicMessage.getClass(), "Music");  
        xstream.alias("Music", musicMessage.new Music().getClass());
        return xstream.toXML(musicMessage);
    }

    public static String test(String xmlStr) {
        String response = "MusicRespMsg-->error";
        try {
            TextReqMsg textReqMsg = TextReqMsg.requestMessage(xmlStr);
            MusicRespMsg musicRespMsg = new MusicRespMsg();
          musicRespMsg.setToUserName(textReqMsg.getFromUserName());
          musicRespMsg.setFromUserName(textReqMsg.getToUserName());
            int musics = 1;
            for(int i=0; i<musics; i++) {
                MusicRespMsg.Music music = musicRespMsg.new Music();
                music.setTitle("残酷月光");
                music.setDescription(" 林宥嘉 词:向月娥 曲:陈小霞");
                music.setMusicUrl("http://wma.5282.cc/2008-11//20140226/1.mp3");
                music.setHQMusicUrl("http://wma.5282.cc/2008-11//20140226/1.mp3");
                musicRespMsg.getMusic().add(music);
            }
            response = responseMessage(musicRespMsg);
        } catch(Exception e) {
            e.printStackTrace();
        }
        return response;
    }
}

回复图文消息

/*
 * MsgType--->
 * news:图文消息
 */
public class NewsRespMsg extends BaseRespMsg {

    private int ArticleCount;       //是 图文消息个数,限制为10条以内
    private List<Article> Articles; //是 多条图文消息信息,默认第一个item为大图,注意,如果图文数超过10,则将会无响应

    public int getArticleCount() {
        return ArticleCount;
    }
    public void setArticleCount(int articleCount) {
        ArticleCount = articleCount;
    }

    public List<Article> getArticles() {
        if(Articles == null) Articles = new ArrayList<Article>();
        return Articles;
    }
    public void setArticles(List<Article> articles) {
        Articles = articles;
    }

    public class Article{
        private String Title;               //否 图文消息标题
        private String Description;         //否 图文消息描述
        private String PicUrl;              //否 图片链接,支持JPG、PNG格式,较好的效果为大图360*200,小图200*200
        private String Url;                 //否 点击图文消息跳转链接

        public String getTitle() {
            return Title;
        }
        public void setTitle(String title) {
            Title = title;
        }

        public String getDescription() {
            return Description;
        }
        public void setDescription(String description) {
            Description = description;
        }

        public String getPicUrl() {
            return PicUrl;
        }
        public void setPicUrl(String picUrl) {
            PicUrl = picUrl;
        }

        public String getUrl() {
            return Url;
        }
        public void setUrl(String url) {
            Url = url;
        }
    }

    /*
     * 返回的文本示例
     * <xml>
     *   <ToUserName><![CDATA[toUser]]></ToUserName>
     *   <FromUserName><![CDATA[fromUser]]></FromUserName>
     *   <CreateTime>12345678</CreateTime>
     *   <MsgType><![CDATA[news]]></MsgType>
     *   <ArticleCount>2</ArticleCount>
     *   <Articles>
     *      <item>
     *          <Title><![CDATA[title1]]></Title> 
     *          <Description><![CDATA[description1]]></Description>
     *          <PicUrl><![CDATA[picurl]]></PicUrl>
     *          <Url><![CDATA[url]]></Url>
     *      </item>
     *      <item>
     *          <Title><![CDATA[title]]></Title>
     *          <Description><![CDATA[description]]></Description>
     *          <PicUrl><![CDATA[picurl]]></PicUrl>
     *          <Url><![CDATA[url]]></Url>
     *      </item>
     *   </Articles>
     * </xml>
     */
    public static String responseMessage(NewsRespMsg newsMessage) {
        newsMessage.setCreateTime(new Date().getTime());
      newsMessage.setMsgType(WeChatEntitiesType.RESP_MESSAGE_TYPE_NEWS);

        xstream.alias("xml", newsMessage.getClass());
        xstream.alias("item", newsMessage.new Article().getClass());
        return xstream.toXML(newsMessage);
    }

    public static String test(String xmlStr) {
        String response = "NewsRespMsg-->error";
        try {
            TextReqMsg textReqMsg = TextReqMsg.requestMessage(xmlStr);
            NewsRespMsg newsRespMsg = new NewsRespMsg();
          newsRespMsg.setToUserName(textReqMsg.getFromUserName());
          newsRespMsg.setFromUserName(textReqMsg.getToUserName());
            int articleCount = 3;
            newsRespMsg.setArticleCount(articleCount);
            for(int i=0; i<articleCount; i++) {
                NewsRespMsg.Article articla = newsRespMsg.new Article();
                articla.setTitle("title"+i);
                articla.setDescription("description"+i);
              articla.setPicUrl("http://img5.imgtn.bdimg.com/it/u=1938623644,625001929&fm=11&gp=0.jpg");
                articla.setUrl("http://www.baidu.com");
                newsRespMsg.getArticles().add(articla);
            }
            response = responseMessage(newsRespMsg);
        } catch(Exception e) {
            e.printStackTrace();
        }
        return response;
    }
}
2014-04-21 17:45:21 lixiaobai 阅读数 4437
  • 微信公众平台开发4-消息管理-微信开发php

    微信公众平台开发之消息管理是子恒老师《微信公众平台开发》视频教程的第4部。详细讲解了用php开发微信,对微信公众平台中的消息管理开发。内容包含微信关键字回复,多图文消息回复开发,接收图片消息,视频,小视频消息等等。欢迎反馈,微信/QQ:68183131

    6302 人正在学习 去看看 秦子恒

微信开发中,首先遇到的问题就是处理如何接收和响应用户消息 , 本文将向大家介绍一下方法和关键的代码。

本文使用的接口库是  https://github.com/chendong152/Weixin_api_.net 非常感谢 TD的作者


ASP.NET开发的  接收微信消息和响应用户消息代码如下:

文件名 :  v.ashx

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml;
using Td.Weixin.Public.Common;
using Td.Weixin.Public.Message;

namespace WeiWeiXin.Net6
{
    /// <summary>
    /// v 的摘要说明
    /// </summary>
    public class v : IHttpHandler
    {

        /// <summary>
        ///    开发者 验证 模块
        /// </summary>
        /// <param name="context"></param>
        public bool ProcessRequest2(HttpContext context)
        {
            context.Response.ContentType = "text/plain";
            //  context.Response.Write("Hello World");
            try
            {
                string echoStr = context.Request["echoStr"]; 
                if (!string.IsNullOrEmpty(echoStr))
                {
                    context.Response.Write(echoStr);
                    return true;
                }
                else
                {
                    // context.Response.Write("end");
                    //   context.Response.End();
                }
            }
            catch (Exception e)
            {
                //   context.Response.Write("end" + e.Message + e.ToString());
                // context.Response.End();
            }
            return false;
        }

        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/plain";
            //如果 是 验证  则 直接 退出 
            if (ProcessRequest2(context))
                return;

            context.Response.ContentType = "text/plain";
            var m = ReceiveMessage.ParseFromContext();

            if (m == null)
                return;

            //被关注
            if (m.MsgType == MessageType.Event && m.InnerToXmlText().IndexOf("subscribe") >= 0)
            {       
                //发送AIML请求
                var r2 = m.GetTextResponse();
                string result = "[微笑]欢迎关注";  
                r2.Data = (TextMsgData)result;
                r2.Response();
                return;
            }

            //数据解析
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(m.ToXmlText());//"<xml><description><![CDATA[木子屋:http://www.mzwu.com/]]></description></xml>");

            //菜单 或者 用户文本输入
            if (m.MsgType == MessageType.Text || (m.MsgType == MessageType.Event && m.InnerToXmlText().IndexOf("subscribe") < 0))
            {
                //读取
                string rr = "";

                if (m.MsgType == MessageType.Text)
                {
                    rr = xmlDoc.SelectSingleNode("//Content").FirstChild.InnerText.ToLower().Trim();
                }
                else
                {
                    rr = xmlDoc.SelectSingleNode("//EventKey").FirstChild.InnerText.ToLower().Trim();
                }
               
                //发送 
                var r2 = m.GetTextResponse();
                string result = "欢迎使用,您发送的是:" +rr;//  
                r2.Data = (TextMsgData)result;
                r2.Response();
                return;
            }
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

这段代码中具有开发者验证的功能,同时也考虑到了 由菜单发送到平台的文本的接收和响应。



最后 广告一下 : 完整的 微微信.NET 可以在这里找到  udoo123.taobao.com

2019-08-27 07:58:07 qq_35029061 阅读数 11
  • 微信公众平台开发4-消息管理-微信开发php

    微信公众平台开发之消息管理是子恒老师《微信公众平台开发》视频教程的第4部。详细讲解了用php开发微信,对微信公众平台中的消息管理开发。内容包含微信关键字回复,多图文消息回复开发,接收图片消息,视频,小视频消息等等。欢迎反馈,微信/QQ:68183131

    6302 人正在学习 去看看 秦子恒

微信开发与代码的编写(二)

普通消息的接收和回复

微信公众平台消息管理接口介绍

  要实现微信公众号的普通消息的接收和回复,我们需要先熟悉微信公众平台API中消息接口部分,点此进入,点击后将进入到【消息管理】部分,如下图所示:

  

  对于普通消息的接收和回复我们只需要关注上图中的"接收消息——接收普通消息"和"发送消息——被动回复消息"

 

消息接收

  先来说说接收消息, 当普通微信用户向公众账号发消息时,微信服务器会先接收到用户发送的消息,然后将用户消息按照指定的XML格式组装好数据,最后POST消息的XML数据包到开发者填写的URL上。

  接收到的普通消息的消息类型目前有以下几种:

  1 文本消息
  2 图片消息
  3 语音消息
  4 视频消息
  5 小视频消息
  6 地理位置消息
  7 链接消息

  每一种消息类型都有其指定的XML数据格式,这7种消息的xml格式请到官方文档查看,有具体的格式定义和属性说明。格式很简单,基本共有属性包括ToUserName、FromUserName、CreateTime、MsgType、MsgId,并且每种类型有自己特殊的属性。

  接收消息的过程其实就是获取post请求的这个xml,然后对这个xml进行分析的过程。post请求的入口还是之前提到的微信公众号接入的那个地址,整个公众号的所有请求都会走这个入口,只是接入时是get请求,其它情况下是post请求。

 

消息回复

  微信服务器在将用户的消息发给公众号的开发者服务器地址后,会等待开发者服务器回复响应消息。微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次。

  假如服务器无法保证在五秒内处理并回复,必须做出下述回复,这样微信服务器才不会对此作任何处理,并且不会发起重试(这种情况下,可以使用客服消息接口进行异步回复),否则,将出现严重的错误提示。详见下面说明:

  1、(推荐方式)直接回复success
  2、直接回复空串(指字节长度为0的空字符串,而不是XML结构体中content字段的内容为空)

 一旦遇到以下情况,微信都会在公众号会话中,向用户下发系统提示“该公众号暂时无法提供服务,请稍后再试”:

  1、开发者在5秒内未回复任何内容
  2、开发者回复了异常数据,比如JSON数据等

  另外,请注意,回复图片等多媒体消息时需要预先通过素材管理接口上传临时素材到微信服务器,可以使用素材管理中的临时素材,也可以使用永久素材。

  消息回复目前支持回复文本、图片、图文、语音、视频、音乐,每一种类型的消息都有特定的XML数据格式。这几种回复消息的xml数据格式请参考官方文档,有具体的格式定义和属性说明。格式很简单,基本共有属性包括ToUserName、FromUserName、CreateTime、MsgType,并且每种类型有自己特殊的属性。

 

微信公众号的普通消息的接收和回复

接收消息

  接收消息和被动回复消息这两个动作是不分家的,这本来就是一个交互场景,一般情况就是公众号通过分析接收到的消息,会给出对应的回复。

  之前说过了,接收消息的过程其实就是获取微信服务器通过post请求的发送给我们公众号服务器的xml数据,然后我们的公众号服务器再对这个xml进行解析处理的过程。为了方便解析XML数据,我们借助于dom4j,dom4j是一个十分优秀的JavaXML API,具有性能优异、功能强大和极其易使用的特点,是用来读写XML文件的。针对微信服务器发来的xml请求数据,我们写一个parseXml方法来处理,parseXml方法的代码如下:

 /**
      * 解析微信发来的请求(XML)
      *
      * @param request 封装了请求信息的HttpServletRequest对象
      * @return map 解析结果
      * @throws Exception
      */
     public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {
         // 将解析结果存储在HashMap中
         Map<String, String> map = new HashMap<String, String>();
         // 从request中取得输入流
         InputStream inputStream = request.getInputStream();
         // 读取输入流
         SAXReader reader = new SAXReader();
         Document document = reader.read(inputStream);
         // 得到xml根元素
         Element root = document.getRootElement();
         // 得到根元素的所有子节点
         List<Element> elementList = root.elements();
 
         // 遍历所有子节点
         for (Element e : elementList) {
            System.out.println(e.getName() + "|" + e.getText());
             map.put(e.getName(), e.getText());
         }
 
         // 释放资源
         inputStream.close();
         inputStream = null;
         return map;
     }

  然后在处理微信请求的入口servlet的doPost方法中调用parseXml方法即可,调用代码如下:

  /**
      * 处理微信服务器发来的消息
      */
     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         // TODO 接收、处理、响应由微信服务器转发的用户发送给公众帐号的消息
         // 将请求、响应的编码均设置为UTF-8(防止中文乱码)
         request.setCharacterEncoding("UTF-8");
         response.setCharacterEncoding("UTF-8");
         System.out.println("请求进入");
         String responseMessage;
         try {
             //解析微信发来的请求,将解析后的结果封装成Map返回
             Map<String,String> map = MessageHandlerUtil.parseXml(request);
             System.out.println("开始构造响应消息");
             responseMessage = MessageHandlerUtil.buildResponseMessage(map);
             System.out.println(responseMessage);
             if(responseMessage.equals("")){
                 responseMessage ="未正确响应";
             }
         } catch (Exception e) {
             e.printStackTrace();
             System.out.println("发生异常:"+ e.getMessage());
             responseMessage ="未正确响应";
         }
         //发送响应消息
         response.getWriter().println(responseMessage);
     }

 这样我们就完成了消息的接收,消息接收之后,我们就要根据消息类型进行响应了,写一个根据消息类型构造返回消息的方法,代码如下:

 /**
       * 根据消息类型构造返回消息
     * @param map 封装了解析结果的Map
       * @return responseMessage(响应消息)
      */
      public static String buildResponseMessage(Map map) {
         //响应消息
         String responseMessage = "";
         //得到消息类型
         String msgType = map.get("MsgType").toString();
         System.out.println("MsgType:" + msgType);
         //消息类型
         MessageType messageEnumType = MessageType.valueOf(MessageType.class, msgType.toUpperCase());
         switch (messageEnumType) {
             case TEXT:
                 //处理文本消息
                 responseMessage = handleTextMessage(map);
                 break;
             case IMAGE:
                 //处理图片消息
                 responseMessage = handleImageMessage(map);
                 break;
             case VOICE:
                 //处理语音消息
                 responseMessage = handleVoiceMessage(map);
                 break;
             case VIDEO:
                 //处理视频消息
                responseMessage = handleVideoMessage(map);
                 break;
             case SHORTVIDEO:
                 //处理小视频消息
                 responseMessage = handleSmallVideoMessage(map);
                break;
             case LOCATION:
                 //处理位置消息
                 responseMessage = handleLocationMessage(map);
                 break;
             case LINK:
                 //处理链接消息
                 responseMessage = handleLinkMessage(map);
                 break;
             case EVENT:
                //处理事件消息,用户在关注与取消关注公众号时,微信会向我们的公众号服务器发送事件消息,开发者接收到事件消息后就可以给用户下发欢迎消息
                 responseMessage = handleEventMessage(map);
             default:
                break;
         }
         //返回响应消息
         return responseMessage;
     }

  这样我们就完成了根据消息类型进行响应了,在处理微信请求的入口servlet的doPost方法中调用buildResponseMessage方法即可,doPost方法的完整代码在上面已经贴出来了.buildResponseMessage方法中使用到了一个MessageType类,这是一个消息类型枚举类,MessageType类的代码如下:


 /**
  * 接收到的消息类型
  */
 public enum MessageType {
     TEXT,//文本消息
     IMAGE,//图片消息
     VOICE,//语音消息
     VIDEO,//视频消息
     SHORTVIDEO,//小视频消息
     LOCATION,//地理位置消息
     LINK,//链接消息
     EVENT//事件消息
}

 

回复消息

  下面我基于这样一个业务场景来演示构造回复的消息,接收到文本消息"文本",回复文本消息;接收到“图片”,回复图片消息;接收到“语音”,回复语音消息;接收到“视频”,回复视频消息;接收到“音乐”,回复音乐消息;接收到“图文”,回复图文消息。下面具体说明各种消息的构建,只贴出核心代码,一些辅助代码类请自行下载项目代码参考.

回复文本消息

  接收的文本消息的XML数据格式如下:

 <xml>
  <ToUserName><![CDATA[toUser]]></ToUserName>
  <FromUserName><![CDATA[fromUser]]></FromUserName> 
  <CreateTime>1348831860</CreateTime>  
  <MsgType><![CDATA[text]]></MsgType>
  <Content><![CDATA[this is a test]]></Content>
  <MsgId>1234567890123456</MsgId>
 </xml>

  回复的文本消息的XML数据格式如下:

 <xml>
 <ToUserName><![CDATA[发消息的人,即订阅者]]></ToUserName>
 <FromUserName><![CDATA[微信公众号本身]]></FromUserName>
 <CreateTime>消息创建时间(整形)</CreateTime>
 <MsgType><![CDATA[text]]></MsgType>
 <Content><![CDATA[消息内容]]></Content>
 </xml>

  其中接收消息格式中的ToUserName便是回复消息的FromUserName,接收消息格式中的FromUserName便是回复消息的ToUserName。CreateTime为消息发送的时间戳。MsgType为消息类型,文本为text。Content为消息内容。具体每一种类型消息的回复,就是构造此种类型的xml格式内容,格式大同小异,只是音乐、视频、语音、图文格式相对于文本消息构造的xml内容稍微复杂一点。

  写一个构建文本消息的方法,代码如下:

  /**
      * 构造文本消息
      * @param map 封装了解析结果的Map
      * @param content 文本消息内容
      * @return 文本消息XML字符串
      */
     private static String buildTextMessage(Map<String, String> map, String content) {
         //发送方帐号
         String fromUserName = map.get("FromUserName");
         // 开发者微信号
         String toUserName = map.get("ToUserName");
         /**
          * 文本消息XML数据格式
          * <xml>
          <ToUserName><![CDATA[toUser]]></ToUserName>
          <FromUserName><![CDATA[fromUser]]></FromUserName>
          <CreateTime>1348831860</CreateTime>
          <MsgType><![CDATA[text]]></MsgType>
          <Content><![CDATA[this is a test]]></Content>
          <MsgId>1234567890123456</MsgId>
          </xml>
          */
         return String.format(
                 "<xml>" +
                         "<ToUserName><![CDATA[%s]]></ToUserName>" +
                         "<FromUserName><![CDATA[%s]]></FromUserName>" +
                         "<CreateTime>%s</CreateTime>" +
                         "<MsgType><![CDATA[text]]></MsgType>" +
                         "<Content><![CDATA[%s]]></Content>" +
                         "</xml>",
                 fromUserName, toUserName, getMessageCreateTime(), content);
     }

 

回复图片消息

  写一个构建图片消息的方法,代码如下:

  /**
       * 构造图片消息
       * @param map 封装了解析结果的Map
       * @param mediaId 通过素材管理接口上传多媒体文件得到的id
       * @return 图片消息XML字符串
       */
     private static String buildImageMessage(Map<String, String> map, String mediaId) {
         //发送方帐号
         String fromUserName = map.get("FromUserName");
         // 开发者微信号
         String toUserName = map.get("ToUserName");
        /**
         * 图片消息XML数据格式
          *<xml>
          <ToUserName><![CDATA[toUser]]></ToUserName>
          <FromUserName><![CDATA[fromUser]]></FromUserName>
          <CreateTime>12345678</CreateTime>
          <MsgType><![CDATA[image]]></MsgType>
          <Image>
          <MediaId><![CDATA[media_id]]></MediaId>
          </Image>
          </xml>
          */
         return String.format(
                 "<xml>" +
                         "<ToUserName><![CDATA[%s]]></ToUserName>" +
                         "<FromUserName><![CDATA[%s]]></FromUserName>" +
                         "<CreateTime>%s</CreateTime>" +
                         "<MsgType><![CDATA[image]]></MsgType>" +
                         "<Image>" +
                         "   <MediaId><![CDATA[%s]]></MediaId>" +
                         "</Image>" +
                         "</xml>",
                 fromUserName, toUserName, getMessageCreateTime(), mediaId);
     }

 

回复音乐消息

  写一个构建音乐消息的方法,代码如下:

  /**
      * 构造音乐消息
       * @param map 封装了解析结果的Map
      * @param music 封装好的音乐消息内容
      * @return 音乐消息XML字符串
      */
     private static String buildMusicMessage(Map<String, String> map, Music music) {
         //发送方帐号
         String fromUserName = map.get("FromUserName");
         // 开发者微信号
         String toUserName = map.get("ToUserName");
         /**
          * 音乐消息XML数据格式
          *<xml>
          <ToUserName><![CDATA[toUser]]></ToUserName>
          <FromUserName><![CDATA[fromUser]]></FromUserName>
          <CreateTime>12345678</CreateTime>
          <MsgType><![CDATA[music]]></MsgType>
          <Music>
          <Title><![CDATA[TITLE]]></Title>
          <Description><![CDATA[DESCRIPTION]]></Description>
          <MusicUrl><![CDATA[MUSIC_Url]]></MusicUrl>
          <HQMusicUrl><![CDATA[HQ_MUSIC_Url]]></HQMusicUrl>
          <ThumbMediaId><![CDATA[media_id]]></ThumbMediaId>
          </Music>
          </xml>
          */
         return String.format(
                 "<xml>" +
                         "<ToUserName><![CDATA[%s]]></ToUserName>" +
                         "<FromUserName><![CDATA[%s]]></FromUserName>" +
                         "<CreateTime>%s</CreateTime>" +
                         "<MsgType><![CDATA[music]]></MsgType>" +
                         "<Music>" +
                         "   <Title><![CDATA[%s]]></Title>" +
                         "   <Description><![CDATA[%s]]></Description>" +
                         "   <MusicUrl><![CDATA[%s]]></MusicUrl>" +
                         "   <HQMusicUrl><![CDATA[%s]]></HQMusicUrl>" +
                         "</Music>" +
                         "</xml>",
                 fromUserName, toUserName, getMessageCreateTime(), music.title, music.description, music.musicUrl, music.hqMusicUrl);
     }

 

回复视频消息

  写一个构建视频消息的方法,代码如下:

   /**
       * 构造视频消息
      * @param map 封装了解析结果的Map
      * @param video 封装好的视频消息内容
      * @return 视频消息XML字符串
      */
     private static String buildVideoMessage(Map<String, String> map, Video video) {
         //发送方帐号
         String fromUserName = map.get("FromUserName");
         // 开发者微信号
         String toUserName = map.get("ToUserName");
         /**
          * 音乐消息XML数据格式
          *<xml>
          <ToUserName><![CDATA[toUser]]></ToUserName>
          <FromUserName><![CDATA[fromUser]]></FromUserName>
          <CreateTime>12345678</CreateTime>
          <MsgType><![CDATA[video]]></MsgType>
         <Video>
          <MediaId><![CDATA[media_id]]></MediaId>
          <Title><![CDATA[title]]></Title>
          <Description><![CDATA[description]]></Description>
          </Video>
         </xml>
          */
         return String.format(
                 "<xml>" +
                         "<ToUserName><![CDATA[%s]]></ToUserName>" +
                        "<FromUserName><![CDATA[%s]]></FromUserName>" +
                         "<CreateTime>%s</CreateTime>" +
                         "<MsgType><![CDATA[video]]></MsgType>" +
                        "<Video>" +
                         "   <MediaId><![CDATA[%s]]></MediaId>" +
                         "   <Title><![CDATA[%s]]></Title>" +
                         "   <Description><![CDATA[%s]]></Description>" +
                         "</Video>" +
                         "</xml>",
                 fromUserName, toUserName, getMessageCreateTime(), video.mediaId, video.title, video.description);
     }

 

回复语音消息

  写一个构建语音消息的方法,代码如下:

  /**
       * 构造语音消息
      * @param map 封装了解析结果的Map
      * @param mediaId 通过素材管理接口上传多媒体文件得到的id
      * @return 语音消息XML字符串
      */
     private static String buildVoiceMessage(Map<String, String> map, String mediaId) {
         //发送方帐号
         String fromUserName = map.get("FromUserName");
        // 开发者微信号
         String toUserName = map.get("ToUserName");
         /**
          * 语音消息XML数据格式
          *<xml>
          <ToUserName><![CDATA[toUser]]></ToUserName>
          <FromUserName><![CDATA[fromUser]]></FromUserName>
          <CreateTime>12345678</CreateTime>
          <MsgType><![CDATA[voice]]></MsgType>
          <Voice>
          <MediaId><![CDATA[media_id]]></MediaId>
          </Voice>
          </xml>
          */
         return String.format(
                 "<xml>" +
                         "<ToUserName><![CDATA[%s]]></ToUserName>" +
                         "<FromUserName><![CDATA[%s]]></FromUserName>" +
                         "<CreateTime>%s</CreateTime>" +
                         "<MsgType><![CDATA[voice]]></MsgType>" +
                         "<Voice>" +
                         "   <MediaId><![CDATA[%s]]></MediaId>" +
                         "</Voice>" +
                         "</xml>",
                 fromUserName, toUserName, getMessageCreateTime(), mediaId);
     }

 

回复图文消息

  写一个构建图文消息的方法,代码如下:

   /**
      * 构造图文消息
       * @param map 封装了解析结果的Map
      * @return 图文消息XML字符串
      */
     private static String buildNewsMessage(Map<String, String> map) {
         String fromUserName = map.get("FromUserName");
         // 开发者微信号
         String toUserName = map.get("ToUserName");
         NewsItem item = new NewsItem();
         item.Title = "微信开发学习总结(一)——微信开发环境搭建";
         item.Description = "工欲善其事,必先利其器。要做微信公众号开发,那么要先准备好两样必不可少的东西:\n" +
                 "\n" +
                 "  1、要有一个用来测试的公众号。\n" +
                 "\n" +
                 "  2、用来调式代码的开发环境";
         item.PicUrl = "http://images2015.cnblogs.com/blog/289233/201601/289233-20160121164317343-2145023644.png";
         item.Url = "http://www.cnblogs.com/xdp-gacl/p/5149171.html";
         String itemContent1 = buildSingleItem(item); 
         NewsItem item2 = new NewsItem();
        item2.Title = "微信开发学习总结(二)——微信开发入门";
         item2.Description = "微信服务器就相当于一个转发服务器,终端(手机、Pad等)发起请求至微信服务器,微信服务器然后将请求转发给我们的应用服务器。应用服务器处理完毕后,将响应数据回发给微信服务器,微信服务器再将具体响应信息回复到微信App终端。";
         item2.PicUrl = "";
         item2.Url = "http://www.cnblogs.com/xdp-gacl/p/5151857.html";
         String itemContent2 = buildSingleItem(item2);
 
 
         String content = String.format("<xml>\n" +
                 "<ToUserName><![CDATA[%s]]></ToUserName>\n" +
                 "<FromUserName><![CDATA[%s]]></FromUserName>\n" +
               "<CreateTime>%s</CreateTime>\n" +
                 "<MsgType><![CDATA[news]]></MsgType>\n" +
                 "<ArticleCount>%s</ArticleCount>\n" +
                 "<Articles>\n" + "%s" +
                 "</Articles>\n" +
                 "</xml> ", fromUserName, toUserName, getMessageCreateTime(), 2, itemContent1 + itemContent2);
         return content;
 
     }
 
     /**
      * 生成图文消息的一条记录
      *
      * @param item
      * @return
      */
     private static String buildSingleItem(NewsItem item) {
         String itemContent = String.format("<item>\n" +
                 "<Title><![CDATA[%s]]></Title> \n" +
                 "<Description><![CDATA[%s]]></Description>\n" +
                 "<PicUrl><![CDATA[%s]]></PicUrl>\n" +
                 "<Url><![CDATA[%s]]></Url>\n" +
                 "</item>", item.Title, item.Description, item.PicUrl, item.Url);
         return itemContent;
     }

  根据上述提到的消息回复业务场景,我们可以写一个handleTextMessage方法来作为构造各种回复消息的处理入口,代码如下:

 /**
      * 接收到文本消息后处理
      * @param map 封装了解析结果的Map
      * @return
      */
     private static String handleTextMessage(Map<String, String> map) {
         //响应消息
         String responseMessage;
         // 消息内容
         String content = map.get("Content");
         switch (content) {
             case "文本":
                 String msgText = "孤傲苍狼又要开始写博客总结了,欢迎朋友们访问我在博客园上面写的博客\n" +
                         "<a href=\"http://www.cnblogs.com/xdp-gacl\">孤傲苍狼的博客</a>";
                 responseMessage = buildTextMessage(map, msgText);
                 break;
             case "图片":
                 //通过素材管理接口上传图片时得到的media_id
                 String imgMediaId = "dSQCiEHYB-pgi7ib5KpeoFlqpg09J31H28rex6xKgwWrln3HY0BTsoxnRV-xC_SQ";
                 responseMessage = buildImageMessage(map, imgMediaId);
                 break;
             case "语音":
                 //通过素材管理接口上传语音文件时得到的media_id
                 String voiceMediaId = "h3ul0TnwaRPut6Tl1Xlf0kk_9aUqtQvfM5Oq21unoWqJrwks505pkMGMbHnCHBBZ";
                 responseMessage = buildVoiceMessage(map,voiceMediaId);
                 break;
             case "图文":
                 responseMessage = buildNewsMessage(map);
                 break;
             case "音乐":
                 Music music = new Music();
                music.title = "赵丽颖、许志安 - 乱世俱灭";
                 music.description = "电视剧《蜀山战纪》插曲";
                 music.musicUrl = "http://gacl.ngrok.natapp.cn/music/music.mp3";
                 music.hqMusicUrl = "http://gacl.ngrok.natapp.cn/music/music.mp3";
                 responseMessage = buildMusicMessage(map, music);
                 break;
             case "视频":
                 Video video = new Video();
                 video.mediaId = "GqmIGpLu41rtwaY7WCVtJAL3ZbslzKiuLEXfWIKYDnHXGObH1CBH71xtgrGwyCa3";
                 video.title = "小苹果";
                 video.description = "小苹果搞笑视频";
                 responseMessage = buildVideoMessage(map, video);
                 break;
             default:
                 responseMessage = buildWelcomeTextMessage(map);
                 break;
 
         }
         //返回响应消息
         return responseMessage;
     }

  到此,回复想消息的相关处理代码就编写完成了,将项目部署到Tomcat服务器进行测试,记得使用Ngrok将内网的服务器映射到外网,否则无法使用微信测试,如下:

  

使用微信进行消息回复测试,测试效果如下:

可以看到,每一种消息都正常响应了.

  这里需要说一下图片,语音,视频的回复消息构造,这三种消息构造时的都需要一个mediaId,而这个mediaId是通过素材管理接口上传多媒体文件得到的,为了构造图片,语音,视频的这几种回复消息,我事先准备好了测试素材,如下图所示:

  

  然后通过微信公众号平台提供的素材管理接口将图片,语音,视频上传到微信服务器上,上传成功后,微信服务器会给我们返回一个mediaId,用于标识上传成功的多媒体素材,上传素材的工具类代码如下:

 1 package me.gacl.wx.util;
  2 
  3 import com.alibaba.fastjson.JSON;
  4 import com.alibaba.fastjson.JSONException;
  5 import com.alibaba.fastjson.JSONObject;
  6 import org.apache.commons.httpclient.HttpClient;
  7 import org.apache.commons.httpclient.HttpException;
  8 import org.apache.commons.httpclient.methods.PostMethod;
  9 import org.apache.commons.httpclient.methods.multipart.FilePart;
 10 import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
 11 import org.apache.commons.httpclient.methods.multipart.Part;
 12 import org.apache.commons.httpclient.methods.multipart.StringPart;
 13 import org.apache.commons.httpclient.protocol.Protocol;
 14 import org.apache.commons.httpclient.protocol.SSLProtocolSocketFactory;
 15 import org.apache.http.HttpStatus;
 16 
 17 import javax.net.ssl.*;
 18 import java.io.*;
 19 import java.net.HttpURLConnection;
 20 import java.net.URL;
 21 import java.security.cert.CertificateException;
 22 import java.security.cert.X509Certificate;
 23 
 24 /**
 25  * Created by allen on 2016/1/29.
 26  */
 27 public class WeChatApiUtil {
 28     // token 接口(GET)
 29     private static final String ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
 30     // 素材上传(POST)https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE
 31     private static final String UPLOAD_MEDIA = "https://api.weixin.qq.com/cgi-bin/media/upload";
 32     // 素材下载:不支持视频文件的下载(GET)
 33     private static final String DOWNLOAD_MEDIA = "http://file.api.weixin.qq.com/cgi-bin/media/get?access_token=%s&media_id=%s";
 34 
 35     public static String getTokenUrl(String appId, String appSecret) {
 36         return String.format(ACCESS_TOKEN, appId, appSecret);
 37     }
 38 
 39     public static String getDownloadUrl(String token, String mediaId) {
 40         return String.format(DOWNLOAD_MEDIA, token, mediaId);
 41     }
 42 
 43     /**
 44      * 通用接口获取Token凭证
 45      *
 46      * @param appId
 47      * @param appSecret
 48      * @return
 49      */
 50     public static String getToken(String appId, String appSecret) {
 51         if (appId == null || appSecret == null) {
 52             return null;
 53         }
 54 
 55         String token = null;
 56         String tockenUrl = WeChatApiUtil.getTokenUrl(appId, appSecret);
 57         String response = httpsRequestToString(tockenUrl, "GET", null);
 58         JSONObject jsonObject = JSON.parseObject(response);
 59         if (null != jsonObject) {
 60             try {
 61                 token = jsonObject.getString("access_token");
 62             } catch (JSONException e) {
 63                 token = null;// 获取token失败
 64             }
 65         }
 66         return token;
 67     }
 68 
 69     /**
 70      * 微信服务器素材上传
 71      *
 72      * @param file  表单名称media
 73      * @param token access_token
 74      * @param type  type只支持四种类型素材(video/image/voice/thumb)
 75      */
 76     public static JSONObject uploadMedia(File file, String token, String type) {
 77         if (file == null || token == null || type == null) {
 78             return null;
 79         }
 80 
 81         if (!file.exists()) {
 82             System.out.println("上传文件不存在,请检查!");
 83             return null;
 84         }
 85 
 86         String url = UPLOAD_MEDIA;
 87         JSONObject jsonObject = null;
 88         PostMethod post = new PostMethod(url);
 89         post.setRequestHeader("Connection", "Keep-Alive");
 90         post.setRequestHeader("Cache-Control", "no-cache");
 91         FilePart media;
 92         HttpClient httpClient = new HttpClient();
 93         //信任任何类型的证书
 94         Protocol myhttps = new Protocol("https", new SSLProtocolSocketFactory(), 443);
 95         Protocol.registerProtocol("https", myhttps);
 96 
 97         try {
 98             media = new FilePart("media", file);
 99             Part[] parts = new Part[]{new StringPart("access_token", token),
100                     new StringPart("type", type), media};
101             MultipartRequestEntity entity = new MultipartRequestEntity(parts,
102                     post.getParams());
103             post.setRequestEntity(entity);
104             int status = httpClient.executeMethod(post);
105             if (status == HttpStatus.SC_OK) {
106                 String text = post.getResponseBodyAsString();
107                 jsonObject = JSONObject.parseObject(text);
108             } else {
109                 System.out.println("upload Media failure status is:" + status);
110             }
111         } catch (FileNotFoundException e) {
112             e.printStackTrace();
113         } catch (HttpException e) {
114             e.printStackTrace();
115         } catch (IOException e) {
116             e.printStackTrace();
117         }
118         return jsonObject;
119     }
120 
121     /**
122      * 多媒体下载接口
123      *
124      * @param fileName 素材存储文件路径
125      * @param token    认证token
126      * @param mediaId  素材ID(对应上传后获取到的ID)
127      * @return 素材文件
128      * @comment 不支持视频文件的下载
129      */
130     public static File downloadMedia(String fileName, String token,
131                                      String mediaId) {
132         String url = getDownloadUrl(token, mediaId);
133         return httpRequestToFile(fileName, url, "GET", null);
134     }
135 
136     /**
137      * 多媒体下载接口
138      *
139      * @param fileName 素材存储文件路径
140      * @param mediaId  素材ID(对应上传后获取到的ID)
141      * @return 素材文件
142      * @comment 不支持视频文件的下载
143      */
144     public static File downloadMedia(String fileName, String mediaId) {
145         String appId = "wxbe4d433e857e8bb1";
146         String appSecret = "ccbc82d560876711027b3d43a6f2ebda";
147         String token = WeChatApiUtil.getToken(appId, appSecret);
148         return downloadMedia(fileName,token,mediaId);
149     }
150 
151     /**
152      * 以http方式发送请求,并将请求响应内容输出到文件
153      *
154      * @param path   请求路径
155      * @param method 请求方法
156      * @param body   请求数据
157      * @return 返回响应的存储到文件
158      */
159     public static File httpRequestToFile(String fileName, String path, String method, String body) {
160         if (fileName == null || path == null || method == null) {
161             return null;
162         }
163 
164         File file = null;
165         HttpURLConnection conn = null;
166         InputStream inputStream = null;
167         FileOutputStream fileOut = null;
168         try {
169             URL url = new URL(path);
170             conn = (HttpURLConnection) url.openConnection();
171             conn.setDoOutput(true);
172             conn.setDoInput(true);
173             conn.setUseCaches(false);
174             conn.setRequestMethod(method);
175             if (null != body) {
176                 OutputStream outputStream = conn.getOutputStream();
177                 outputStream.write(body.getBytes("UTF-8"));
178                 outputStream.close();
179             }
180 
181             inputStream = conn.getInputStream();
182             if (inputStream != null) {
183                 file = new File(fileName);
184             } else {
185                 return file;
186             }
187 
188             //写入到文件
189             fileOut = new FileOutputStream(file);
190             if (fileOut != null) {
191                 int c = inputStream.read();
192                 while (c != -1) {
193                     fileOut.write(c);
194                     c = inputStream.read();
195                 }
196             }
197         } catch (Exception e) {
198         } finally {
199             if (conn != null) {
200                 conn.disconnect();
201             }
202 
203             /*
204              * 必须关闭文件流
205              * 否则JDK运行时,文件被占用其他进程无法访问
206              */
207             try {
208                 inputStream.close();
209                 fileOut.close();
210             } catch (IOException execption) {
211             }
212         }
213         return file;
214     }
215 
216     /**
217      * 上传素材
218      * @param filePath 媒体文件路径(绝对路径)
219      * @param type 媒体文件类型,分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb)
220      * @return
221      */
222     public static JSONObject uploadMedia(String filePath,String type){
223         File f = new File(filePath); // 获取本地文件
224         String appId = "wxbe4d433e857e8bb1";
225         String appSecret = "ccbc82d560876711027b3d43a6f2ebda";
226         String token = WeChatApiUtil.getToken(appId, appSecret);
227         JSONObject jsonObject = uploadMedia(f, token, type);
228         return jsonObject;
229     }
230 
231     /**
232      * 发送请求以https方式发送请求并将请求响应内容以String方式返回
233      *
234      * @param path   请求路径
235      * @param method 请求方法
236      * @param body   请求数据体
237      * @return 请求响应内容转换成字符串信息
238      */
239     public static String httpsRequestToString(String path, String method, String body) {
240         if (path == null || method == null) {
241             return null;
242         }
243 
244         String response = null;
245         InputStream inputStream = null;
246         InputStreamReader inputStreamReader = null;
247         BufferedReader bufferedReader = null;
248         HttpsURLConnection conn = null;
249         try {
250             TrustManager[] tm = {new JEEWeiXinX509TrustManager()};
251             SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
252             sslContext.init(null, tm, new java.security.SecureRandom());
253             SSLSocketFactory ssf = sslContext.getSocketFactory();
254             System.out.println(path);
255             URL url = new URL(path);
256             conn = (HttpsURLConnection) url.openConnection();
257             conn.setSSLSocketFactory(ssf);
258 
259             conn.setDoOutput(true);
260             conn.setDoInput(true);
261             conn.setUseCaches(false);
262             conn.setRequestMethod(method);
263             if (null != body) {
264                 OutputStream outputStream = conn.getOutputStream();
265                 outputStream.write(body.getBytes("UTF-8"));
266                 outputStream.close();
267             }
268 
269             inputStream = conn.getInputStream();
270             inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
271             bufferedReader = new BufferedReader(inputStreamReader);
272             String str = null;
273             StringBuffer buffer = new StringBuffer();
274             while ((str = bufferedReader.readLine()) != null) {
275                 buffer.append(str);
276             }
277 
278             response = buffer.toString();
279         } catch (Exception e) {
280 
281         } finally {
282             if (conn != null) {
283                 conn.disconnect();
284             }
285             try {
286                 bufferedReader.close();
287                 inputStreamReader.close();
288                 inputStream.close();
289             } catch (IOException execption) {
290 
291             }
292         }
293         return response;
294     }
295 
296     public static void main(String[] args) throws Exception{
297         //媒体文件路径
298         String filePath = "D:/JavaSoftwareDevelopeFolder/IntelliJ IDEA_Workspace/WxStudy/web/media/image/我.jpg";
299         //String filePath = "D:/JavaSoftwareDevelopeFolder/IntelliJ IDEA_Workspace/WxStudy/web/media/voice/voice.mp3";
300         //String filePath = "D:\\JavaSoftwareDevelopeFolder\\IntelliJ IDEA_Workspace\\WxStudy\\web\\media\\video\\小苹果.mp4";
301         //媒体文件类型
302         String type = "image";
303         //String type = "voice";
304         //String type = "video";
305         JSONObject uploadResult = uploadMedia(filePath, type);
306         //{"media_id":"dSQCiEHYB-pgi7ib5KpeoFlqpg09J31H28rex6xKgwWrln3HY0BTsoxnRV-xC_SQ","created_at":1455520569,"type":"image"}
307         System.out.println(uploadResult.toString());
308 
309         //下载刚刚上传的图片以id命名
310         String media_id = uploadResult.getString("media_id");
311         File file = downloadMedia("D:/" + media_id + ".png", media_id);
312         System.out.println(file.getName());
313 
314     }
315 }
316 
317 class JEEWeiXinX509TrustManager implements X509TrustManager {
318     public void checkClientTrusted(X509Certificate[] chain, String authType)
319             throws CertificateException {
320     }
321 
322     public void checkServerTrusted(X509Certificate[] chain, String authType)
323             throws CertificateException {
324     }
325 
326     public X509Certificate[] getAcceptedIssuers() {
327         return null;
328     }
329 }

 在工具类写一个main方法测试素材上传和下载,代码如下:

 public static void main(String[] args) throws Exception{
         //媒体文件路径
         String filePath = "D:/JavaSoftwareDevelopeFolder/IntelliJ IDEA_Workspace/WxStudy/web/media/image/我.jpg";
         //String filePath = "D:/JavaSoftwareDevelopeFolder/IntelliJ IDEA_Workspace/WxStudy/web/media/voice/voice.mp3";
         //String filePath = "D:\\JavaSoftwareDevelopeFolder\\IntelliJ IDEA_Workspace\\WxStudy\\web\\media\\video\\小苹果.mp4";
          //媒体文件类型
         String type = "image";
         //String type = "voice";
         //String type = "video";
         JSONObject uploadResult = uploadMedia(filePath, type);
         //{"media_id":"dSQCiEHYB-pgi7ib5KpeoFlqpg09J31H28rex6xKgwWrln3HY0BTsoxnRV-xC_SQ","created_at":1455520569,"type":"image"}
         System.out.println(uploadResult.toString());
 
         //下载刚刚上传的图片以id命名
         String media_id = uploadResult.getString("media_id");
         File file = downloadMedia("D:/" + media_id + ".png", media_id);
         System.out.println(file.getName());
 
     }

 运行结果如下:

  

   可以看到,素材上传成功后,微信服务器就会返回一个media_id,用于标识上传后的文件.有了这个media_id后,我们就可以构建我们想要的图片,语音,视频回复消息了.

  下面再说一下音乐的回复消息的构造,音乐素材也是我事先在服务器上准备了一个music.mp3音乐文件,并且保证可以正常使用外网访问,如下所示:

  

  然后将MusicUrl和HQMusicUrl的地址指向了服务器上的music.mp3文件的访问地址,如下:

 Music music = new Music();
 music.title = "赵丽颖、许志安 - 乱世俱灭";
 music.description = "电视剧《蜀山战纪》插曲";
 music.musicUrl = "http://gacl.ngrok.natapp.cn/media/music/music.mp3";
 music.hqMusicUrl = "http://gacl.ngrok.natapp.cn/media/music/music.mp3";
 responseMessage = buildMusicMessage(map, music);

 这样就可以正常构造音乐回复消息了.

 

 

 

 

 

没有更多推荐了,返回首页