1、公众号后台配置:点击基本配置-修改配置
URL:填写服务端建立的接口地址(接口要能接受get/post请求)
token:随便写
秘钥:自动生成
配好之后,点击提交,微信会往接口发送一条get请求的数据,服务端校验后,把微信发送的数据中的echoStr字段原样返回,微信接收到会提示修改成功。
2、配置服务端接口
/**
* 接受微信发送的消息
* @param request 公参
* @return 返回结果
*/
@SneakyThrows
@RequestMapping(value = "/getTencentMsg", method = {RequestMethod.POST, RequestMethod.GET})
@ApiIgnore
public void getTencentMsg(HttpServletRequest request, HttpServletResponse response) {
String method = request.getMethod();
if(RequestMethodEnum.GET.getDesc().equals(method)){
String signature = request.getParameter("signature");
String timestamp = request.getParameter("timestamp");
String nonce = request.getParameter("nonce");
String echoStr = request.getParameter("echostr");
String token = "weiyouzz";
boolean checkSignature = wxUtils.checkSignature(signature, timestamp, nonce, token);
if (checkSignature) {
response.getWriter().write(echoStr+"");
}
}else {
//post请求跟消息相关,往下翻到第三点
}
}
//校验微信请求
/**
* 验证微信签名
*/
public boolean checkSignature(String signature, String timestamp,String nonce, String token) {
// 1.将token、timestamp、nonce三个参数进行字典序排序
String[] arr = new String[]{token, timestamp, nonce};
Arrays.sort(arr);
// 2. 将三个参数字符串拼接成一个字符串进行sha1加密
StringBuilder content = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
content.append(arr[i]);
}
MessageDigest md = null;
String tmpStr = null;
try {
md = MessageDigest.getInstance("SHA-1");
// 将三个参数字符串拼接成一个字符串进行sha1加密
byte[] digest = md.digest(content.toString().getBytes());
tmpStr = byteToStr(digest);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
content = null;
// 3.将sha1加密后的字符串可与signature对比,标识该请求来源于微信
return tmpStr != null && tmpStr.equals(signature.toUpperCase());
}
private static String byteToStr(byte[] byteArray) {
StringBuilder strDigest = new StringBuilder();
for (int i = 0; i < byteArray.length; i++) {
strDigest.append(byteToHexStr(byteArray[i]));
}
return strDigest.toString();
}
private static String byteToHexStr(byte mByte) {
char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
'B', 'C', 'D', 'E', 'F'};
char[] tempArr = new char[2];
tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
tempArr[1] = Digit[mByte & 0X0F];
String s = new String(tempArr);
return s;
}
//可能用到的包
import java.util.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import lombok.SneakyThrows;
import springfox.documentation.annotations.ApiIgnore;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
RequestMethodEnum枚举自己建或者复制下面的
public enum RequestMethodEnum {
/** get*/
GET(1,"GET"),
/** post*/
POST(2,"POST");
private final Integer code;
private final String desc;
RequestMethodEnum(Integer id, String name){
this.code = id;
this.desc = name;
}
public Integer getCode() {
return code;
}
public String getDesc() {
return desc;
}
}
3、获取消息并回应,还是走上面这个接口,但是请求方式是post
else {
// 预先设定返回的 response 类型为 xml
tencentAdvertisingService.getMessage(request,response);
}
@Override
public void getMessage(HttpServletRequest request, HttpServletResponse response) {
try {
response.setHeader("Content-type", "application/xml");
// 读取参数,解析Xml为map
Map<String, String> map = wxUtils.transferXmlToMap(wxUtils.readRequest(request));
JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(map));
if(ObjectUtils.isNotEmpty(jsonObject)){
String msgType = jsonObject.getString("MsgType");
String toUserName = jsonObject.getString("ToUserName");
String fromUserName = jsonObject.getString("FromUserName");
String createTime = jsonObject.getString("CreateTime");
//回复,可以回复表情,蓝色可点击链接文字等
String content ;
if (TencentMsgTypeConstant.EVENT.equals(msgType)) {//关注自动回复
content = "[Party]终于等到你!欢迎你的关注!\n" +
"<a href=\"https://www.baidu.com\">百度</a>\n" +
"\n" +
"<a href=\"https://www.csdn.net\">CSDN</a>\n" +
"\n" +
"/:rose点击<a href=\"https://www.csdn.net\">【CSDN】</a>看更多优质博客\n" +
"/:gift点击<a href=\"https://www.csdn.net\">【CSDN】</a>看更多优质博客";
} else {//收到消息自动回复
content = "/:sun已经收到您的消息~\n" +
">> <a href=\"https://www.csdn.net\">【CSDN】</a>\n" +
">> <a href=\"https://www.csdn.net\">【CSDN】</a>\n" +
">> <a href=\"https://www.csdn.net\">【CSDN】</a>\n" +
">> <a href=\"https://www.csdn.net\">【CSDN】</a>\n" +
">> <a href=\"https://www.csdn.net\">【CSDN】</a>";
}
response.setCharacterEncoding("UTF-8");
response.getWriter().write(getXmlReturnMsg(fromUserName,toUserName,System.currentTimeMillis() / 1000,content));
}
}catch (Exception e){log.info(e.getMessage());}
}
//工具类
public Map transferXmlToMap(String strxml) throws IOException {
strxml = strxml.replaceFirst("encoding=\".*\"", "encoding=\"UTF-8\"");
if (null == strxml || "".equals(strxml)) {
return null;
}
Map m = new HashMap();
InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
SAXBuilder builder = new SAXBuilder();
Document doc = null;
try {
doc = builder.build(in);
} catch (JDOMException e) {
// 统一转化为 IO 异常输出
throw new IOException(e.getMessage());
}
// 解析 DOM
Element root = doc.getRootElement();
List list = root.getChildren();
Iterator it = list.iterator();
while (it.hasNext()) {
Element e = (Element) it.next();
String k = e.getName();
String v = "";
List children = e.getChildren();
if (children.isEmpty()) {
v = e.getTextNormalize();
} else {
v = getChildrenText(children);
}
m.put(k, v);
}
//关闭流
in.close();
return m;
}
/**
* 辅助 transferXmlToMap 方法递归提取子节点数据
*/
private String getChildrenText(List<Element> children) {
StringBuffer sb = new StringBuffer();
if (!children.isEmpty()) {
Iterator<Element> it = children.iterator();
while (it.hasNext()) {
Element e = (Element) it.next();
String name = e.getName();
String value = e.getTextNormalize();
List<Element> list = e.getChildren();
sb.append("<" + name + ">");
if (!list.isEmpty()) {
sb.append(getChildrenText(list));
}
sb.append(value);
sb.append("</" + name + ">");
}
}
return sb.toString();
}
/**
* 读取 request body 内容作为字符串
*
* @param request
* @return
* @throws IOException
*/
public String readRequest(HttpServletRequest request) throws IOException {
InputStream inputStream;
StringBuffer sb = new StringBuffer();
inputStream = request.getInputStream();
String str;
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
while ((str = in.readLine()) != null) {
sb.append(str);
}
in.close();
inputStream.close();
return sb.toString();
}
/**
* 构建普通消息
* @param toUser 接收方账号(openId)
* @param fromUser 开发者账号
* @param createTime 创建时间,整型
* @param content 内容
* @return 回复消息
*/
public String getXmlReturnMsg(String toUser,String fromUser,Long createTime,String content) {
return "<xml>\n" +
" <ToUserName><![CDATA["+toUser+"]]></ToUserName>\n" +
" <FromUserName><![CDATA["+fromUser+"]]></FromUserName>\n" +
" <CreateTime>"+createTime+"</CreateTime>\n" +
" <MsgType><![CDATA[text]]></MsgType>\n" +
" <Content><![CDATA["+content+"]]></Content>\n" +
"</xml>";
}