18700浏览
楼主: kevinzhang19701

[项目] 小题大做系列II(PM2.5微信控)炒鸡长文体虚慎入

[复制链接]

luna  初级技神

发表于 2015-12-7 10:06:22

kevinzhang19701 发表于 2015-12-4 20:13
不好意思,休假去日本一周。回来后会尽快写完整

回复

使用道具 举报

kevinzhang19701  高级技匠
 楼主|

发表于 2015-12-7 17:06:52

本帖最后由 kevinzhang19701 于 2015-12-7 17:09 编辑

加油加油加油(重要的事情说三遍);P
小题大做系列II(PM2.5微信控)炒鸡长文体虚慎入图1

小题大做系列II(PM2.5微信控)炒鸡长文体虚慎入图2

小题大做系列II(PM2.5微信控)炒鸡长文体虚慎入图3
回复

使用道具 举报

kevinzhang19701  高级技匠
 楼主|

发表于 2015-12-7 20:11:54

本帖最后由 kevinzhang19701 于 2015-12-8 10:51 编辑

12.3 XML长啥样
  1. <pre><bookstore>
  2. <book category="CHILDREN">
  3.   <title>Harry Potter</title>
  4.   <author>J K. Rowling</author>
  5.   <year>2005</year>
  6.   <price>29.99</price>
  7. </book>
  8. <book category="WEB">
  9.   <title>Learning XML</title>
  10.   <author>Erik T. Ray</author>
  11.   <year>2003</year>
  12.   <price>39.95</price>
  13. </book>
  14. </bookstore> </pre>
复制代码
如上样例,这些用"<>"和"</>"成对括起来的就是正宗的XML代码。

我们不用了解得很深入,对本项目有用的概念,就是记住微信在回复消息的时候,使用的就是XML格式的字符串。数据来往,就是接受和发送这些符合格式要求的串(字符串含有“元素”、“属性”等)。不过,有一点大家要注意:XML字符串,需要我们自己进行编码和解析。

关于XML的引申阅读链接:http://www.w3school.com.cn/xml/index.asp

12.4 XML的编码和解析

让我们自己编码,问题不大,可以先摸清楚微信文本消息的格式,然后用字符串拼接出来。

然而让我们解析XML字符串,就有一定困难了。不过,老夫这个矮子仍旧可以站在巨人的肩上,借助一个开源项目:dom4j,来完成。

回复

使用道具 举报

kevinzhang19701  高级技匠
 楼主|

发表于 2015-12-7 20:23:32

本帖最后由 kevinzhang19701 于 2015-12-8 10:55 编辑

13. dom4j开源项目

dom4j的快速入门教程链接如下:

http://dom4j.sourceforge.net/dom4j-1.6.1/guide.html

但是我担心翻不了墙的小伙伴会无法看到。
小题大做系列II(PM2.5微信控)炒鸡长文体虚慎入图1

下载地址在Sourceforge,别忘记下载完成后的jar文件要放入Java的lib目录,或者直接在NetBeans里导入这个jar。

http://sourceforge.net/projects/dom4j/files/
小题大做系列II(PM2.5微信控)炒鸡长文体虚慎入图2

我们的重点在解析上,也就是我们需要从微信服务器传给项目服务器的一长串XML字符串里,提取我们想要的数据值,其他我们就不关心了。整个解析过程可以分如下三步:

13.1 从输入流读取微信服务器传过来的一长串字符串(XML格式)。

13.2 将字符串转换成dom4j可以处理的类型,赋给变量。

13.3 从这个变量中提取需要的参数值(即微信服务器传过来的数据),这一步我们仰赖dom4j自动帮我们完成。

别着急,后面代码我会有解释,先让老夫卖个关子。

回复

使用道具 举报

kevinzhang19701  高级技匠
 楼主|

发表于 2015-12-7 20:38:20

本帖最后由 kevinzhang19701 于 2015-12-8 11:02 编辑

14. 微信消息的XML格式

14.1 接受消息

