首先在公众平台管理页面开启服务器配置
签名对象
@Data
public class WXConnectionRequest {
//微信加密签名
private String signature;
//时间戳
private String timestamp;
//随机数
private String nonce;
//随机字符串
private String echostr;
}
验签
@ApiOperation("connection:接收推送事件")
@PostMapping(value = "/connection")
public String connection(WXConnectionRequest request, HttpServletRequest req) throws Exception {
String shaStr = sortAndEncrypt("你服务器配置的令牌", request.getTimestamp(), request.getNonce());
if (request.getSignature().equals(shaStr)) {
//业务处理 todo
//业务处理完成返回随机字符串
return request.getEchostr();
}
return "";
}
//字典序排序加密
private String sortAndEncrypt(String appSecret, String timestamp, String nonce) {
ArrayList<String> list = new ArrayList<>();
list.add(appSecret);
list.add(timestamp);
list.add(nonce);
Collections.sort(list);
return DigestUtils.sha1Hex(list.get(0) + list.get(1) + list.get(2));
}
业务处理最麻烦的就是解析微信的xml,需引入pom依赖
<!-- 解析xml -->
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.9</version>
</dependency>
解析xml工具类
import java.io.InputStream;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
public class MessageUtil {
/**
* 解析微信发来的请求(XML)
*
* @param request
* @return
* @throws Exception
*/
public static Map<String, String> parseXml(HttpServletRequest request) throws Exception {
// 将解析结果存储在HashMap中
Map<String, String> map = new HashMap<String, String>();
// 从request中取得输入流
InputStream inputStream = request.getInputStream();
// 读取输入流
SAXReader reader = new SAXReader();
Document document = reader.read(inputStream);
// 得到xml根元素
Element root = document.getRootElement();
// 得到根元素的所有子节点
@SuppressWarnings("unchecked")
List<Element> elementList = root.elements();
// 遍历所有子节点
for (Element e : elementList)
map.put(e.getName(), e.getText());
// 释放资源
inputStream.close();
inputStream = null;
return map;
}
/**
* 扩展xstream,使其支持CDATA块
*
*/
private static XStream xstream = new XStream(new XppDriver() {
@Override
public HierarchicalStreamWriter createWriter(Writer out) {
return new PrettyPrintWriter(out) {
// 对所有xml节点的转换都增加CDATA标记
boolean cdata = true;
@Override
protected void writeText(QuickWriter writer, String text) {
if (cdata) {
writer.write("<![CDATA[");
writer.write(text);
writer.write("]]>");
} else {
writer.write(text);
}
}
};
}
});
}
接收微信推送
public void pullSubscribe(HttpServletRequest req) throws Exception {
req.setCharacterEncoding("UTF-8");
Map<String, String> map = MessageUtil.parseXml(req);
String openId = map.get("FromUserName").toString();
// String toUserName = map.get("ToUserName").toString();
// String content = map.get("Content").toString();
String msgType = map.get("MsgType");
String event = map.get("Event");
if (MsgType.equals(msgType)) {
CustomerInfo customerInfo = customerInfoService.getOne(new LambdaQueryWrapper<CustomerInfo>().eq(CustomerInfo::getOpenid, openId));
if (customerInfo != null) {
//订阅
if (MessageSubscribe.equals(event)) {
log.info("用户{},openid{},关注了公众号",customerInfo.getCustomerName(),customerInfo.getOpenid());
customerInfo.setFocusFlag(1);
}//取消订阅
else if (MessageUnsubscribe.equals(event)) {
log.info("用户{},openid{},取关了公众号",customerInfo.getCustomerName(),customerInfo.getOpenid());
customerInfo.setFocusFlag(0);
}
customerInfoService.updateById(customerInfo);
}
}
}
还有其它事件在此不一一举例了,可以查看官方文档,难点就是解析xml获取参数和验证微信签名。