物联网数据中心实验总结

物联网数据中心

1、了解项目背景

	 科技进步,农业生产规模也不断的提高,农产品在大棚中的种类越来越多,人工可以操作的空间也就相对非常的局限。
	 因此,实现农业大棚的生产的自动化和信息智能化,就能够更加方便有效的对大棚进行监控,提高资源的利用率和农业生产的水平,这也是未来发展的趋势。

2、项目模块分析

项目模块划分以及需要的文件

详细模块划分

1、客户端
1、客户端的网络模块

ClientImpl implements Client
要求:将Collection集合发送给服务器端
1、连接服务器
2、使用ObjectOutputStream输出流发送数据
客户端使用的是对象输出流
使用管道流,通过管道发送数据到输入流

oos = new ObjectOutputStream(socket.getOutputStream());

此处输入的对象Collection c
也就是采集模块返回的Collection集合
3、流要把Collection这个集合写出去

oos.writeObject(c);
2、采集模块

GatherImpl implements Gather
要求:读取data-file的文件,然后采集成为一批Environment对象
1.使用文件输入流BufferedReaderLine来读取文件

BufferedReader br = new BufferedReader(new FileReader(fileName));

这里的fileName就是这个文件的路径
2. 循环读每一行,将每一行字符串进行分割
读取文件时,使用while循环去判断文件是否达到文件末尾

while((s=br.readLine())!=null){}

分割字符串的时候,要使用split这个方法
这里的“\”的作用是用来将“|”这个竖杠转换为字符,然后再用这个“|”来作为分割的字符

String[] sp=s.split("\\|");

//3、将每一行转化为Environment对象,并设置属性的值
这里需要定义一个Environment的类
Environment对象包含的属性有
Environment类中的属性
将一行数据中的环境数据如何转化成所需的数据
转换以后的数据需要进行的处理

(3)进行统计数量
(4)对这次读取的文件进行备份

2、服务器端
1、服务器端的网络模块

ServerImpl implements Server
要求:接受客户端发送的数据,然后入库
服务器端使用的是对象输入流
需要建立线程类,然后用这个线程来进行入库
1、连接端口,启动服务器
while用来让服务器一直开着,然后如果有客户端连接了服务器,那就启动一个线程,让这个线程去单独处理这个客户端
抓取异常,然后在出现异常的时候报错:入库的数据为空
2、重写线程的run方法
线程启动之后,会自动调用run方法里面的代码
---------1)使用ObjectInputStream输入流来接收数据
---------2)要将这个读取到的对象进行包装,包装成管道流,从管道中拿到输入流,然后读取数据,在转换成对象

ois = new ObjectInputStream(socket.getInputStream());

---------3)再new一个集合,然后用这个集合接收对象,这里只读取一次

Collection<Environment> coll = (Collection<Environment>) ois.readObject();

--------4)将上面读取到的集合,开启入库模块

db.saveDB(coll);
2、入库模块

DBStoreImpl implements DBStore
要求,将服务器端发送来的Collection集合中的数据保存到数据库中
1、连接数据库
使用配置文件注入的信息进行数据库的连接

Class.forName(driver);
conn=DriverManager.getConnection(url,username,password);

连接好以后,要取消自动提交,使用批处理提交数据时会节省很多时间,可以提高数据插入的效率
2、使用jdbc的批处理进行数据的插入
-------1)设置初始值,用来插入第一条数据
-------2)循环进行批处理,使用时间戳来获取日的信息

Timestamp date = env.getGather_date();
//这里拿到的是默认时间的日历对象
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
//这个月的第几天
int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
set.add(dayOfMonth);

-------3)根据每一条数据的采集的时间中的日这个数据来进行插入
使用建表语句,将数据插入到表中

sql = "insert into e_detail_"+dayOfMonth+
"(name,srcId,desId,devId,sersorAddress,count,cmd,status,data,gather_date) values(?,?,?,?,?,?,?,?,?,?)";

3、使用批处理进行赋值
4、添加数据,设置变量 i 自增,然后当变量 i 等于batchSize的值时,进行提交一次数据
5、最后在循环外面要再提交一次数据,避免上一轮循环的变量i没有达到batchSize的值而引起的数据丢失
6、使用查询语句统计表中的数据个数,然后显示在控制台和日志中。

3、日志模块

LogImpl implements Log
要求:封装log4j的功能,用来取代输出语句,和将输出语句的内容存放到文件中

4、备份模块

BackupImpl implement Backup
要求:网络传输时,将数据进行备份
数据入库时,将数据进行备份
采集模块运行时,将上一次的采集数据进行备份,然后下次采集之前要跳过之前的数据,
最终的目的:第一次采集结束,第二次的采集不会重复

load(String fileName, boolean del)方法:
-----1)判断文件是否存在,如果文件存在,则进行下面的操作,如果不存在则直接结束程序
-----2)创建文件对象输入流

ObjectInputStream ois= new ObjectInputStream(new FileInputStream(file));

-----3)程序退出之后,文件的物理文件会被删除,会有延时性
store(String fileName, Object obj, boolean append)方法:
-----1)将数据obj 备份到fileName这个文件中,同样要判断文件是否存在,如果文件目录不存在,则创建目录

