2016-12-27 16:31:38 getluo 阅读数 1358
  • 微信公众平台深度开发v2.0第1季——微信公众号基础...

    “微信公众平台深度开发Java版 v2.0”系列课程共有6季,使用JAVA语言,系统讲解微信公众平台订阅号、服务号官方列出的全部功能接口,包括:自定义菜单、个性化菜单(按需定制菜单)、群发消息、客服消息(有限次消息推送)、模板消息接(无限次消息推送)、微信网页开发(微信WEB开发、微信游戏)、微信JSSDK开发、用户管理、获取用户基本信息、网页授权获取用户基本信息(通过WEB得到用户信息)、二维码(临时二维码、永久二维码)、事件推送、接收普通消息、被动回复用户消息,等知识点。 以及,针对微信公众号开发的服务端架构设计方案。课程以微信公众号开发视角,讲解JAVA开发微信公众号所需的框架、第三方工具。 购买套餐还赠送经典微信开发课程——[微信公众号_独立知识点]环境搭建。该课程针对各种复杂的网络环境,讲解如何构建开发环境,已解决“没有服务器”、“没有固定IP”等开发者遇到的窘境。 课程采用独立知识点讲解,一个知识点,一组课程,真正做到“简单、高效、”以短的时间、实现的学习。更多课程信息请访问CSDN。网址:http://edu.csdn.net/lecturer/631 “微信公众平台企业号开发Java版”陆续上线。 详情 qq2326321088

    78975 人正在学习 去看看 翟东平

首先需要公众号有模板消息的权限,这里不多说明了。


要实现的功能就是在第三方网站通过调用接口在对给用户发消息,当然也可以给用户标签组群发消息。


获取access_token代码:

$weixin_appid = "";
$weixin_secret = "";
$weixin_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$weixin_appid."&secret=".$weixin_secret;
$weixin_return = get_url_contents ( $weixin_url );
$weixin = json_decode ( $weixin_return );
$access_token = $weixin->access_token;
//模板ID
$template_id = "";

发送消息代码:

				$dataarray = array(
						"touser"=>$openid,//用户的openid
						"template_id"=>$template_id,//消息模板id
						"url"=>$_POST['yanbao_url'],
						"data"=>array(
						    "first"=>array(
				                       "value"=>$_POST['yanbao_title'],
				                       "color"=>"#173177"
				                    ),
				                    "keyword1"=>array(
				                       "value"=>$_POST['yanbao_name'],
				                       "color"=>"#173177"
				                    ),
				                    "keyword2"=>array(
				                       "value"=>$_POST['yanbao_desc'],
				                       "color"=>"#173177"
				                    ),
				                    "remark"=>array(
				                       "value"=>$_POST['yanbao_more'],
				                       "color"=>"#173177"
				                    )
								)
				            );
				$data = json_encode($dataarray);
				$output = json_decode(do_post($url,$data));//do_post是模拟post的函数,请自行定义
				if($output->errcode == '0'){
					echo '<div class="updated"><p>发送成功!</p></div>';
				}else{
					echo '<div class="error"><p>发送失败!错误码:'.$output->errcode.'</p></div>';
				}

获取用户标签代码:

				<tr valign="top">
					<th scope="row"><label>用户标签</label></th>
					<td>
						<select name="yanbao_user_tag" id="yanbao_user_tag" style="min-width: 150px">
							<option value="">请选择</option>
							<option value="all">所有用户</option>
							<?php 
								$yanbao_user_tag_url = "https://api.weixin.qq.com/cgi-bin/tags/get?access_token=".$access_token;
								$yanbao_user_tag_return = get_url_contents ( $yanbao_user_tag_url );
								$yanbao_user_tag = json_decode ( $yanbao_user_tag_return );
								$tags = $yanbao_user_tag->tags;
								foreach ($tags as $tag) {
									echo '<option value="'.$tag->id.'">'.$tag->name.'('.$tag->count.')</option>';
								}
							?>		
						</select>
						<span class="description">(选择了用户标签就是<strong>群发</strong>给该标签下的用户)</span>
					</td>
				</tr>

获取用户代码:

