之前的消息发送与接收都是用户给微信发一条,之后微信回复给用户,也就是API上面所说的被动回复消息,那么微信是否支持主动给关注用户发消息吗,答案是肯定的,但是却有一些限制。看下微信开发文档上怎么说就明白了:
当用户主动发消息给公众号的时候(包括发送信息、点击自定义菜单、订阅事件、扫描二维码事件、支付成功事件、用户维权),微信将会把消息数据推送给开发者,开发者在一段时间内(目前修改为48小时)可以调用客服消息接口,通过POST一个JSON数据包来发送消息给普通用户,在48小时内不限制发送次数。此接口主要用于客服等有人工消息处理环节的功能,方便开发者为用户提供更加优质的服务。
这次就针对客服消息分享下我的心得和体会
1 客服接口-发消息接口使用说明
接口调用请求说明
http请求方式: POST https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
各消息类型所需的JSON数据包如下:
发送文本消息
{"touser":"OPENID","msgtype":"text","text":{"content":"Hello World"} }
发送图片消息
{"touser":"OPENID","msgtype":"image","image":{"media_id":"MEDIA_ID"} }
发送语音消息
{"touser":"OPENID","msgtype":"voice","voice":{"media_id":"MEDIA_ID"} }
......,基本上来说常用的消息类型,客服接口都是支持的
2 封装客服消息接口
public static String makeTextCustomMessage(String openId,String content){content.replace("\"", "\\\"");String jsonMsg="{\"touser\":\"%s\",\"msgtype\":\"text\",\"text\":{\"content\":\"%s\"}}";return String.format(jsonMsg, openId,content);}/*** 组装图片客服消息* * @param openId 消息发送对象* @param mediaId 媒体文件id* @return*/public static String makeImageCustomMessage(String openId, String mediaId) {String jsonMsg = "{\"touser\":\"%s\",\"msgtype\":\"image\",\"image\":{\"media_id\":\"%s\"}}";return String.format(jsonMsg, openId, mediaId);}/*** 组装语音客服消息* * @param openId 消息发送对象* @param mediaId 媒体文件id* @return*/public static String makeVoiceCustomMessage(String openId, String mediaId) {String jsonMsg = "{\"touser\":\"%s\",\"msgtype\":\"voice\",\"voice\":{\"media_id\":\"%s\"}}";return String.format(jsonMsg, openId, mediaId);}/*** 组装视频客服消息* * @param openId 消息发送对象* @param mediaId 媒体文件id* @param thumbMediaId 视频消息缩略图的媒体id* @return*/public static String makeVideoCustomMessage(String openId, String mediaId, String thumbMediaId) {String jsonMsg = "{\"touser\":\"%s\",\"msgtype\":\"video\",\"video\":{\"media_id\":\"%s\",\"thumb_media_id\":\"%s\"}}";return String.format(jsonMsg, openId, mediaId, thumbMediaId);}/*** 组装音乐客服消息* * @param openId 消息发送对象* @param music 音乐对象* @return*/public static String makeMusicCustomMessage(String openId, Music music) {String jsonMsg = "{\"touser\":\"%s\",\"msgtype\":\"music\",\"music\":%s}";jsonMsg = String.format(jsonMsg, openId, JSONObject.fromObject(music).toString());// 参数名称替换 @20140125jsonMsg = jsonMsg.replace("musicUrl", "musicurl");jsonMsg = jsonMsg.replace("HQMusicUrl", "hqmusicurl");jsonMsg = jsonMsg.replace("thumbMediaId", "thumb_media_id");return jsonMsg;}/*** 组装图文客服消息* * @param openId 消息发送对象* @param articleList 图文消息列表* @return*/public static String makeNewsCustomMessage(String openId, List<Article> articleList) {String jsonMsg = "{\"touser\":\"%s\",\"msgtype\":\"news\",\"news\":{\"articles\":%s}}";jsonMsg = String.format(jsonMsg, openId, JSONArray.fromObject(articleList).toString().replaceAll("\"", "\\\""));// 将jsonMsg中的picUrl替换为picurljsonMsg = jsonMsg.replace("picUrl", "picurl");return jsonMsg;}public static boolean sendCustomMessage(String token,String jsonMsg){boolean flag=false;//String accessToken=getAccessToken("xxxx","xxxx").getToken();String requestUrl="https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN";requestUrl=requestUrl.replace("ACCESS_TOKEN", token);JSONObject jsonResult=CommonUtil.httpsRequest(requestUrl, "POST", jsonMsg);if(jsonResult!=null){int errorCode=jsonResult.getInt("errcode");String errorMessage=jsonResult.getString("errmsg");if(errorCode==0){flag=true;}else{System.out.println("客服消息发送失败:"+errorCode+","+errorMessage);flag=false;}}return flag;}
3 调用客服消息发送接口给指定用户发送客服消息
List<Article> all=new ArrayList<Article>();Article a2=new Article();a2.setDescription("最崇拜的明星Justin Timberlake");a2.setPicUrl("http://img3.douban.com/view/photo/photo/public/p1408738004.jpg");a2.setTitle("贾斯汀·汀布莱克(Justin Timberlake),1981年1月31日出生于美国田纳西州孟菲斯市,美国男歌手、演员、音乐制作人、主持人,前男子演唱组合超级男孩成员。");a2.setUrl("http://baike.haosou.com/doc/3382630-3560934.html?from=1358&sid=3560934&redirect=search");all.add(a2);String articleMsg=makeNewsCustomMessage("xxx", all);boolean res=sendCustomMessage(token,articleMsg);if(res){System.out.println("客服消息发送成功");}else{System.out.println("客服消息发送失败");}
到这里程序就写好了,来看下运行效果:
4 多客服的使用
多客服功能主要用于处理需人工操作、耗时较长的场景,我们都知道如果微信服务器在5秒钟没给用户返回消息则会出现“公众号暂时无法提供服务”。这样用户体验会很差,有这种情况不妨考虑下多客服。
下面是API:http://mp.weixin.qq.com/wiki/5/ae230189c9bd07a6b221f48619aeef35.html
个人建议是可以把多客服看成是一种比较特别的消息类型,这样的话只需修改一下MessageUtil就OK了,加入如下代码:
/** * 客服消息对象转换成xml * * @return xml */ public static String customMessageToXml(CustomServiceMessage customServiceMessage) { xstream.alias("xml", customServiceMessage.getClass()); return xstream.toXML(customServiceMessage); }
并且加一种消息类型:
/** * 多客服消息*/ public static final String TRANSFER_CUSTOMER_SERVICE = "transfer_customer_service";
5 修改微信消息处理核心工具类
// 文本消息 if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) { String content=requestMap.get("Content");if(content.startsWith("人工客服")){CustomServiceMessage cus=new CustomServiceMessage();cus.setToUserName(fromUserName); cus.setFromUserName(toUserName); cus.setCreateTime(new Date().getTime()); cus.setMsgType(MessageUtil.TRANSFER_CUSTOMER_SERVICE); TransInfo t=new TransInfo();t.setKfAccount("你的客服账号");cus.setTransInfo(t); respMessage=MessageUtil.customMessageToXml(cus);}else{respContent = "您发送的是文本消息!"; }}
package com.debug.weixin.message.res;import com.debug.weixin.pojo.TransInfo;public class CustomServiceMessage extends BaseMessage {private TransInfo TransInfo;public TransInfo getTransInfo() {return TransInfo;}public void setTransInfo(TransInfo transInfo) {TransInfo = transInfo;}}
package com.debug.weixin.pojo;public class TransInfo {private String KfAccount;public String getKfAccount() {return KfAccount;}public void setKfAccount(String kfAccount) {KfAccount = kfAccount;}
}
上面的代码如需测试需使用微信关注“多客服助手”或下载安装“windows多客服”,具体参照如下链接:
http://dkf.qq.com/
这里在贴2个我的运行截图:
下面是windows的客户端,就类似QQ的界面
差不多就这样子了