JAVA實踐專案---樹莓派資訊自動化採集後入庫專案(六)
專案原始碼可訪問我的github:https://github.com/Spacider/Gather-and-store
如果覺得好的話請給個star哦~
開發IDE: IDEA 2018.03 JDK 1.8
開發環境: macOS 10.13.6 (如windows請對專案中部分路徑進行改寫)
資料庫: Oracle 11g
上節完畢專案主體已經基本開發完成,下列進行一系列優化操作:
1.備份模組:
先編寫一個介面:
/** * 備份模組 * 1. 客戶端傳送集合沒有傳送出去或連不上伺服器需要備份 * 2. 服務端接收了集合物件寫入資料庫出錯,對集合進行備份 */ public interface BackUp extends WossModel{ /** * 將集合儲存到檔案中 * @param coll 需要備份的集合 */ void storeEnvs(Collection<Environment> coll ); /** * 將集合從檔案中讀取 * @return */ Collection<Environment> loadEnvs(); }
具體實現:
通過物件流套檔案流的形式把物件存入備份檔案中:
@Override public void storeEnvs(Collection<Environment> coll) { File file = new File(path); FileOutputStream fos = null; ObjectOutputStream oos = null; try { if (!file.exists()) { file.createNewFile(); } fos = new FileOutputStream(file,true); oos = new ObjectOutputStream(fos); oos.writeObject(coll); oos.flush(); System.out.println("已經存入備份檔案中 ,path:" +path); } catch (IOException e) { e.printStackTrace(); } finally { IOUtil.close(fos,oos); } }
從備份檔案中取出相應物件!
@Override public Collection <Environment> loadEnvs() { FileInputStream fis = null; ObjectInputStream ois = null; Object backupObject = null; try { fis = new FileInputStream(path); ois = new ObjectInputStream(fis); backupObject = ois.readObject(); // System.out.println("已經從 path:" + path + "取出備份檔案"); log.info("從 path:" + path + "取出備份檔案中..."); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } return (Collection <Environment>) backupObject; }
2.日誌模組
先編寫一個介面叫Log
,裡邊封裝了日誌的四種級別:
public interface Log extends WossModel{
/**
* 輸出 debug 級別的日誌
* @param msg
*/
void debug(String msg);
/**
* 輸出 info 級別的日誌
* @param msg
*/
void info(String msg);
/**
* 輸出 warn 級別的日誌
* @param msg
*/
void warn(String msg);
/**
* 輸出 error 級別的日誌
* @param msg
*/
void error(String msg);
}
日誌模組的實現就是呼叫log4j的日誌配置,然後做對應的輸出:
private Logger LOGGER = Logger.getLogger(LogImpl.class);
public LogImpl() {
PropertyConfigurator.configure("/Users/wjh/Desktop/FirstProject/src/main/resources/log4j.properties");
}
@Override
public void debug(String msg) {
LOGGER.debug(msg);
}
@Override
public void info(String msg) {
LOGGER.info(msg);
}
@Override
public void warn(String msg) {
LOGGER.warn(msg);
}
@Override
public void error(String msg) {
LOGGER.error(msg);
}
@Override
public void init(Properties properties) {
}
3.配置模組
首先配置一個介面為WossModel
,裡面有一個方法,有了這個方法之後當一個類如果實現了這個介面,我們就可以把Properties
檔案傳給它,在Properties
檔案中我們又可以傳入相應的引數,這樣做可以靈活替換類中的可變參,讓整個程式變得靈活起來!
/**
* 初始化配置引數
*/
public interface WossModel {
void init(Properties properties);
}
再定義一個介面為Configuration
,在這個介面的實現中會通過反射去獲取各個類(又可以說是一個模組)的物件,保證了物件的唯一性!這一部分又可以看做是一個注入過程,讓物件的建立變得靈活,變得安全!
/**
* 獲取各個配置模組物件
* 對所有物件進行管理
*/
public interface Configuration {
/**
* 獲取採集模組物件
*/
Gather getGather();
/**
* 獲取客戶端模組物件
*/
EnvClient getClient();
/**
* 獲取伺服器端物件
*/
EnvServer getServer();
/**
* 獲取入庫模組物件
*/
DBStore getDBStore();
/**
* 獲取日誌模組物件
*/
Log getLog();
/**
* 獲取備份模組物件
*/
BackUp getBackUp();
}
最後一個介面是ConfigurationAware
,這個介面的主要用途就是當遇到一個模組物件呼叫到另一個模組物件時間,就可以把剛才寫的Configuration
整個注入進去,有了這個Configuration
物件就相當於可以獲取到了其他所有配置模組的物件,這樣你就可以靈活去獲取到你需要的物件並且呼叫其內的方法了!
public interface ConfigurationAware {
void SetConfiguration(Configuration conf);
}
具體實施
講了這麼多,具體咋實施呢:
給你需要的類上介面!
例如:
客戶端的類:
讓介面實現WossModel
介面,那麼子實現就預設也實現了這個介面!
由於在客戶端類中
public interface EnvClient extends WossModel {
}
public class EnvClientImpl implements EnvClient , ConfigurationAware {
}
當繼承了WossModel
介面之後我們就可以實現其方法來接入Properties
檔案:
public void init(Properties properties) {
port = Integer.parseInt(properties.getProperty("port"));
}
這樣我們就可以替換掉port
屬性,等會有寫怎樣去通過寫入XML檔案的形式讀取到這個port屬性!
最後是重頭戲,實現Configuration
類,編寫ConfigurationImpl
類:
按照如下形式去
<?xml version="1.0" encoding="UTF-8" ?>
<EMS>
<Log class="com.briup.util.Impl.LogImpl">
</Log>
<gather class="com.briup.Client.Impl.GatherImpl">
<logFile>/Users/wjh/Desktop/FirstProject/src/radwtmp</logFile>
<positionFile>/Users/wjh/Desktop/FirstProject/src/main/resources/FilePostion.properties</positionFile>
</gather>
<EnvClient class = "com.briup.Client.Impl.EnvClientImpl">
<host>127.0.0.1</host>
<port>9999</port>
<path>/Users/wjh/Desktop/FirstProject/src/BackUptmp</path>
</EnvClient>
<EnvServer class="com.briup.Server.Impl.EnvServerImpl">
<port>9999</port>
</EnvServer>
<BackUp class="com.briup.util.Impl.BackUpImpl">
<BackUppath>/Users/wjh/Desktop/FirstProject/src/BackUptmp</BackUppath>
</BackUp>
<DBStore class="com.briup.Server.Impl.DBStoreImpl">
</DBStore>
</EMS>
以
<物件名 class="物件的全限定名">
<需要替換的屬性名>屬性值</需要替換的屬性名>
</物件名>
來進行編寫
在ConfigurationImpl
的構造器中,編寫對XML檔案進行解析的程式碼!
這裡還是用之前用到的Dom4j,先獲取到根節點,然後獲取最大的子節點,也就是物件名
fis = new FileInputStream("/Users/wjh/Desktop/FirstProject/src/main/resources/EMS.xml");
document = saxReader.read(fis);
EMS = document.getRootElement();
List<Element> EMSlist = EMS.elements();
使用一個map集合來儲存我們得到的物件:
// 使用 Map 集合來存放 模組名-物件
private Map<String,WossModel> ObjectMap = new HashMap <>();
再遍歷物件名的時候,獲取物件名的class屬性,也就是全限定名,通過Class.forName()
來獲取到的對應的物件,然後存入map集合中,然後繼續遍歷下一層,碰到有需要可變引數的模組的時候把可變引數提取出來,交給Properties
,等待物件成功建立以後通過其中的init
方法把Properties
物件傳入,最後如果遇到了類繼承了ConfigurationAware
介面(也就是說這個類會呼叫其他類的物件),就呼叫SetConfiguration
方法把Configuration
物件傳入!這樣就可以在一個類中去呼叫其他類的物件了:
for (Element element : EMSlist){
//gather -- EnvClient -- EnvServer -- BackUp -- DBStore --
String elementName = element.getName();
String elementClass = element.attribute("class").getText();
WossModel obj = (WossModel) Class.forName(elementClass).newInstance();
if (obj instanceof ConfigurationAware){
((ConfigurationAware) obj).SetConfiguration(this);
}
// 遍歷子節點,為應該賦值的變數賦值
List<Element> ChildEMSList = element.elements();
Properties properties =new Properties();
for (Element element1 : ChildEMSList){
properties.setProperty(element1.getName(),element1.getText());
}
// 呼叫其 init 方法,對變數進行賦值
obj.init(properties);
ObjectMap.put(elementName,obj);
}
當做完了這一切,物件的建立變得異常簡單:
@Override
public Gather getGather() {
return (Gather) ObjectMap.get("gather");
}
@Override
public EnvClient getClient() {
return (EnvClient) ObjectMap.get("EnvClient");
}
@Override
public EnvServer getServer() {
return (EnvServer) ObjectMap.get("EnvServer");
}
@Override
public DBStore getDBStore() {
return (DBStore) ObjectMap.get("DBStore");
}
@Override
public Log getLog() {
return (Log) ObjectMap.get("Log");
}
@Override
public BackUp getBackUp() {
return (BackUp) ObjectMap.get("BackUp");
}
在配置模組之後,就可以通過這樣來創造一個新的物件:
ConfigurationImpl configuration = new ConfigurationImpl();
Gather gather = configuration.getGather();
而在繼承了ConfigurationAware
介面的類中,可以通過
private Configuration configuration;
private Log logger;
@Override
public void SetConfiguration(Configuration conf) {
this.configuration = conf;
logger = configuration.getLog();
}
日誌也變得如此簡單:
logger.info("插入資料庫成功:" + count + "資料");
logger.error("插入資料庫失敗");
專案的說明就此結束,專案的說明中的程式碼不一定完整,完整程式碼在 https://github.com/Spacider/Gather-and-store
這是一個練手專案,通過這個專案你可以對java基礎有更深層次的瞭解,其中運用了注入,模組分割等常用的方法,使你之後對spring等框架的理解更深一個層次!
本人語言溝通能力尚缺,可能講的地方會出問題,請指教!希望能和大家一起學習,一起進步!
個人網站:http://www.spacider.com/
CSDN:https://blog.csdn.net/qq_37163479
聯絡QQ:729215049