<tr valign="top">
					<th scope="row"><label>用户</label></th>
					<td>
						<select name="yanbao_user" id="yanbao_user">
							<option selected="selected" value="">请选择</option>
							<?php 
								/*
								$yanbao_user_url = "https://api.weixin.qq.com/cgi-bin/user/get?access_token=".$access_token."&next_openid=";
								$yanbao_user_return = get_url_contents ( $yanbao_user_url );
								$yanbao_user = json_decode ( $yanbao_user_return );
								$openids = $yanbao_user->data->openid;
								foreach ($openids as $openid) {
									$added_user = Moge_check_weixin_user_added($openid);
									if($added_user){
										echo '<option value="'.$openid.'">'.$added_user->nickname.'</option>';
									}else{
										$user = Moge_weixin_get_user_info($access_token,$openid);
										$wpdb->query("insert into ".$wpdb->prefix."erphp_weixin_users (openid,nickname) values('".$openid."','".$user->nickname."')");
										echo '<option value="'.$openid.'">'.$user->nickname.'</option>';
									}
								}*/
								
								$weixin_users = Moge_get_weixin_users();//获取本地数据库里的微信用户函数
								if($weixin_users){
									foreach ($weixin_users as $user) {
										echo '<option value="'.$user->openid.'">'.$user->nickname.'</option>';
									}
								}
								
							?>
						</select>
						<span class="description">(若已选择了用户标签,此项选择就无效了。)</span>
					</td>
				</tr>


这里主要遇到一个问题就是如果高效快速的获取用户列表的昵称(nickname),通过以下的接口

https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID

只能获取用户的openid,我尝试过针对每个用户获取其详细资料,结果页面直接卡死了(用户数量太多)。虽然看到有批量获取资料,但是不适合用,最后没办法,只能先循环获取然后存在本地数据库,定期获取更新下数据库了,有个弊端就是取消关注的人还是会在本地数据库里。

2017-04-22 12:10:27 hq0556 阅读数 1404
  • 微信公众平台深度开发v2.0第1季——微信公众号基础...

    “微信公众平台深度开发Java版 v2.0”系列课程共有6季,使用JAVA语言,系统讲解微信公众平台订阅号、服务号官方列出的全部功能接口,包括:自定义菜单、个性化菜单(按需定制菜单)、群发消息、客服消息(有限次消息推送)、模板消息接(无限次消息推送)、微信网页开发(微信WEB开发、微信游戏)、微信JSSDK开发、用户管理、获取用户基本信息、网页授权获取用户基本信息(通过WEB得到用户信息)、二维码(临时二维码、永久二维码)、事件推送、接收普通消息、被动回复用户消息,等知识点。 以及,针对微信公众号开发的服务端架构设计方案。课程以微信公众号开发视角,讲解JAVA开发微信公众号所需的框架、第三方工具。 购买套餐还赠送经典微信开发课程——[微信公众号_独立知识点]环境搭建。该课程针对各种复杂的网络环境,讲解如何构建开发环境,已解决“没有服务器”、“没有固定IP”等开发者遇到的窘境。 课程采用独立知识点讲解,一个知识点,一组课程,真正做到“简单、高效、”以短的时间、实现的学习。更多课程信息请访问CSDN。网址:http://edu.csdn.net/lecturer/631 “微信公众平台企业号开发Java版”陆续上线。 详情 qq2326321088

    78975 人正在学习 去看看 翟东平

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

本篇根据开发者文档-被动回复用户消息编写。请对照查看,一些传入与返回参数就不过多介绍。地址为: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;
    }
}
2016-08-04 16:44:46 Draling 阅读数 2577
  • 微信公众平台深度开发v2.0第1季——微信公众号基础...

    “微信公众平台深度开发Java版 v2.0”系列课程共有6季,使用JAVA语言,系统讲解微信公众平台订阅号、服务号官方列出的全部功能接口,包括:自定义菜单、个性化菜单(按需定制菜单)、群发消息、客服消息(有限次消息推送)、模板消息接(无限次消息推送)、微信网页开发(微信WEB开发、微信游戏)、微信JSSDK开发、用户管理、获取用户基本信息、网页授权获取用户基本信息(通过WEB得到用户信息)、二维码(临时二维码、永久二维码)、事件推送、接收普通消息、被动回复用户消息,等知识点。 以及,针对微信公众号开发的服务端架构设计方案。课程以微信公众号开发视角,讲解JAVA开发微信公众号所需的框架、第三方工具。 购买套餐还赠送经典微信开发课程——[微信公众号_独立知识点]环境搭建。该课程针对各种复杂的网络环境,讲解如何构建开发环境,已解决“没有服务器”、“没有固定IP”等开发者遇到的窘境。 课程采用独立知识点讲解,一个知识点,一组课程,真正做到“简单、高效、”以短的时间、实现的学习。更多课程信息请访问CSDN。网址:http://edu.csdn.net/lecturer/631 “微信公众平台企业号开发Java版”陆续上线。 详情 qq2326321088

    78975 人正在学习 去看看 翟东平

