1.0 开发背景
外包公司,所以各种各样的项目都有接触,有个需求,客户要做不同的二维码,通过二维码关注以后,给用户发送不同的消息,顺便统计用户来源,
本文用到了 微信带参数二维码接口和消息管理里的相关接口
注意 :在微信公众号后台,设置了服务器配置 URL 并启用后,会导致 微信后台设置的回复规则,以及底部菜单都全部失效!直接清空了!因为这时候 微信已经把公众号消息和事件 推送给开发者配置的url中,让开发者进行处理了。
本文先讲述微信官方后台设置带参二维码,后续更新使用第三方平台开发实现这个功能,从而保证了用户微信公众号官方设置底部菜单以及自定义回复没有失效!
2.0 开发准备
2.1老样子 官方文档 来一波 带参二维码 接收事件
2.2 需要在微信后台 配置服务器配置 ,微信会在你修改这个配置的时候 给你填写的URL发送数据,需要提前把项目上传服务器!
这个东西 配置好之后 可以点击开启了 ,开启后啊,这个微信会把所有用户发送的信息,给转发给填写的url 上。开发者必须在五秒内回复微信服务器。否则 微信会进行三次重试,重试均失败后,会给用户提示 该公众号暂时无法提供服务。 而且在公众平台还有告警通知。
下面看代码
package com.ysh.wxtest.controller;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import weixin.popular.bean.xmlmessage.XMLMessage;
import weixin.popular.bean.xmlmessage.XMLTextMessage;
import weixin.popular.support.ExpireKey;
import weixin.popular.support.expirekey.DefaultExpireKey;
import weixin.popular.util.SignatureUtil;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 消息接收控制层
* @author YaoShiHang
* @Date 15:15 2017-10-16
*/
@Controller
public class WxqrcodeController {
private final String TOKEN="xxxxxxxxxx"; //Wx 开发者设置的 token
private Logger loger = Logger.getLogger(getClass());
//重复通知过滤
private static ExpireKey expireKey = new DefaultExpireKey();
//微信推送事件 url
@RequestMapping("/openwx/getticket")
public void getTicket(HttpServletRequest request, HttpServletResponse response)
throws Exception {
ServletInputStream inputStream = request.getInputStream();
ServletOutputStream outputStream = response.getOutputStream(); String signature = request.getParameter("signature");
String timestamp = request.getParameter("timestamp");
String nonce = request.getParameter("nonce");
String echostr = request.getParameter("echostr");
//首次请求申请验证,返回echostr
if(echostr!=null){
outputStreamWrite(outputStream,echostr);
return;
}
//验证请求签名
if(!signature.equals(SignatureUtil.generateEventMessageSignature(TOKEN,timestamp,nonce))){
System.out.println("The request signature is invalid");
return;
}
boolean isreturn= false;
loger.info("1.收到微信服务器消息");
Map wxdata=parseXml(request);
if(wxdata.get("MsgType")!=null){
if("event".equals(wxdata.get("MsgType"))){
loger.info("2.1解析消息内容为:事件推送");
if( "subscribe".equals(wxdata.get("Event"))){
loger.info("2.2用户第一次关注 返回true哦");
isreturn=true;
}
}
}
if(isreturn == true){
//转换XML
String key = wxdata.get("FromUserName")+ "__"
+ wxdata.get("ToUserName")+ "__"
+ wxdata.get("MsgId") + "__"
+ wxdata.get("CreateTime");
loger.info("3.0 进入回复 转换对象:"+key);
if(expireKey.exists(key)){
//重复通知不作处理
loger.info("3.1 重复通知了");
return;
}else{
loger.info("3.1 第一次通知");
expireKey.add(key);
}
loger.info("3.2 回复你好");
//创建回复
XMLMessage xmlTextMessage = new XMLTextMessage(
wxdata.get("FromUserName"),
wxdata.get("ToUserName"),
"你好");
//回复
xmlTextMessage.outputStreamWrite(outputStream);
return;
}
loger.info("3.2 回复空");
outputStreamWrite(outputStream,"");
}
/**
* 数据流输出
* @param outputStream
* @param text
* @return
*/
private boolean outputStreamWrite(OutputStream outputStream, String text){
try {
outputStream.write(text.getBytes("utf-8"));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
return true;
}
/**
* dom4j 解析 xml 转换为 map
* @param request
* @return
* @throws Exception
*/
public static Map parseXml(HttpServletRequest request) throws Exception {
// 将解析结果存储在HashMap中
Map map = new HashMap();
// 从request中取得输入流
InputStream inputStream = request.getInputStream();
// 读取输入流
SAXReader reader = new SAXReader();
Document document = reader.read(inputStream);
// 得到xml根元素
Element root = document.getRootElement();
// 得到根元素的所有子节点
List elementList = root.elements();
// 遍历所有子节点
for (Element e : elementList)
map.put(e.getName(), e.getText());
// 释放资源
inputStream.close();
inputStream = null;
return map;
}
/**
* 回复微信服务器"文本消息"
* @param response
* @param returnvaleue
*/
public void output(HttpServletResponse response, String returnvaleue) {
try {
PrintWriter pw = response.getWriter();
pw.write(returnvaleue);
loger.info("****************return valeue***************="+returnvaleue);
pw.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
提供一个大神的帮助类
package weixin.popular.bean.xmlmessage;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.UUID;
import com.qq.weixin.mp.aes.AesException;
import com.qq.weixin.mp.aes.WXBizMsgCrypt;
import weixin.popular.bean.message.message.Message;
public abstract class XMLMessage {
protected String toUserName;
protected String fromUserName;
protected String msgType;
protected XMLMessage(String toUserName, String fromUserName, String msgType) {
super();
this.toUserName = toUserName;
this.fromUserName = fromUserName;
this.msgType = msgType;
}
/**
* 子类自定义XML
* @return XML
*/
public abstract String subXML();
/**
* 转换为 Message 对象
* @return Message
*/
public abstract Message convert();
public String toXML(){
StringBuilder sb = new StringBuilder();
sb.append("" );
sb.append("+toUserName+"]]> ");
sb.append("+fromUserName+"]]> ");
sb.append("" +System.currentTimeMillis()/1000+"");
sb.append("+msgType+"]]> ");
sb.append(subXML());
sb.append("");
return sb.toString();
}
public boolean outputStreamWrite(OutputStream outputStream){
try {
outputStream.write(toXML().getBytes("utf-8"));
outputStream.flush();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
public boolean outputStreamWrite(OutputStream outputStream,WXBizMsgCrypt bizMsgCrypt){
if(bizMsgCrypt != null){
try {
String outputStr = bizMsgCrypt.encryptMsg(toXML(), System.currentTimeMillis()+"",UUID.randomUUID().toString());
outputStream.write(outputStr.getBytes("utf-8"));
outputStream.flush();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
} catch (AesException e) {
e.printStackTrace();
return false;
}
return true;
}else{
return outputStreamWrite(outputStream);
}
}
public String getToUserName() {
return toUserName;
}
public String getFromUserName() {
return fromUserName;
}
public String getMsgType() {
return msgType;
}
}