这个功能再微信公众号开发文档里面叫做被动回复用户消息;假如说用户触发了某一个业务,然后需要你来推送一些东西的时候用,当然比较多的还是模板消息,比如

springboot 微信公众号静默授权获取openId_xml

这个之后说

我们现在说普通的消息

先看一下微信的开发文档

springboot 微信公众号静默授权获取openId_xml_02

不难看出,就是说当用户发送消息过来的时候你可以获取到,然后我们返回给微信一个xml类型的数据到response中,即可回复给用户消息

springboot 微信公众号静默授权获取openId_User_03

话不多说,上代码,我这里将所有的消息发送放在了service,然后将请求的request转换成了map,后面会贴出这个工具类,

这段代码的前面是之前的接入验证,然后是转换request,然后就是业务逻辑层了

public void wxLogin(HttpServletRequest request,HttpServletResponse response) throws UnsupportedEncodingException{
		//设置编码,不然接收到的消息乱码
		request.setCharacterEncoding("UTF-8");
		response.setCharacterEncoding("UTF-8");
		String signature = request.getParameter("signature");//微信加密签名
		String timestamp = request.getParameter("timestamp");//时间戳
		String nonce = request.getParameter("nonce");//随机数
		String echostr = request.getParameter("echostr");//随机字符串
		PrintWriter out = null;
			//接入验证
			  if(WeiXinUtil.checkSignature(signature, timestamp, nonce)){
				  if (echostr!=null) {
					  System.out.println(echostr);
					  try {
						out = response.getWriter();
					} catch (IOException e) {
						e.printStackTrace();
					}
					  out.write(echostr);//验证成功返回的值
					  return;
				}

//从这里开始
				  Map<String, String> reqXmlData;
				  try {
					  reqXmlData = XMLUtils.parseXmlFromRequest(request);
					  weiXinService.doRequestXmlData(request.getQueryString(), reqXmlData,response);
				  } catch (Exception e) {
					  e.printStackTrace();
				  }
			}
	}

业务逻辑代码

这里首先提取一下request中的参数

String msgType = reqXmlData.get(XMLUtils.c_xml_msg_key_MsgType);//获取消息类型
		String content = reqXmlData.get(XMLUtils.c_xml_msg_key_Content);//获取消息内容
		String event = reqXmlData.get(XMLUtils.c_xml_msg_key_Event);//获取事件类型
		String openId = reqXmlData.get(XMLUtils.c_xml_msg_key_FromUserName);//获取发送者openID
		String formUser = reqXmlData.get(XMLUtils.c_xml_msg_key_ToUserName);//获取接受者ID
		String eventKey = reqXmlData.get(XMLUtils.c_xml_msg_key_EventKey);//获取扫码事件的key

文本消息的类型是text,也就是说用户发送的文本,你被动接收。比如

springboot 微信公众号静默授权获取openId_Data_04

然后处理

//文本消息
		if(XMLUtils.c_xml_msg_type_text.equals(msgType)){
			doMsg(response, content, openId, formUser);
		}

注意这里的fromUser和openid,当用户发送消息给公众号的时候,用户是发送者,但是我们是给用户回复消息,所以我们是发送者,容易混淆

doMsg

if ("?".equals(content)||"?".equals(content)) {
			MsgUtil.sendTextMsgToUser("帮助命令:1、接收文本消息   2、接收图片消息    3、接收图文消息    "
					+ "4、接收模板消息    5、生成带参数的二维码 ", openId,formUser,response);
		}
		if ("1".equals(content)) {
			MsgUtil.sendTextMsgToUser("文本消息", openId,formUser,response);
		}

我这里写了一个帮助信息,辅助自己测试,你们不清楚可以打断点跟踪一下,看看用户发送来的消息是什么

sendTextMsgToUser这个方法就是将消息封装

/**
	 * 发送文本消息
	 * @param msg
	 * @param toUser
	 */
	public static void sendTextMsgToUser(String msg, String toUser,String formUser,HttpServletResponse resp) {
		TextMsg textMsg = new TextMsg();
		textMsg.setContent(msg);
		textMsg.setToUserName(toUser);
		textMsg.setFromUserName(formUser);
		sendMsg(resp, textMsg);
	}

然后textMsg的消息类,由于这边用到的消息比较多,所以我封装了一个basemsg

import java.util.Date;

/**
 * 
 * @author Administrator
 *
 */