1、开启开发者模式之后,需要第三方服务器接收到消息后,进行转发。
2、最多可添加100个客服人员
3、多客服登录网址:https://mpkf.weixin.qq.com

如果公众号处于开发模式,普通微信用户向公众号发消息时,微信服务器会先将消息POST到开发者填写的url上,如果希望将消息转发到多客服系统,则需要开发者在响应包中返回MsgType为transfer_customer_service的消息,微信服务器收到响应后会把当次发送的消息转发至多客服系统。

消息被转发到多客服以后,会被自动分配给一个在线的客服帐号,您也可以在返回transfer_customer_service消息时,在XML中附上TransInfo信息指定分配给某个客服帐号

/// <summary>
/// 消息转发到多客服
/// </summary>
/// <param name="fromUserName">接收方帐号</param>
/// <param name="toUserName">开发者微信号</param>
/// <returns></returns>
public string TransferService(string fromUserName, string toUserName)
{
    return "<xml><ToUserName><![CDATA[" + fromUserName + "]]></ToUserName><FromUserName><![CDATA[" + toUserName + "]]></FromUserName><CreateTime>" + ConvertDateTimeInt(DateTime.Now) + "</CreateTime><MsgType><![CDATA[transfer_customer_service]]></MsgType></xml>";
}

/// <summary>
/// 消息转发到指定客服
/// </summary>
/// <param name="fromUserName">接收方帐号</param>
/// <param name="toUserName">开发者微信号</param>
/// <param name="KfAccount">指定会话接入的客服账号</param>
/// <returns></returns>
public string TransferService(string fromUserName, string toUserName, string KfAccount)
{
    return "<xml><ToUserName><![CDATA[" + fromUserName + "]]></ToUserName><FromUserName><![CDATA[" + toUserName + "]]></FromUserName><CreateTime>" + ConvertDateTimeInt(DateTime.Now) + "</CreateTime><MsgType><![CDATA[transfer_customer_service]]></MsgType><TransInfo><KfAccount><![CDATA[" + KfAccount + "]]></KfAccount> </TransInfo></xml>";
}
2017-06-08 21:31:24 e62ces0iem 阅读数 1522
  • 微信公众平台深度开发v2.0第1季——微信公众号基础...

    “微信公众平台深度开发Java版 v2.0”系列课程共有6季,使用JAVA语言,系统讲解微信公众平台订阅号、服务号官方列出的全部功能接口,包括:自定义菜单、个性化菜单(按需定制菜单)、群发消息、客服消息(有限次消息推送)、模板消息接(无限次消息推送)、微信网页开发(微信WEB开发、微信游戏)、微信JSSDK开发、用户管理、获取用户基本信息、网页授权获取用户基本信息(通过WEB得到用户信息)、二维码(临时二维码、永久二维码)、事件推送、接收普通消息、被动回复用户消息,等知识点。 以及,针对微信公众号开发的服务端架构设计方案。课程以微信公众号开发视角,讲解JAVA开发微信公众号所需的框架、第三方工具。 购买套餐还赠送经典微信开发课程——[微信公众号_独立知识点]环境搭建。该课程针对各种复杂的网络环境,讲解如何构建开发环境,已解决“没有服务器”、“没有固定IP”等开发者遇到的窘境。 课程采用独立知识点讲解,一个知识点,一组课程,真正做到“简单、高效、”以短的时间、实现的学习。更多课程信息请访问CSDN。网址:http://edu.csdn.net/lecturer/631 “微信公众平台企业号开发Java版”陆续上线。 详情 qq2326321088

    78975 人正在学习 去看看 翟东平

本文目录 :

  1. 给单一用户发文本消息
  2. 给多个用户发文本消息
  3. 给所有用户发文本消息
  4. 有更好的方案吗?
  5. 遇到的问题
  6. 小结


微信提供的api,对于针对用户openid发消息的话,没有向所有关注者群发消息的接口,但提供了向单一用户和多用户发文本消息的接口,我们可以基于此开发向所有用户群发消息的接口。
补充:后面我发现其实可以有更好的实现方案,详看 ‘有更好的方案吗?‘。

文中遇到部分的接口请查看上一文:

微信开发之获取用户详细列表


1、 给单一用户发文本消息

微信开发文档入口:

客服接口-发消息

我的代码接口:

/**
 * 向一个粉丝发送消息
 */
