【公众号开发】访问第三方接口应用于开发 · 回复图文消息

编程入门 行业动态 更新时间:2024-10-26 00:30:53

【公众号开发】访问<a href=https://www.elefans.com/category/jswz/34/1770258.html style=第三方接口应用于开发 · 回复图文消息"/>

【公众号开发】访问第三方接口应用于开发 · 回复图文消息

【公众号开发】(2)

文章目录

  • 【公众号开发】(2)
    • 1. 第三方接口
      • 1.1 申请免费接口
      • 1.2 解读接口文档
      • 1.3 postman测试接口
      • 1.4 公众号开发访问第三方接口原理
      • 1.5 访问第三方接口示例
        • 1.5.1 引入依赖
        • 1.5.2 获取form格式的body字符串的方法
        • 1.5.3 发送get请求
        • 1.5.4 发送post请求
        • 1.5.5 json序列化与反序列化相关方法
        • 1.5.6 获取单词方法
        • 1.5.7 测试
        • 1.5.8 TextMessage的包装方法
        • 1.5.9 修改controller层代码
        • 1.5.10 重启并给测试公众号发消息测试
    • 2. 回复图文消息
      • 2.1 封装类
        • 2.1.1 Article对象
        • 2.1.2 NewsMessage对象
      • 2.2 编写回复图文消息的方法
        • 2.2.1 封装一个NewsMessage对象并返回
        • 2.2.2 在controller约定一个分支回复图文消息
        • 2.2.3 发“图文”这个文本消息给公众号进行测试
        • 2.2.4 装杯带来的小坑

【公众号开发】(2)

natapp:NATAPP -

开发手册:开发前必读 / 首页 (qq)

微信测试公众号:微信公众平台 (qq)

重新配置哦:


之后不提醒了

1. 第三方接口

聚合数据 - API接口开放平台_API接口大全_免费API数据接口服务 (juhe)

在这个网站中注册一个账号后登录:

在这里,有超级多的现成的api,可以实现对应的功能:

而我们要的就是里面免费的api去实现我们需要的功能(不过白嫖每天访问有次数限制)

而我们要学习的就是 申请免费接口,用于我们的开发,实现我们的自定义功能!

接下来,我们用一个可以免费实现的功能 “同义词接口” 为示例,其他免费接口根据实际情况举一反三即可!

1.1 申请免费接口

进入个人中心,数据中心,我的api, 申请新数据:

搜索一下:

申请:

我的API查看:

实名一下:

点进去查看接口文档(功能与使用):

错误码之后需要再说:

1.2 解读接口文档

接口与格式约定

参数约定:

  • 意味着我们请求的时候,要给定什么参数,接受响应时,可以获得什么数据

1.3 postman测试接口

key输入错误:

key输入要输入你的接口所描述的请求key:

  • 这个key可以说是身份标识吧

  • 补充:type不传默认为1

查看请求的统计:

1.4 公众号开发访问第三方接口原理

1.5 访问第三方接口示例

有些接口是有示例代码的,可以去看看,这里不带着大家看了

例如笑话大全接口的api页面:

1.5.1 引入依赖
<dependency>            <groupId>net.sf.json-lib</groupId>          <artifactId>json-lib</artifactId>         <version>2.2.3</version>        <classifier>jdk15</classifier>     
</dependency>

之后就是编写业务代码了

我们直接抄一些示例代码发送请求的工具类和方法即可:

  • 感兴趣可以去阅读一下代码~

这里我做过改良的~

public class HttpUtils {public static final String URL = "";//申请接口的请求key// TODO: 您需要改为自己的请求keypublic static final String KEY = "key";
}
1.5.2 获取form格式的body字符串的方法
public static String getFormBody(Map<String, Object> map) {Set<Map.Entry<String, Object>> entrySet = map.entrySet();StringBuilder builder = new StringBuilder();for(Map.Entry<String, Object> entry : entrySet) {builder.append(entry.toString());builder.append("&");}String formBody = builder.toString();if(StringUtils.hasLength(formBody)) {formBody = formBody.substring(0, formBody.length() - 1);}System.out.println(formBody);return formBody;
}

这个方法可以将一个哈希表的所有键值对转化为form格式:key1=val1&key2=val2

