2016-12-27 16:31:38 getluo 阅读数 1358
  • 微信公众号开发7-用户管理-微信开发php

    微信公众平台开发之微信用户开发管理是子恒老师《微信公众平台开发》视频教程的第7部。详细讲解了用php开发微信,对微信公众平台中的粉丝用户管理开发。内容包含微信公众平台用户分组,获取微信用户列表,查询用户详情等等。欢迎反馈,微信/QQ:68183131

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

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


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


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

2018-07-16 18:06:19 bianyamei 阅读数 384
  • 微信公众号开发7-用户管理-微信开发php

    微信公众平台开发之微信用户开发管理是子恒老师《微信公众平台开发》视频教程的第7部。详细讲解了用php开发微信,对微信公众平台中的粉丝用户管理开发。内容包含微信公众平台用户分组,获取微信用户列表,查询用户详情等等。欢迎反馈,微信/QQ:68183131

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

消息其实是由用户发给你的公众帐号的,消息先被微信平台接收到,然后微信平台会将该消息转给你在开发模式接口配置中指定的URL地址。

把消息推送中定义的所有消息都有的字段提取出来,封装成一个基类,这些公有的字段包括:ToUserName(开发者微信号)、FromUserName(发送方帐号,OPEN_ID)、CreateTime(消息的创建时间)、MsgType(消息类型)、MsgId(消息ID),封装后基类BaseMessage的代码如下:


/**
 * 请求消息基类(普通用户 -> 公众帐号)
 * @author bym @date 2018年7月4日
 */
public class BaseMessage {
	// 开发者微信号
	private String ToUserName;
	// 发送方帐号(一个OpenID)
	private String FromUserName;
	// 消息创建时间 (整型)
	private long CreateTime;
	// 消息类型
	private String MsgType;
	// 消息id,64位整型
	private long MsgId;
	
	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;
	}

	public long getMsgId() {
		return MsgId;
	}

	public void setMsgId(long msgId) {
		MsgId = msgId;
	}
}
请求消息之文本消息

/**
 * 文本消息
 * @author bym @date 2018年7月4日
 */
public class TextMessage extends BaseMessage {
	// 消息内容
	private String Content;

	public String getContent() {
		return Content;
	}

	public void setContent(String content) {
		Content = content;
	}
}

请求消息之图片消息


/**
 * 图片消息
 * @author bym @date 2018年7月4日
 */
public class ImageMessage extends BaseMessage {
	// 图片链接
	private String PicUrl;

	public String getPicUrl() {
		return PicUrl;
	}

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

请求消息之地理位置消息


/**
 * 地理位置消息
 * @author bym @date 2018年7月4日
 */
public class LocationMessage extends BaseMessage {
	// 地理位置维度
	private String Location_X;
	// 地理位置经度
	private String Location_Y;
	// 地图缩放大小
	private String Scale;
	// 地理位置信息
	private String Label;

	public String getLocation_X() {
		return Location_X;
	}

	public void setLocation_X(String location_X) {
		Location_X = location_X;
	}

	public String getLocation_Y() {
		return Location_Y;
	}

	public void setLocation_Y(String location_Y) {
		Location_Y = location_Y;
	}

	public String getScale() {
		return Scale;
	}

	public void setScale(String scale) {
		Scale = scale;
	}

	public String getLabel() {
		return Label;
	}

	public void setLabel(String label) {
		Label = label;
	}
}

请求消息之链接消息   

/**
 * 链接消息
 * @author bym @date 2018年7月4日
 */
public class LinkMessage extends BaseMessage {
	// 消息标题
	private String Title;
	// 消息描述
	private String Description;
	// 消息链接
	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 getUrl() {
		return Url;
	}

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

请求消息之语音消息

/**
 * 语音消息
 * @author bym @date 2018年7月4日
 */
public class VoiceMessage extends BaseMessage {
	// 媒体ID
	private String MediaId;
	// 语音格式
	private String Format;
	// 语音识别结果,UTF8编码
	private String Recognition;

	public String getMediaId() {
		return MediaId;
	}

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

	public String getFormat() {
		return Format;
	}

	public void setFormat(String format) {
		Format = format;
	}

	public String getRecognition() {
		return Recognition;
	}

	public void setRecognition(String recognition) {
		Recognition = recognition;
	}
}

请求消息之视频消息


/**
 * 视频消息
 * @author bym @date 2018年7月4日
 */
public class VideoMessage extends BaseMessage {
	// 视频消息媒体id
	private String MediaId;
	// 视频消息缩略图的媒体id
	private String ThumbMediaId;

	public String getMediaId() {
		return MediaId;
	}

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

	public String getThumbMediaId() {
		return ThumbMediaId;
	}

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

响应消息的基类

/**
 * 消息基类(公众帐号 -> 普通用户)
 * @author bym @date 2018年7月4日
 */
public class BaseMessage {
	// 接收方帐号(收到的OpenID)
		private String ToUserName;
		// 开发者微信号
		private String FromUserName;
		// 消息创建时间 (整型)
		private long CreateTime;
		// 消息类型(text/music/news)
		private String MsgType;
		// 位0x0001被标志时,星标刚收到的消息
		private int FuncFlag;

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

		public int getFuncFlag() {
			return FuncFlag;
		}

