美文网首页微信公众号开发
微信公众号快速开发(三)多种消息类型处理

微信公众号快速开发(三)多种消息类型处理

作者: 永动的图灵机 | 来源:发表于2020-03-08 13:51 被阅读0次

之前介绍了自动回复,下面介绍一些常见的消息处理样式

开始开发——关键字回复

功能描述

当我们公众号发送一些关键词的时候,公众号会回复自动回复有关关键词的信息。

实现思路

  1. 消息类型为文本样式
  2. 接收的客服端消息中要包含该关键字

代码开发

为便于扩展,将消息处理的方法写到服务层,新建收发信息的dto

一、便于扩展为不同类型的消息,修改收发消息的封装,改用dto模式

  • 基础消息实体类
@Data
@XmlAccessorType(XmlAccessType.FIELD) // 映射类中的所有字段到XML
public class MsgSendEntity {
    /**
     * 公有部分
     */
    //  开发者微信号
    @XmlElement(name = "ToUserName") // 指定名称映射
    private String toUserName;

    // 发送方帐号(一个OpenID)
    @XmlElement(name = "FromUserName")
    private String fromUserName;

    // 消息创建时间 (整型)
    @XmlElement(name = "CreateTime")
    private Long createTime;

    // 消息类型
    @XmlElement(name = "MsgType")
    private String msgType;

    // 消息id,64位整型
    @XmlElement(name = "MsgId")
    private Long msgId;

}
@Data
@XmlAccessorType(XmlAccessType.FIELD)
public class MsgReplyEntity {
    //  用户的OpenID
    @XmlElement(name = "ToUserName")
    private String toUserName;

    // 测试号的微信号
    @XmlElement(name = "FromUserName")
    private String fromUserName;

    // 消息创建时间 (整型)
    @XmlElement(name = "CreateTime")
    private Long createTime;

    // 消息类型
    @XmlElement(name = "MsgType")
    private String msgType;

    // 文本消息内容
    @XmlElement(name = "Content")
    private String content;
}
  • 新建消息实体类的dto
@Data
@XmlRootElement(name = "xml") // 根节点
@XmlAccessorType(XmlAccessType.FIELD) // 映射类中的所有字段到XML
public class MsgSendDto extends MsgSendEntity {

    // 文本消息内容
    @XmlElement(name = "Content")
    private String content;
}
@Data
@XmlRootElement(name="xml")
@XmlAccessorType(XmlAccessType.FIELD)
public class MsgReplyDto extends MsgReplyEntity {

}

二、抽取消息处理的服务类与消息处理的方法到服务层

@Service
public class MsgHandleServiceImpl implements IMsgHandleService {
    
    @Override
    public MsgReplyEntity handle(MsgSendEntity msgSend) {
        WeChatUtil.getLogger().info("客户端接收的内容为:{}"+msgSend);

        // 服务端消息回复的实体类
        MsgReplyEntity msgReply = new MsgReplyEntity();
        // 根据接收的信息回复,接收和发送方相反
        msgReply.setFromUserName(msgSend.getToUserName());
        msgReply.setToUserName(msgSend.getFromUserName());
        msgReply.setCreateTime(new Date().getTime());

        String msgType = msgSend.getMsgType();
        String contentReply = null;
        // 处理不同类型的消息
        if (msgType.equals(WeChatConstants.MSG_TYPE_TEXT)) {
            // 默认回复相同的类型消息
            msgReply.setMsgType(msgType);
            String contentSend = msgSend.getContent();

            // 关键词处理
            if (contentSend.contains("你好")) {
                contentReply = "你好吗\r\nhow are you";
            } else if (contentSend.contains("哈哈")||contentSend.contains("haha")) {
                contentReply = "我也喜欢哈哈大笑";
            } else if (contentSend.contains("chet")){
                msgReply.setMsgType(WeChatConstants.MSG_TYPE_NEWS);
                //设置图文个数
                msgReply.setArticleCount(1);
                //设置图文明细列表
                ArticleItem item = new ArticleItem();
                item.setTitle("chet的github博客");
                item.setPicUrl("https://chetwhy.github.io/");
                item.setDescription("chet的掘金博客");
                item.setUrl("https://juejin.im/timeline");
                msgReply.setItem(new ArticleItem[]{item});
            }else {
                // 非关键字,原样返回
                contentReply = msgSend.getContent();
            }
            msgReply.setContent(contentReply);
        }
        
        WeChatUtil.getLogger().info("服务端回复的内容为:{}"+msgReply);
        return msgReply;
    }
}

