微信公众号之被动消息回复和客服消息

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qy_0626/article/details/86609669

本文为博主原创 转载请注明出处 尊重笔者劳动成果 十分感谢

场景:用户关注公众号后给用户回复一个消息

 效果如下:

实现公众号和用户产生特定动作的交互有两种方式可以实现:

1. 被动回复用户消息

2. 客服消息

这两种有何不同呢? 被动消息回复本质是对微信服务器发过来消息的一次回复。因此需要开发者在5秒内做出响应 否则将会提示“该公众号暂时无法提供服务” 而客服消息其实是一个接口 当不能保证5秒内对为微信服务器响应的时候可以先回复“success”然后调用发送客服消息异步发送消息

注意:客服消息是有次数限制的!!! 具体查看接口权限处的次数 且开发者收到微信服务的推送在48小时内可以调用客服接口

发送客服消息需要先检查公众号是否有客服消息权限 查看客服消息权限可以在微信公众号控制台 最后一个接口权限查看,如下图:

扫描二维码关注公众号,回复: 6650498 查看本文章

 下面附上被动消息回复以及客服消息的代码 此处被动消息未做排重处理

被动消息回复

1.构造一个消息 例如文本消息

2.响应消息 即发送消息给微信服务器

定义一个消息类型枚举类

package com.net.wx;

/**
 * 被动回复消息类型
 * Created by zhangq on 2019/1/23.
 */
public enum MessageType {
    TEXT,IMAGE,VOICE,VIDEO,MUSIC,NEWS
}

 编写构造消息的工具类 注意此处的字段 FromUserName 和 ToUserName 这两个数据来自微信服务器给开发者服务器推送的XML中的字段,因此响应微信服务器消息的时候,发送方和接受方反过来即可

package com.net.wx;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.json.JSONObject;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 构造被动回复工具类
 * Created by zhangq on 2019/1/23.
 */
public class MessageUtil {

    /**
     * 根据消息类型 构造返回消息数据
     * @param jsonObject 承装消息数据
     * @param msgType 消息类型  取自消息类型枚举类
     * @return 构造后消息数据结构
     */
    public static String buildXml(JSONObject jsonObject, MessageType msgType) {
        String result = "";
        switch (msgType) {
            case TEXT:
                result =buildTextMessage(jsonObject);
                break;
            case IMAGE:
                result =buildImageMessage(jsonObject);
                break;
            case NEWS:
                result =buildNewsMessage(jsonObject);
                break;
            default:
                break;
        }
        return result;
    }


    /**
     * 构造文本消息
     * @param json 文本消息参数
     * @return String
     */
    private static String buildTextMessage(JSONObject  json) {
        String fromUserName = json.get("FromUserName").toString();
        String toUserName = json.get("ToUserName").toString();
        String content = json.get("content").toString();

        return String.format("<xml><ToUserName><![CDATA[%s]]></ToUserName><FromUserName><![CDATA[%s]]></FromUserName><CreateTime>%s</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[%s]]></Content></xml>",
                fromUserName, toUserName, getUtcTime(), content);
    }


    /**
     * 构造图片消息
     * @param json 图片消息参数
     * @return String
     */
    private static String buildImageMessage(JSONObject json) {
        String fromUserName = json.get("FromUserName").toString();
        String toUserName = json.get("ToUserName").toString();
        String mediaid =  json.get("mediaid").toString();
        return String.format("<xml><ToUserName><![CDATA[%s]]></ToUserName><FromUserName><![CDATA[%s]]></FromUserName><CreateTime>%s</CreateTime><MsgType><![CDATA[image]]></MsgType><Image><MediaId><![CDATA[%s]]></MediaId></Image></xml>",
                fromUserName, toUserName, getUtcTime(), mediaid);

    }
    /**
     * 构造图文消息 单条图文消息
     * @param json 图文消息参数
     * @return String
     */
    private static String buildNewsMessage(JSONObject json) {
        String fromUserName = json.get("FromUserName").toString();
        String toUserName = json.get("ToUserName").toString();
        String title =  json.get("Title").toString();
        String description =  json.get("Description").toString();
        String picUrl =  json.get("PicUrl").toString();
        String url =  json.get("Url").toString();

        return String.format("<xml><ToUserName>< ![CDATA[%s]]></ToUserName><FromUserName>< ![CDATA[%s]]></FromUserName><CreateTime>%s</CreateTime><MsgType>< ![CDATA[news]]></MsgType><ArticleCount>1</ArticleCount><Articles><item><Title>< ![CDATA[%s]]></Title> <Description>< ![CDATA[%s]]></Description><PicUrl>< ![CDATA[%s]]></PicUrl><Url>< ![CDATA[%s] ]></Url></item></Articles></xml>",
                fromUserName, toUserName, getUtcTime(),title,description,picUrl,url);

    }