		public void setFuncFlag(int funcFlag) {
			FuncFlag = funcFlag;
		}
}

响应文本消息


/**
 * 文本消息
 * @author bym @date 2018年7月4日
 */
public class TextMessage extends BaseMessage {
	// 回复的消息内容
	private String Content;

	public String getContent() {
		return Content;
	}

	public void setContent(String content) {
		Content = content;
	}
}

响应图片消息

/**
 * 图片消息
 * @author bym @date 2018年7月4日
 */
public class ImageMessage extends BaseMessage {
	// 图片
	private Image Image;

	public Image getImage() {
		return Image;
	}

	public void setImage(Image image) {
		Image = image;
	}
}

图片消息中Image类的定义

/**
 * 图片model
 * @author bym @date 2018年7月4日
 */
public class Image {
	// 媒体文件id
	private String MediaId;

	public String getMediaId() {
		return MediaId;
	}

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

响应图文消息

/**
 * 文本消息
 * @@author bym @date 2018年7月4日
 */
public class NewsMessage extends BaseMessage {
	// 图文消息个数,限制为10条以内
	private int ArticleCount;
	// 多条图文消息信息,默认第一个item为大图
	private List<Article> Articles;
	
	public int getArticleCount() {
		return ArticleCount;
	}

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

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

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

	
	
}

图文消息中Article类的定义

/**
 * 图文model
 * @author bym @date 2018年7月4日
 */
public class Article {
	// 图文消息名称
	private String Title;
	// 图文消息描述
	private String Description;
	// 图片链接,支持JPG、PNG格式,较好的效果为大图640*320,小图80*80
	private String PicUrl;
	// 点击图文消息跳转链接
	private String Url;

	public String getTitle() {
		return Title;
	}

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

	public String getDescription() {
		return null == Description ? "" : Description;
	}

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

	public String getPicUrl() {
		return null == PicUrl ? "" : PicUrl;
	}

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

	public String getUrl() {
		return null == Url ? "" : Url;
	}

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

响应语音消息


/**
 * 语音消息
 * @author bym @date 2018年7月4日
 */
public class VoiceMessage extends BaseMessage {
	// 语音
	private Voice Voice;

	public Voice getVoice() {
		return Voice;
	}

	public void setVoice(Voice voice) {
		Voice = voice;
	}
}

语音消息中Voice类的定义

/**
 * 语音model
 * @author bym @date 2018年7月4日
 */
public class Voice {
	// 媒体文件id
	private String MediaId;

	public String getMediaId() {
		return MediaId;
	}

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

响应音乐消息


/**
 * 音乐消息
 * @author bym @date 2018年7月4日
 */
public class MusicMessage extends BaseMessage {
	// 音乐
	private Music Music;

	public Music getMusic() {
		return Music;
	}

	public void setMusic(Music music) {
		Music = music;
	}
}

音乐消息中Music类的定义


/**
 * 音乐model
 * @author bym @date 2018年7月4日
 */
public class Music {
	// 音乐标题
	private String Title;
	// 音乐描述
	private String Description;
	// 音乐链接
	private String MusicUrl;
	// 高质量音乐链接,WIFI环境优先使用该链接播放音乐
	private String HQMusicUrl;
	// 缩略图的媒体id,通过上传多媒体文件得到的id
	private String ThumbMediaId;

	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 musicUrl) {
		HQMusicUrl = musicUrl;
	}

	public String getThumbMediaId() {
		return ThumbMediaId;
	}

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

响应视频消息


/**
 * 视频消息
 * @author bym @date 2018年7月4日
 */
public class VideoMessage extends BaseMessage {
	// 视频
	private Video Video;

	public Video getVideo() {
		return Video;
	}

	public void setVideo(Video video) {
		Video = video;
	}
}

视频消息中Video类的定义


/**
 * 视频model
 * @author bym @date 2018年7月4日
 */
public class Video {
	// 媒体文件id
	private String MediaId;
	// 缩略图的媒体id
	private String ThumbMediaId;

	public String getMediaId() {
		return MediaId;
	}

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

	public String getThumbMediaId() {
		return ThumbMediaId;
	}

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

解析请求消息

微信服务器会用doPost的方法将用户信息发送给我们.前边写doGet的时候把doPost写好了.

doPost方法有两个参数,request中封装了请求相关的所有内容,可以从request中取出微信服务器发来的消息;而通过response我们可以对接收到的消息进行响应,即发送消息。

那么如何解析请求消息的问题也就转化为如何从request中得到微信服务器发送给我们的xml格式的消息了。这里我们借助于开源框架dom4j去解析xml(这里使用的是dom4j-1.6.1.jar),然后将解析得到的结果存入HashMap,解析请求消息的方法如下:

