您当前的位置: 首页 > 

lootaa

暂无认证

  • 0浏览

    0关注

    68博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

公众号接收普通消息并回复

lootaa 发布时间:2022-09-22 14:59:20 ,浏览量:0

洛塔服务号回复003获取代码。

功能说明

涉及官方文档的两个知识点:接受普通消息、被动回复用户消息。希望实现的效果是公众号中用户发送什么就直接回复什么,但是有个类型不同意,所以做了调整

  • 接收文字:原样回复文字
  • 接收图片:原样回复图片
  • 接收语音:原样回复语音
  • 接收视频:回复已经上传好的视频(原样回复视频有坑)
  • 接收地理位置:回复mp3音乐(音乐文件有坑)
  • 接收链接:回复图文消息 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述
前置条件

在公众号的基本配置中,需要先调整服务器配置并开启。 服务器配置需要先写一个方法并部署上去,提供get方式请求路径,将此路径填写到服务器地址(URL)中。

  • 服务器地址(URL):get方法,按照规则校验并返回
  • 令牌(Token):这个随便写就行
  • 消息加解密密钥(EncodingAESKey):明文模式这个不用,下一篇单独写加解密的
  • 消息加解密方式:先用明文的

后台使用springboot来开发,nginx做端口转发。 nginx配置:

        location /lootaa-wechat/ {
                proxy_pass http://127.0.0.1:2022/lootaa-wechat/;
                proxy_set_header  X-Real-IP  $remote_addr;
                proxy_set_header Host $host;
        }

application.properties配置

server.port=2022
server.servlet.context-path=/lootaa-wechat

