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

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

开始开发——关键字回复

功能描述

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

实现思路

  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 = "2ffbf0ff3516af025942ec8ca67f27d8"; 

    /**
     * 公众号配置相关
     */
    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";
}
复制代码

测试样例

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

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

功能描述

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

实现思路

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

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

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

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

代码开发

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)

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

代码开发

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

功能描述

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

实现思路——自定义菜单

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

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

  • 菜单分为一级菜单和二级菜单,一级最多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

代码开发

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方法,查看运行日志,生成成功

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

三、若日志显示成功,客户端没反应,尝试重新关注订阅号,或重启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

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

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

功能描述

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

实现思路

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

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

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

api.weixin.qq.com/cgi-bin/tem…

代码开发

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

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

如图

)

二、封装发送模板信息的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方法测试即可


(持续更新)

转载于:https://juejin.im/post/5d2c94cff265da1b8f1af399

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值