	@SuppressWarnings("unchecked")
	public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {
		
		Map<String, String> map = new HashMap<String, String>();

		
		InputStream inputStream = request.getInputStream();
		
		SAXReader reader = new SAXReader();
		Document document = reader.read(inputStream);
	
		Element root = document.getRootElement();
		
		List<Element> elementList = root.elements();

		
		for (Element e : elementList)
			map.put(e.getName(), e.getText());

		inputStream.close();
		inputStream = null;

		return map;
	}

将响应消息转化成xml返回

这里我们将采用开源框架xstream来实现Java类到xml的转换(这里使用的是xstream-1.3.1.jar),代码如下:

private static XStream xstream = new XStream(new XppDriver() {
		public HierarchicalStreamWriter createWriter(Writer out) {
			return new PrettyPrintWriter(out) {
				
				boolean cdata = true;

				public void startNode(String name, Class clazz) {
					super.startNode(name, clazz);
				}

				protected void writeText(QuickWriter writer, String text) {
					if (cdata) {
						writer.write("<![CDATA[");
						writer.write(text);
						writer.write("]]>");
					} else {
						writer.write(text);
					}
				}
			};
		}
	});

	
	public static String messageToXml(TextMessage textMessage) {
		xstream.alias("xml", textMessage.getClass());
		return xstream.toXML(textMessage);
	}

	public static String messageToXml(ImageMessage imageMessage) {
		xstream.alias("xml", imageMessage.getClass());
		return xstream.toXML(imageMessage);
	}

	
	public static String messageToXml(VoiceMessage voiceMessage) {
		xstream.alias("xml", voiceMessage.getClass());
		return xstream.toXML(voiceMessage);
	}

	
	public static String messageToXml(VideoMessage videoMessage) {
		xstream.alias("xml", videoMessage.getClass());
		return xstream.toXML(videoMessage);
	}

	
	public static String messageToXml(MusicMessage musicMessage) {
		xstream.alias("xml", musicMessage.getClass());
		return xstream.toXML(musicMessage);
	}

	
	public static String messageToXml(NewsMessage newsMessage) {
		XStream xstream = new XStream();
		xstream.alias("xml", newsMessage.getClass());
		xstream.alias("item", new Article().getClass());
		return xstream.toXML(newsMessage);
	}   
	
}

为什要把数据放在CDATA中,xml CDATA有什么用https://blog.csdn.net/u014401141/article/details/53453818

由于xstream框架本身并不支持CDATA块的生成,writeText方法是对xtream做了扩展,使其支持在生成xml各元素值时添加CDATA块。

消息处理工具的封装

将消息相关的处理方法全部封装到工具类MessageUtil中,该类的完整代码如下:


/**
 * 
 * @author bym @date 2018年7月4日
 *
 */

public class MessageUtil {
	
	public static final String REQ_MESSAGE_TYPE_TEXT = "text";
	
	public static final String REQ_MESSAGE_TYPE_IMAGE = "image";
	
	public static final String REQ_MESSAGE_TYPE_VOICE = "voice";
	
	public static final String REQ_MESSAGE_TYPE_VIDEO = "video";
	
	public static final String REQ_MESSAGE_TYPE_LOCATION = "location";
	
	public static final String REQ_MESSAGE_TYPE_LINK = "link";

	
	public static final String REQ_MESSAGE_TYPE_EVENT = "event";

	
	public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";
	
	public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";
	
	public static final String EVENT_TYPE_SCAN = "scan";
	
	public static final String EVENT_TYPE_LOCATION = "LOCATION";
	
	public static final String EVENT_TYPE_CLICK = "CLICK";

	
	public static final String RESP_MESSAGE_TYPE_TEXT = "text";
	
	public static final String RESP_MESSAGE_TYPE_IMAGE = "image";
	
	public static final String RESP_MESSAGE_TYPE_VOICE = "voice";
	
	public static final String RESP_MESSAGE_TYPE_VIDEO = "video";
	
	public static final String RESP_MESSAGE_TYPE_MUSIC = "music";
	
	public static final String RESP_MESSAGE_TYPE_NEWS = "news";

	@SuppressWarnings("unchecked")
	public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {
		
		Map<String, String> map = new HashMap<String, String>();

		
		InputStream inputStream = request.getInputStream();
		
		SAXReader reader = new SAXReader();
		Document document = reader.read(inputStream);
	
		Element root = document.getRootElement();
		
		List<Element> elementList = root.elements();

		
		for (Element e : elementList)
			map.put(e.getName(), e.getText());

		inputStream.close();
		inputStream = null;

		return map;
	}

	private static XStream xstream = new XStream(new XppDriver() {
		public HierarchicalStreamWriter createWriter(Writer out) {
			return new PrettyPrintWriter(out) {
				
				boolean cdata = true;

				public void startNode(String name, Class clazz) {
					super.startNode(name, clazz);
				}

				protected void writeText(QuickWriter writer, String text) {
					if (cdata) {
						writer.write("<![CDATA[");
						writer.write(text);
						writer.write("]]>");
					} else {
						writer.write(text);
					}
				}
			};
		}
	});

	
	public static String messageToXml(TextMessage textMessage) {
		xstream.alias("xml", textMessage.getClass());
		return xstream.toXML(textMessage);
	}

	public static String messageToXml(ImageMessage imageMessage) {
		xstream.alias("xml", imageMessage.getClass());
		return xstream.toXML(imageMessage);
	}

	
	public static String messageToXml(VoiceMessage voiceMessage) {
		xstream.alias("xml", voiceMessage.getClass());
		return xstream.toXML(voiceMessage);
	}

	
	public static String messageToXml(VideoMessage videoMessage) {
		xstream.alias("xml", videoMessage.getClass());
		return xstream.toXML(videoMessage);
	}

	
	public static String messageToXml(MusicMessage musicMessage) {
		xstream.alias("xml", musicMessage.getClass());
		return xstream.toXML(musicMessage);
	}

	
	public static String messageToXml(NewsMessage newsMessage) {
		XStream xstream = new XStream();
		xstream.alias("xml", newsMessage.getClass());
		xstream.alias("item", new Article().getClass());
		return xstream.toXML(newsMessage);
	}   
	
}

 

2016-06-12 15:05:57 w410589502 阅读数 2851
  • 微信公众号开发7-用户管理-微信开发php

