JAVA 实践项目 --- 树莓派信息自动化采集后入库项目 (二)

本贴最后更新于 2461 天前,其中的信息可能已经斗转星移

项目源代码可访问我的 github:https://github.com/Spacider/Gather-and-store
如果觉得好的话请给个 star 哦~

项目初始

开发 IDE: IDEA 2018.03 JDK 1.8
开发环境: macOS 10.13.6 (如 windows 请对项目中部分路径进行改写)
数据库: Oracle 11g


正式开发

  1. 用 IDEA 创建一个 maven 项目,这个百度都可以找到,我在这里就不细讲了。
  2. 解决项目所有的依赖 jar 包,在项目下的 pom.xml 文件中添加如下内容:
<dependencies> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc6</artifactId> <version>11.2.0.3</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.39</version> </dependency> <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-dbcp2</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>commons-dbutils</groupId> <artifactId>commons-dbutils</artifactId> <version>1.6</version> </dependency> </dependencies>

第一阶段数据的采集

imagepng

这里是我们向树莓派获取温度和湿度的模块示意图,通过 XML 文件的交互就可以获得我们需要的数据,获得到数据以后我们拆分得到的 XML 并向 log 文件中存入我们解析好的数据!

首先,模块结构:
imagepng

然后开始编写代码:

  1. 我们创建一个包为 Server,然后创建一个类 DataServer,这个类的作用是用来模拟树莓派系统的,他的主要职能是接收 XML 文件,并返回对应的数据,这里是模拟,所以我们每次都返回一个相同的数据用于测试。

我们先定义个 Thread 类,以便于配合 while 语句来让 Server 端一直保持接收数据的状态。通过构造器将 Socket 对象传入 Thread 类中,通过 Socket 对象我们就可以对获取对应的流对接收与发送进行控制!

class ServerThread extends Thread{ private Socket socket; public ServerThread(Socket socket){ this.socket = socket; } @Override public void run() { } }

接下来我们的认识就是重写 run 方法,我们需要接收客户端发来的 XML 文件,由于发送过程中每一行都有一个换行符,所以嵌套一个 BufferedReader 对象时,我们就可以通过 readLine() 方法来根据行读取文件,末尾结束的标志是 </Message>