get方法访问配置(路径使用的http://test.lootaa.com/lootaa-wechat/wx)

@RestController
public class Test003 {
	@GetMapping("wx")
	public void wxGet(HttpServletRequest request, PrintWriter pw) {
		// 微信加密签名,需要使用本地计算出来的和这个对比,确认是微信发送的消息
		String signature = request.getParameter("signature");
		String timestamp = request.getParameter("timestamp"); // 时间戳
		String nonce = request.getParameter("nonce"); // 随机数
		String echostr = request.getParameter("echostr"); // 随机字符串
		// 将token、timestamp、nonce三个参数进行字典序排序
		List list = new ArrayList();
		list.add("lootaa"); // 公众号后台设置的token
		list.add(timestamp);
		list.add(nonce);
		Collections.sort(list);
		// 将三个参数字符串拼接成一个字符串进行sha1加密
		String tokenStr = "";
		for (int i = 0; i < list.size(); i++) {
			tokenStr += list.get(i);
		}
		String signatureStr = DigestUtils.sha1Hex(tokenStr);
		// 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
		if (signature.equals(signatureStr)) {
			pw.write(echostr); // 原样返回echostr参数内容
		} else {
			pw.write("");
		}
	}

打包部署到服务器后,将此路径和token填写到后台中,点击保存即可。

辅助类

为了方便解析,将接收到的xml格式转化为map。

	public static Map xmlToMap(HttpServletRequest request) {
		Map map = new HashMap();
		SAXReader reader = new SAXReader();
		try {
			InputStream ins = request.getInputStream();
			Document doc = reader.read(ins);
			Element root = doc.getRootElement();
			@SuppressWarnings("unchecked")
			List list = root.elements();
			for (Element element : list) {
				map.put(element.getName(), element.getText());
			}
			ins.close();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (DocumentException e) {
			e.printStackTrace();
		}
		return map;
	}
引入包
		
            dom4j
            dom4j
            1.6.1
        
接收文字

接收消息的方法名称和校验的名称要一致,不过类型要用post。加上注解接口:@PostMapping(“wx”),本篇最后放有完整代码。

测试接收文字并原样返回(接收和回复类型没有任何绑定关系,仅为了方便测试)。 接收文字部分的坑:中文乱码(测试系统使用的是ubuntu16.04) 乱码解决方式:new String(content.getBytes(), “iso-8859-1”)

		Map map = xmlToMap(request);
		System.out.println(JSON.parseObject(JSON.toJSONString(map)).toString());
		String messageType = map.get("MsgType");
		if (Objects.equals(messageType, "text")) { // 文本消息
			// {"Content":"测试下","CreateTime":"1663780190","ToUserName":"gh_9d20c62dcf0d","FromUserName":"ohUHp6iaFJq6SISTVwHS5lkb9Pb8","MsgType":"text","MsgId":"23819604629026729"}
			String content = map.get("Content"); // 消息文本
			String result = "" + ""
					+ "" + ""
					+ System.currentTimeMillis() + "" + ""
					+ "";
			pw.write(result);
		}

其中接收到的完整内容转化为json后格式为

{  
"Content":"测试下",  
"CreateTime":"1663780190",  
"ToUserName":"gh_9d20c62dcf0d",  
"FromUserName":"ohUHp6iaFJq6SISTVwHS5lkb9Pb8",  
"MsgType":"text",  
"MsgId":"23819604629026729"  
}
接收图片

接收图片部分基本没坑,将mediaId直接返回即可。

		if (Objects.equals(messageType, "image")) { // 图片消息
			// {"MediaId":"Nl1phIqlMqLH7N446u7PYa3iT69UxiCbuNJpbzA00D7aZ6-eW62lta-_O_fkdnQJ","CreateTime":"1663780280","ToUserName":"gh_9d20c62dcf0d","FromUserName":"ohUHp6iaFJq6SISTVwHS5lkb9Pb8","MsgType":"image","PicUrl":"http://mmbiz.qpic.cn/mmbiz_jpg/lxdgRzs8PuI2BiaFpJibv4e0b5venTHsMibrPXRz784bvagCY5csHVCuLPYNLbmPLNamhq2NZuaWSWOtpZew8kkyQ/0","MsgId":"23819606330260341"}
//			String pictureUrl = map.get("PicUrl"); //图片地址,可以进行保存等操作
			String mediaId = map.get("MediaId");
			String result = "" + ""
					+ "" + ""
					+ System.currentTimeMillis() + "" + ""
					+ "";
			pw.write(result);
		}

其中接收到的完整内容转化为json后格式为

{  
"MediaId":"Nl1phIqlMqLH7N446u7PYa3iT69UxiCbuNJpbzA00D7aZ6-eW62lta-_O_fkdnQJ",  
"CreateTime":"1663780280",  
"ToUserName":"gh_9d20c62dcf0d",  
"FromUserName":"ohUHp6iaFJq6SISTVwHS5lkb9Pb8",  
"MsgType":"image",  
"PicUrl":"http://mmbiz.qpic.cn/mmbiz_jpg/lxdgRzs8PuI2BiaFpJibv4e0b5venTHsMibrPXRz784bvagCY5csHVCuLPYNLbmPLNamhq2NZuaWSWOtpZew8kkyQ/0",  
"MsgId":"23819606330260341"  
}
接收语音

接收语音部分基本没坑,将mediaId直接返回即可。

		if (Objects.equals(messageType, "voice")) { // 语音消息
			// {"Format":"amr","MediaId":"Nl1phIqlMqLH7N446u7PYYPIUixzIjXtGuiooawIAHb8iE7ZrAO6PjPdHQiqDriJ","CreateTime":"1663780307","ToUserName":"gh_9d20c62dcf0d","FromUserName":"ohUHp6iaFJq6SISTVwHS5lkb9Pb8","MsgType":"voice","MsgId":"23819606645717223","Recognition":""}
			String mediaId = map.get("MediaId"); // 可以使用获取临时素材接口,得到语音文件
			String result = "" + ""
					+ "" + ""
					+ System.currentTimeMillis() + "" + ""
					+ "";
			pw.write(result);
		}

其中接收到的完整内容转化为json后格式为

{  
"Format":"amr",  
"MediaId":"Nl1phIqlMqLH7N446u7PYYPIUixzIjXtGuiooawIAHb8iE7ZrAO6PjPdHQiqDriJ",  
"CreateTime":"1663780307",  
"ToUserName":"gh_9d20c62dcf0d",  
"FromUserName":"ohUHp6iaFJq6SISTVwHS5lkb9Pb8",  
"MsgType":"voice",  
"MsgId":"23819606645717223",  
"Recognition":""  
}
接收视频

接收视频比较简单,但是原样返回是不行的,会报错“该公众号服务出现故障,请稍后重试”,出现错误的原因分析着可能是mediaId的问题。可以改用以下两种方式中的任意一种

  • 方式一:调用保存素材接口将收到的语音保存本地,再调用上传素材接口,获取新的mediaId(没测试)
  • 方式二:再后台上传一个视频(需要审核),调用查询视频素材接口获取到mediaId 我使用方式二拿到了对应的mediaId,就能直接返回了。
		if (Objects.equals(messageType, "video") || Objects.equals(messageType, "shortvideo")) { // 视频消息或小视频消息
			// {"MediaId":"Nl1phIqlMqLH7N446u7PYUzIk2ScQ-EmZMkChQBjzc8tCdFNBjSzszMmlEefC0pj8KXFLiNR-QrJ0aGR9pHhNQ","CreateTime":"1663780331","ToUserName":"gh_9d20c62dcf0d","FromUserName":"ohUHp6iaFJq6SISTVwHS5lkb9Pb8","MsgType":"video","ThumbMediaId":"Nl1phIqlMqLH7N446u7PYRuQm0Tn26NmuGbrtOK91CgZF_NqWm9ELodlQ-NUR7HX","MsgId":"23819609424509645"}
			String mediaId = map.get("MediaId"); // 可以使用获取临时素材接口,得到视频文件。但是这个media不能直接返回,会报错
			System.out.println(mediaId);
			String result = "" + ""
					+ "" + ""
					+ System.currentTimeMillis() + "" + ""
					+ "";
			pw.write(result);
		}

其中接收到的完整内容转化为json后格式为

{  
"MediaId":"Nl1phIqlMqLH7N446u7PYUzIk2ScQ-EmZMkChQBjzc8tCdFNBjSzszMmlEefC0pj8KXFLiNR-QrJ0aGR9pHhNQ",  
"CreateTime":"1663780331",  
"ToUserName":"gh_9d20c62dcf0d",  
"FromUserName":"ohUHp6iaFJq6SISTVwHS5lkb9Pb8",  
"MsgType":"video",  
"ThumbMediaId":"Nl1phIqlMqLH7N446u7PYRuQm0Tn26NmuGbrtOK91CgZF_NqWm9ELodlQ-NUR7HX",  
"MsgId":"23819609424509645"  
}
接收地理位置、回复音乐

接收地理位置基本没坑,但是回复音乐有坑。

  • 文档大小写问题:官方文档中,语音的地址参数写的MusicURL,但是给的demo中用的MusicUrl,大小写不一致,测试发现应该使用小写的这个,用大写的会收不到消息(用MusicUrl)。
  • mp3文件问题:mp3文件必须是可以直接下载类型的,不能是预览类型。简单理解就是用浏览器打开mp3文件,直接调用下载并保存了就可以用,如果是在浏览器上预览并可以点击播放的就不能用。如果是tomcat中放mp3文件测试,需要修改查看类型(tomcat配置中的那篇有介绍方式)
		if (Objects.equals(messageType, "location")) { // 地理位置消息
			// {"Location_X":"39.488064","CreateTime":"1663780362","Location_Y":"117.409882","Label":"天津市宝坻区锦秀香江医院西北门南290米","Scale":"15","ToUserName":"gh_9d20c62dcf0d","FromUserName":"ohUHp6iaFJq6SISTVwHS5lkb9Pb8","MsgType":"location","MsgId":"23819608037557589"}
			String result = "" + ""
					+ "" + ""
					+ System.currentTimeMillis() + "" + ""
					+ "6XvVazVT3F4qsVQ-QW23lhyagwQKJCDlX8N72L6s3vWt3wRdr_kyv57ykWM073PS";
			pw.write(result);
		}

其中接收到的完整内容转化为json后格式为

{  
"Location_X":"39.488064",  
"CreateTime":"1663780362",  
"Location_Y":"117.409882",  
"Label":"天津市宝坻区锦秀香江医院西北门南290米",  
"Scale":"15",  
"ToUserName":"gh_9d20c62dcf0d",  
"FromUserName":"ohUHp6iaFJq6SISTVwHS5lkb9Pb8",  
"MsgType":"location",  
"MsgId":"23819608037557589"  
}
接收链接、回复图文

接收链接的方式比较特别,不是随便打开一个网址就能发送到公众号的(直接转发会发现只能发送给好友或者群)。而复制链接再发送给公众号,相当于发送的是文字,并不是链接。 发送链接的方式:打开要发送的文档,右上角选择收藏,然后从公众号中发送消息选择收藏,点击对应链接文件。

		if (Objects.equals(messageType, "link")) { // 链接消息
			String title = map.get("Title");
			String description = map.get("Description");
			String url = map.get("Url");
			String result = "" + ""
					+ "" + ""
					+ System.currentTimeMillis() + ""
					+ "1"
					+ "";
			pw.write(result);
		}

其中接收到的完整内容转化为json后格式为

{  
"Description":"只发布,不群发",  
"CreateTime":"1663829663",  
"Title":"素材不群发",  
"ToUserName":"gh_9d20c62dcf0d",  
"FromUserName":"ohUHp6iaFJq6SISTVwHS5lkb9Pb8",  
"MsgType":"link",  
"Url":"http://mp.weixin.qq.com/s?__biz=Mzk0MTE1NTIwNQ==&mid=2247483657&idx=1&sn=5972ffc790e35d5e2c3cbe7ae87b67e3&chksm=c2d7f7e3f5a07ef55c39279071ec7f6625588e9bc67ba0b8d977c88f5665b7a1b60eef3c3aa3&mpshare=1&scene=24&srcid=0922iAEbMMAMtEEIOXq2wy2w&sharer\_sharetime=1663815207140&sharer_shareid=db3f25b006d12b80ede9b491c1a93d54#rd",  
"MsgId":"23820313330345365"  
}
完整代码
package com.lootaa.wechat;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.digest.DigestUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSON;

/**
 * 前置条件:基本配置中开启了服务器配置
 * 完整项目源码可关注公众号"lootaayun"(洛塔),回复003获取
 */
@RestController
public class Test003 {

	@GetMapping("wx")
	public void wxGet(HttpServletRequest request, PrintWriter pw) {
		// 微信加密签名,需要使用本地计算出来的和这个对比,确认是微信发送的消息
		String signature = request.getParameter("signature");
		String timestamp = request.getParameter("timestamp"); // 时间戳
		String nonce = request.getParameter("nonce"); // 随机数
		String echostr = request.getParameter("echostr"); // 随机字符串
		// 将token、timestamp、nonce三个参数进行字典序排序
		List list = new ArrayList();
		list.add("lootaa"); // 公众号后台设置的token
		list.add(timestamp);
		list.add(nonce);
		Collections.sort(list);
		// 将三个参数字符串拼接成一个字符串进行sha1加密
		String tokenStr = "";
		for (int i = 0; i < list.size(); i++) {
			tokenStr += list.get(i);
		}
		String signatureStr = DigestUtils.sha1Hex(tokenStr);
		// 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
		if (signature.equals(signatureStr)) {
			pw.write(echostr); // 原样返回echostr参数内容
		} else {
			pw.write("");
		}
	}

	public static Map xmlToMap(HttpServletRequest request) {
		Map map = new HashMap();
		SAXReader reader = new SAXReader();
		try {
			InputStream ins = request.getInputStream();
			Document doc = reader.read(ins);
			Element root = doc.getRootElement();
			@SuppressWarnings("unchecked")
			List list = root.elements();
			for (Element element : list) {
				map.put(element.getName(), element.getText());
			}
			ins.close();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (DocumentException e) {
			e.printStackTrace();
		}
		return map;
	}

	/**
	 * 如果不能确保5秒钟之内回复消息,微信会发起重试。对于此种情况,两种解决方法 1. 所有消息都有MsgId字段,用来做判断避免重复处理 2.
	 * 先返回一条固定消息,然后再启线程单独处理(比如处理完成后在用客服消息接口发送给用户)
	 */
	@PostMapping("wx")
	public void wxPost(HttpServletRequest request, HttpServletResponse response, PrintWriter pw)
			throws UnsupportedEncodingException {
		Map map = xmlToMap(request);
		System.out.println(JSON.parseObject(JSON.toJSONString(map)).toString());
		String messageType = map.get("MsgType");
		if (Objects.equals(messageType, "text")) { // 文本消息
			// {"Content":"测试下","CreateTime":"1663780190","ToUserName":"gh_9d20c62dcf0d","FromUserName":"ohUHp6iaFJq6SISTVwHS5lkb9Pb8","MsgType":"text","MsgId":"23819604629026729"}
			String content = map.get("Content"); // 消息文本
			String result = "" + ""
					+ "" + ""
					+ System.currentTimeMillis() + "" + ""
					+ "";
			pw.write(result);
		}
		if (Objects.equals(messageType, "image")) { // 图片消息
			// {"MediaId":"Nl1phIqlMqLH7N446u7PYa3iT69UxiCbuNJpbzA00D7aZ6-eW62lta-_O_fkdnQJ","CreateTime":"1663780280","ToUserName":"gh_9d20c62dcf0d","FromUserName":"ohUHp6iaFJq6SISTVwHS5lkb9Pb8","MsgType":"image","PicUrl":"http://mmbiz.qpic.cn/mmbiz_jpg/lxdgRzs8PuI2BiaFpJibv4e0b5venTHsMibrPXRz784bvagCY5csHVCuLPYNLbmPLNamhq2NZuaWSWOtpZew8kkyQ/0","MsgId":"23819606330260341"}
//			String pictureUrl = map.get("PicUrl"); //图片地址,可以进行保存等操作
			String mediaId = map.get("MediaId");
			String result = "" + ""
					+ "" + ""
					+ System.currentTimeMillis() + "" + ""
					+ "";
			pw.write(result);
		}
		if (Objects.equals(messageType, "voice")) { // 语音消息
			// {"Format":"amr","MediaId":"Nl1phIqlMqLH7N446u7PYYPIUixzIjXtGuiooawIAHb8iE7ZrAO6PjPdHQiqDriJ","CreateTime":"1663780307","ToUserName":"gh_9d20c62dcf0d","FromUserName":"ohUHp6iaFJq6SISTVwHS5lkb9Pb8","MsgType":"voice","MsgId":"23819606645717223","Recognition":""}
			String mediaId = map.get("MediaId"); // 可以使用获取临时素材接口,得到语音文件
			String result = "" + ""
					+ "" + ""
					+ System.currentTimeMillis() + "" + ""
					+ "";
			pw.write(result);
		}
		if (Objects.equals(messageType, "video") || Objects.equals(messageType, "shortvideo")) { // 视频消息或小视频消息
			// {"MediaId":"Nl1phIqlMqLH7N446u7PYUzIk2ScQ-EmZMkChQBjzc8tCdFNBjSzszMmlEefC0pj8KXFLiNR-QrJ0aGR9pHhNQ","CreateTime":"1663780331","ToUserName":"gh_9d20c62dcf0d","FromUserName":"ohUHp6iaFJq6SISTVwHS5lkb9Pb8","MsgType":"video","ThumbMediaId":"Nl1phIqlMqLH7N446u7PYRuQm0Tn26NmuGbrtOK91CgZF_NqWm9ELodlQ-NUR7HX","MsgId":"23819609424509645"}
			String mediaId = map.get("MediaId"); // 可以使用获取临时素材接口,得到视频文件。但是这个media不能直接返回,会报错
			System.out.println(mediaId);
			String result = "" + ""
					+ "" + ""
					+ System.currentTimeMillis() + "" + ""
					+ "";
			pw.write(result);
		}
		if (Objects.equals(messageType, "location")) { // 地理位置消息
			// {"Location_X":"39.488064","CreateTime":"1663780362","Location_Y":"117.409882","Label":"天津市宝坻区锦秀香江医院西北门南290米","Scale":"15","ToUserName":"gh_9d20c62dcf0d","FromUserName":"ohUHp6iaFJq6SISTVwHS5lkb9Pb8","MsgType":"location","MsgId":"23819608037557589"}
			String result = "" + ""
					+ "" + ""
					+ System.currentTimeMillis() + "" + ""
					+ "6XvVazVT3F4qsVQ-QW23lhyagwQKJCDlX8N72L6s3vWt3wRdr_kyv57ykWM073PS";
			pw.write(result);
		}
		if (Objects.equals(messageType, "link")) { // 链接消息
			String title = map.get("Title");
			String description = map.get("Description");
			String url = map.get("Url");
			String result = "" + ""
					+ "" + ""
					+ System.currentTimeMillis() + ""
					+ "1"
					+ "";
			pw.write(result);
		}

	}

}

关注
打赏
1663829960
查看更多评论
立即登录/注册

微信扫码登录

0.0364s