三、封装的常量类

public class WeChatConstants {

    /**
     * 公众号appid
     */
    public static String APP_ID = "wxa02348cd5ec17d28"; 

    /**
     * AppSecret
     */
    public static String APPSECRET = "***"; 

    /**
     * 公众号配置相关
     */
    public static final String URL = "ups.tiaodu.cn";
    public static final String TOKEN = "123qwe";

    /**
     * 消息类型
     */
    public static final String MSG_TYPE_TEXT = "text";
    public static final String MSG_TYPE_NEWS = "news";
}

测试样例

在手机微信或电脑微信直接发送带【关键字】的信息即可

image

开始开发——接收事件推送

功能描述

微信公众号有多种不同事件信息,包括其触发事件的类型,响应处理。最常见的,当我们点击关注某公众号之后,公众号将自动推送给我们介绍信息后者活动宣传等。

实现思路

一、参考微信公众平台技术文档->消息管理->接收事件推送

image

二、查看对应消息事件格式,扩展消息实体的dto

image

三、在原消息基础上,添加事件的逻辑判断

下面以关注/取消事件和自定义菜单事件做演示

代码开发

1为MsgSendDto添加事件属性

...
public class MsgSendDto {
    ...
    // 事件类型 subscribe(订阅)、unsubscribe(取消订阅)、CLICK(点击菜单)
    @XmlElement(name = "Event")
    private String event;
}    

2增加常量类

public class WeChatConstants {
    ...
        
    public static final String MSG_TYPE_EVENT = "event";
    public static final String MSG_TYPE_EVENT_SUBSCRIBE = "subscribe";
}    

3消息处理方法,增加判断逻辑

@Service
public class MsgHandleServiceImpl {

    public MsgReplyEntity handle(MsgSendEntity msgSend) {
        ...
           
        // 处理不同类型的消息
        if (msgType.equals(WeChatConstants.MSG_TYPE_TEXT)) {
            ...
        }else if(msgType.equals(WeChatConstants.MSG_TYPE_EVENT)){
            // 订阅事件
            if(msgSend.getEvent().equals(WeChatConstants.MSG_TYPE_EVENT_SUBSCRIBE)){
                msgReply.setMsgType(WeChatConstants.MSG_TYPE_TEXT);
                msgReply.setContent("感谢关注chetwhy![亲亲]\r\n现在回复【chet】\r\n马上查阅java博客![大兵]");
            }
        }

        WeChatUtil.getLogger().info("服务端回复的内容为:{}"+msgReply);
        return msgReply;
    }
}

测试样例

一、先取消对测试公众的关注(断点调试依然可以看到消息类型为event)

二、在测试号管理中再次扫描二维码关注

image

代码开发

开始开发——自定义菜单及其事件

功能描述

当我们点开一个订阅的公共号时,点击聊天输入框最左侧的按钮,可以切换到公众号的菜单栏,有的菜单选项中多个子菜单,有的菜单选择会自动跳转到其他页面。这为我们的公众号提供更为便捷的窗口和功能的扩展。

实现思路——自定义菜单

一、参考微信公众平台技术文档->自定义菜单->【自定义菜单...接口】和消息管理->接收事件推送->[4-6菜单事件]

image

二、按照文档,我们应先创建自定义的菜单。简单的说:

  • 菜单分为一级菜单和二级菜单,一级最多3个,二级最多5个;
  • 菜单借口大致有10种类型,分为按钮(click,view),扫码(scancode_push,scancode_waitmsg),拍照相册(pic_sysphoto,pic_photo_or_album,pic_weixin),位置(location_select),文件(media_id)等
  • post请求,https协议,请求参数需携带access_token

公众平台以access_token为接口调用凭据,来调用接口,所有接口的调用需要先获取access_token,access_token在2小时内有效,过期需要重新获取,但1天内获取次数有限,开发者需自行存储

三、根据请求示例,封装好我们自定义的json数据

四、根据文档->获取access_token,编写工具类获取返回的token

image

代码开发