我们在微信客户端里发一个言,站在微信服务器的角度来看,就是发送了一个消息(可能是文本消息、语音消息、图像消息、音乐视频消息、地理位置消息等)。这个消息传到微信服务器后,服务器会判断传过来的微信公众号运作在编辑模式还是开发模式,一旦确认是开发模式,那么微信服务器就直接把消息打包成XML字符串转给项目服务器,全部由项目服务器接着去做后续处理。

老夫定义了"/??"为用户获取设备数据的关键词。

项目服务器必须要处理这个叫做“文本消息”的XML字符串。

请大家注意下列连接(接受消息):

http://mp.weixin.qq.com/wiki/17/ ... 44d9c96eaf51f9.html

这是开发者文档中重要的一部分,我们关注的是“文本消息”和她的格式。其他格式的消息本项目暂时不使用,如您有兴趣,比如想做个语音消息,可以参考文档的其他部分。

文本消息的格式如下图:
小题大做系列II(PM2.5微信控)炒鸡长文体虚慎入图1

各位看到上面的文本消息格式和解释了吧,我就不啰嗦了。对我们的项目来说,需要提取的是<MsgType>和<Content>两个值。前者我们限定在"text"(老夫只看文本消息,忽略其他的),后者我们限定在"/??"(老夫只看用户是不是发送了/??查询数据,其他忽略)。这两个地方,可以根据您的项目的要求灵活运用。

14.2 回复消息

现在我们已可以判断用户是否发送了查询关键词/??,那么接下来怎么回复给用户呢?请阅读如下链接:

http://mp.weixin.qq.com/wiki/18/ ... 46dc39de20f672.html

“回复文本消息”说明了我们要回复给微信服务器的也是一串XML格式的字符串,格式如下:
小题大做系列II(PM2.5微信控)炒鸡长文体虚慎入图2

看上去好像和传过来的消息挺像的。这里的ToUserName和FromUserName只需要简单地将传过来的文本消息的To和From交换一下,即可实现回复给发言的那个用户了。

这里的Content参数,就要组织好回复的7个数据的XML串。整个回复文本的样子应该是下面这个样子滴:
  1. <xml>
  2.   <ToUserName><![CDATA[o4v_mtz6brovlFn77_HpgV_0Q39I]]></ToUserName>
  3.   <FromUserName><![CDATA[gh_9b78ebc75c88]]></FromUserName>
  4.   <CreateTime><![CDATA[1449493779]]></CreateTime>
  5.   <MsgType><![CDATA[text]]></MsgType>
  6.   <Content><![CDATA[PM1:20ug/m3\nPM2.5:24ug/m3\nPM10:27ug/m3\n温度:23.80℃\n湿度:33.70%\n亮度:0\n噪声:0]]></Content>
  7. </xml>
复制代码
那么,上面的7个参数数据从哪里来?对,从我们的数据库里来,而且我们只取数据库最后那一条最新鲜的值。

回复

使用道具 举报

kevinzhang19701  高级技匠
 楼主|

发表于 2015-12-7 21:17:22

本帖最后由 kevinzhang19701 于 2015-12-8 11:12 编辑

15. 完整的wxtest.class源代码