public function sendMsgToOne($openid, $content)
{
    $access_token = $this->getAccessToken();
    if (!$access_token) {
        return false;
    }

    $url ="https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token={$access_token}";
    $post_arr = [
                    'touser' => $openid,
                    'msgtype' => 'text',
                    'text' => ['content'=>$content]
                ];
    $post_str = json_encode($post_arr, JSON_UNESCAPED_UNICODE);
    $return = httpRequest($url, 'POST', $post_str);
    $wxdata = json_decode($return, true);
    if (isset($wxdata['errcode']) && $wxdata['errcode'] != 0) {
        $this->setError('微信错误码:'.$wxdata['errcode'].',错误信息:'.$wxdata['errmsg']);
        return false;
    }

    return true;
}


2、 给多个用户发文本消息

微信开发文档入口:

根据OpenID列表群发【订阅号不可用,服务号认证后可用】

我的代码接口:

/**
 * 指定一部分人群发消息
 * @param array $openids
 * @param string $content
 * @return boolean
 */
public function sendMsgToMass($openids, $content)
{
    $access_token = $this->getAccessToken();
    if (!$access_token) {
        return false;
    }

    $url ="https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token={$access_token}";
    $post_arr = [
                    'touser' => $openids,
                    'msgtype' => 'text',
                    'text' => ['content'=>$content]
                ];
    $post_str = json_encode($post_arr, JSON_UNESCAPED_UNICODE);
    $return = httpRequest($url, 'POST', $post_str);
    $wxdata = json_decode($return, true);
    if (isset($wxdata['errcode']) && $wxdata['errcode'] != 0) {
        $this->setError('微信错误码:'.$wxdata['errcode'].',错误信息:'.$wxdata['errmsg']);
        return false;
    }

    return true;
}


3、 给所有用户发文本消息

利用上面的两个接口,实现一个统一的接口,如下:
下面接口入参$openids支持数组和字符串,字符串支持多个openid用连接,具体请看代码吧。

/**
 * 发送消息,自动识别id数
 * @param string or array $openids
 * @param string $content
 * @return boolean
 */
public function sendMsg($openids, $content)
{
    if (empty(openids)) {
        return true;
    }
    if (is_string($openids)) {
        $openids = explode(',', $openids);
    }

    if (count($openids) > 1) {
        $result = $this->sendMsgToMass($openids, $content);
    } else {
        $result = $this->sendMsgToOne($openids[0], $content);
    }

    if ($result === false) {
        return false;
    }

    return true;
}

下面实现向所有用户群发消息, 使用的时候请判断接口返回是否为false,若是,可用getError()获取详细错误信息,具体可参考上一文 微信开发之获取用户详细列表

/**
 * 给所有粉丝发消息
 * @param string $content
 * @return boolean
 */
public function sendMsgToAll($content)
{
    $next_openid = '';
    do {
        $id_list = $this->getFanIdList($next_openid);
        if ($id_list === false) {
            return false;
        }

        $result = $this->sendMsg($id_list['data']['openid'], $content);
        if ($result === false) {
            return false;
        }

        $next_openid = $id_list['next_openid'];
    } while($id_list['count']);

    return true;
}


4、 有更好的方案吗?

微信开发文档入口:

根据标签进行群发【订阅号与服务号认证后均可用】

我一直以为微信没有提供直接向所有用户群发的接口,其实是有的!
在上面的微信文档中,我发现,这个接口竟然被归类在根据标签进行群发里面。不过不需要用标签这个概念,里面有个关键的变量是is_to_all,把它置为 true 即可。
这样子可以节省上一接口中的相关api的调用次数,更能提高web响应的性能!

我的代码接口:

/**
 * 给所有粉丝发消息
 * @param string $content
 * @return boolean
 */
public function sendMsgToAll($content)
{
    $access_token = $this->getAccessToken();
    if (!$access_token) {
        return false;
    }

    $url ="https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token={$access_token}"; 
    $post_arr = [
                    'filter' => ['is_to_all'=>true, 'tag_id'=>0],
                    'msgtype' => 'text',
                    'text' => ['content'=>$content]
                ];
    $post_str = json_encode($post_arr, JSON_UNESCAPED_UNICODE);
    $return = httpRequest($url, 'POST', $post_str);
    $wxdata = json_decode($return, true);
    if ($this->checkError($wxdata, $url)) {
         return false;
    }

    return true;
}


5、 遇到的问题

在向单一用户发消息的时候,遇到报45015错误的接收报文:

{
    "errcode":45015,
    "errmsg":"response out of time limit or subscription is canceled hint: [***]"
}

原因是当用户微信不活跃时间超过48小时,不会将信息推送到用户微信公众号。

: 上面说法来源于腾讯官方,评论区园友实际测试也是,谢谢这位朋友指出。
为了验证这个说法的正确性,我试着先向公众号发个信息,果然公众号可以向单一用户推送消息了。