    微信公众平台开发之微信用户开发管理是子恒老师《微信公众平台开发》视频教程的第7部。详细讲解了用php开发微信,对微信公众平台中的粉丝用户管理开发。内容包含微信公众平台用户分组,获取微信用户列表,查询用户详情等等。欢迎反馈,微信/QQ:68183131

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

注:部分内容摘抄自柳峰的微信公众平台开发的博客

1、接受普通消息

当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。

(1)请求消息

微信服务器与公众账号服务器交互的消息可以分为3类:请求消息、事件和响应消息。

  请求消息是指用户发送给公众账号的消息,它包括文本消息、图片消息、语音消息、视频消息、地理位置消息和链接消息

各消息类型的推送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>
2、被动回复用户消息

当用户发送消息给公众号时(或某些特定的用户操作引发的事件推送时),会产生一个POST请求,开发者可以在响应包(Get)中返回特定XML结构,来对该消息进行响应(现支持回复文本、图片、图文、语音、视频、音乐)。严格来说,发送被动响应消息其实并不是一种接口,而是对微信服务器发过来消息的一次回复。
微信服务器在将用户的消息发给公众号的开发者服务器地址(开发者中心处配置)后,微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次,如果在调试中,发现用户无法收到响应的消息,可以检查是否消息处理超时。关于重试的消息排重,有msgid的消息推荐使用msgid排重。事件类型消息推荐使用FromUserName + CreateTime 排重。
如果开发者希望增强安全性,可以在开发者中心处开启消息加密,这样,用户发给公众号的消息以及公众号被动回复用户消息都会继续加密(但),详见被动回复消息加解密说明。
假如服务器无法保证在五秒内处理并回复,必须做出下述回复,这样微信服务器才不会对此作任何处理,并且不会发起重试(这种情况下,可以使用客服消息接口进行异步回复),否则,将出现严重的错误提示。详见下面说明:
(1)、(推荐方式)直接回复success
(2)、直接回复空串(指字节长度为0的空字符串,而不是XML结构体中content字段的内容为空)
一旦遇到以下情况,微信都会在公众号会话中,向用户下发系统提示“该公众号暂时无法提供服务,请稍后再试”:
(1)、开发者在5秒内未回复任何内容
(2)、开发者回复了异常数据,比如JSON数据等
另外,请注意,回复图片等多媒体消息时需要预先通过素材管理接口上传临时素材到微信服务器,可以使用素材管理中的临时素材,也可以使用永久素材。

2消息的封装
接下来要做的就是将消息推送(请求)、消息回复(响应)中定义的消息进行封装,建立与之对应的Java类(Java是一门面向对象的编程语言,封装后使用起来更方便),下面的请求消息是指消息推送中定义的消息,响应消息指消息回复中定义的消息。

请求消息的基类
把消息推送中定义的所有消息都有的字段提取出来,封装成一个基类,这些公有的字段包括:ToUserName(开发者微信号)、FromUserName(发送方帐号,OPEN_ID)、CreateTime(消息的创建时间)、MsgType(消息类型)、MsgId(消息ID),封装后基类org.liufeng.course.message.req.BaseMessage的代码如下:

package org.liufeng.course.message.req;  
  
/** 
 * 消息基类(普通用户 -> 公众帐号) 
 *  
 * @author liufeng 
 * @date 2013-05-19 
 */  
public class BaseMessage {  
    // 开发者微信号  
    private String ToUserName;  
    // 发送方帐号(一个OpenID)  
    private String FromUserName;  
    // 消息创建时间 (整型)  
    private long CreateTime;  
    // 消息类型(text/image/location/link)  
    private String MsgType;  
    // 消息id,64位整型  
    private long MsgId;  
  
    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;  
    }  
  
    public long getMsgId() {  
        return MsgId;  
    }  
  
    public void setMsgId(long msgId) {  
        MsgId = msgId;  
    }  
}  

请求消息之文本消息

package org.liufeng.course.message.req;  
  
/** 
 * 文本消息 
 *  
 * @author liufeng 
 * @date 2013-05-19 
 */  
public class TextMessage extends BaseMessage {  
    // 消息内容  
    private String Content;  
  
    public String getContent() {  
        return Content;  
    }  
  
    public void setContent(String content) {  
        Content = content;  
    }  
} 

请求消息之图片消息

package org.liufeng.course.message.req;  
  
/** 
 * 图片消息 
 *  
 * @author liufeng 
 * @date 2013-05-19 
 */  
public class ImageMessage extends BaseMessage {  
    // 图片链接  
    private String PicUrl;  
  
    public String getPicUrl() {  
        return PicUrl;  
    }  
  