1.5.3 发送get请求
public static String doGet(String httpUrl, Map<String, Object> map) {// 有queryString的就加String formBody = HttpUtils.getFormBody(map);if(StringUtils.hasLength(formBody)) {httpUrl += "?" + formBody;}HttpURLConnection connection = null;InputStream inputStream = null;BufferedReader bufferedReader = null;String result = null;// 返回结果字符串try {// 创建远程url连接对象URL url = new URL(httpUrl);// 通过远程url连接对象打开一个连接,强转成httpURLConnection类connection = (HttpURLConnection) url.openConnection();// 设置连接方式:getconnection.setRequestMethod("GET");// 设置连接主机服务器的超时时间:15000毫秒connection.setConnectTimeout(15000);// 设置读取远程返回的数据时间:60000毫秒connection.setReadTimeout(60000);// 发送请求connection.connect();// 通过connection连接,获取输入流if (connection.getResponseCode() == 200) {inputStream = connection.getInputStream();// 封装输入流,并指定字符集bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));// 存放数据StringBuilder sbf = new StringBuilder();String temp;while ((temp = bufferedReader.readLine()) != null) {sbf.append(temp);sbf.append(System.getProperty("line.separator"));}result = sbf.toString();}} catch (IOException e) {e.printStackTrace();} finally {// 关闭资源if (null != bufferedReader) {try {bufferedReader.close();} catch (IOException e) {e.printStackTrace();}}if (null != inputStream) {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}if (connection != null) {connection.disconnect();// 关闭远程连接}}return result;
}
1.5.4 发送post请求
public static String doPost(String httpUrl, Map<String, Object> map) {HttpURLConnection connection = null;InputStream inputStream = null;OutputStream outputStream = null;BufferedReader bufferedReader = null;String result = null;try {URL url = new URL(httpUrl);// 通过远程url连接对象打开连接connection = (HttpURLConnection) url.openConnection();// 设置连接请求方式connection.setRequestMethod("POST");// 设置连接主机服务器超时时间:15000毫秒connection.setConnectTimeout(15000);// 设置读取主机服务器返回数据超时时间:60000毫秒connection.setReadTimeout(60000);// 默认值为:false,当向远程服务器传送数据/写数据时,需要设置为trueconnection.setDoOutput(true);// 设置传入参数的格式:请求参数应该是 name1=value1&name2=value2 的形式。connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");// 通过连接对象获取一个输出流outputStream = connection.getOutputStream();// 通过输出流对象将参数写出去/传输出去,它是通过字节数组写出的outputStream.write(getFormBody(map).getBytes());// 通过连接对象获取一个输入流,向远程读取if (connection.getResponseCode() == 200) {inputStream = connection.getInputStream();// 对输入流对象进行包装:charset根据工作项目组的要求来设置bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));StringBuilder sbf = new StringBuilder();String temp;// 循环遍历一行一行读取数据while ((temp = bufferedReader.readLine()) != null) {sbf.append(temp);sbf.append(System.getProperty("line.separator"));}result = sbf.toString();}} catch (IOException e) {e.printStackTrace();} finally {// 关闭资源if (null != bufferedReader) {try {bufferedReader.close();} catch (IOException e) {e.printStackTrace();}}if (null != outputStream) {try {outputStream.close();} catch (IOException e) {e.printStackTrace();}}if (null != inputStream) {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}if (connection != null) {connection.disconnect();}}return result;
}
1.5.5 json序列化与反序列化相关方法
public class JsonUtils {public static ObjectMapper objectMapper = new ObjectMapper();public static Map<String, Object> jsonToMap(String jsonString) {Map map = null;try {map = objectMapper.readValue(jsonString, Map.class);} catch (JsonProcessingException e) {throw new RuntimeException(e);}return map;}public static String objectToJson(Object object) {String jsonString = null;try {jsonString = objectMapper.writeValueAsString(object);} catch (JsonProcessingException e) {throw new RuntimeException(e);}return jsonString;}
}
1.5.6 获取单词方法
  1. 构造参数表
  2. 发起请求
  3. 处理响应
public static List<String> getWords(Integer type, String word) {// 构造参数表Map<String, Object> params = new HashMap<>();params.put("key", KEY);params.put("type", type);params.put("word", word);//发起请求接受响应final String response = doPost(URL, params);System.out.println("接口返回:" + response);try {Map<String, Object> ret = JsonUtils.jsonToMap(response);int error_code = (Integer) ret.get("error_code");String reason = (String) ret.get("reason");if (error_code == 0) {System.out.println("调用接口成功");Map<String, Object> result = (Map<String, Object>) ret.get("result");String t = (String) result.get("type");//返回的typeList<String> words = (List<String>) result.get("words");System.out.println(t);System.out.println(words);return words;} else {System.out.println("调用接口失败:" + reason);return null;}} catch (Exception e) {e.printStackTrace();}return null;
}
1.5.7 测试
public static void main(String[] args) {getWords(1, "开心");
}

1.5.8 TextMessage的包装方法
/*** 获取同义词* @param map* @return*/
public static TextMessage getSynonym(Map<String, String> map) {TextMessage message = new TextMessage();message.setToUserName(map.get("FromUserName"));message.setFromUserName(map.get("ToUserName"));message.setCreateTime(System.currentTimeMillis() / 1000);message.setMsgType("text");message.setContent("回复同义词:  " + HttpUtils.getWords(1, map.get("Content")));return message;
}/*** 获取反义词* @param map* @return*/
public static TextMessage getAntonym(Map<String, String> map) {TextMessage message = new TextMessage();message.setToUserName(map.get("FromUserName"));message.setFromUserName(map.get("ToUserName"));message.setCreateTime(System.currentTimeMillis() / 1000);message.setMsgType("text");message.setContent("回复反义词:  " + HttpUtils.getWords(2, map.get("Content")));return message;
}
1.5.9 修改controller层代码

1.5.10 重启并给测试公众号发消息测试

第一次访问要加载很多东西,响应时间需要较长,这很正常哦~

到这里,相信你已经了解了访问第三方接口的大致流程,结合实际需求,业务逻辑,开始举一反三吧!

  • 无非就是申请接口,查看功能介绍,接口文档,构造请求,发送请求,处理响应~

补充:xml序列化和反序列化的方法相关方法,可能需要用到

public class XmlUtils {public static String objectToXml(Object o) {//获取序列化工具XStream对象XStream xStream = new XStream();//指定类型xStream.processAnnotations(o.getClass());//转化为xml字符串String xml = xStream.toXML(o);//返回return xml;}public static Map<String, String> xmlToMap(ServletInputStream inputStream) {Map<String, String> map = new HashMap<>();SAXReader reader = new SAXReader();// xml字符串解析方法try {//通过请求的输入流,获取Document对象Document document = reader.read(inputStream);// 获取root节点Element root = document.getRootElement();// 获取所有子节点List<Element> elements = root.elements();// 遍历集合for(Element e : elements) {map.put(e.getName(), e.getStringValue());}} catch (DocumentException e) {throw new RuntimeException(e);}return map;}public static Map<String, Object> xmlToMap(String xml) {Map<String, Object> map = new HashMap<>();try {DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = factory.newDocumentBuilder();org.w3c.dom.Document document = builder.parse(new InputSource(new StringReader(xml)));org.w3c.dom.Element root = document.getDocumentElement();map = parseElement(root);} catch (Exception e) {e.printStackTrace();}return map;}private static Map<String, Object> parseElement(org.w3c.dom.Element element) {Map<String, Object> map = new HashMap<>();NodeList nodeList = element.getChildNodes();for (int i = 0; i < nodeList.getLength(); i++) {Node node = nodeList.item(i);if (node.getNodeType() == Node.ELEMENT_NODE) {org.w3c.dom.Element childElement = (org.w3c.dom.Element) node;if (childElement.getChildNodes().getLength() > 1) {map.put(childElement.getTagName(), parseElement(childElement));} else {map.put(childElement.getTagName(), childElement.getTextContent());}}}return map;}
}

2. 回复图文消息

基础消息能力 / 被动回复用户消息 (qq)

  • 可能有时候,我不会发开发者文档的具体位置,只会发重点截图(感兴趣的可以去文档查一查,学一学)

这里以图文消息为例,其他消息按照模板返回即可,这个最具有代表性,情况覆盖面比较大~

开发者需要回复的消息模板:

<xml><ToUserName><![CDATA[toUser]]></ToUserName><FromUserName><![CDATA[fromUser]]></FromUserName><CreateTime>12345678</CreateTime><MsgType><![CDATA[news]]></MsgType><ArticleCount>1</ArticleCount><Articles><item><Title><![CDATA[title1]]></Title><Description><![CDATA[description1]]></Description><PicUrl><![CDATA[picurl]]></PicUrl><Url><![CDATA[url]]></Url></item></Articles>
</xml>
  • item代表一个Article元素(一个文本元素)

参数描述:

我们回复的图文消息就差不多这种:

  1. 有标题
  2. 描述(简介)
  3. 图片(封面)
  4. 点击就可以跳转链接(微信站内页面、网页…)

2.1 封装类

2.1.1 Article对象
@Data
@XStreamAlias("item")
public class Article {@XStreamAlias("Title")private String title;@XStreamAlias ("Description")private String description;@XStreamAlias("PicUrl")private String picUrl;@XStreamAlias ("Url")private String url;
}

别忘了,这个图文信息被item标签包裹~

2.1.2 NewsMessage对象
@XStreamAlias("xml")
@Data
public class NewsMessage {@XStreamAlias("ToUserName")private String toUserName;@XStreamAlias("FromUserName")private String fromUserName;@XStreamAlias("CreateTime")private long createTime;@XStreamAlias("MsgType")private String msgType;@XStreamAlias("ArticleCount")private Integer articleCount;@XStreamAlias("Articles")private List<Article> articles;
}

别忘了,最外层标签xml~

List对象xml序列化规则:

  1. 这个属性的标签包裹其值
    • 这里就是Articles标签包裹
  2. 其值的序列化为集合遍历每个元素,每个元素的序列化依次排列
    • 这里就是item标签包裹的文本消息

2.2 编写回复图文消息的方法

2.2.1 封装一个NewsMessage对象并返回
public static NewsMessage getReplyNewsMessage(Map<String, Object> map) {NewsMessage newsMessage = new NewsMessage();newsMessage.setToUserName((String) map.get("FromUserName"));newsMessage.setFromUserName((String) map.get("ToUserName"));newsMessage.setCreateTime(System.currentTimeMillis() / 1000);newsMessage.setMsgType("news");newsMessage.setArticleCount(1);Article article = new Article();article.setTitle("文1");article.setDescription("描述1");article     .setPicUrl("");article.setUrl("=blog");List<Article> articleList = new ArrayList<>();articleList.add(article);newsMessage.setArticles(articleList);System.out.println(newsMessage);return newsMessage;
}

这里的PicUrl是用户发送过来,缓存在微信公众号服务器的图片链接,或者你也可以填写其他网络图片~

2.2.2 在controller约定一个分支回复图文消息

这里我的代码做出一些跳转,具体参见:wx-demo · 游离态/马拉圈2023年10月 - 码云 - 开源中国 (gitee)

调用xml转化工具后返回回去即可~

2.2.3 发“图文”这个文本消息给公众号进行测试

发图文两个字给公众号

点击链接可以跳转:

控制台查看:

2.2.4 装杯带来的小坑
newsMessage.setArticles(new ArrayList<Article>() {{this.add(new Article(){{this.setTitle("文1");this.setDescription("描述1");this.setUrl("=blog");this.setPicUrl("");}});
}});

如果你是通过匿名内部类的方式去构造对象并设置,xml序列化的时候会被序列化的乱七八糟,血的教训啊😫😫😫

具体为什么,我也不知道,可能是匿名内部类实例代码块的机制有关吧,有一些细节出现偏差,瑕疵导致的吧~

不要装杯!写正常易懂的代码就好了!

看到没有,这个List对象被序列化得乱七八糟的~

ok,就这样了,其他消息格式大家自己去研究,举一反三~


文章到此结束!谢谢观看
可以叫我 小马,我可能写的不好或者有错误,但是一起加油鸭🦆

代码:wx-demo · 游离态/马拉圈2023年10月 - 码云 - 开源中国 (gitee)


更多推荐

【公众号开发】访问第三方接口应用于开发 · 回复图文消息

本文发布于:2023-12-06 19:39:28,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1668625.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:第三方   公众   接口   消息   图文

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!