小结

简单利用微信向单一用户和多用户的发消息接口,实现向所有用户群发消息,但利用标签接口群发效率回更好哦。其他的语音、图文等消息发送也是类似的。


主要参考文档

微信开发文档:https://mp.weixin.qq.com/wiki

-end-

2014-11-02 10:48:05 fuyifang 阅读数 19993
  • 微信公众平台深度开发v2.0第1季——微信公众号基础...

    “微信公众平台深度开发Java版 v2.0”系列课程共有6季,使用JAVA语言,系统讲解微信公众平台订阅号、服务号官方列出的全部功能接口,包括:自定义菜单、个性化菜单(按需定制菜单)、群发消息、客服消息(有限次消息推送)、模板消息接(无限次消息推送)、微信网页开发(微信WEB开发、微信游戏)、微信JSSDK开发、用户管理、获取用户基本信息、网页授权获取用户基本信息(通过WEB得到用户信息)、二维码(临时二维码、永久二维码)、事件推送、接收普通消息、被动回复用户消息,等知识点。 以及,针对微信公众号开发的服务端架构设计方案。课程以微信公众号开发视角,讲解JAVA开发微信公众号所需的框架、第三方工具。 购买套餐还赠送经典微信开发课程——[微信公众号_独立知识点]环境搭建。该课程针对各种复杂的网络环境,讲解如何构建开发环境,已解决“没有服务器”、“没有固定IP”等开发者遇到的窘境。 课程采用独立知识点讲解,一个知识点,一组课程,真正做到“简单、高效、”以短的时间、实现的学习。更多课程信息请访问CSDN。网址:http://edu.csdn.net/lecturer/631 “微信公众平台企业号开发Java版”陆续上线。 详情 qq2326321088

    78975 人正在学习 去看看 翟东平

以下是做微信公众号开发用到最多的两个客服消息发送类型,文本信息和图文信息。

1、发送文本消息

{
    "touser":"OPENID",
    "msgtype":"text",
    "text":
    {
         "content":"Hello World"
    }
}

参数是否必须说明
access_token调用接口凭证
touser普通用户openid
msgtype消息类型,text
content文本消息内容

2、发送图文消息

图文消息条数限制在10条以内,注意,如果图文数超过10,则将会无响应。

{
    "touser":"OPENID",
    "msgtype":"news",
    "news":{
        "articles": [
         {
             "title":"Happy Day",
             "description":"Is Really A Happy Day",
             "url":"URL",
             "picurl":"PIC_URL"
         },
         {
             "title":"Happy Day",
             "description":"Is Really A Happy Day",
             "url":"URL",
             "picurl":"PIC_URL"
         }
         ]
    }
}
参数是否必须说明
access_token调用接口凭证
touser普通用户openid
msgtype消息类型,news
title标题
description描述
url点击后跳转的链接
picurl图文消息的图片链接,支持JPG、PNG格式,较好的效果为大图640*320,小图80*80

使用网页调试工具调试该接口

3、发送文本消息代码实例

发送文本消息实例,图文信息只是参数不一致而已,不再列举。

    protected void btnSen_Click(object sender, EventArgs e)
    {
        var accessToken = SettingHelper.GetSettingByAccessToken();
        if (string.IsNullOrWhiteSpace(accessToken))
            accessToken = SettingHelper.GetAccessToken();

        if (string.IsNullOrWhiteSpace(accessToken))
        {
            Response.Write(accessToken); return;
        }
       
          string text = @"\n您今天的跟进提醒如下:
\r累计有9个分配待跟进客户;今日待回访客户有20名;逾期未跟进客户有20名;N日内到期客户有20名;
您今天的业务催办如下:
\r逾期未认购客户共计20名;逾期未签约客户15名;逾期未办理按揭客户15名;逾期未交款客户共计12名;
N日内到期款客户15名;
您今天的工作很充实,加油哦~";
        string OPENID = "olQhety1vUipp6_Q3YeOvi_TKUdo";
        var data = "{ \"touser\":\"" + OPENID + "\", \"msgtype\":\"text\", \"text\": { \"content\":\"Hello World  " + text + "\" }}";
        var json = HttpHelper.Post("https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" + accessToken, data);
        Response.Write(json);
        Response.End();
    }

服务号客服消息在用户48小时内未进行互动情况下,消息是不允许发送的,企业号消息推送无限制。其他消息发送类型,点击进入微信开发平台开发文档


更多关注付义方技术博客:http://blog.csdn.net/fuyifang


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