public class TextMsg extends BaseMessage {
	private String Content;
	private String MsgId;
	public TextMsg(){
		this.setMsgType("text");
		this.setCreateTime(new Date().getTime());
	}
	public String getContent() {
		return Content;
	}
	public void setContent(String content) {
		Content = content;
	}
	public String getMsgId() {
		return MsgId;
	}
	public void setMsgId(String msgId) {
		MsgId = msgId;
	}
	
}
public class BaseMessage {
	private String ToUserName;
	private String FromUserName;
	private long CreateTime;
	private String MsgType;
	
	
	public String getToUserName() {
		return ToUserName;
	}
	public void setToUserName(String toUserName) {
		ToUserName = toUserName;
	}
	public String getFromUserName() {
		return FromUserName;
	}
	public void setFromUserName(String fromUserName) {
		FromUserName = fromUserName;
	}
	public long getCreateTime() {
		return CreateTime;
	}
	public void setCreateTime(long createTime) {
		CreateTime = createTime;
	}
	public String getMsgType() {
		return MsgType;
	}
	public void setMsgType(String msgType) {
		MsgType = msgType;
	}
}

文本消息主要包含这些东西就行,你只需要把这些属性封装即可

springboot 微信公众号静默授权获取openId_xml_05

然后是

/**
	 * 抽取的发送消息的方法
	 * @param resp
	 * @param msg
	 */
	private static void sendMsg(HttpServletResponse response, BaseMessage msg) {
		//将封装的消息转为xml
		String textMessageToXml = XMLUtils.textMessageToXml(msg);
		logger.info("发送的消息是-------"+textMessageToXml);
		PrintWriter out=null;
		try {
			out = response.getWriter();
			//写入返回的response中
			out.println(textMessageToXml);
		} catch (IOException e) {
			logger.error("发送微信消息失败",e);
			e.printStackTrace();
		}finally{
			//注意关流,不然会发送失败
			out.close();
		}
	}

这个注释很清楚了,就不再多说了

发送成功的日志消息

springboot 微信公众号静默授权获取openId_Data_06

如果失败就按照返回错误码排查

下面贴出来xmlutil工具类

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.example.weixin.demo.message.BaseMessage;
import com.example.weixin.demo.message.News;
import com.thoughtworks.xstream.XStream;

/**
 * 
 * @author Administrator
 *
 */
public abstract class XMLUtils {
	// xml消息体的key定义
	public static final String c_xml_msg_key_ToUserName ="ToUserName";
	public static final String c_xml_msg_key_FromUserName ="FromUserName";
	public static final String c_xml_msg_key_CreateTime="CreateTime";
	public static final String c_xml_msg_key_MsgType ="MsgType";
	public static final String c_xml_msg_key_Event ="Event";
	public static final String c_xml_msg_key_EventKey="EventKey";
	public static final String c_xml_msg_key_Ticket="Ticket";

	// xml消息类型定义
	public static final String c_xml_msg_type_event = "event";
	public static final String c_xml_msg_type_text = "text";
	public static final String c_xml_msg_type_location = "location";

	// 事件类型定义
	public static final String c_xml_msg_event_photo = "pic_photo_or_album";
	public static final String c_xml_msg_event_subscribe = "subscribe";
	public static final String c_xml_msg_event_unsubscribe = "unsubscribe";
	public static final String c_xml_msg_event_scan = "SCAN";
	public static final String c_xml_msg_event_click = "CLICK";
	public static final String c_xml_msg_key_Content = "Content";

	/**
	 * 请求xml转为map
	 * @param request
	 * @return
	 * @throws Exception
	 */
	public static Map<String,String> parseXmlFromRequest(HttpServletRequest request) throws Exception{
		SAXReader saxReader = new SAXReader();
		Document document = saxReader.read(request.getInputStream());
		List<Element> elements = document.getRootElement().elements();
		Map<String,String> msgMap = new HashMap<>();
		for(int m=0,len=elements.size();m<len;m++){
			Element element = elements.get(m);
			msgMap.put(element.getName(),element.getText());
		}
		return msgMap;
	}
	/**
	 * map转为xml
	 * @param map
	 * @return
	 * @throws Exception
	 */
	public static String parseMapToXml(Map<String, String> map) throws Exception{
		Document document = DocumentHelper.createDocument();
		Element rootElement = document.addElement("xml");
		for (Map.Entry<String, String> me : map.entrySet()) {
			Element empName = rootElement.addElement(me.getKey());
			empName.setText(me.getValue());
		}
		return document.asXML();
	}
	/**
	 * 消息类转为xml
	 * @param msg
	 * @return
	 */
	public static String textMessageToXml(BaseMessage msg){
		XStream xstream = new XStream();
		xstream.alias("xml", msg.getClass());
		return xstream.toXML(msg);
	}
	/**
	 * 新闻消息转为xml
	 * @param msg
	 * @return
	 */
	public static String newsMessageToXml(BaseMessage msg){
		XStream xstream = new XStream();
		xstream.alias("xml", msg.getClass());
		xstream.alias("item",new News().getClass());
		return xstream.toXML(msg);
	}
}