JAVA實踐項目---樹莓派信息自動化採集後入庫項目(四)

項目源代碼可訪問我的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);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章