File p = new File(parent);
if (!p.exists()){
   p.mkdirs();
}

-----2)使用管道流将文件输出到指定路径中。
-----3)刷新,关闭资源
写好这个类之后,就要去修改入库文件的信息,让这些文件直接会开启一轮的备份

//读取备份文件的位置
log.info("读取备份文件上一次采集的位置");
Object obj = backup.load("gather.txt",Backup.LOAD_REMOVE);
if (obj!=null){
    //跳过已经读的字节数
    br.skip((Long)obj);
}

其他类与这个类似

5、配置模块

ConfigurationImpl implements Configuration
要求:
1、给其他的模块进行初始化的配置
2、其他模块的变量不需要自己再去重新赋值
3、在配置模块中读取conf.xml的信息,使用dom4j解析,然后进行初始化
4、配置模块需要创建其他模块的对象,并通过get方法或去其他模块的对象
具体实现:
1、创建其他模块的对象
在其他模块中要调用配置模块中的get方法来获取对象,
例如:

map.get("gather");

2、配置模块解析其他模块的数据
将其他模块(需要进行初始化的模块),实现PropertiesAware接口,然后在init方法中实现初始化
配置模块:
解析xml文件,封装properties
调用其他模块的init,然后将数据传递过去

SAXReader sax = new SAXReader();
Document document = sax.read(ConfigurationImpl.class.getClassLoader().getResourceAsStream("conf.xml"));
 //获取根元素
Element root = document.getRootElement();
//element 获取某个元素的子元素
List<Element> list = root.elements();
for (Element element:list){
	//获取标签名
	String key = element.getName();
	//获取class的属性值
	String value = element.attributeValue("class");
	//通过反射创建其他模块的对象
	PropertiesAware obj = (PropertiesAware) Class.forName(value).newInstance();
	//将获取的标签名,和属性值放到map集合中
	map.put(key,obj);

	//获取其他模块的属性,并注入给其他模块
	List<Element> pros = element.elements();
	//每一个p都有一个对象
	Properties p = new Properties();
	for (Element pro:pros){
	String value1 = pro.getText();
	String key1 = pro.getName();
	p.setProperty(key1,value1);
}
obj.init(p);

//将自身的对象的引用,传入给其他模块
for (Object obj:map.values()){
	//去判断是不是...
    //目的是为了知道能不能转换
    //可以提高程序的稳定性
    if (obj instanceof ConfigurationAware){
    ConfigurationAware conf = (ConfigurationAware) obj;
    conf.setConfiguration(this);
    }
}

其他模块:
实现接口,重写init方法,在init中给属性赋值

public void init(Properties properties) throws Exception {
        //给属性赋值
        parent = properties.getProperty("file—path");
    }

3、其他模块中如何获取另外的其他的模块的对象
实现ConfigurationAware接口
配置模块需要将自身的引用传入给其他的模块
eg:
这个是将配置模块的对象,传送给采集模块

public void setConfiguration(Configuration configuration) throws Exception {
        this.conf=configuration;
        this.backup = conf.getBackup();
        this.log = conf.getLogger();
    }

3、项目实现

4、项目遇到的问题以及解决方法

1)如何将采集到的数据封装成对象:

(1)每次循环开始(就是每一次开始读取一行的时候)都要新创建一个Environment对象,
(2)然后将第二步分割开的字符放到集合中(这个集合也是每一次循环开始都要重新创建),按照放入集合的元素下标来对这个对象的属性进行赋值,赋值结束后会将这个对象添加到coll集合中(coll集合是用来存放这些数据的),其中在进行赋值的时候,会遇到的问题有:
---------1)赋值时的类型转换问题

environment.setCount(Integer.parseInt(sp[4]));
			这里是在Environment类中,count这个属性是int类型的,而sp[4]获取到的是字符串
			所以采用了Integer.parseInt()方法将sp[4]进行了类型转换
environment.setGather_date(new Timestamp(Long.parseLong(sp[8])));
		而这里的强制类型转换是因为,gather_date在类中是TimeStamp,所以获取到的字符串要进行强制转换
		这里的强制转换,是先将字符串转换成long类型,然后在new一个新的Timestamp对象来进行强制转换的。

---------2)温度和湿度的区分,根据上面的要求可以知道,这里的温度和湿度是出自于锁读到的同一行文字,所以就要去判断传感器地址是否为16,如果传感器地址为16的话,那就要把这个传感器所获取的对象分开来进行赋值,温度先赋值,然后new一个新对象,然后再去进行湿度的赋值
除了这两个以外,还需要去判断其他的传感器地址,来进行相应的赋值

2)如何将配置文件中的对象注入给线程类中的对象:

将线程类转换为内部类,就可以调用外围类的资源,就可以获取conf的get方法啦

3)log4j的log4j.properties文件详解

link.

5、心得

通过这一次的学习,巩固了之前所学的知识,掌握了一些做项目所需要的技术,更加系统的了解了整个项目实现的过程,理解了这些程序之间的关系,这一次的学习还有不足的地方,希望在下一次的学习中能做的更好。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值