    public void setPicUrl(String picUrl) {  
        PicUrl = picUrl;  
    }  
}


请求消息之地理位置消息

package org.liufeng.course.message.req;  
  
/** 
 * 地理位置消息 
 *  
 * @author liufeng 
 * @date 2013-05-19 
 */  
public class LocationMessage extends BaseMessage {  
    // 地理位置维度  
    private String Location_X;  
    // 地理位置经度  
    private String Location_Y;  
    // 地图缩放大小  
    private String Scale;  
    // 地理位置信息  
    private String Label;  
  
    public String getLocation_X() {  
        return Location_X;  
    }  
  
    public void setLocation_X(String location_X) {  
        Location_X = location_X;  
    }  
  
    public String getLocation_Y() {  
        return Location_Y;  
    }  
  
    public void setLocation_Y(String location_Y) {  
        Location_Y = location_Y;  
    }  
  
    public String getScale() {  
        return Scale;  
    }  
  
    public void setScale(String scale) {  
        Scale = scale;  
    }  
  
    public String getLabel() {  
        return Label;  
    }  
  
    public void setLabel(String label) {  
        Label = label;  
    }  
}  

请求消息之链接消息

package org.liufeng.course.message.req;  
  
/** 
 * 链接消息 
 *  
 * @author liufeng 
 * @date 2013-05-19 
 */  
public class LinkMessage extends BaseMessage {  
    // 消息标题  
    private String Title;  
    // 消息描述  
    private String Description;  
    // 消息链接  
    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 getUrl() {  
        return Url;  
    }  
  
    public void setUrl(String url) {  
        Url = url;  
    }  
}  

请求消息之语音消息

package org.liufeng.course.message.req;  
  
/** 
 * 音频消息 
 *  
 * @author liufeng 
 * @date 2013-05-19 
 */  
public class VoiceMessage extends BaseMessage {  
    // 媒体ID  
    private String MediaId;  
    // 语音格式  
    private String Format;  
  
    public String getMediaId() {  
        return MediaId;  
    }  
  
    public void setMediaId(String mediaId) {  
        MediaId = mediaId;  
    }  
  
    public String getFormat() {  
        return Format;  
    }  
  
    public void setFormat(String format) {  
        Format = format;  
    }  
}  

响应消息的基类
同样,把消息回复中定义的所有消息都有的字段提取出来,封装成一个基类,这些公有的字段包括:ToUserName(接收方帐号,用户的OPEN_ID)、FromUserName(开发者的微信号)、CreateTime(消息的创建时间)、MsgType(消息类型)、FuncFlag(消息的星标标识),封装后基类org.liufeng.course.message.resp.BaseMessage的代码如下:

package org.liufeng.course.message.resp;  
  
/** 
 * 消息基类(公众帐号 -> 普通用户) 
 *  
 * @author liufeng 
 * @date 2013-05-19 
 */  
public class BaseMessage {  
    // 接收方帐号(收到的OpenID)  
    private String ToUserName;  
    // 开发者微信号  
    private String FromUserName;  
    // 消息创建时间 (整型)  
    private long CreateTime;  
    // 消息类型(text/music/news)  
    private String MsgType;  
    // 位0x0001被标志时,星标刚收到的消息  
    private int FuncFlag;  
  
    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;  
    }  
  
    public int getFuncFlag() {  
        return FuncFlag;  
    }  
  
    public void setFuncFlag(int funcFlag) {  
        FuncFlag = funcFlag;  
    }  
}  

响应消息之文本消息

package org.liufeng.course.message.resp;  
  
/** 
 * 文本消息 
 *  
 * @author liufeng 
 * @date 2013-05-19 
 */  
public class TextMessage extends BaseMessage {  
    // 回复的消息内容  
    private String Content;  
  
    public String getContent() {  
        return Content;  
    }  
  
    public void setContent(String content) {  
        Content = content;  
    }  
}  

响应消息之音乐消息

package org.liufeng.course.message.resp;  
  
/** 
 * 音乐消息 
 *  
 * @author liufeng 
 * @date 2013-05-19 
 */  
public class MusicMessage extends BaseMessage {  
    // 音乐  
    private Music Music;  
  
    public Music getMusic() {  
        return Music;  
    }  
  
    public void setMusic(Music music) {  
        Music = music;  
    }  
} 

音乐消息中Music类的定义

package org.liufeng.course.message.resp;  
  
/** 
 * 音乐model 
 *  
 * @author liufeng 
 * @date 2013-05-19 
 */  
public class Music {  
    // 音乐名称  
    private String Title;  
    // 音乐描述  
    private String Description;  
    // 音乐链接  
    private String MusicUrl;  
    // 高质量音乐链接,WIFI环境优先使用该链接播放音乐  
    private String HQMusicUrl;  
  
    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 musicUrl) {  
        HQMusicUrl = musicUrl;  
    }  
  
} 
响应消息之图文消息

package org.liufeng.course.message.resp;  
  
import java.util.List;  
  
/** 
 * 文本消息 
 *  
 * @author liufeng 
 * @date 2013-05-19 
 */  
public class NewsMessage extends BaseMessage {  
    // 图文消息个数,限制为10条以内  
    private int ArticleCount;  
    // 多条图文消息信息,默认第一个item为大图  
    private List<Article> Articles;  
  
    public int getArticleCount() {  
        return ArticleCount;  
    }  
  