is = socket.getInputStream(); br = new BufferedReader(new InputStreamReader(is)); String str = null; StringBuilder sb = new StringBuilder(); while ((str = br.readLine()) != null) { sb.append(str + "\r\n"); // 如果读取到最后一行,则退出 if (str.trim().equals("</Message>")) { break; } }

为了关闭资源方便,我们用到了关闭资源辅助类:
创建 util 包,创建 IOUtil 方法。

public class IOUtil { public static void close(Closeable... closeableList) { try { for (Closeable closeable : closeableList) { if (closeable != null) { closeable.close(); } } } catch (IOException e) { e.printStackTrace(); } } }

读取到 XML 文件时,我们就需要对相应的 Client 端返回一个新的 XML 文件,为了方便我们编写一个 SAXReaderHelper 类来协助我们的操作,编写一个方法 BackXml 来进行相关的处理。该方法通过解析从客户端发来的 xml 文件,获取 SensorAddress 值来模拟传感器的选择,从而返回不同的模拟数据。

  • sensorAddress 为 16 采集到的数据为 10 位,前 8 位为湿度和温度数据,后两位为序号。
  • sensorAddress 为 256 采集到的数据为 6 位,前四位为光照数据,后两位为序号。
  • sensorAddress 为 1280 采集到的数据为 6 位,前四位为二氧化碳数据,后两位为序号。
/** * 根据不同的 SensorAddress 返回不同的XML * @param bris */ public static String BackXml(String sb){ ByteArrayInputStream bais = null; // 把客户端传过来的 xml 转化为字符串存储 String TotalStr = sb.toString(); byte[] TotalBytes = TotalStr.getBytes(); bais = new ByteArrayInputStream(TotalBytes); SAXReader reader = new SAXReader(); Document document = null; String BackStr = null; // 获取根节点 try { document = reader.read(bais,"utf-8"); Element Message = document.getRootElement(); String str = null; // 获取结点 SensorAddress 的值 String SensorAddress = Message.element("SensorAddress").getText(); if (SensorAddress.equals("16")){ str = "5d606f7802"; BackStr = getBakXml(str); }else if (SensorAddress.equals("256")){ str = "5d6002"; BackStr = getBakXml(str); }else if (SensorAddress.equals("1280")){ str = "5d6002"; BackStr = getBakXml(str); } } catch (DocumentException e) { System.out.println("返回XML文件失败"); } finally { IOUtil.close(bais); } return BackStr; } /** * 拼接返回的 XML (提供模拟的 Server 端使用) * @param DataStr * @return */ public static String getBakXml(String DataStr){ String str = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"+ "<Message>\r\n"+ "<SrcID>100</SrcID>\r\n"+ "<DstID>101</DstID>\r\n"+ "<DevID>2</DevID>\r\n"+ "<SensorAddress>0</SensorAddress>\r\n"+ "<Counter>0</Counter>\r\n"+ "<Cmd>3</Cmd>\r\n"+ "<Data>"+DataStr+"</Data>\r\n"+ "<Status>1</Status>\r\n"+ "</Message>\r\n"; return str; }

在封装了方法以后,我们就可以一行解决问题:

// 根据不同的 SensorAddress 返回不同的XML String BackStr = SAXReaderHelper.BackXml(sb.toString());

最后通过输出流再次将封装好的模拟数据发送给 Client

os = socket.getOutputStream(); pw = new PrintWriter(os); pw.write(BackStr.toCharArray()); pw.flush();

最后关闭资源~这样我们就编写好了一个模拟的树莓派 Server 端。通过 while(true) 写死循环,这样就可以一直不停的接收数据!

ServerSocket server = new ServerSocket(8888); while (true){ Socket socket = server.accept(); new ServerThread(socket).start(); }

  1. Client 端编写
    Client 端是发送 XML 文件到 Server 端的,其中还是用流进行传输。

首先我们编写 ClientReceiveHelper 类开进行辅助我们操作。

这是拼接发送的 XML 文件的方法!

/** * 拼装发送的 XML 文件 * @param SensorAddress * @param counter * @return */ private final static String XmlToSend(String SensorAddress,String counter){ String str = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"+ "<Message>\r\n"+ "<SrcID>100</SrcID>\r\n"+ "<DstID>101</DstID>\r\n"+ "<DevID>2</DevID>\r\n"+ "<SensorAddress>"+SensorAddress+"</SensorAddress>\r\n"+ "<Counter>"+counter+"</Counter>\r\n"+ "<Cmd>3</Cmd>\r\n"+ "<Status>1</Status>\r\n"+ "</Message>\r\n"; return str; }

客户端通过的是 TCP/IP 向 Server 端发送消息。
然后编写发送消息的方法 ClientGetXml

public final static void ClientGetXml(String SensorAddress,int counter){ }

通过 Socket 来开启一个连接

socket = new Socket("127.0.0.1", 8888);

加锁:考虑到一种特殊情况,socket 交替执行时可能会出现时间片用完的情况,这种情况下可能会导致上一个 socket 的数据传输给了下个 socket 使用,导致数据的错误!
通过发送 XML 让 Server 返回一个 XML 文件给我们,本阶段我们以获取到了上文 Server 发送的 XML 文件为正确。

synchronized (socket) { os = socket.getOutputStream(); pw = new PrintWriter(os); String str = XmlToSend(SensorAddress, counter + ""); pw.write(str.toCharArray()); pw.flush(); is = socket.getInputStream(); br = new BufferedReader(new InputStreamReader(is)); String Backstr = null; // 拼接读取返回的 XML 文件 StringBuilder sb = new StringBuilder(); while ((Backstr = br.readLine()) != null) { // 在末尾加入 \r\n 方便观察,也方便读取 sb.append(Backstr + "\r\n"); if (Backstr.trim().equals("</Message>")) { break; } } }

编写到这里, 你可以打印一下 BackStr,看下是否发生了死锁(可能未关闭资源或连接未断开等)和传输到的数据是否正确。

经过如上的编写,你就可以编写 Client 如:
方法中的参数为 SensorAddress 的值(判断温度湿度或光照或二氧化碳),和 counter 操作的传感器个数!ClientGetXml 就是上文我们编写的 Client 的操作方法。

public final class GuangClient { public static void guangGetObj(){ ClientReceiveHelper.ClientGetXml("256",1); } }

imagepng

如果你已经获得了 Server 端发送的数据,那么恭喜你,你这一阶段的编写已经取得了成功,可以进行下一阶段的编写!

本文中为代码详解,可能与源代码不一定相同,可以查看我的 github:https://github.com/Spacider/Gather-and-store 查看源代码与你的代码进行比对!如果觉得我写的好的话请给一个 star 哦!

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3201 引用 • 8217 回帖
  • 实践项目
    6 引用

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...