微信公众号的二次开发(三、接收事件推送获取用户信息)

在上篇《微信公众号的二次开发(二 自定义菜单的创建)》中我们介绍了自定义菜单的创建。本篇文章将介绍如何通过接收事件推送来获取用户信息。首先我们阅读官方文档:

根据官方文档的介绍 微信公众号会将时间推送到开发者填写的URL上,这个URL就是我们在
微信公众号的二次开发(一 订阅号没有获取网页授权的解决方法) 中配置的服务器配置的地址。这里还有一点要注意,在配置服务器地址时,官方文档上明确注明接口为GET方法。

而在接受推送事件时,我们就要用POST方法来接受微信后台传递的数据。

    @ApiOperation("Used to Verify the Signature of Wechat Public Platform")
    @RequestMapping(value = "checkSignature", method = RequestMethod.POST)
    public void responseEvent(HttpServletRequest req, HttpServletResponse resp,HttpSession session) throws Exception {
        req.setCharacterEncoding("UTF-8");
        resp.setCharacterEncoding("UTF-8");
        PrintWriter out = resp.getWriter();
        String message = "success";
        try {
            //把微信返回的xml信息转义成map
            Map<String, String> map = XmlUtil.xmlToMap(req);
            String fromUserName = map.get("FromUserName");//消息来源用户标识  	发送方帐号(一个OpenID)
            String toUserName = map.get("ToUserName");//消息目的用户标识
            String msgType = map.get("MsgType");//消息类型
            String content = map.get("Content");//消息内容
            String eventType = map.get("Event");
            String  key=map.get("EventKey");
            MessageUtil messageUtil=new MessageUtil();

            if(MessageUtil.MSGTYPE_EVENT.equals(msgType)){//如果为事件类型
                if(MessageUtil.MESSAGE_SUBSCIBE.equals(eventType)){//处理订阅事件
                    message = messageUtil.subscribeForText(toUserName, fromUserName,session);
                }else if(MessageUtil.MESSAGE_UNSUBSCIBE.equals(eventType)){//处理取消订阅事件
                    message = messageUtil.unsubscribe(fromUserName);
                }else if(MessageUtil.MESSAGE_CLICK.equals(eventType)){
                    //根据自定义菜单中的key来进行业务处理
                    if(key.equals("32")){
                        content="<a href='http://www.mdline.cn'>健康档案</a>";
                        message = messageUtil.textMsg(toUserName, fromUserName,content);

                     }
              }
             }else{
                //微信消息分为事件推送消息和普通消息,非事件即为普通消息类型
                switch (msgType) {
                    case "text":{//文本消息
                        if(content.equals("测试")){
                            content ="这是开发测试";
                        }else{
                            content ="未能识别,详情访问:http://www.mdline.cn";
                        }
                        message = messageUtil.textMsg(toUserName, fromUserName,content);
                        break;
                    }
                    default:{//其他类型的普通消息
                        break;
                    }
                }
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }finally{
            out.println(message);
            if(out!=null){
                out.close();
            }
        }

    }


下面是处理订阅事件即关注公众号时的方法:

/*
     * 响应订阅事件--回复文本消息
     */
    public  String subscribeForText(String toUserName,String fromUserName,HttpSession session){
        //订阅成功后,根据openId获取用户信息 并注册。  fromUserName即为该用户的openid。
        //因为订阅号没有获取用户信息授权的权限,code获取不到。无法用code换取openid。因此获取openid后直接调用获取用户信息的方法
        // 获取基础刷新的接口访问凭证(目前还没明白为什么用authInfo.get("AccessToken");这里面的access_token就不行)
        String accessToken = WeiXinUtils.getAccessToken().getToken();
        try {
            messageUtil.userService.getUserInfo(accessToken,fromUserName,session);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return textMsg(toUserName, fromUserName, "欢迎关注,精彩内容不容错过!!!,详情请访问网址:http://www.mdline.cn");
    }

在这里 因为springboot无法扫描到工具类中的userService 所以我们要在工具类中添加下面的代码来将其注册到bean中。


    @Autowired
    private UserService userService;

    public  static MessageUtil messageUtil ;

    @PostConstruct
    public void init() {
        messageUtil = this;
        messageUtil.userService=this.userService;
        //初使化时将已静态化的accessTokenOcrRepository实例化
    }

这样我们就可以在工具类中调用userService的方法。

  @Override
    public User getUserInfo(String accessToken, String openId,HttpSession session) throws IOException {

        User 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 User();
                // 用户的标识
                weixinUserInfo.setOpenId(jsonObject.getString("openid"));
                // 昵称
                weixinUserInfo.setNickName(jsonObject.getString("nickname"));
                // 用户的性别(1是男性,2是女性,0是未知)
                weixinUserInfo.setSex(jsonObject.getInteger("sex"));
                weixinUserInfo.setLanguage(jsonObject.getString("zh_CN"));
                weixinUserInfo.setSubscribeTime(jsonObject.getString("subscribe_time"));
                // 用户所在国家
                weixinUserInfo.setCountry(jsonObject.getString("country"));
                // 用户所在省份
                weixinUserInfo.setProvince(jsonObject.getString("province"));
                // 用户所在城市
                weixinUserInfo.setCity(jsonObject.getString("city"));
                // 用户头像
                weixinUserInfo.setHeadImgUrl(jsonObject.getString("headimgurl"));
            } catch (Exception e) {
                    int errorCode = jsonObject.getInteger("errcode");
                    String errorMsg = jsonObject.getString("errmsg");
                    System.out.println("由于"+errorCode +"错误码;错误信息为:"+errorMsg+";导致获取用户信息失败");
            }
        }
        //获取用户信息后,可以存入数据库
        User user = userDao.save(weixinUserInfo);
         session.setAttribute(weixinUserInfo.getOpenId(),user);
       return user;
    }

