微信公众号的用户怎么提取
1、(一)思路我们来研踅字忏蓣究一下,要想获取到个人信息,是如何一个流程呢?路线图:上面,画了一个简单的一个流程图,我想,芬简砝鬃看着这个应该觉得不难吧。是的,确实思路很简单,但是,,里面的坑也不少。接下来,我对两种情况都进行讲解。(二)情况一:通过用户与服务器进行消息交互,来获取用户信息思路:针对这种情况的话,比较简单,因为,我们在做用户与服务器进行消息交互的时候,我们可以知道,用户发送的内容是以XML的形式进行发送的,然后服务器,首先接受到XML,然后再把XML转为Map对象,再从Map对象中获取对应的内容即可。那么,发送的XML的字段是个怎么样呢?字段信息:ToUserName:发送给谁的IDFromUserName:发消息方的ID(其实也就是用户的OpenId)CreateTime:消息发送时间,时间戳MsgType:消息类似,有文本,图片,音频,视频,事件推送等Content:发送的内容通过这个,我想大家,再结合上面给的流程图,是不是发现了什么呢?是的,这个OpenId,我们已经获取了呀,那是不是可以直接获取到用户信息了呢?。。。。emmmmmm,这样说吧。差不多是可以的,那具体是怎么做呢?紧接着往下看,仔细看我其中的注释步骤:1:解析发送过来的XML信息格式,将其转为Map格式/** * XML格式转为map格式 * @param request * @return */ public static Map<String , String> xmlToMap(HttpServletRequest request){ Map<String ,String> map = new HashMap<String , String>(); try { InputStream inputStream =null; inputStream = request.getInputStream(); SAXReader reader = new SAXReader(); Document doc = reader.read(inputStream); Element rootElement = doc.getRootElement(); List<Element> elements = rootElement.elements(); for (Element el:elements) { map.put(el.getName() , el.getText()); } inputStream.close(); return map ; } catch (Exception e) { e.printStackTrace(); return null ; } }备注:记得导入相应的包哦。。比如dom4j还有xsreader。。2:获取用户的个人信息package com.hnu.scw.utils;import com.hnu.scw.model.AccessToken;import net.sf.json.JSONObject;/*** @author scw* @create 2018-01-18 16:42* @desc 用于获取微信用户的信息**/public class WeiXinUserInfoUtils {private static final String GET_USERINFO_URL = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";/** * 获取微信用户账号的相关信息 * @param opendID 用户的openId,这个通过当用户进行了消息交互的时候,才有 * @return */public static String getUserInfo(String opendID){AccessToken accessToken = WeiXinUtils.getAccessToken();//获取access_tokenString token = accessToken.getToken();String url = GET_USERINFO_URL.replace("ACCESS_TOKEN" , token);url = url.replace("OPENID" ,opendID);JSONObject jsonObject = WeiXinUtils.doGetStr(url);return jsonObject.toString();}}备注:传入的参数就是咱们之前说过的,FromUserName的值,这个应该不用多解释吧。因为,对于传入的XML,我们已经存入了Map中,那么直接从Map取出对应的字段信息就可以了,String fromUserName = map.get("FromUserName");3:通过上面,我们就得到了具体的用户信息的Json格式了,当然,我上面的方法将Json内容转为了String,我这里只是用于查看是否获取到信息了而已,所以,你们就根据各自的需求进行处理就可以了,该解析的就解析即可。。总结:上面的这种方法是不是很简单,这个没什么难的,而且这个根据微信公众号的开发手册也可以分析出来。缺点:我们发现了,这种方法,只有当用户进行了消息交互,才会有FromUserName(这时候可以等价看成是OpenId),那么我们在实际开发中,肯定遇到了一种情况,就是用户没有进行消息交互,直接点击一个菜单按钮,然后就把用户信息自动显示到了一个页面中,那这样是怎么做,方法是一样吗?不多说,继续看下面~~~~~~~~~(三)情况二:通过点击按钮,来直接获取到用户信息思路:首先,点击菜单按钮,要先到网页授权的接口去请求(主要是获取Code,这是必须要的一个参数),然后再重定向到我们自己菜单按钮实际想去的URL,然后再获取OpenId,再通过OpenId,获取用户信息。。哇塞,咦,思路挺简单的嘛。。那么,我们开始工作。。步骤:1:创建菜单对于这个自定义菜单的话,不是主要介绍的了,这个如果做过微信公众号开发的,应该都明白吧。所以,我这就贴一点关键代码:ViewButton viewButton = new ViewButton();viewButton.setName("view菜单");viewButton.setType("view");//viewButton.setUrl("http://myjava.ngrok.xiaomiqiu.cn/tomainpage");viewButton.setUrl("https://open.weixin.qq.com/connect/oauth2/authorize?appid=XXXXXX&redirect_uri=http://myjava.ngrok.xiaomiqiu.cn/tologin/userinfo&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect");备注:大家,请注意,这个view菜单的URL,和我们平常的跳转的区别再哪里。。分析:知识点1:https://open.weixin.qq.com/connect/oauth2/authorize?appid=XXXX这个就是网页授权的接口地址,其中的appid就是我们自己微信公众号申请的时候,给我们的唯一值,这个大家去微信公众号查看即可。知识点2:redirect_uri=http://myjava.ngrok.xiaomiqiu.cn/tologin/userinfo&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect");这个就是我们实际想要点击按钮,跳转到的页面,这个就和咱们平常的跳转是一样的,所以一定要记住,要先去授权页面,再重定向回去(主要是为了获取code参数)。2:配置微信公众号的网页授权域名备注:这个是在自己微信公众号的开发管理模块里面的,而且,我这里用的是测试号进行的(当然,如果有企业号这更加好呀。界面也是一样)注意点:对添加的回调页面域名:首先,不能加入http://这个,对于平常的链接,我想都有这个,这个是请求协议,但这里千万不能加入;另外,只需要写总的域名地址,不需要精确到最内层。打个比方:一般的:http://myjava.ngrok.xiaomiqiu.cn/tologin/userinfo这里就配置就只需要:(其实就是配置我们的服务器域名即可)myjava.ngrok.xiaomiqiu.cn3:编写,相应的处理内容(关键代码,请仔细看)备注:我用的是SSH(SpringMVC+Spring+Hibernate)框架来进行开发的,当然,用Servlet也可以,用SSM(SpringMVC+Spring+Mybatis)或者用SSH(Struts+Spring+Hibernate)都可以,这个根据自己的需求即可相应的改变呢!!(另外,这个几个框架,我其他的文章都有很详细的介绍了,所以自己看看相应配置即可)Controller层代码:package com.hnu.scw.controller;import com.hnu.scw.bean.WeiXinUser;import com.hnu.scw.service.WeiXinUserInfoService;import com.hnu.scw.utils.WeiXinUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import java.util.HashMap;import java.util.Map;/*** @author scw* @create 2018-01-18 17:47* @desc 获取微信用户的所有信息,这个主要是为了不要用户自己填写个人信息**/@Controllerpublic class WeiXinUserInfoController {@Autowiredprivate WeiXinUserInfoService userService;/** * 进行网页授权,便于获取到用户的绑定的内容 * @param request * @param session * @param map * @return */@RequestMapping("/tologin/userinfo")public String check(HttpServletRequest request , HttpSession session, Map<String, Object> map) {//首先判断一下session中,是否有保存着的当前用户的信息,有的话,就不需要进行重复请求信息WeiXinUser weiXinUser = null ;if(session.getAttribute("currentUser") != null){weiXinUser = (WeiXinUser) session.getAttribute("currentUser");}else {/** * 进行获取openId,必须的一个参数,这个是当进行了授权页面的时候,再重定向了我们自己的一个页面的时候, * 会在request页面中,新增这个字段信息,要结合这个ProjectConst.Get_WEIXINPAGE_Code这个常量思考 */String code = request.getParameter("code");try {//得到当前用户的信息(具体信息就看weixinUser这个javabean)weiXinUser = getTheCode(session, code);//将获取到的用户信息,放入到session中session.setAttribute("currentUser", weiXinUser);} catch (Exception e) {e.printStackTrace();}}map.put("weiXinUser", weiXinUser);return "hello";}/** * 获取用户的openId * @param session * @param code * @return 返回封装的微信用户的对象 */private WeiXinUser getTheCode(HttpSession session, String code) {Map<String , String> authInfo = new HashMap<>();String openId = "";if (code != null){// 调用根据用户的code得到需要的授权信息authInfo= userService.getAuthInfo(code);//获取到openIdopenId = authInfo.get("Openid");}// 获取基础刷新的接口访问凭证(目前还没明白为什么用authInfo.get("AccessToken");这里面的access_token就不行)String accessToken = WeiXinUtils.getAccessToken().getToken();//获取到微信用户的信息WeiXinUser userinfo = userService.getUserInfo(accessToken ,openId);return userinfo;}}Service层接口:package com.hnu.scw.service;import com.hnu.scw.bean.WeiXinUser;import java.util.Map;/*** 用于进行微信用户个人信息的操作接口*/public interface WeiXinUserInfoService {/** * 获取到微信个人用户的信息 * @param accessToken * @param openId * @return */WeiXinUser getUserInfo(String accessToken, String openId);/** *用于获取网页授权后的信息字段,其中主要是获取openId * @param code 授权码 * @return */Map<String , String > getAuthInfo(String code);/** * 进行网页授权的认证 * @param code 授权码 * @return */Map<String,String> oauth2GetOpenid(String code);}Service层实现:package com.hnu.scw.service.imp;import com.hnu.scw.bean.WeiXinUser;import com.hnu.scw.projectconst.ProjectConst;import com.hnu.scw.service.WeiXinUserInfoService;import com.hnu.scw.utils.WeiXinUtils;import net.sf.json.JSONObject;import org.springframework.stereotype.Service;import java.util.HashMap;import java.util.Map;/*** @author scw* @create 2018-01-18 17:51* @desc 用于获取微信用户的信息**/@Servicepublic class WeiXinUserInfoImlp implements WeiXinUserInfoService {/** * 获取微信用户的信息 * @param accessToken * @param openId * @return */@Overridepublic WeiXinUser getUserInfo(String accessToken, String openId) {WeiXinUser weixinUserInfo = null;// 拼接获取用户信息接口的请求地址String requestUrl = ProjectConst.GET_WEIXIN_USER_URL.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);// 获取用户信息(返回的是Json格式内容)JSONObject jsonObject = WeiXinUtils.doGetStr(requestUrl);if (null != jsonObject) {try {//封装获取到的用户信息weixinUserInfo = new WeiXinUser();// 用户的标识weixinUserInfo.setOpenId(jsonObject.getString("openid"));// 昵称weixinUserInfo.setNickname(jsonObject.getString("nickname"));// 用户的性别(1是男性,2是女性,0是未知)weixinUserInfo.setSex(jsonObject.getInt("sex"));// 用户所在国家weixinUserInfo.setCountry(jsonObject.getString("country"));// 用户所在省份weixinUserInfo.setProvince(jsonObject.getString("province"));// 用户所在城市weixinUserInfo.setCity(jsonObject.getString("city"));// 用户头像weixinUserInfo.setHeadImgUrl(jsonObject.getString("headimgurl"));} catch (Exception e) {if (0 == weixinUserInfo.getSubscribe()) {System.out.println("用户并没有关注本公众号");} else {int errorCode = jsonObject.getInt("errcode");String errorMsg = jsonObject.getString("errmsg");System.out.println("由于"+errorCode +"错误码;错误信息为:"+errorMsg+";导致获取用户信息失败");}}}return weixinUserInfo;}/** * 进行用户授权,获取到需要的授权字段,比如openId * @param code 识别得到用户id必须的一个值 * 得到网页授权凭证和用户id * @return */@Overridepublic Map<String, String> oauth2GetOpenid(String code) {//自己的配置appid(公众号进行查阅)String appid = ProjectConst.PROJECT_APPID;//自己的配置APPSECRET;(公众号进行查阅)String appsecret = ProjectConst.PROJECT_APPSECRET;//拼接用户授权接口信息String requestUrl = ProjectConst.GET_WEBAUTH_URL.replace("APPID", appid).replace("SECRET", appsecret).replace("CODE", code);//存储获取到的授权字段信息Map<String, String> result = new HashMap<String, String>();try {JSONObject OpenidJSONO = WeiXinUtils.doGetStr(requestUrl);//OpenidJSONO可以得到的内容:access_token expires_in refresh_token openid scopeString Openid = String.valueOf(OpenidJSONO.get("openid"));String AccessToken = String.valueOf(OpenidJSONO.get("access_token"));//用户保存的作用域String Scope = String.valueOf(OpenidJSONO.get("scope"));String refresh_token = String.valueOf(OpenidJSONO.get("refresh_token"));result.put("Openid", Openid);result.put("AccessToken", AccessToken);result.put("scope", Scope);result.put("refresh_token", refresh_token);} catch (Exception e) {e.printStackTrace();}return result;}/** * 获取到微信用户的唯一的OpendID * @param code 这是要获取OpendId的必须的一个参数 * @return */@Overridepublic Map<String , String> getAuthInfo(String code) {//进行授权验证,获取到OpenID字段等信息Map<String, String> result = oauth2GetOpenid(code);// 从这里可以得到用户openidString openId = result.get("Openid");return result;}}4:GET请求接口的代码:package com.hnu.scw.utils;import com.hnu.scw.menu.BaseButton;import com.hnu.scw.menu.ClickButton;import com.hnu.scw.menu.CustomeMenu;import com.hnu.scw.menu.ViewButton;import com.hnu.scw.model.AccessToken;import net.sf.json.JSONObject;import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.client.ClientProtocolException;import org.apache.http.client.methods.HttpGet;import org.apache.http.client.methods.HttpPost;import org.apache.http.entity.StringEntity;import org.apache.http.impl.client.DefaultHttpClient;import org.apache.http.util.EntityUtils;import java.io.IOException;import java.io.UnsupportedEncodingException;/*** @author scw* @create 2018-01-17 14:13* @desc 用户获取access_token,众号调用各接口时都需使用access_token**/public class WeiXinUtils {/** * Get请求,方便到一个url接口来获取结果 * @param url * @return */public static JSONObject doGetStr(String url){DefaultHttpClient defaultHttpClient = new DefaultHttpClient();HttpGet httpGet = new HttpGet(url);JSONObject jsonObject = null;try{HttpResponse response = defaultHttpClient.execute(httpGet);HttpEntity entity = response.getEntity();if(entity != null){String result = EntityUtils.toString(entity, "UTF-8");jsonObject = JSONObject.fromObject(result);}} catch (ClientProtocolException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return jsonObject;}5:获取Access_Token代码:(这个就是在4中的类中的方法)/** * 获取access_token * @return */public static AccessToken getAccessToken(){AccessToken accessToken = new AccessToken();String url = ACCESS_TOKEN_URL.replace("APPID" ,APPID).replace("APPSECRET",APPSECRET);JSONObject jsonObject = doGetStr(url);if(jsonObject !=null){accessToken.setToken(jsonObject.getString("access_token"));accessToken.setExpireIn(jsonObject.getInt("expires_in"));}return accessToken;}6:Access_Token的实体类package com.hnu.scw.model;/*** @author scw* @create 2018-01-17 14:35* @desc 封装AccessToken的实体**/public class AccessToken {private String token;private int expireIn;public String getToken() {return token;}public void setToken(String token) {this.token = token;}public int getExpireIn() {return expireIn;}public void setExpireIn(int expireIn) {this.expireIn = expireIn;}}7:用户信息的实体类package com.hnu.scw.bean;/*** @author scw* @create 2018-01-18 17:11* @desc 对于微信用户本身存在的信息的一个javabean,不需要在数据库中进行处理**/public class WeiXinUser {// 用户的标识private String openId;// 关注状态(1是关注,0是未关注),未关注时获取不到其余信息private int subscribe;// 用户关注时间,为时间戳。如果用户曾多次关注,则取最后关注时间private String subscribeTime;// 昵称private String nickname;// 用户的性别(1是男性,2是女性,0是未知)private int sex;// 用户所在国家private String country;// 用户所在省份private String province;// 用户所在城市private String city;// 用户的语言,简体中文为zh_CNprivate String language;// 用户头像private String headImgUrl;public String getOpenId() {return openId;}public void setOpenId(String openId) {this.openId = openId;}public int getSubscribe() {return subscribe;}public void setSubscribe(int subscribe) {this.subscribe = subscribe;}public String getSubscribeTime() {return subscribeTime;}public void setSubscribeTime(String subscribeTime) {this.subscribeTime = subscribeTime;}public String getNickname() {return nickname;}public void setNickname(String nickname) {this.nickname = nickname;}public int getSex() {return sex;}public void setSex(int sex) {this.sex = sex;}public String getCountry() {return country;}public void setCountry(String country) {this.country = country;}public String getProvince() {return province;}public void setProvince(String province) {this.province = province;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}public String getLanguage() {return language;}public void setLanguage(String language) {this.language = language;}public String getHeadImgUrl() {return headImgUrl;}public void setHeadImgUrl(String headImgUrl) {this.headImgUrl = headImgUrl;}}8:一些静态常量的接口地址:package com.hnu.scw.projectconst;/*** @author scw* @create 2018-01-18 15:31* @desc 项目相关的静态量**/public class ProjectConst {/** * 用于获取当前与微信公众号交互的用户信息的接口(一般是用第一个接口地址) */public static final String GET_WEIXIN_USER_URL = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID";public final static String GetPageUsersUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";/** * 用于进行网页授权验证的接口URL,通过这个才可以得到opendID等字段信息 */public final static String GET_WEBAUTH_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";/** * 用于进行当点击按钮的时候,能够在网页授权之后获取到code,再跳转到自己设定的一个URL路径上的接口,这个主要是为了获取之后于 * 获取openId的接口相结合 * 注意:参数:toselfURL 表示的是当授权成功后,跳转到的自己设定的页面,所以这个要根据自己的需要进行修改 */public final static String Get_WEIXINPAGE_Code = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=toselfURL&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect";/** * 获取access_token的URL */private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";}9:大功告成。。。。完美解决。。参考于网站https://blog.csdn.net/cs_hnu_scw/article/details/79103129