1封装自定义菜单的json数据

 {
     "button":[
     {    
          "type":"click",
          "name":"今日歌曲",
          "key":"V1001_TODAY_MUSIC"
      },
      {
           "name":"菜单",
           "sub_button":[
           {    
               "type":"view",
               "name":"搜索",
               "url":"http://www.soso.com/"
            },
            {
                 "type":"miniprogram",
                 "name":"wxa",
                 "url":"http://mp.weixin.qq.com",
                 "appid":"wx286b93c14bbf93aa",
                 "pagepath":"pages/lunar/index"
             },
            {
               "type":"click",
               "name":"赞一下我们",
               "key":"V1001_GOOD"
            }]
       }]
 }

起名字费劲,我这里照搬的微信的菜单名,两个按钮型一级菜单,其中有两个子菜单

2创建获取access token的工具类方法

public class WeChatUtil {
    // 获取access_token的路径模板
    public static final String GET_ACCESSTOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
    
    public static String accessToken;

    public static long expiresTime;
    
    /**
     * 获取access_token
     * @return access_token
     */
    public static String getAccessToken(){
        // 第一次获取或access token已过期
        if(accessToken==null||new Date().getTime()>expiresTime){
            // 替换示例种参数,发送https的get请求
            String result = HttpUtil.get(GET_ACCESSTOKEN_URL.replace("APPID", WeChatConstants.APP_ID).replace("APPSECRET", WeChatConstants.APPSECRET));
            JSONObject json = JSONObject.parseObject(result);
            accessToken = json.getString("access_token");
            // 有效事件,单位秒
            Long expires_in = json.getLong("expires_in");
            // 设置凭据的失效时间,默认7200s,提前五分钟过期
            expiresTime = new Date().getTime()+((expires_in-60*5)*1000);
            WeChatUtil.getLogger().info("access_token={},expires_time={}",accessToken,expiresTime);
        }
        return accessToken;
    }
}    

3船舰自定菜单的工具类方法

public class WeChatUtil {
    
    // 自定义菜单接口
    public static final String CREATE_MENU_URL = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";
    
    /**
     * 创建自定义菜单
     * @param menuJson
     */
    public static void createMenu(String menuJson){
        //发起请求到指定的接口,并且带上菜单json数据
        String result = HttpUtil.post(CREATE_MENU_URL.replace("ACCESS_TOKEN",getAccessToken()), menuJson);
        WeChatUtil.getLogger().info("创建自定义菜单结果:{}", result);
    }
}    

4.写一个主方法,将之前封装的json传入createMenu方法。运行即可

public static void main(String[] args) {
    String menu = "...";
    createMenu(menu);
}

测试样例

一、直接运行上述的main方法,查看运行日志,生成成功

image

二、查看微信客户端的聊天页面,点开二级菜单

image

三、若日志显示成功,客户端没反应,尝试重新关注订阅号,或重启natapp

实现思路——自定义菜单事件

一、封装菜单事件的参数,扩展dto

二、增加消息处理的业务逻辑

代码开发

一、消息发送实体类

public class MsgSendDto extends MsgSendEntity {
    ...
    
    // 菜单的key值
    @XmlElement(name = "EventKey")
    private String eventKey;
}


二、消息处理方法,key即为json中的"key"键

@Service
public class MsgHandleServiceImpl implements IMsgHandleService {

    @Override
    public MsgReplyEntity handle(MsgSendDto msgSend) {
        ...
        
        // 处理不同类型的消息
        if (msgType.equals(WeChatConstants.MSG_TYPE_TEXT)) {
            ...
                
        }else if(msgType.equals(WeChatConstants.MSG_TYPE_EVENT)){
            // 订阅事件
            if(msgSend.getEvent().equals(WeChatConstants.MSG_TYPE_EVENT_SUBSCRIBE)){
                ...
            }else if(msgSend.getEvent().equals(WeChatConstants.MSG_TYPE_EVENT_CLICK)){
                String eventKey = msgSend.getEventKey();
                //判断按钮的key值
                if ("V1001_TODAY_MUSIC".equals(eventKey)){
                    contentReply = "《年少有为》- 李荣浩\n" +
                            "《The Spectre》- Alan Walker";
                }else if("V1001_GOOD".equals(eventKey)){
                    contentReply = "谢谢您的点赞关注[拇指]";
                }
                msgReply.setMsgType("text");
                msgReply.setContent(contentReply);
            }
        }

        WeChatUtil.getLogger().info("服务端回复的内容为:{}"+msgReply);
        return msgReply;
    }
}

测试样例

一、运行springboot

二、点开微信菜单栏,点击菜单按钮

image

开始开发——发送模板信息

功能描述

