版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qy_0626/article/details/86609669
本文为博主原创 转载请注明出处 尊重笔者劳动成果 十分感谢
场景:用户关注公众号后给用户回复一个消息
效果如下:
实现公众号和用户产生特定动作的交互有两种方式可以实现:
1. 被动回复用户消息
2. 客服消息
这两种有何不同呢? 被动消息回复本质是对微信服务器发过来消息的一次回复。因此需要开发者在5秒内做出响应 否则将会提示“该公众号暂时无法提供服务” 而客服消息其实是一个接口 当不能保证5秒内对为微信服务器响应的时候可以先回复“success”然后调用发送客服消息异步发送消息
注意:客服消息是有次数限制的!!! 具体查看接口权限处的次数 且开发者收到微信服务的推送在48小时内可以调用客服接口
发送客服消息需要先检查公众号是否有客服消息权限 查看客服消息权限可以在微信公众号控制台 最后一个接口权限查看,如下图:
下面附上被动消息回复以及客服消息的代码 此处被动消息未做排重处理
被动消息回复
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();
}