springboot实现公众号接收回复消息和超过5秒被动回复消息
目录
- 1.首先第一步要接收微信消息,需要在公众号里设置与开发-基本配置里配置一下服务器配置
- 2.配置好公众号以后,开始接收微信消息
现在项目有个需求,需要用户在公众号发送图片消息的时候,我后台程序能接收到这个图片,并用ai处理图片并返回信息。
1.首先第一步要接收微信消息,需要在公众号里设置与开发-基本配置里配置一下服务器配置
文章图片
这个url配置了以后,所以微信公众号的消息都会被推送到这个url对应的接口上,Token感觉没啥用,随便写一个完事,加密随机生成,不加密消息的话也没用。
最坑爹的是在提交配置的时候,微信要根据你填的这个url验证一下token认证,而这个url实际是后台处理消息的接口,搞不清楚咋肥四,我就先把这个接口写成验证token的,等提交完配置再改回我的处理消息接口代码。验证token这里随便找了段代码,亲测有效。
@RequestMapping(value = "https://www.it610.com/testToken")public void testToken(HttpServletRequest request, HttpServletResponse response) throws Exception {String token="tokenxxx"; logger.error("WechatController----WechatController"); System.out.println("========WechatController========= "); logger.info("请求进来了..."); Enumeration pNames = request.getParameterNames(); while (pNames.hasMoreElements()) {String name = (String) pNames.nextElement(); String value = https://www.it610.com/article/request.getParameter(name); // out.print(name +"=" + value); String log = "name =" + name + "value ="https://www.it610.com/article/+ value; logger.error(log); }String signature = request.getParameter("signature"); /// 微信加密签名String timestamp = request.getParameter("timestamp"); /// 时间戳String nonce = request.getParameter("nonce"); /// 随机数String echostr = request.getParameter("echostr"); // 随机字符串PrintWriter out = response.getWriter(); out.print(echostr); out.close(); }
【springboot实现公众号接收回复消息和超过5秒被动回复消息】
2.配置好公众号以后,开始接收微信消息 官方文档在这里:文本消息 | 微信开放文档
也就是说微信会给你发送xml格式的消息,后台需要能接收这个消息
要接收xml消息和以后发送消息啥的,需要先引入一些依赖:
com.fasterxml.jackson.dataformat jackson-dataformat-xmlcom.fasterxml.jackson.core jackson-databind2.10.0 com.fasterxml.jackson.core jackson-core2.10.0 com.fasterxml.jackson.core jackson-annotations2.10.0 com.fasterxml.jackson.jaxrs jackson-jaxrs-xml-providerorg.projectlombok lombokorg.apache.httpcomponents httpcore4.4.10 org.apache.httpcomponents httpclient4.5.6 dom4j dom4j1.6 com.thoughtworks.xstream xstream1.4.4
以为对应的图标消息是这样的:
文章图片
所以写个消息的实体类:
package com.bomc.recordLife.entry; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @Data@NoArgsConstructor@AllArgsConstructor@JacksonXmlRootElement(localName= "xml")public class WxMessageImg {@JacksonXmlProperty(localName= "ToUserName")private String ToUserName; @JacksonXmlProperty(localName= "FromUserName")private String FromUserName; @JacksonXmlProperty(localName= "CreateTime")private longCreateTime; @JacksonXmlProperty(localName= "MsgType")private String MsgType; @JacksonXmlProperty(localName= "Event")private String Event; @JacksonXmlProperty(localName= "PicUrl")private String PicUrl; @JacksonXmlProperty(localName= "MediaId")private String MediaId; @JacksonXmlProperty(localName= "MsgId")private longMsgId; @JacksonXmlProperty(localName= "Content")private String Content; }
还是先记录一下如果不怕超时直接给用户返回消息的情况:
@PostMapping(value = "https://www.it610.com/article/analyzeImg2",consumes = "text/xml", produces = "text/xml; charset=utf-8")@ResponseBodypublic Object analyzeImg2(@RequestBody WxMessageImg wxMessageImg){ //拼一下要返回的信息对象WxMessageImg resultMessage=new WxMessageImg(); try {//忽略图片逻辑,直接闹个结果String resultStr="处理完图片返回的信息"; String openid = wxMessageImg.getFromUserName(); //用户 openidString mpid = wxMessageImg.getToUserName(); //公众号原始 IDresultMessage.setToUserName(openid); resultMessage.setFromUserName(mpid); resultMessage.setCreateTime(new Date().getTime()); resultMessage.setContent(resultStr); resultMessage.setMsgType("text"); //用这个工具类处理出一串玩意直接返回String outMesStr = WxMessageUtil.textMessageToXml(resultMessage); System.out.println(outMesStr); return outMesStr; } catch (Exception e) {e.printStackTrace(); } return null; }
工具类:
package com.bomc.recordLife.util; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.bomc.recordLife.entry.WxMessageImg; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @Description: 消息工具类 * @Author: lst * @Date 2020-08-19 */public class WxMessageUtil { /*** 返回消息类型:文本*/public static final String RESP_MESSAGE_TYPE_TEXT = "text"; /*** 返回消息类型:音乐*/public static final String RESP_MESSAGE_TYPE_MUSIC = "music"; /*** 返回消息类型:图文*/public static final String RESP_MESSAGE_TYPE_NEWS = "news"; /*** 返回消息类型:图片*/public static final String RESP_MESSAGE_TYPE_Image = "image"; /*** 返回消息类型:语音*/public static final String RESP_MESSAGE_TYPE_Voice = "voice"; /*** 返回消息类型:视频*/public static final String RESP_MESSAGE_TYPE_Video = "video"; /*** 请求消息类型:文本*/public static final String REQ_MESSAGE_TYPE_TEXT = "text"; /*** 请求消息类型:图片*/public static final String REQ_MESSAGE_TYPE_IMAGE = "image"; /*** 请求消息类型:链接*/public static final String REQ_MESSAGE_TYPE_LINK = "link"; /*** 请求消息类型:地理位置*/public static final String REQ_MESSAGE_TYPE_LOCATION = "location"; /*** 请求消息类型:音频*/public static final String REQ_MESSAGE_TYPE_VOICE = "voice"; /*** 请求消息类型:视频*/public static final String REQ_MESSAGE_TYPE_VIDEO = "video"; /*** 请求消息类型:推送*/public static final String REQ_MESSAGE_TYPE_EVENT = "event"; /*** 事件类型:subscribe(订阅)*/public static final String EVENT_TYPE_SUBSCRIBE = "subscribe"; /*** 事件类型:unsubscribe(取消订阅)*/public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe"; /*** 事件类型:CLICK(自定义菜单点击事件)*/public static final String EVENT_TYPE_CLICK = "CLICK"; /*** 事件类型:VIEW(自定义菜单URl视图)*/public static final String EVENT_TYPE_VIEW = "VIEW"; /*** 事件类型:LOCATION(上报地理位置事件)*/public static final String EVENT_TYPE_LOCATION = "LOCATION"; /*** 事件类型:LOCATION(上报地理位置事件)*/public static final String EVENT_TYPE_SCAN = "SCAN"; /*** @Description: 解析微信发来的请求(XML)* @param @param request* @param @return* @param @throws Exception* @author dapengniao* @date 2016年3月7日 上午10:04:02*/public static Map parseXml(HttpServletRequest request) {// 将解析结果存储在HashMap中Map map = new HashMap(); // 读取输入流SAXReader reader = new SAXReader(); Document document = null; InputStream inputStream = null; try {// 从request中取得输入流inputStream = request.getInputStream(); document = reader.read(inputStream); // 得到xml根元素Element root = document.getRootElement(); // 得到根元素的所有子节点ListelementList = root.elements(); // 遍历所有子节点elementList.stream().forEach(element -> {map.put(element.getName(), element.getStringValue()); }); } catch (DocumentException e) {e.printStackTrace(); } catch (IOException e) {e.printStackTrace(); }finally {// 释放资源if(null != inputStream){try {inputStream.close(); } catch (IOException e) {e.printStackTrace(); }}} return map; } /*** @Description: 文本消息对象转换成xml* @param @param textMessage* @param @return* @author dapengniao* @date 2016年3月8日 下午4:13:22*/public static String textMessageToXml(WxMessageImg textMessage) {XStream xStream = new XStream(new DomDriver("UTF-8")); //XStream xStream = new XStream(); xStream.alias("xml", textMessage.getClass()); return xStream.toXML(textMessage); } }
如果用postman调用的需要这样:
文章图片
以上就是接收消息和被动回复消息,但是有个大坑,一开始我想着处理完消息在直接返回信息回去,但是处理时间总是超过5秒,每次超过5秒它就报一下服务出现故障,一共请求三次,三次都超时就给你报三次故障。
文章图片
后来客户不愿意报这玩意儿,就只好改成直接返回success再异步调用处理图片方法,处理完再用客服消息主动给用户发消息。
因为要处理图片花费的时间比较多,所以开个线程搞成异步调用处理图片再推送消息,这样的话直接返回字符串success
文章图片
在controller里面写个方法接收一下,用@RequestBody 直接把发来的xml变成对象
@RequestMapping(value = "https://www.it610.com/article/analyzeImg")@ResponseBodypublic StringanalyzeImg(@RequestBody WxMessageImg wxMessageImg) throws Exception {//异步调用,先直接返回success,不然会显示程序异常new Thread(new Runnable() {public void run() {getImgData(wxMessageImg); }}).start(); return "SUCCESS"; //return null; }
public Object getImgData(WxMessageImg wxMessageImg){ try {//忽略图片逻辑,直接闹个结果String resultStr="处理完图片返回的信息"; String openid = wxMessageImg.getFromUserName(); //用户 openidpostMessage(openid,resultStr); } catch (Exception e) {e.printStackTrace(); } return null; }
微信的破文档找个推送客户消息太费劲了,网上都到的基本都是发送模板消息,但我只是想发个文本消息呀!!
后来才找到发送客服消息的url是:https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=
发送模板消息的url是:https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=
官方接口介绍
文章图片
发送文本信息
文章图片
所以我们需要的就是这个url和发送的文本格式,就这么简单几个值而已:
public String postMessage(String openid,String content) throws Exception {//String access_token=WxMessageUtil.obtainAccessToken(); //appid和appsecret为公众号里面的String tokenData = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appId+"&secret="+appSecret; // 返回的用户信息json字符串String result=HttpUtil.doGet(tokenData); System.out.println(result); JSONObject jsonObject = JSON.parseObject(result); //先获取access_tokenString access_token=String.valueOf(jsonObject.get("access_token")); System.out.println(access_token); //消息推送接口String path = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" + access_token; JSONObject jsonData = https://www.it610.com/article/new JSONObject(); jsonData.put("touser", openid); jsonData.put("msgtype", "text"); JSONObject text = new JSONObject(); text.put("content",content); jsonData.put("text",text); System.out.println(jsonData); System.out.println(path); //HttpUtil.doPostJson(path, jsonData.toJSONString()); HttpRequest.sendPost(path, jsonData.toJSONString()); return "SUCCESS"; //return null; }
这样就能成功给用户异步回复消息,不会担心超过5秒报异常的问题了
package com.bomc.recordLife.util; import java.io.*; import java.net.URL; import java.net.URLConnection; import java.util.List; import java.util.Map; public class HttpRequest {/*** 向指定URL发送GET方法的请求* * @param url*发送请求的URL* @param param*请求参数,请求参数应该是 name1=value1&name2=value2 的形式。* @return URL 所代表远程资源的响应结果*/public static String sendGet(String url, String param) {String result = ""; BufferedReader in = null; try {String urlNameString = url + "?" + param; URL realUrl = new URL(urlNameString); // 打开和URL之间的连接URLConnection connection = realUrl.openConnection(); // 设置通用的请求属性connection.setRequestProperty("accept", "*/*"); connection.setRequestProperty("connection", "Keep-Alive"); connection.setRequestProperty("user-agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)"); // 建立实际的连接connection.connect(); // 获取所有响应头字段Map> map = connection.getHeaderFields(); // 遍历所有的响应头字段for (String key : map.keySet()) {System.out.println(key + "--->" + map.get(key)); }// 定义 BufferedReader输入流来读取URL的响应in = new BufferedReader(new InputStreamReader(connection.getInputStream())); String line; while ((line = in.readLine()) != null) {result += line; }} catch (Exception e) {System.out.println("发送GET请求出现异常!" + e); e.printStackTrace(); }// 使用finally块来关闭输入流finally {try {if (in != null) {in.close(); }} catch (Exception e2) {e2.printStackTrace(); }}return result; } /*** 向指定 URL 发送POST方法的请求* * @param url*发送请求的 URL* @param param*请求参数,请求参数应该是 name1=value1&name2=value2 的形式。* @return 所代表远程资源的响应结果*/public static String sendPost(String url, String param) {PrintWriter out = null; BufferedReader in = null; String result = ""; try {URL realUrl = new URL(url); // 打开和URL之间的连接URLConnection conn = realUrl.openConnection(); // 设置通用的请求属性conn.setRequestProperty("accept", "application/json, text/javascript, */*; q=0.01"); conn.setRequestProperty("Accept-Encoding", "gzip, deflate"); conn.setRequestProperty("Connection", "keep-alive"); conn.setRequestProperty("Accept-Language", "zh-CN,zh; q=0.8"); conn.setRequestProperty("Content-Length", "80"); conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36"); conn.setRequestProperty("user-agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)"); // 发送POST请求必须设置如下两行conn.setDoOutput(true); conn.setDoInput(true); // 获取URLConnection对象对应的输出流OutputStreamWriter outWriter = new OutputStreamWriter(conn.getOutputStream(), "utf-8"); out = new PrintWriter(outWriter); // 发送请求参数out.print(param); // flush输出流的缓冲out.flush(); // 定义BufferedReader输入流来读取URL的响应in = new BufferedReader(new InputStreamReader(conn.getInputStream(),"UTF-8")); String line; while ((line = in.readLine()) != null) {result += line; }} catch (Exception e) {System.out.println("发送 POST 请求出现异常!"+e); e.printStackTrace(); }//使用finally块来关闭输出流、输入流finally{try{if(out!=null){out.close(); }if(in!=null){in.close(); }}catch(IOException ex){ex.printStackTrace(); }}return result; }public static void main(String[] args) {//发送 GET 请求/* String s=HttpRequest.sendGet("http://localhost:6144/Home/RequestString", "key=123&v=456"); System.out.println(s); *///发送 POST 请求/* String sr=HttpRequest.sendPost("http://www.cheshouye.com/api/weizhang/get_all_config",""); JSONObject jsStr = JSONObject.fromObject(sr); JSONArray jsonarray = jsStr.getJSONArray("configs"); for(int i=0; i
到此这篇关于springboot实现公众号接收回复消息和超过5秒被动回复消息的文章就介绍到这了,更多相关springboot 公众号接收回复 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
推荐阅读
- SpringBoot如何使用@Cacheable进行缓存与取值
- JavaScript实现文本转换为文件示例详解
- MyBatis-Plus实现条件查询的三种格式例举详解
- SpringBoot自动配置特点与原理详细分析
- Spring|Spring Boot快速实现 IP地址解析的示例详解
- SpringBoot|SpringBoot SPI 机制和实现自定义 starter
- 100行代码实现一个RISC-V架构下的多线程管理框架
- 17.08.19|17.08.19 Jfinal+QuartzPlugin实现定时执行任务
- JavaWeb|最棒的SpringBoot多模块应用开发教程
- springboot|SpringBoot 日志系列:(一)日志类型