    //当前系统时间
    private static String getUtcTime() {
        Date dt = new Date();// 如果不需要格式,可直接用dt,dt就是当前系统时间
        DateFormat df = new SimpleDateFormat("yyyyMMddhhmm");// 设置显示格式
        String nowTime = "";
        nowTime = df.format(dt);
        long dd = (long) 0;
        try {
            dd = df.parse(nowTime).getTime();
        } catch (Exception e) {

        }
        return String.valueOf(dd);
    }


}

调用被动消息回复的方法 响应微信服务器

    @Autowired
    HttpServletRequest      request;
       
    //微信功能处理
    public String WexHandeler(HttpServletResponse response) throws Exception {
        try {
            JSONObject info = XML.toJSONObject(IOUtils.toString(request.getInputStream()));
            log.info("info:" + info);
            if (info.get("xml") != null) {
                JSONObject event = (JSONObject) info.get("xml");
                if (event.get("MsgType") != null) {
                    String Event = (String) event.get("Event");//事件类型 关注事件还是取消关注等
                    if (!StringUtils.isEmpty(Event)) { //如果是事件
                        try {
                            if ("SCAN".equals(Event)) {//扫描带参数二维码事件 用户已关注时的事件推送
                                String toUserName = (String) event.get("ToUserName");//开发者微信号
                                String fromUserName = (String) event.get("FromUserName");//发送方帐号(一个OpenID)
                                String eventKey = (String) event.get("EventKey");//事件KEY值,是一个32位无符号整数,即创建二维码时的二维码scene_id
                                String ticket = (String) event.get("Ticket");//二维码的ticket,可用来换取二维码图片
                                log.info(">>>>>>>>>>>>>>>>>>接受的数据为:");
                                log.info("toUserName:"+toUserName);
                                log.info("fromUserName:"+fromUserName);
                                log.info("scene_id:"+eventKey);
                                log.info("ticket:"+ticket);
   
                                //构造被动回复消息
                                event.put("content","Holle");
                                String result = MessageUtil.buildXml(event, MessageType.TEXT);
                                sendMsg(response,result); //发送消息
                            }
                        } catch (Exception e) {
                            return e.getMessage();
                        }
                    }
                }
            }
        } catch (Exception e) {
            return request.getParameter("echostr");
        }
        return request.getParameter("echostr");
    }


    /**
     *
     * 被动消息回复
     * @param response
     * @param result
     * @throws Exception
     */
    private void sendMsg(HttpServletResponse response,String result) throws Exception {
        response.setContentType("text/html;charset=utf-8"); //设置输出编码格式
        log.info("response info:"+result);
        response.getWriter().println(result);
        response.getWriter().flush();
        response.getWriter().close();
    }

 发送客服消息

 发送客服消息前 先响应微信服务器“success”否则,将出现严重的错误提示“该公众号暂时无法提供服务

编写消息类

package com.net.wx;

/**
 * 回复消息类
 * Created by zhangq on 2019/1/23.
 */
public class GeneralMessage {

    //消息发送者  若是公众好接收消息 则为具体的关注者  若是公众号发送消息则为公共号自身
    public String fromUserName;
    //消息接收者
    public String toUserName;
    //消息生成时间
    public String createTime;
    //消息类型
    public MessageType msgType;
    //素材ID 通过素材管理中的接口上传多媒体文件,得到的id。
    public String mediaId;
    //消息内容
    public String content;
    //图文标题
    public String title;
    //图文描述
    public String description;



    public GeneralMessage(){}

    //快捷封装文本消息
    public GeneralMessage(String toUserName,String content){
        this.toUserName = toUserName;
        this.content = content;
    }


    public String getFromUserName() {
        return fromUserName;
    }

    public void setFromUserName(String fromUserName) {
        this.fromUserName = fromUserName;
    }

    public String getToUserName() {
        return toUserName;
    }

    public void setToUserName(String toUserName) {
        this.toUserName = toUserName;
    }

    public String getCreateTime() {
        return createTime;
    }

    public void setCreateTime(String createTime) {
        this.createTime = createTime;
    }

    public MessageType getMsgType() {
        return msgType;
    }

    public void setMsgType(MessageType msgType) {
        this.msgType = msgType;
    }

    public String getMediaId() {
        return mediaId;
    }