    public void setArticleCount(int articleCount) {  
        ArticleCount = articleCount;  
    }  
  
    public List<Article> getArticles() {  
        return Articles;  
    }  
  
    public void setArticles(List<Article> articles) {  
        Articles = articles;  
    }  
}  

图文消息中Article类的定义

package org.liufeng.course.message.resp;  
  
/** 
 * 图文model 
 *  
 * @author liufeng 
 * @date 2013-05-19 
 */  
public class Article {  
    // 图文消息名称  
    private String Title;  
    // 图文消息描述  
    private String Description;  
    // 图片链接,支持JPG、PNG格式,较好的效果为大图640*320,小图80*80,限制图片链接的域名需要与开发者填写的基本资料中的Url一致  
    private String PicUrl;  
    // 点击图文消息跳转链接  
    private String Url;  
  
    public String getTitle() {  
        return Title;  
    }  
  
    public void setTitle(String title) {  
        Title = title;  
    }  
  
    public String getDescription() {  
        return null == Description ? "" : Description;  
    }  
  
    public void setDescription(String description) {  
        Description = description;  
    }  
  
    public String getPicUrl() {  
        return null == PicUrl ? "" : PicUrl;  
    }  
  
    public void setPicUrl(String picUrl) {  
        PicUrl = picUrl;  
    }  
  
    public String getUrl() {  
        return null == Url ? "" : Url;  
    }  
  
    public void setUrl(String url) {  
        Url = url;  
    }  
  
}

4、解析请求消息

doPost方法有两个参数,request中封装了请求相关的所有内容,可以从request中取出微信服务器发来的消息;而通过response我们可以对接收到的消息进行响应,即发送消息。
那么如何解析请求消息的问题也就转化为如何从request中得到微信服务器发送给我们的xml格式的消息了。这里我们借助于开源框架dom4j去解析xml(这里使用的是dom4j-1.6.1.jar),然后将解析得到的结果存入HashMap,解析请求消息的方法如下:

/** 
 * 解析微信发来的请求(XML) 
 *  
 * @param request 
 * @return 
 * @throws Exception 
 */  
@SuppressWarnings("unchecked")  
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)  
        map.put(e.getName(), e.getText());  
  
    // 释放资源  
    inputStream.close();  
    inputStream = null;  
  
    return map;  
}  


将响应消息转换成xml返回

我们先前已经将响应消息封装成了Java类,方便我们在代码中使用。那么,请求接收成功、处理完成后,该如何将消息返回呢?这里就涉及到如何将响应消息转换成xml返回的问题,这里我们将采用开源框架xstream来实现Java类到xml的转换(这里使用的是xstream-1.3.1.jar)

package org.liufeng.course.util;  
  
import java.io.InputStream;  
import java.io.Writer;  
import java.util.HashMap;  
import java.util.List;  
import java.util.Map;  
  
import javax.servlet.http.HttpServletRequest;  
  
import org.dom4j.Document;  
import org.dom4j.Element;  
import org.dom4j.io.SAXReader;  
import org.liufeng.course.message.resp.Article;  
import org.liufeng.course.message.resp.MusicMessage;  
import org.liufeng.course.message.resp.NewsMessage;  
import org.liufeng.course.message.resp.TextMessage;  
  
import com.thoughtworks.xstream.XStream;  
import com.thoughtworks.xstream.core.util.QuickWriter;  
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;  
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;  
import com.thoughtworks.xstream.io.xml.XppDriver;  
  
/** 
 * 消息工具类 
 *  
 * @author liufeng 
 * @date 2013-05-19 
 */  
public class MessageUtil {  
  
    /** 
     * 返回消息类型:文本 
     */  
    public static final String RESP_MESSAGE_TYPE_TEXT = "text";  
  
    /** 
     * 返回消息类型:音乐 
     */  
    public static final String RESP_MESSAGE_TYPE_MUSIC = "music";  
  
    /** 
     * 返回消息类型:图文 
     */  
    public static final String RESP_MESSAGE_TYPE_NEWS = "news";  
  
    /** 
     * 请求消息类型:文本 
     */  
    public static final String REQ_MESSAGE_TYPE_TEXT = "text";  
  
    /** 
     * 请求消息类型:图片 
     */  
    public static final String REQ_MESSAGE_TYPE_IMAGE = "image";  
  
    /** 
     * 请求消息类型:链接 
     */  
    public static final String REQ_MESSAGE_TYPE_LINK = "link";  
  
    /** 
     * 请求消息类型:地理位置 
     */  
    public static final String REQ_MESSAGE_TYPE_LOCATION = "location";  
  
    /** 
     * 请求消息类型:音频 
     */  
    public static final String REQ_MESSAGE_TYPE_VOICE = "voice";  
  
    /** 
     * 请求消息类型:推送 
     */  
    public static final String REQ_MESSAGE_TYPE_EVENT = "event";  
  
    /** 
     * 事件类型:subscribe(订阅) 
     */  
    public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";  
  
    /** 
     * 事件类型:unsubscribe(取消订阅) 
     */  
    public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";  
  
    /** 
     * 事件类型:CLICK(自定义菜单点击事件) 
     */  
    public static final String EVENT_TYPE_CLICK = "CLICK";  
  
