当传感器把数据发送给网关,那么网关就需要将数据进行解析,并且将解析的数据发送给服务端,进行存储如图:
那我们的项目也就分为客户端和服务端图中的网关就相当于我们的客户端,图中都得云服务器就相当于我们的服务器我们需要将解析好的数据发送给服务器,服务端将发送过来的数据进行存储。具体模块图如下:
学习了三种进行xml解析的方式
dom解析,sax解析,dom4j解析 (主流的方式,简单易懂)
dom解析
//创建解析工厂并且获取到document对象 String filePath = "src/work/person.xml"; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder documentBuilder = factory.newDocumentBuilder(); Document document = documentBuilder.parse(new File(filePath));//filePath表示传入的xml文件的路径 // 获取根节点 Element root = document.getDocumentElement(); //获取到节点的属性集合 NamedNodeMap listMap = root.getAttributes();//这里举例获取到根节点的属性集合 // 获取根节点的所有子节点 NodeList list = root.getChildNodes(); // 得到标签所有的属性 NamedNodeMap attributes = element.getAttributes();//遍历得到的根节点sax解析
//通过不断的重写父类的方法得到xml的解析结果,基于事件的解析方式,只能解析一次,解析过得数据不能再解析 //不能过随机读取,只能够顺序读取 //获取到sax解析的父类 SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); //重写他们的方法就可以得到解析到的xml对象 startDocument() startElement() characters() endElement() endDocument()dom4j解析
//想要使用dom4j解析,就必须要引入相应的jar包 //得到解析器 SAXReader saxReader = new SAXReader(); //解析一个xml文件 Document document = saxReader.read(filePath);//filePath表示传入的xml文件的路径 //3.得到根节点 Element rootElement = document.getRootElement(); //得到标签的名字 System.out.println("<"+rootElement.getName()+">"); elements.forEach(t ->{ System.out.print("<"+t.getName()); List<Attribute> list =t.attributes(); list.forEach(p->{ System.out.print(" "+p.getName() + "=" + p.getValue()); //默认的命名空间uri System.out.println(p.getNamespaceURI()); }); System.out.print(">"); System.out.println(); List<Element> list2 = t.elements(); list2.forEach(l->{ System.out.print("<"+l.getName()+">"); System.out.print(l.getTextTrim()); System.out.println("</"+l.getName()+">"); }); });1.sql语句的 分类
DQL(数据查询语言):主要是select语句.
DML(数据操纵语言):主要是insert语句,update语句,delete语句,会产生事务
需要在语句后面commit或者rollback进行事务的结束,否则数据库不会更新数据
DDL(数据定义语言):create,alter,drop,truncate语句
TCL(事务控制语言):commit,rollback,savepoint语句,维护数据的一致性
DCL(数据控制语言):grant,revoke语句,用于执行权限授予和权限收回操作
2.select语句
select语句永远不会修改表的内容
3.常用的几个函数
|| :拼接函数,字符串用单引号括起来 nvl :可以将null值进行替换distinct:进行去重处理format:进行输出格式的4.排序
查询数据的时候进行排序,就是根据某个字段的值,按照升序或者降序的情况将记录显示出来
select col_name,... from tb_name order by col_name [asc|desc] --order by语句,只对查询记录显示调整,并不改变查询结果,所以执行权最低,最后执行 --排序的默认值是asc:表示升序,desc:表示降序 --如果有多个列排序,后面的列排序的前提是前面的列排好序以后有重复(相同)的值。5.条件查询
and的优先级比or要高
--where子句的优先级别最高 --between and操作符,表示在俩个值之间 select id,last_name,salary from s_emp where salary between 700 and 1500; --in(),表示值在一个指定的列表中 select id,last_name,salary from s_emp where id in (1,3,5,7,9); --like,模糊查询,在值不精确的时候使用 -- %,通配0到多个字符 -- _,通配一个字符,并且是一定要有一个字符 -- \,转义字符,需要使用escape关键字指定,转义字符只能转义后面的一个字符 select id,last_name,salary from s_emp where last_name like'C%'; -- is null 和 is not null select id,last_name,commission_pct from s_emp where commission_pct is null;伪列:Oracle数据库中伪列rownum最核心的作用就是:完成分页查询。
6.分组查询
select 字段1,字段2 ----5 from 表 ---1 where 条件 ---2 group by 分组条件 ---3 having 分组筛选条件 ---4 order by 排序条件 ---6 --聚合函数能够出现的位置 1. select后面 2. having后面 3. order by后面7.子查询
子查询的思路就是,把第一个sql语句的查询结果,在第二个sql语句中使用,这时候第一条sql语句的结果,在第二条sql中就可以充当一个where条件中的一个值,或者充当一张虚拟的表。
select last_name,salary from s_emp where salary> (select salary from s_emp where last_name='Smith');8.建表
-- 一般的建表语句 create table 表名( 字段名 数据类型 [列约束类型], 字段名 数据类型 [列约束类型], 字段名 数据类型 [列约束类型], 字段名 数据类型 [列约束类型], 字段名 数据类型 [列约束类型]);9.DML语句
insert into表名(列1,列2,…) values(值1,值2,…);
update 表名 set 列1=值1,列2=值2,… where 条件;
delete from 表名 where 条件 如果不加条件的话会删除表中的所有的数据
drop直接删除掉表以及级联的删除掉和表相关的信息
只有DML语句才会产生事务,其他语句不会产生事务
commit、rollback、DDL语句都可以把当前事务给结束掉
10.序列
常用的创建序列的方法:
create sequence 序列名
11.索引
create index 索引名
on 表名(列名);
1.使用JDBC对数据库进行操作的通用步骤(step):
注册驱动获取数据库连接创建Statement类型或者子类型对象执行sql处理结果(如果需要的话,一般查询语句必须要处理)关闭资源加载驱动的通用写法
private String driverClass="oracle.jdbc.driver.OracleDriver"; private String url="jdbc:oracle:thin:@127.0.0.1:1521:XE"; private String user="briup"; private String password="briup"; //1.加载注册驱动 Class.forName(driverClass); //2.获取连接对象 conn=DriverManager.getConnection(url,user,password); //3.获取Statement对象 stmt=conn.createStatement(); //4.执行SQL语句通过数据库连接池获取到JDBC连接
Properties properties = new Properties(); InputStream is = ConnectionTest.class.getClassLoader().getResourceAsStream("druid.properties"); properties.load(is); //获取连接池对象 DataSource dataSource = DruidDataSourceFactory.createDataSource(properties); // 获取连接 conn=dataSource.getConnection();MetaData
元数据,可以通过connection的getMetadata()方法获取到元数据对象,然后可以获得到数据库的名字,版本,以及版本的信息
svn就类似一个版本控制的工具,可以通过连接到svn上来提交每个版本的信息,一旦发现有问题,就可以回溯到某一个指定的版本
对java项目构建,依赖管理和项目信息管理
项目构建的步骤
清理clean:将之前编译得到的旧文件class字节码文件删除编译compile:将java源程序编译成class字节码文件测试test:自动测试,自动调用junit程序报告report:测试程序执行的结果打包package:动态Web工程打War包,java工程打jar包安装install:Maven特定的概念,将打包得到的文件复制到maven仓库中的指定位置7. 部署deploy:将工程生成的结果放到服务器中或者容器中,使其可以运行项目依赖的格式
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13</version> </dependency>一般创建Maven项目的时候,创建的都是聚合项目,然后为其添加子模块,打包的方式一定要为pom,在父项目中写好通用的依赖,然后
其他的模块自动依赖父项目,会自动地依赖好jar包
1.一个小的插件的使用
lombok可以让类不用写构造方法和getset方法,会极大的提高数据的灵活性(比如修改属性的时候修改getset方法和构造器)
2.新建后的Maven项目
分为三个模块
enviroment-common:专门用来写整个项目需要用到的实体类与工具类,以及依赖其他项目所共有的依赖,为其他模块做好基础enviroment-gateway:网关类,即客户端,负责从文件中读取到数据,按对象的方式先进行存储然后发送给服务端enviroment-server:服务端,通过serversocked获取到客户端发送过来的数据,然后将数据存储到数据库中(本项目是存储在31张表中)上图就是项目的common的模块
主要是由下面的模块构成:
exception(主要为此项目代码中提供异常类,以及用枚举创建的几个异常类型)
EnviromentException:掌握异常类的写法ExceptionMessageEnum:掌握枚举的写法pojo(简单的java对象):通过观察信息的格式,给每一条信息抽象出来一个对象,利用对象进行操作数据
Enviromet:掌握面向对象的思想,将每条信息抽象为对象,具体的内容抽象为属性utils(工具类):写一些项目通用的工具类
BackUpUtil(这个里面包含了项目的所有工具方法)
store(File file,Object data,boolean append),通过传入文件,以及要传到文件的数据,以及是否要覆盖源文件
利用这个方法可以对处理的信息进行备份,防止信息处理之后无法找到源数据
在项目前期的构建上,这种方法是可以的,当部署的时候会发生问题,因为在生成的jar包的时候不会加载进来
source文件夹,导致文件的路径错误.应该使用资源流的方式通过类的加载器来获得到该文件
代码如下:
类名.class.getResourceAsStream(“要操作的文件名,无须路径,直接文件名+后缀即可”)
2. read(File file,boolean append),接着上次的阅读过得地方继续读取 3. load(InputStream is) ,用于properties文件的读取 4. close(Connection connection,Statement statement,ResultSet resultSet) 用于关闭流的方法IdWorker(雪花算法)
雪花算法在一个类中只需要new一个对象,否则的话就会导致程序的极度卡慢,因为加载一次类会进行大量的运算上图就是gateway模块的内容
gather
IGather为实现网关功能的接口
public Collection<Enviroment> gather() throws EnviromentException;该功能的目的是读取数据并封装好一个个对象然后再封装到集合中
GatherImpl为该接口的实现类
首先要读取到发送到网关中的数据文件,然后利用方法对其对其一个一个进行解析数据格式:100|101|2|16|1|3|5d606f7802|1|1516323596029利用split分别对其进行分割,然后给environment对象赋值,并添加到集合当中每次解析都要进行备份,下一次从上一次结束的位置开始读取,遇到异常,存储到异常文件中,下一次判断异常文件是否为空,不为空的话就先解析次异常文件。send
ISender为网关接收到数据之后存储到集合中发送给服务端
void send(Collection<Enviroment> data) throws EnviromentException;SenderImpl为该接口的实现类
将GatherImpl中得到集合利用socket作为桥梁,用对象流将其传给服务端,
在数据量较大的时候可以用bufferedOutputStream包装一下,会提高发送的速率
这里同样要掌握properties文件的读取方式
properties.load()方法中参数为inputStream,方便流的读取,以后也可以用这种方式进行文件的读取
Application
通过多线程的形式一直对文件进行读取,并发送给客户端
上图上server模块的内容
revicer
Revicer为接收数据的接口,目的是返回一个Enviroment集合
Collection<Enviroment> revicer() throws EnviromentException;RevicerImpl为接口的实现类,通过ServerSocket来获取到Socket返回的集合
首先通过properties文件获取到端口号,接收到信息直接接收到发过来的数据,然后将其强转为Enviroment集合即可
database
IStore为将数据存入数据库的接口,目的是将数据进行分类存储
IStoreImpl为接口的实现类,负责将集合中内容进行存储到数据库
通过读取properties文件获取到驱动的内容
难点:将数据按照日分到31张表当中,怎么让分的时候少new几个prepareStatement对象
通过遍历当前获得的集合,进来先判断该日的数字是否和上一个的数字相同,相同的话就不需要再new对象。
通过在外面定义一个变量每次都更新day值,然后日期类用SimpleDateFormat转换为字符串。
其他的分别赋值就可以,再进行一下子批处理就可以了
日志
直接引入log4j依赖,然后写一个日志格式的properties文件,创建logger对象,logger.infor()就可以获得日志的打印
Logger logger = Logger.getLogger(GatherImpl.class); logger.info(); logger.debug();本机测试
具体修改文件路径,修改工具包中的方法为使用资源流在全项目中寻找
虚拟机测试
因为在使用的是国外的虚拟机,需要修改时区为上海时间(因为本地昆山距离上海太近,所以导致北京时间不敏感)修改虚拟机时间为上海时间,修改ip地址。。。两台虚拟机进行通信
//修改虚拟机当前时区为上海 cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime echo 'Asia/Shanghai' >/etc/timezone因为自己的虚拟机问题,导致连接一直不可用,GG。。。
Logger logger = Logger.getLogger(GatherImpl.class); logger.info(); logger.debug(); ```
本机测试
具体修改文件路径,修改工具包中的方法为使用资源流在全项目中寻找
虚拟机测试
因为在使用的是国外的虚拟机,需要修改时区为上海时间(因为本地昆山距离上海太近,所以导致北京时间不敏感)修改虚拟机时间为上海时间,修改ip地址。。。两台虚拟机进行通信
//修改虚拟机当前时区为上海 cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime echo 'Asia/Shanghai' >/etc/timezone因为自己的虚拟机问题,导致连接一直不可用,GG。。。
等以后学了就搞