项目源代码可访问我的 github:https://github.com/Spacider/Gather-and-store
如果觉得好的话请给个 star 哦~
开发 IDE: IDEA 2018.03 JDK 1.8
开发环境: macOS 10.13.6 (如 windows 请对项目中部分路径进行改写)
数据库: Oracle 11g
第三阶段:从日志文件中采集并发送数据
在 JAVA 实践项目---树莓派信息自动化采集后入库项目(三)中写到将数据写入日志文件中,接下来我们就要从日志文件中数据取出来并发送给 Server 端。
此层项目结构为
接下来开始看代码:
1.采集模块:
- 定义一个
Gather
借口
public interface Gather {
/**
* 采集模块接口实现
* 对 src 下日志进行处理,一行日志封装成一个 Environment 对象或者两个 Environment 对象
* 所有采集到的对象封装到集合中
* @return
*/
Collection<Environment> gather();
}
- 有了接口之后再定义个包为
Impl
,专门用来放实现类,在 Impl 下定义一个类为GatherImpl
,它实现了Gather
接口。
public final class GatherImpl implements Gather {
}
在实现类中写一个采集的主方法:
public Collection<Environment> gather(){
}
写方法实现之前想到一个问题:如果客户端发送到服务器的过程中出现意外怎么办?数据是否会丢失?会不会发送错行?
在经过考虑以后,想出一个解决方案:
使用
RandomAccessFile
流,它有一个 seek() 方法可以跳过之前已经读取过的字节数,这样的话我们每发送一次,就把已经发送的字节数储存在一个文件中,每次都读取这个文件,保证现在发的是上一次的末尾。
代码实现:
- 读取储存文件,如果文件不存在,说明第一次运行,则创造一个新文件:
Properties properties = new Properties();
File positionFile = new File(“/Users/wjh/Desktop/FirstProject/src/main/resources/FilePostion.properties”);
if (!positionFile.exists()){
positionFile.createNewFile();
}
properties.load(new FileReader(positionFile));
String FilePostion = properties.getProperty("FilePostion");
- 跳过已经读取的字节数,并通过
String
类的split
方法拆分字符串
while ((str = raf.readLine()) != null) {
// 运用 | 来拆分字符串
String[] stringList = str.split("\\|");
getenv(stringList);
}
// 将最后的位数写回文件
properties.setProperty("FilePostion" , position+"");
pw = new PrintWriter(positionFile);
properties.store(pw,null);
getenv 方法的作用是根据所传入的拆分后的字符串来生成新的对象并返回,这里在实际与树莓派交互过程中出现了脏数据的情况,通过 if 语句来筛选出正确数据,实现:
private void getenv(String[] stringList){
String sensorAddress = stringList[3];
int FinalDate = 0;
FinalDate = Integer.parseInt(stringList[6].substring(0, 4), 16);
if (sensorAddress.equals("16")) {
if (stringList[6].length() != 10){
System.out.println("得到的数据为脏数据, 温度湿度错误数据:" + stringList[6]);
}else {
/**
* 温度计算公式:value(int) float Temperature = ((float)value*0.00268127)- 46.85;
* 湿度:value(int) float Humidity = ((float)value*0.00190735)-6;
*/
// 生成温度对象,并添加到 list 中
float Temperature = (float) ((FinalDate * 0.00268127) - 46.85);
environmentList.add(SetNameAndData(stringList, "温度", Temperature));
// 生成湿度对象,并添加到 list 中
FinalDate = Integer.parseInt(stringList[6].substring(4, 8), 16);
float Humidity = (float) ((FinalDate * 0.00190735) - 6);
environmentList.add(SetNameAndData(stringList, "湿度", Humidity));
}
}else if (sensorAddress.equals("256")){
if (stringList[6].length() != 6) {
System.out.println("得到的数据为脏数据, 光照错误数据:" + stringList[6]);
}else{
environmentList.add(SetNameAndData(stringList, "光照强度", FinalDate));
}
}else if (sensorAddress.equals("1280")){
if (stringList[6].length() != 6) {
System.out.println("得到的数据为脏数据, 二氧化碳错误数据:" + stringList[6]);
}else{
environmentList.add(SetNameAndData(stringList, "二氧化碳", FinalDate));
}
}else{
System.out.println("得到的数据错误");
}
}
SetNameAndData 方法为不同的 Enviroment 对象封装名字和数据:
private Environment SetNameAndData(String[] stringList, String name ,float Data){
String sensorAddress = stringList[3];
Environment envir = new Environment();
try {
envir.setSrcID(stringList[0]);
envir.setDstID(stringList[1]);
envir.setDevID(stringList[2]);
envir.setSensorAddress(sensorAddress);
envir.setCount(Integer.parseInt(stringList[4]));
envir.setCmd(Integer.parseInt(stringList[5]));
envir.setStatus(Integer.parseInt(stringList[7]));
DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Timestamp ts = new Timestamp(format.parse(stringList[8]).getTime());
envir.setGather_date(ts);
envir.setName(name);
envir.setData(Data);
} catch (ParseException e) {
logger.error("设置名字和数据失败");
}
return envir;
}
在 GatherImpl 的 gather()
方法中写一个打印语句:
for (Environment environment : environmentList) {
System.out.println(environment);
}
写到这里,你就可以通过:
public static void main(String[] args) {
GatherImpl gather = new GatherImpl();
gather.gather();
}
来进行测试,最后打印出 environment
对象集说明书写正确。
2.发送模块
- 同样,定义一个接口为
EnvClient
:
public interface EnvClient extends WossModel {
/**
* 发送采集模块采集的集合对象
*/
void send(Collection<Environment> col);
}
- 有了接口以后写它的实现类
EnvClientImpl
,它有一个很简单的功能,就是把上文封装好的对象发给服务器:
public class EnvClientImpl implements EnvClient {
public void send(Collection<Environment> col) {
}
}
代码:
socket = new Socket(host,port);
os = socket.getOutputStream();
oos = new ObjectOutputStream(os);
// 运用对象流把生成的对象发给 Server 端
oos.writeObject(col);
oos.flush();
写好这一切以后,定义这一阶段的的主入口,把内容串起来:
public final class ClientMain {
/**
* 集合 Client 并提供向外的入口
* 通过采集所获得的 list 发给 Server
*/
public static void ClientSendMain(){
ConfigurationImpl configuration = new ConfigurationImpl();
Gather gather = configuration.getGather();
List<Environment> environmentList = (List <Environment>) gather.gather();
configuration.getClient().send(environmentList);
}
}
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于