    /** 
     * 解析微信发来的请求(XML) 
     *  
     * @param request 
     * @return 
     * @throws Exception 
     */  
    @SuppressWarnings("unchecked")  
    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)  
            map.put(e.getName(), e.getText());  
  
        // 释放资源  
        inputStream.close();  
        inputStream = null;  
  
        return map;  
    }  
  
    /** 
     * 文本消息对象转换成xml 
     *  
     * @param textMessage 文本消息对象 
     * @return xml 
     */  
    public static String textMessageToXml(TextMessage textMessage) {  
        xstream.alias("xml", textMessage.getClass());  
        return xstream.toXML(textMessage);  
    }  
  
    /** 
     * 音乐消息对象转换成xml 
     *  
     * @param musicMessage 音乐消息对象 
     * @return xml 
     */  
    public static String musicMessageToXml(MusicMessage musicMessage) {  
        xstream.alias("xml", musicMessage.getClass());  
        return xstream.toXML(musicMessage);  
    }  
  
    /** 
     * 图文消息对象转换成xml 
     *  
     * @param newsMessage 图文消息对象 
     * @return xml 
     */  
    public static String newsMessageToXml(NewsMessage newsMessage) {  
        xstream.alias("xml", newsMessage.getClass());  
        xstream.alias("item", new Article().getClass());  
        return xstream.toXML(newsMessage);  
    }  
  
    /** 
     * 扩展xstream,使其支持CDATA块 
     *  
     * @date 2013-05-19 
     */  
    private static XStream xstream = new XStream(new XppDriver() {  
        public HierarchicalStreamWriter createWriter(Writer out) {  
            return new PrettyPrintWriter(out) {  
                // 对所有xml节点的转换都增加CDATA标记  
                boolean cdata = true;  
  
                @SuppressWarnings("unchecked")  
                public void startNode(String name, Class clazz) {  
                    super.startNode(name, clazz);  
                }  
  
                protected void writeText(QuickWriter writer, String text) {  
                    if (cdata) {  
                        writer.write("<![CDATA[");  
                        writer.write(text);  
                        writer.write("]]>");  
                    } else {  
                        writer.write(text);  
                    }  
                }  
            };  
        }  
    });  
}  

说明:由于xstream框架本身并不支持CDATA块的生成,40~62行代码是对xtream做了扩展,使其支持在生成xml各元素值时添加CDATA块。




2016-12-23 16:53:57 u013248535 阅读数 29155
  • 微信公众号开发7-用户管理-微信开发php

    微信公众平台开发之微信用户开发管理是子恒老师《微信公众平台开发》视频教程的第7部。详细讲解了用php开发微信,对微信公众平台中的粉丝用户管理开发。内容包含微信公众平台用户分组,获取微信用户列表,查询用户详情等等。欢迎反馈,微信/QQ:68183131

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

发送消息,是指用户公众号向用户发送相应形式的消息。根据微信开发文档,由以下四种形式:被动回复,群发接口,客服消息接口以及模板消息接口。本文将基于Java语言以及个人微信测试号,说明被动回复、客服消息接口以及模板消息接口的使用实现,群发接口并未涉及。
1. 被动回复
被动回复只能应用于在接收到用户的互动数据之后,才能向用户发送消息。这一部分较为简单,正式进行微信开发的第一步就是,在公众号中基本配置->服务器配置中设置URL(服务器地址)时,这时该URL链接指定的地址就是对应着Java Web下的一个Servlet,配置好对应的Token及相关参数之后,则微信服务器将会将所有的用户与公众号的互动信息都转发到该Servlet,然后开发者根据接收到的用户互动数据,再进行处理。所谓的被动回复,就是在该Servlet中判断接收到你指定的消息时(例如某个字眼),则直接将想要回复的消息打包成官方指定的XML数据格式,写回到输出流中即可。在这里不过过多解释,如下示例代码:

response.getWriter().write( MessageUtil.MessageToXML(new TextMessage.Builder(fromUserName,toUserName,new Date().getTime(),"最新资讯请查看下方微信菜单栏,谢谢您的关注").build()));

2.客服消息接口
客服消息接口,应用于公众号主动向特定用户(必须满足该用户在48小时内与公众号有交互)发送特定格式的消息,应用场景例如:用户在微页面上完成了抽奖,而这时候公众号主动向用户推送中奖信息。所回复的不同消息的格式,参见开发者文档,下面以回复文本消息作为示例,需要注意的是推送的消息data必须满足json格式,请求类型为post。返回的json数据中,若errorcode为0,则代表推送成功。

 //推送中奖消息
        String data = "{"+
                "\"touser\":\""+openid+"\","+
                "\"msgtype\":\"text\","+
                "\"text\":"+
                "{"+
                "\"content\":\""+content+"\""+
                "}"+
                "}";
        System.out.println(data);
        String reMsg0 = UrlReqUtil.post("https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token="+access_token,data);
        JSONObject jsonObject = JSONObject.fromObject(reMsg0);
        if(0 != (Integer) jsonObject.get("errcode")) throw new RuntimeException("通知用户失败");