    public void setMediaId(String mediaId) {
        this.mediaId = mediaId;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

 编写构造客服消息工具类

package com.net.wx;

import org.json.JSONObject;

/**
 * 构造客服消息工具类
 * Created by zhangq on 2019/1/23.
 */
public class CustomMessageUtil {


    /**
     * 构造客服文本消息
     * @return 消息内容
     */
    public static JSONObject sendCustomTextMsg(GeneralMessage msg){
//        {
//            "touser":"OPENID",
//            "msgtype":"text",
//            "text":
//            {
//                "content":"Hello World"
//            }
//        }
        JSONObject jsonStr =new JSONObject();
        String openid = "";
        String context = "";
        try{
            openid = msg.getToUserName();
            context = msg.getContent();
        }catch (Exception e) {
            e.printStackTrace();
        }
        jsonStr.put("touser", openid);
        jsonStr.put("msgtype", "text");
        JSONObject text =new JSONObject();
        text.put("content", context);
        jsonStr.put("text", text);
        return jsonStr;
    }

    /**
     * 构造客服图片消息
     * @return 消息内容
     */
    public static JSONObject sendCustomImageMsg(GeneralMessage msg){
//        {
//            "touser":"OPENID",
//            "msgtype":"image",
//            "image":
//            {
//                "media_id":"MEDIA_ID"
//            }
//        }
        JSONObject jsonStr =new JSONObject();
        String openid = "";
        String media_id = "";
        try{
            openid = msg.getToUserName();
            media_id = msg.getMediaId();
        }catch (Exception e) {
            e.printStackTrace();
        }
        jsonStr.put("touser", openid);
        jsonStr.put("msgtype", "image");
        JSONObject media =new JSONObject();
        media.put("media_id", media_id);
        jsonStr.put("image", media);
        return jsonStr;
    }


    /**
     * 构造客服语音消息
     * @return 消息内容
     */
    public static JSONObject sendCustomVoiceMsg(GeneralMessage msg){
//        {
//            "touser":"OPENID",
//            "msgtype":"voice",
//            "voice":
//            {
//                "media_id":"MEDIA_ID"
//            }
//        }
        JSONObject jsonStr =new JSONObject();
        String openid = "";
        String media_id = "";
        try{
            openid = msg.getToUserName();
            media_id = msg.getMediaId();
        }catch (Exception e) {
            e.printStackTrace();
        }
        jsonStr.put("touser", openid);
        jsonStr.put("msgtype", "voice");
        JSONObject voice =new JSONObject();
        voice.put("media_id", media_id);
        jsonStr.put("voice", voice);
        return jsonStr;
    }
}

发送客服消息

    //微信功能处理
    public String WexHandeler(HttpServletResponse response) throws Exception {
        try {
            JSONObject info = XML.toJSONObject(IOUtils.toString(request.getInputStream()));
            log.info("info:" + info);
            if (info.get("xml") != null) {
                JSONObject event = (JSONObject) info.get("xml");
                if (event.get("MsgType") != null) {
                    String Event = (String) event.get("Event");//事件类型 关注事件还是取消关注等
                    if (!StringUtils.isEmpty(Event)) { //如果是事件
                        try {
                            if ("subscribe".equals(Event)) {  //带参数二维码的关注事件
                                //关注方法
                                String toUserName = (String) event.get("ToUserName");//开发者微信号
                                String fromUserName = (String) event.get("FromUserName");//发送方帐号(一个OpenID)
                                String eventKey = (String) event.get("EventKey");//事件KEY值,是一个32位无符号整数,即创建二维码时的二维码scene_id
                                String ticket = (String) event.get("Ticket");//二维码的ticket,可用来换取二维码图片
                                log.info(">>>>>>>>>>>>>>>>>>接受的数据为:");
                                log.info("toUserName:"+toUserName);
                                log.info("fromUserName:"+fromUserName);
                                log.info("scene_id:"+eventKey);
                                log.info("ticket:"+ticket);
                                
                                //直接回复success
                                sendSuccess(response); 
                                //发送客服消息
                                GeneralMessage msg = new GeneralMessage(fromUserName,"Holle");
                                sendCustomMsg(msg);
                            } 
                        } catch (Exception e) {
                            return e.getMessage();
                        }
                    }
                }
            }
        } catch (Exception e) {
            return request.getParameter("echostr");
        }
        return request.getParameter("echostr");
    }

    /**
     * 发送客服消息
     * @param msg 消息内容
     */
    public void sendCustomMsg(GeneralMessage msg){
        try {
            String url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN";
            String access_token = wx.get_access_token();
            url = url.replace("ACCESS_TOKEN",access_token);
            JSONObject jsonStr = CustomMessageUtil.sendCustomTextMsg(msg);
            log.info("send custom msg:"+jsonStr);
            String result= HttpUtil.postJsonForString(url,jsonStr);
            log.info("send custom msg result:"+result);
        }catch (Exception e){
            log.warn(e.getMessage());
        }
    }

    /**
     * 回复服务器
     * 假如服务器无法保证在五秒内处理并回复,必须做出下述回复,这样微信服务器才不会对此作任何处理,并且不会发起重试(这种情况下,可以使用客服消息接口进行异步回复),否则,将出现严重的错误提示。详见下面说明:
     * 1、直接回复success(推荐方式) 2、直接回复空串(指字节长度为0的空字符串,而不是XML结构体中content字段的内容为空)
     * @param response
     * @throws Exception
     */
    private void sendSuccess(HttpServletResponse response) throws Exception {
        response.setContentType("text/html;charset=utf-8"); //设置输出编码格式
        String result = "success";
        response.getWriter().println(result);
        response.getWriter().flush();
        response.getWriter().close();
    }

猜你喜欢

转载自blog.csdn.net/qy_0626/article/details/86609669