这个也很常见,比如当我们在公众号平台购买商品后,平台会发送下单结果的通知信息,这个类似与邮寄一样,也是模板信息。文档也说,模板消息仅用于公众号向用户发送重要的服务通知,只能用于符合其要求的服务场景中,如信用卡刷卡通知,商品购买成功通知等。

实现思路

一、参考微信公众平台技术文档->消息管理->模板消息接口

image

二、在测试公众号中配置新增模板

image

三、编写工具类方法,支持https的post请求,url为:

https://api.weixin.qq.com/cgi-bin/template/api_set_industry?access_token=ACCESS_TOKEN

代码开发

一、测试公众号->模板消息接口->新增配置模板

我这里依然使用官方文档的例子

image

如图

image

)

二、封装发送模板信息的json数据,相关信息都改成自己的,template_id即上面的【模板ID】

{
    "touser":"o50E15lhQXW0SlsYg3bKFrywtKC8",
    "template_id":"RXl8FLezLbHaBrPWTwK295CNgkNpR69Et40K3oOoK0",
    "url":"http://weixin.qq.com/download",  
    "miniprogram":{
        "appid":"xiaochengxuappid12345",
        "pagepath":"index?foo=bar"
    },          
    "data":{
        "first": {
            "value":"恭喜你购买成功!",
            "color":"#173177"
        },
        "keyword1":{
            "value":"巧克力",
            "color":"#173177"
        },
        "keyword2": {
            "value":"39.8元",
            "color":"#173177"
        },
        "keyword3": {
            "value":"2014年9月22日",
            "color":"#173177"
        },
        "remark":{
            "value":"欢迎再次购买!",
            "color":"#173177"
        }
    }
}

三、创建发送模板信息的方法

// 发送模板消息的接口
public static final String SEND_TEMPLATE_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN";

/**
  * 发送模板信息
  * @param data 模板json数据
  */
public static void sendTemplate(String data){
    String result = HttpUtil.post(SEND_TEMPLATE_URL.replace("ACCESS_TOKEN", getAccessToken()),data);
    WeChatUtil.getLogger().info("发送模板消息结果:{}",result);
}

测试样例

使用第二步的json数据,直接在main方法测试即可

image

详细过程,可参考源代码(持续更新):https://github.com/chetwhy/cloud-flow

相关文章

  • 微信公众号快速开发(三)多种消息类型处理

    之前介绍了自动回复,下面介绍一些常见的消息处理样式 开始开发——关键字回复 功能描述 当我们公众号发送一些关键词的...

  • 微信公众号开发 (4) 网页授权

    一、前言 微信公众号开发 (1) 微信接入认证成为开发者 微信公众号开发 (2) 消息处理 微信公众号开发 (3)...

  • 微信公众号开发 (3) 菜单处理

    一、前言 微信公众号开发 (1) 微信接入认证成为开发者 微信公众号开发 (2) 消息处理 本文将实现 根据App...

  • 反射在微信公众平台开发中的应用

    1、开发背景 在微信公众号开发的时候,我们都会去解析微信消息,然后根据不同的消息类型做对应的操作。下面是一段微信的...

  • 微信公众号开发-入门篇

    微信公众号分为三种类型: 订阅号; 服务号; 企业号;想要进行微信公众号的开发,必须熟悉一门后台开发语言,如jav...

  • 微信公众号账号类型说明

    微信公众号账号类型详细说明 写在前面 需求:开发微信公众号账号,选择合适类型 一、帐号分类 1. 服务号 服务号:...

  • 常见问题

    为了帮助开发者快速熟悉微信公众号开发,我们推出了微信公众平台开发者问答系统。 进入微信公众平台开发者问答系统

  • 微信公众号如何无限制的定向推送消息--服务号模板消息

    最近开发有一个需求:将特定的消息推送到微信公众号的指定用户。类似这样的消息: 查阅开发文档,公众号主动推送消息有三...

  • 微信开发

    微信开发 公众号开发 微信WEB开发 JSSDK 小程序开发 公众号开发 公众号 订阅号 服务号 企业号 公众号开...

  • 微信消息的验证

    微信公众号开发中,微信平台向第三方服务器转发的消息,在处理之前,是应该进行校验的。这一点,稍有安全常识的开发者都应...

网友评论

    本文标题:微信公众号快速开发(三)多种消息类型处理

    本文链接:https://www.haomeiwen.com/subject/ovpddhtx.html