此为本项目核心代码之三,技术涉及非常广泛,如果您有疑问,欢迎跟帖咨询。
  1. import java.io.IOException;
  2. import java.io.PrintWriter;
  3. import java.io.InputStream;
  4. import javax.servlet.ServletException;
  5. import javax.servlet.annotation.WebServlet;
  6. import javax.servlet.http.HttpServlet;
  7. import javax.servlet.http.HttpServletRequest;
  8. import javax.servlet.http.HttpServletResponse;
  9. import java.util.Arrays;
  10. import org.apache.commons.codec.digest.DigestUtils;
  11. import org.apache.commons.io.IOUtils;
  12. import org.dom4j.*;
  13. import org.dom4j.io.*;
  14. import java.sql.Connection;
  15. import java.sql.DriverManager;
  16. import java.sql.SQLException;
  17. import java.sql.Statement;
  18. import java.sql.ResultSet;
  19. @WebServlet(urlPatterns = {"/wxtest"})
  20. public class wxtest extends HttpServlet
  21. {
  22.     protected void processRequest(HttpServletRequest request, HttpServletResponse response)
  23.             throws ServletException, IOException
  24.     {
  25.         response.setContentType("text/html;charset=UTF-8");
  26.         request.setCharacterEncoding("UTF-8");
  27.         response.setCharacterEncoding("UTF-8");
  28.         PrintWriter out = response.getWriter();
  29.                
  30.         String myVal01 = ""; //7个变量对应7个参数
  31.         String myVal02 = "";
  32.         String myVal03 = "";
  33.         String myVal04 = "";
  34.         String myVal05 = "";
  35.         String myVal06 = "";
  36.         String myVal07 = "";
  37.         
  38.         Connection conn = null;  // 涉及数据库打交道的变量
  39.         Statement stmt = null;
  40.         ResultSet rs1 = null;
  41.         int i = 0;
  42.         String mySQL = "SELECT * FROM t01 ORDER BY tid DESC LIMIT 1;"; // 从数据表里读取最后那条记录的SQL语句
  43.         try
  44.         {
  45.             conn = DriverManager.getConnection("jdbc:mysql://localhost/mypm?" +
  46.                                    "user=root&password=15186okia");
  47.             stmt = conn.createStatement();
  48.             rs1 = stmt.executeQuery(mySQL);
  49.             
  50.             while(rs1.next())
  51.             {
  52.                 myVal01 = rs1.getString(2); //分别将获得的数据写入7个变量
  53.                 myVal02 = rs1.getString(3);
  54.                 myVal03 = rs1.getString(4);
  55.                 myVal04 = rs1.getString(5);
  56.                 myVal05 = rs1.getString(6);
  57.                 myVal06 = rs1.getString(7);
  58.                 myVal07 = rs1.getString(8);
  59.             }
  60.         }
  61.         catch (SQLException ex)
  62.         {
  63.             System.out.println("Error in connection: " + ex.toString());
  64.             System.out.println("SQLException: " + ex.getMessage());
  65.             System.out.println("SQLState: " + ex.getSQLState());
  66.             System.out.println("VendorError: " + ex.getErrorCode());
  67.         }
  68.         
  69.         InputStream  postIn = request.getInputStream(); //从输入流获取微信服务器传过来的整个字符串
  70.         
  71.         try
  72.         {
  73.             SAXReader reader = new SAXReader();
  74.             Document myDocument = reader.read(postIn); // 转成dom4j可以处理的格式
  75.             Element root = myDocument.getRootElement(); // 从XML字符串内获取全部元素,组成一棵树
  76.             Element myToUserName = root.element("ToUserName"); // 分别获取需要的值
  77.             Element myFromUserName = root.element("FromUserName");
  78.             Element myCreateTime = root.element("CreateTime");
  79.             Element myMsgType = root.element("MsgType");
  80.             Element myContent = root.element("Content");
  81.             Element myMsgId = root.element("MsgId");
  82.             String sToUserName = myToUserName.getText(); // 转成String类型
  83.             String sFromUserName = myFromUserName.getText();
  84.             String sCreateTime = myCreateTime.getText();
  85.             String sMsgType = myMsgType.getText();
  86.             String sContent = myContent.getText();
  87.             String sMsgId = myMsgId.getText();
  88.             
  89.             if (sMsgType.equals("text") && sContent.equals("/??")) // 用户发来的是文本消息且是查询数据关键词吗?
  90.             {
  91.                 long lCreateTime = System.currentTimeMillis()/1000L; // 消息创建的时间
  92.                 String mySendContent = "";
  93.                 // 以下手工封装回复文本消息的XML字符串
  94.                 mySendContent = "PM1:" + myVal01 + "ug/m3\nPM2.5:" + myVal02 + "ug/m3\nPM10:" + myVal03 + "ug/m3\n温度:" + myVal04 +
  95.                         "℃\n湿度:" + myVal05 + "%\n亮度:" + myVal06 + "\n噪声:" + myVal07;
  96.                 String xmlString01 = "<xml>";
  97.                 String xmlString02 = "<ToUserName><![CDATA[" + sFromUserName + "]]></ToUserName>";
  98.                 String xmlString03 = "<FromUserName><![CDATA[" + sToUserName + "]]></FromUserName>";
  99.                 String xmlString04 = "<CreateTime><![CDATA[" + lCreateTime + "]]></CreateTime>";
  100.                 String xmlString05 = "<MsgType><![CDATA[text]]></MsgType>";
  101.                 String xmlString06 = "<Content><![CDATA[" + mySendContent + "]]></Content>";
  102.                 String xmlString07 = "</xml>";
  103.                 String xmlAll = xmlString01 + xmlString02 + xmlString03 + xmlString04 + xmlString05 + xmlString06
  104.                     + xmlString07;
  105.                 System.out.println(xmlAll);
  106.                 out.print(xmlAll); // 回复给微信服务器,由其转发给用户手机
  107.                 out.close();
  108.             }
  109.             System.out.println("== Done ==");  
  110.         }
  111.         catch (DocumentException ex)
  112.         {
  113.             System.out.println("dom4j Document: " + ex.toString());
  114.         }
  115. }
复制代码
正常情况下,正确反馈应该是下面酱紫滴:
小题大做系列II(PM2.5微信控)炒鸡长文体虚慎入图1

回复

使用道具 举报

kevinzhang19701  高级技匠
 楼主|

发表于 2015-12-7 21:35:16

本帖最后由 kevinzhang19701 于 2015-12-8 11:18 编辑

16. 其他一些注意事项

请允许老夫再啰嗦几句。

本项目只使用了文本消息查询,回复消息也是文本消息。

有小盆友问是否可以接受用户发来的语音、图像、甚至地理位置信息?回答是完全可以接收。不过,由于个人申请的无认证订阅号受到其权限限制,能接受字符串并不意味着可以接受这些语音、图像和地理位置的源数据(微信团队还是很奸诈的,将这些源数据使用MediaId来标识和引用)。这也就是解释了为什么Arduino中文社区里有朋友发的帖子,是使用测试账号制作的自定义菜单来发起查询的(http://www.arduino.cn/forum.php? ... =%E5%BE%AE%E4%BF%A1)。

小题大做系列II(PM2.5微信控)炒鸡长文体虚慎入图1

因为微信团队给测试账号的权限很大很大(顺便说一下上图的自定义菜单是使用JSON而不是XML实现的,需要注意),不过,测试账号就是测试账号,自己用用可以,推广成正式项目就非常可疑了。是吧,这年头骗子太多。

从另外的角度看,如果需要拥有更多的权限、更高大上的形象的话,那么还是需要以公司名义,申请一个乃至多个认证的服务号,或者最高大的企业号。

==

大家可能不太知道,鳗鱼年幼的时候对水温、水质、含氧量等环境要求很高。一旦生活环境稍有不适,会成批死去,严重影响养殖场的收益。几年前,韩国鳗鱼养殖场主们开始使用点状分布的传感器来监控鳗鱼网箱的环境数据,以取代原来每隔一段时间人工测量的繁琐工作。这些数据上传至云端,可以实时从手机上获得。当个别敏感数据的变化超过警戒范围时,手机App会发出警告,及时通知养殖场主是哪个网箱发生了问题,且是什么样的问题。
小题大做系列II(PM2.5微信控)炒鸡长文体虚慎入图2



回复

使用道具 举报

kevinzhang19701  高级技匠
 楼主|

发表于 2015-12-7 22:00:18

本帖最后由 kevinzhang19701 于 2015-12-8 13:07 编辑

17. 结束语

从上个月25号到今天,陆陆续续把这个项目扯完了。篇幅有点长,话也有点啰嗦,不过,其中着实还有不少东西说得挺含糊甚至没来得及提及的,大家要是恶心想吐就跟帖吐槽吧。
小题大做系列II(PM2.5微信控)炒鸡长文体虚慎入图1

科技行业分析公司Linley Group发布了最新的调研报告。报告显示,到2020年,全球使用的物联网设备将达到19亿个。所以,如果有孩子打算上大学的话,请一定选择IT专业(特别是她们)。未来生活中将充斥着无数的传感器,它们的功耗更小、体积更小、更稳定、更灵敏,我们的生活将因为传感器和智能算法而发生重大的变化。不过数据汇合点仍将在云端,这就是为什么西方敌对势力都极其重视云端的原因。

本项目还存在安全方面的问题,比如终端设备提交给项目服务器的数据没有加密、项目服务器与微信服务器数据交换时也没有加密、获取传感器数据后写入数据库前没有做防注入验证等等,这条数据传输链是不稳定不安全的。如果是生产环境的话,这些都要再加以调整。

这个项目还可以进一步扩展成一个志愿者联盟性质的活动。这意味着有兴趣的地府同好可以人手一台,将实时数据提交到地府某个志愿者的服务器上,数据可供社会查询和进一步加工使用(加工后的数据的使用可能需要支付一定费用;P)。这有个好处,因为花纳税人钱的政府只会提供有限的几个点的某些时间点的空气质量数据,而地府同好来自于世界各地,且覆盖范围更广、数据采集更密集,因此提供的数据量、覆盖面、实时性将更好,社会效益和经济效益都有收获(老夫顺便问问,这个粉尘传感器输出数据是否可以信赖?)

(以上灵感来自于:http://www.leiphone.com/news/201508/zxYBDeC5khgC26Zz.html

谨借宝地谨献此文,预祝地府君们圣诞快乐、新年快乐。

(全文完)

回复

使用道具 举报

Eric  初级技神

发表于 2015-12-10 17:34:04

hnyzcj 发表于 2015-11-25 18:45
我的PM2.5也快了,正在紧张打印中

好东西啊,我现在就在玩PM2.5呢,哈哈哈
回复

使用道具 举报

kevinzhang19701  高级技匠
 楼主|

发表于 2015-12-12 20:18:12

本帖最后由 kevinzhang19701 于 2015-12-12 20:20 编辑

非常感谢地府萝卜头的厚爱。
小题大做系列II(PM2.5微信控)炒鸡长文体虚慎入图1

尝鲜包内有Romeo Mini BLE和两枚微马达,外加一个环保袋:D:D
小题大做系列II(PM2.5微信控)炒鸡长文体虚慎入图4

小题大做系列II(PM2.5微信控)炒鸡长文体虚慎入图2

小题大做系列II(PM2.5微信控)炒鸡长文体虚慎入图3
回复

使用道具 举报

Ash  管理员

发表于 2015-12-15 14:58:56

kevinzhang19701 发表于 2015-12-12 20:18
非常感谢地府萝卜头的厚爱。

喜欢就好  
期待你带来更多优秀的作品~
回复

使用道具 举报

kevinzhang19701  高级技匠
 楼主|

发表于 2015-12-15 17:35:11

Ash 发表于 2015-12-15 14:58
喜欢就好  
期待你带来更多优秀的作品~

:loveliness::loveliness::handshake:handshake
回复

使用道具 举报

刹那ZF清英  中级技师

发表于 2015-12-16 08:59:37

:loveliness:哇哦对代码啥的一窍不通的我竟然把前辈的文章看完了————不对,是翻完了。果然还是要回家吃药啊,前辈已经带着萝卜头的小伙伴们(除我之外)在大神的道路上渐行渐远了——连模仿都模仿不来滴    !!!好吧 感谢分享,期待新作——
回复

使用道具 举报

dsweiliang  初级技神

发表于 2015-12-16 11:32:47

哇,好赞啊,果断收藏
回复

使用道具 举报

kevinzhang19701  高级技匠
 楼主|

发表于 2015-12-16 12:30:00

刹那ZF清英 发表于 2015-12-16 08:59
哇哦对代码啥的一窍不通的我竟然把前辈的文章看完了————不对,是翻完了。果然还是要回家吃 ...

您的鱼菜共生炒鸡棒:D:D:handshake
回复

使用道具 举报

swanglei  中级技神

发表于 2015-12-17 01:04:45

这篇真的挺不错。。。
回复

使用道具 举报

qing1987  见习技师

发表于 2016-1-5 10:24:23

学习~
回复

使用道具 举报

kevinzhang19701  高级技匠
 楼主|

发表于 2016-1-8 12:47:27

哇塞,萝卜头又送来惊喜。:lol:lol
小题大做系列II(PM2.5微信控)炒鸡长文体虚慎入图1
回复

使用道具 举报

20060606  高级技匠

发表于 2020-8-21 05:42:14

好创意,赞一个
回复

使用道具 举报

12
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail