JAVA實踐專案---樹莓派資訊自動化採集後入庫專案(四)
阿新 • • 發佈:2018-11-11
專案原始碼可訪問我的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);
}
}