除了响应关注事件,还可以对click等事件进行回复。
在这里插入图片描述
根据官方文档需要我们将回复的消息以xml的形式发送给微信后台。 下面我将用到的工具类贴在下面
XmlUtil类:

import com.hbrc.hbrcpublicserver.entity.wxmenu.TextMessage;
import com.thoughtworks.xstream.XStream;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @ClassName XmlUtil
 * @Description TODO
 * @Author Administrator
 * @Date 2019/6/11 15:49
 * @Version 1.0
 **/
public class XmlUtil {
    /*
     * xml转map
     */
    public static Map<String, String> xmlToMap(HttpServletRequest request) throws IOException, DocumentException {
        HashMap<String, String> map = new HashMap<String,String>();
        SAXReader reader = new SAXReader();
        InputStream ins = request.getInputStream();
        Document doc = reader.read(ins);
        Element root = doc.getRootElement();
        @SuppressWarnings("unchecked")
        List<Element> list = (List<Element>)root.elements();

        for(Element e:list){
            map.put(e.getName(), e.getText());
        }
        ins.close();
        return map;
    }
    /*
     * 文本消息对象转xml
     */
    public static String textMsgToxml(TextMessage textMessage){
        XStream xstream = new XStream();
        xstream.alias("xml", textMessage.getClass());
        return xstream.toXML(textMessage);
    }
}

MessageUtil类:

import com.hbrc.hbrcpublicserver.entity.User;
import com.hbrc.hbrcpublicserver.entity.wxmenu.TextMessage;
import com.hbrc.hbrcpublicserver.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Date;

/**
 * @ClassName MessageUtil
 * @Description TODO
 * @Author Administrator
 * @Date 2019/6/11 16:13
 * @Version 1.0
 * @Description: 消息处理工具类
 **/
@Component
public class MessageUtil {
    public static final String MSGTYPE_EVENT = "event";//消息类型--事件
    public static final String MESSAGE_SUBSCIBE = "subscribe";//消息事件类型--订阅事件
    public static final String MESSAGE_UNSUBSCIBE = "unsubscribe";//消息事件类型--取消订阅事件
    public static final String MESSAGE_TEXT = "text";//消息类型--文本消息
    public static final String MESSAGE_CLICK = "CLICK";//消息类型-点击事件


    @Autowired
    private UserService userService;

    public  static MessageUtil messageUtil ;