3.模板消息接口
模板消息接口的使用场景大体与客服消息接口一致,只是不需要证明对象用户“在线”,即48小时内与当前公众号有交互记录,因而应用范围更为广泛。在具有权限的服务号中使用该接口时,需要向系统申请对应模板,并得到模板号,作为调用凭据。在测试号环境下,则需要自定义模板。例如:
这里写图片描述
其中模板内容需要严格遵循指定的格式,即在需要调用才填入的变量值的定义方式为:{{xxxx.DATA}},其中“xxxx”为调用时对应的字段名。
以下是调用代码:jsonData数据部分遵循json数据格式。
其中touser:为用户在该公众号下的openid
template_id:为模板id
对于每个字段,包含两个值,一是value,即填入模板的具体值;二是color,即对应的字体颜色。
请求方式为post,判断是否成功同样是依据errcode字段,为0则成功。

        //推送模板消息
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String jsonData = "{" +
                "\"touser\":\""+openid+"\"," +
                "\"template_id\":\"maD2W1yaTvkXmh1dRjXEsMHUc9dDP8Xh1eANP***ig\"," +
                "\"topcolor\":\"#FF0000\"," +
                "\"data\":{" +
                "\"title\":{\"value\":\"恭喜您中奖啦\",\"color\":\"#173177\"}," +
                "\"nickname\":{\"value\":\""+nickname+"\",\"color\":\"#173177\"}," +
                "\"prizeLevel\":{\"value\":\""+rewardLevel+"\",\"color\":\"#173177\"}," +
                "\"prizeContent\":{\"value\":\""+ ConfigParamUtil.PRIZE_CONTENT.split(",")[rewardLevel]+"\",\"color\":\"#173177\"}," +
                "\"time\":{\"value\":\""+dateFormat.format(new Date())+"\",\"color\":\"#173177\"}," +
                "\"bonus\":{\"value\":\"10积分\",\"color\":\"#173177\"}}}";
        String reMsg1 = UrlReqUtil.post("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="+access_token,jsonData);
        JSONObject jsonObject = JSONObject.fromObject(reMsg1);
        if(0 != (Integer) jsonObject.get("errcode")) throw new RuntimeException("通知用户失败");
2016-12-26 14:30:19 u014783753 阅读数 923
  • 微信公众号开发7-用户管理-微信开发php

    微信公众平台开发之微信用户开发管理是子恒老师《微信公众平台开发》视频教程的第7部。详细讲解了用php开发微信,对微信公众平台中的粉丝用户管理开发。内容包含微信公众平台用户分组,获取微信用户列表,查询用户详情等等。欢迎反馈,微信/QQ:68183131

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


最近在做一个微信公众号的项目,和微信交互,获取用户基本信息是基本需求。获取用户基本信息有很多途径,现在我们讨论的是“网页授权获取用户基本信息”这种方式。

文章需要参考微信开发者文档:点击打开链接

另,会把部分java实现代码贴出来供参考。

微信公众平台通过OAUTH认证获取用户信息,这个过程大体分为以下几个步骤:

1、根据appid以及回调url获取code(时效==5min);

2、根据code获取access_token(时效in(1天、7天、30天、90天));

3、根据access_token获取用户基本信息;

具体例子如下:

1、根据appid和回调url获取code。

     假如微信公众平台配置的业务回调url为:"https://myreturn.com.cn"、appid为:"fdsaadeicekandead";

    再结合文章前边连接给出的文档,那么我们需要请求的url为:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=fdsaadeicekandead&redirect_uri=https%3A%2F%2FmySite/myreturn&response_type=code&scope=snsapi_base&state=123#wechat_redirect

   发起请求的代码

@RequestMapping("/loginWx/")
	public ModelAndView initWxLogin() {
		try {
			String url = "
https://open.weixin.qq.com/connect/oauth2/authorize?appid=fdsaadeicekandead&redirect_uri=https%3A%2F%2FmySite/myreturn&response_type=code&scope=snsapi_base&state=123#wechat_redirect";
ModelAndView modelAndView = new ModelAndView(url);return modelAndView;} catch (UnsupportedEncodingException e) {e.printStackTrace();return new ModelAndView("error");}}



2、根据code获取access_token的代码如下:

@RequestMapping(value="/myreturn")
	public ModelAndView myreturn(String code, String state){
		if (null != code) {
			try {
                            HttpUriRequest httpUriRequest = RequestBuilder.post()
				.setUri("https://api.weixin.qq.com/sns/oauth2/access_token")
				.addParameter("appid", appid)
				.addParameter("secret", secret).addParameter("code", code).addParameter("grant_type", "authorization_code").build();
				Token token = httpClient.execute(httpUriRequest , responseHandler,HttpClientContext.create());				
			} catch (Exception e) {
				e.printStackTrace();
			}
		
			return new ModelAndView("跳转的url");
		
		}
	}
Toke类参照给出的连接定义即可;


3、根据access_token获取用户的基本信息:

HttpUriRequest httpUriRequest = RequestBuilder.post()
				.setUri(BASE_URI+"/sns/userinfo")
/*				.setUri(BASE_URI+"/cgi-bin/user/info")
*/				.addParameter(getATPN(),access_token)
				.addParameter("openid",openid)
				.addParameter("lang","zh_CN")
				.build();
User user = httpClient.execute(httpUriRequest , responseHandler,HttpClientContext.create());

User参照给出的链接指出的用户信息定义即可;




微信开发

阅读数 44

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