    @PostConstruct
    public void init() {
        messageUtil = this;
        messageUtil.userService=this.userService;
        //初使化时将已静态化的accessTokenOcrRepository实例化
    }



    /*
     * 组装文本消息
     */
    public  String textMsg(String toUserName,String fromUserName,String content){
        TextMessage text = new TextMessage();
        text.setFromUserName(toUserName);
        text.setToUserName(fromUserName);
        text.setMsgType(MESSAGE_TEXT);
        text.setCreateTime(new Date().getTime());
        text.setContent(content);
        return XmlUtil.textMsgToxml(text);
    }

    /*
     * 响应订阅事件--回复文本消息
     */
    public  String subscribeForText(String toUserName,String fromUserName,HttpSession session){
        //订阅成功后,根据openId获取用户信息 并注册。  fromUserName即为该用户的openid。
        //因为订阅号没有获取用户信息授权的权限,code获取不到。无法用code换取openid。因此获取openid后直接调用获取用户信息的方法
        // 获取基础刷新的接口访问凭证(目前还没明白为什么用authInfo.get("AccessToken");这里面的access_token就不行)
        String accessToken = WeiXinUtils.getAccessToken().getToken();
        try {
            messageUtil.userService.getUserInfo(accessToken,fromUserName,session);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return textMsg(toUserName, fromUserName, "欢迎关注,精彩内容不容错过!!!,详情请访问网址:http://www.mdline.cn");
    }

    /*
     * 响应取消订阅事件
     */
    public  String unsubscribe(String fromUserName){
        //取关后 删除数据库中的用户信息,后期如有关联删除失败再做处理。如有关联如 oneToMany 级联属性设置为Cascade.ALL。
        messageUtil.userService.deleteByOpenid(fromUserName);
        System.out.println("用户:"+ fromUserName +"取消关注~");
        return "";
    }
}

TextMessage类:

   // 文本内容
    private String Content;
    // 	消息id,64位整型
    private String  MsgId;

BaseMessage类:

//	开发者微信号
    private String ToUserName;
    //发送方帐号(一个OpenID)
    private String FromUserName;
    //消息创建时间 (整型)
    private long CreateTime;
    /**
     * 消息类型
     * text 文本消息
     * image 图片消息
     * voice 语音消息
     * video 视频消息
     * music 音乐消息
     * event 事件推送
     */
    private String MsgType;

    private String Event;

这里只是文本消息,如果需要回复图文语音等消息可以自行封装。
到这里,订阅号获取用户信息的功能已经基本实现了。
另外多说一句,在接收微信发送给我们的xml包的方法里 我们定义了 String message = “success”;并在finally中返回给微信服务器。

理由参考官方文档入门指引。

ASP.NET微信公众号平台系统源码是一种用于构建微信公众号的框架和代码库。它提供了一系列的接口和功能,帮助开发人员快速地搭建和定制自己的微信公众号平台。 该系统源码基于ASP.NET技术开发,结合微信公众号开放平台的接口和功能进行了集成。它提供了一种便捷的方式,让开发人员可以通过编写少量的代码来实现与微信公众号的交互和功能扩展。 ASP.NET微信公众号平台系统源码具备以下特点和功能: 1. 用户管理:能够管理微信公众号用户信息,包括用户的基本信息、关注状态、交互记录等。 2. 消息管理:能够接收和发送微信公众号消息,包括文本消息、图片消息、语音消息、视频消息等。 3. 菜单管理:能够创建和管理微信公众号的自定义菜单,包括点击菜单、跳转链接、触发推送消息等。 4. 接口管理:能够对接微信公众号开放平台的各种接口,包括获取用户信息、发送模板消息、创建二维码等。 5. 素材管理:能够上传和管理微信公众号的素材,包括图文消息、图片、音频、视频等。 6. 数据统计:能够统计微信公众号用户活跃度、消息互动情况、菜单点击量等数据。 ASP.NET微信公众号平台系统源码的优势在于它具有良好的扩展性和定制性,开发人员可以根据自己的需求进行二次开发和定制。同时,它也提供了一定的安全机制和权限控制,保障了用户信息和数据的安全性。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值