不要重復造輪子?提高生產(chǎn)效率!3個常用的開源工具庫分享
我們實際項目開發(fā)中是比較忌諱造輪子的,但是,自己在學習過程中造輪子絕對是對自己百利而無一害的!造輪子是一種特別能夠提高自己系統(tǒng)編程能力的手段。
今天就分享幾個我常用的開源工具庫,希望對小伙伴們有幫助!
OSHI[1] :一款為 Java 語言提供的基于 JNA 的(本機)操作系統(tǒng)和硬件信息庫。 EasyExcel[2] :一款快速、簡單避免 OOM 的 java 處理 Excel 工具。 Hutool[3] : 一個非常實用的 Java 工具類庫,對文件、流、加密解密、轉碼、正則、線程、XML 等 JDK 方法進行了封裝。
以下是較為詳細一點的介紹,建議小伙伴們看完,方便自己快速上手,用在自己的項目中來提高生產(chǎn)效率。
oshi

介紹
OSHI 是一款為 Java 語言提供的基于 JNA 的(本機)操作系統(tǒng)和硬件信息庫。
JNA(Java Native Access)[4]是一個開源的 Java 框架,是 Sun 公司推出的一種調用本地方法的技術,是建立在經(jīng)典的 JNI 基礎之上的一個框架。之所以說它是 JNI 的替代者,是因為 JNA 大大簡化了調用本地方法的過程,使用很方便,基本上不需要脫離 Java 環(huán)境就可以完成。
JNI(Java Native Interface) 是 JDK 提供的一個編程接口,它允許 Java 程序調用其他語言編寫的程序或者代碼庫,其實 JDK 本身的實現(xiàn)也大量用到 JNI 技術來調用本地 C 程序庫。
通過 OSHI ,我們不需要安裝任何其他本機庫,就能查看內存和 CPU 使用率、磁盤和分區(qū)使用情況、設備、傳感器等信息。
OSHI 旨在提供一種跨平臺的實現(xiàn)來檢索系統(tǒng)信息,支持 Windows、Linux、MacOS、Unix 等主流操作系統(tǒng)。
官方是這樣介紹 oshi 的:(翻譯 Chrome 插件:Mate Translate):

使用 oshi 你可以輕松制作出項目常用的系統(tǒng)監(jiān)控功能,如下圖所示:

引入依賴
Maven
<dependency>
????<groupId>com.github.oshigroupId>
????<artifactId>oshi-coreartifactId>
????<version>5.2.5version>
dependency>
Gradle
//?https://mvnrepository.com/artifact/com.github.oshi/oshi-core
compile?group:?'com.github.oshi',?name:?'oshi-core',?version:?'5.2.5'
功能演示
獲取硬件信息對象HardwareAbstractionLayer :
//系統(tǒng)信息
SystemInfo?si?=?new?SystemInfo();
//操作系統(tǒng)信息
OperatingSystem?os?=?si.getOperatingSystem();
//硬件信息
HardwareAbstractionLayer?hal?=?si.getHardware();
有了代表硬件信息的對象HardwareAbstractionLayer 之后,我們就可以獲取硬件相關的信息了!
下面簡單演示一下獲取內存和 CPU 相關信息。
1.獲取內存相關信息
//內存相關信息
GlobalMemory?memory?=?hal.getMemory();
//獲取內存總容量
String?totalMemory?=?FormatUtil.formatBytes(memory.getTotal());
//獲取可用內存的容量
String?availableMemory?=?FormatUtil.formatBytes(memory.getAvailable());
有了內存總容量和內存可用容量,你就可以計算出當前內存的利用率了。
2.獲取 CPU 相關信息
//CPU相關信息
CentralProcessor?processor?=?hal.getProcessor();
//獲取CPU名字
String?processorName?=?processor.getProcessorIdentifier().getName();
//獲取物理CPU數(shù)
int?physicalPackageCount?=?processor.getPhysicalPackageCount();
//獲取物理核心數(shù)
int?physicalProcessorCount?=?processor.getPhysicalProcessorCount();
EasyExcel
介紹
Java 解析、生成 Excel 常用的框架有 Apache poi、jxl ,但是這兩個框架使用起來都不夠優(yōu)雅,并且非常耗內存,嚴重時會導致內存溢出。
怎么解決這個問題呢?
推薦你使用阿里開源的 EasyExcel。正如這個項目官網(wǎng)介紹的那樣,這是一款快速、簡單避免 OOM 的 java 處理 Excel 工具。
官方是這樣介紹 EasyExcel 的:

引入依賴
Maven
<dependency>
????<groupId>com.alibabagroupId>
????<artifactId>easyexcelartifactId>
????<version>2.2.6version>
dependency>
Gradle
//?https://mvnrepository.com/artifact/com.alibaba/easyexcel
compile?group:?'com.alibaba',?name:?'easyexcel',?version:?'2.2.6'
功能演示
這里直接分享官方提供讀取 Excel 的例子(在實際項目中我對這部分做了簡單的封裝,涉及的地方比較多,就不分享出來了)。
實體對象 (Excel 導入導出實體對象)
@Data
public?class?DemoData?{
????private?String?string;
????private?Date?date;
????private?Double?doubleData;
}
監(jiān)聽器 (自定義 AnalysisEventListener 一次讀取 5 條數(shù)據(jù)存儲到數(shù)據(jù)庫)
//?有個很重要的點?DemoDataListener?不能被spring管理,要每次讀取excel都要new,然后里面用到spring可以構造方法傳進去
public?class?DemoDataListener?extends?AnalysisEventListener<DemoData>?{
????private?static?final?Logger?LOGGER?=?LoggerFactory.getLogger(DemoDataListener.class);
????/**
?????*?每隔5條存儲數(shù)據(jù)庫,實際使用中可以3000條,然后清理list?,方便內存回收
?????*/
????private?static?final?int?BATCH_COUNT?=?5;
????List?list?=?new?ArrayList();
????/**
?????*?假設這個是一個DAO,當然有業(yè)務邏輯這個也可以是一個service。當然如果不用存儲這個對象沒用。
?????*/
????private?DemoDAO?demoDAO;
????public?DemoDataListener()?{
????????//?這里是demo,所以隨便new一個。實際使用如果到了spring,請使用下面的有參構造函數(shù)
????????demoDAO?=?new?DemoDAO();
????}
????/**
?????*?如果使用了spring,請使用這個構造方法。每次創(chuàng)建Listener的時候需要把spring管理的類傳進來
?????*
?????*?@param?demoDAO
?????*/
????public?DemoDataListener(DemoDAO?demoDAO)?{
????????this.demoDAO?=?demoDAO;
????}
????/**
?????*?這個每一條數(shù)據(jù)解析都會來調用
?????*
?????*?@param?data
?????*????????????one?row?value.?Is?is?same?as?{@link?AnalysisContext#readRowHolder()}
?????*?@param?context
?????*/
????@Override
????public?void?invoke(DemoData?data,?AnalysisContext?context)?{
????????LOGGER.info("解析到一條數(shù)據(jù):{}",?JSON.toJSONString(data));
????????list.add(data);
????????//?達到BATCH_COUNT了,需要去存儲一次數(shù)據(jù)庫,防止數(shù)據(jù)幾萬條數(shù)據(jù)在內存,容易OOM
????????if?(list.size()?>=?BATCH_COUNT)?{
????????????saveData();
????????????//?存儲完成清理?list
????????????list.clear();
????????}
????}
????/**
?????*?所有數(shù)據(jù)解析完成了?都會來調用
?????*
?????*?@param?context
?????*/
????@Override
????public?void?doAfterAllAnalysed(AnalysisContext?context)?{
????????//?這里也要保存數(shù)據(jù),確保最后遺留的數(shù)據(jù)也存儲到數(shù)據(jù)庫
????????saveData();
????????LOGGER.info("所有數(shù)據(jù)解析完成!");
????}
????/**
?????*?加上存儲數(shù)據(jù)庫
?????*/
????private?void?saveData()?{
????????LOGGER.info("{}條數(shù)據(jù),開始存儲數(shù)據(jù)庫!",?list.size());
????????demoDAO.save(list);
????????LOGGER.info("存儲數(shù)據(jù)庫成功!");
????}
}
持久層 (mybatis 或者 jpa 來做都行)
/**
?*?假設這個是你的DAO存儲。當然還要這個類讓spring管理,當然你不用需要存儲,也不需要這個類。
?**/
public?class?DemoDAO?{
????public?void?save(List?list) ?{
????????//?如果是mybatis,盡量別直接調用多次insert,自己寫一個mapper里面新增一個方法batchInsert,所有數(shù)據(jù)一次性插入
????????System.out.println(list);
????}
}
讀取數(shù)據(jù)
String?fileName?=?"src/test/resources/demo/demo.xlsx";
//?這里?需要指定讀用哪個class去讀,然后讀取第一個sheet?文件流會自動關閉
EasyExcel.read(fileName,?DemoData.class,?new?DemoDataListener()).sheet().doRead();
輸出結果 (已過濾非必要數(shù)據(jù))
2020-09-16?08:14:33.727?DEBUG?[main]?com.alibaba.excel.context.AnalysisContextImpl:91?-?Began?to?read:ReadSheetHolder{sheetNo=0, sheetName='Sheet1'}?com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder@6f3b5d16
2020-09-16?08:14:33.870?INFO?[main]?com.alibaba.easyexcel.test.demo.read.DemoDataListener:54?-?解析到一條數(shù)據(jù):{"date":1577811661000,"doubleData":1.0,"string":"字符串0"}
2020-09-16?08:14:33.870?INFO?[main]?com.alibaba.easyexcel.test.demo.read.DemoDataListener:54?-?解析到一條數(shù)據(jù):{"date":1577898061000,"doubleData":2.0,"string":"字符串1"}
2020-09-16?08:14:33.871?INFO?[main]?com.alibaba.easyexcel.test.demo.read.DemoDataListener:54?-?解析到一條數(shù)據(jù):{"date":1577984461000,"doubleData":3.0,"string":"字符串2"}
2020-09-16?08:14:33.871?INFO?[main]?com.alibaba.easyexcel.test.demo.read.DemoDataListener:54?-?解析到一條數(shù)據(jù):{"date":1578070861000,"doubleData":4.0,"string":"字符串3"}
2020-09-16?08:14:33.872?INFO?[main]?com.alibaba.easyexcel.test.demo.read.DemoDataListener:54?-?解析到一條數(shù)據(jù):{"date":1578157261000,"doubleData":5.0,"string":"字符串4"}
2020-09-16 08:14:33.872 INFO [main] com.alibaba.easyexcel.test.demo.read.DemoDataListener:80?- 5條數(shù)據(jù),開始存儲數(shù)據(jù)庫!
[DemoData(string=字符串0,?date=Wed?Jan?01?01:01:01?CST?2020,?doubleData=1.0),?DemoData(string=字符串1,?date=Thu?Jan?02?01:01:01?CST?2020,?doubleData=2.0),?DemoData(string=字符串2,?date=Fri?Jan?03?01:01:01?CST?2020,?doubleData=3.0),?DemoData(string=字符串3,?date=Sat?Jan?04?01:01:01?CST?2020,?doubleData=4.0),?DemoData(string=字符串4,?date=Sun?Jan?05?01:01:01?CST?2020,?doubleData=5.0)]
2020-09-16 08:14:33.874 INFO [main] com.alibaba.easyexcel.test.demo.read.DemoDataListener:82 -?存儲數(shù)據(jù)庫成功!
2020-09-16?08:14:33.875?INFO?[main]?com.alibaba.easyexcel.test.demo.read.DemoDataListener:54?-?解析到一條數(shù)據(jù):{"date":1578243661000,"doubleData":6.0,"string":"字符串5"}
2020-09-16?08:14:33.875?INFO?[main]?com.alibaba.easyexcel.test.demo.read.DemoDataListener:54?-?解析到一條數(shù)據(jù):{"date":1578330061000,"doubleData":7.0,"string":"字符串6"}
2020-09-16?08:14:33.876?INFO?[main]?com.alibaba.easyexcel.test.demo.read.DemoDataListener:54?-?解析到一條數(shù)據(jù):{"date":1578416461000,"doubleData":8.0,"string":"字符串7"}
2020-09-16?08:14:33.876?INFO?[main]?com.alibaba.easyexcel.test.demo.read.DemoDataListener:54?-?解析到一條數(shù)據(jù):{"date":1578502861000,"doubleData":9.0,"string":"字符串8"}
2020-09-16?08:14:33.876?INFO?[main]?com.alibaba.easyexcel.test.demo.read.DemoDataListener:54?-?解析到一條數(shù)據(jù):{"date":1578589261000,"doubleData":10.0,"string":"字符串9"}
2020-09-16 08:14:33.877 INFO [main] com.alibaba.easyexcel.test.demo.read.DemoDataListener:80?- 5條數(shù)據(jù),開始存儲數(shù)據(jù)庫!
[DemoData(string=字符串5,?date=Mon?Jan?06?01:01:01?CST?2020,?doubleData=6.0),?DemoData(string=字符串6,?date=Tue?Jan?07?01:01:01?CST?2020,?doubleData=7.0),?DemoData(string=字符串7,?date=Wed?Jan?08?01:01:01?CST?2020,?doubleData=8.0),?DemoData(string=字符串8,?date=Thu?Jan?09?01:01:01?CST?2020,?doubleData=9.0),?DemoData(string=字符串9,?date=Fri?Jan?10?01:01:01?CST?2020,?doubleData=10.0)]
2020-09-16 08:14:33.877 INFO [main] com.alibaba.easyexcel.test.demo.read.DemoDataListener:82 -?存儲數(shù)據(jù)庫成功!
2020-09-16 08:14:33.877 INFO [main] com.alibaba.easyexcel.test.demo.read.DemoDataListener:80?-?0條數(shù)據(jù),開始存儲數(shù)據(jù)庫!
[]
2020-09-16 08:14:33.877 INFO [main] com.alibaba.easyexcel.test.demo.read.DemoDataListener:82 -?存儲數(shù)據(jù)庫成功!
2020-09-16 08:14:33.877 INFO [main] com.alibaba.easyexcel.test.demo.read.DemoDataListener:73 -?所有數(shù)據(jù)解析完成!
Process?finished?with?exit?code?0
Hutool

介紹
Hutool 是一個非常實用的 Java 工具類庫,對文件、流、加密解密、轉碼、正則、線程、XML 等 JDK 方法進行了封裝。
非常使用的開源工具類庫,推薦小伙伴們在自己項目中使用。
官方是這樣介紹 Hutool 的:

引入依賴
Maven
<dependency>
????<groupId>cn.hutoolgroupId>
????<artifactId>hutool-allartifactId>
????<version>5.4.2version>
dependency>
Gradle
//?https://mvnrepository.com/artifact/cn.hutool/hutool-all
compile?group:?'cn.hutool',?name:?'hutool-all',?version:?'5.4.2'
功能演示
簡單演示幾個比較實用的功能。
郵件
在 Java 中發(fā)送郵件主要品依靠 javax.mail 包,但是由于使用比較繁瑣,因此 Hutool 針對其做了封裝。由于依賴第三方包,因此將此工具類歸類到 extra 模塊中。
實際項目中可以自定義郵箱配置,然后讓配置保存在數(shù)據(jù)庫,并在緩存中保存一份。
如果不想自定義配置的話,直接在配置文件中把郵箱配置寫死就行了。
有了郵件的相關配置之后,定義郵件服務器之后即可發(fā)送郵件,非常方便:
MailAccount?account?=?new?MailAccount();
account.setHost("smtp.yeah.net");
account.setPort("25");
account.setAuth(true);
account.setFrom("[email protected]");
account.setUser("hutool");
account.setPass("q1w2e3");
MailUtil.send(account,?CollUtil.newArrayList("[email protected]"),?"測試",?"郵件來自Hutool測試",?false);
唯一 ID
在分布式環(huán)境中,唯一 ID 生成應用十分廣泛,生成方法也多種多樣,Hutool 針對一些常用生成策略做了簡單封裝。

https://juejin.im/post/6844903935296176141
Hutool 提供的唯一 ID 生成器的工具類,涵蓋了:
UUID ObjectId(MongoDB) Snowflake(Twitter)
拿 UUID 舉例!
Hutool 重寫java.util.UUID的邏輯,對應類為cn.hutool.core.lang.UUID,使生成不帶-的 UUID 字符串不再需要做字符替換,性能提升一倍左右。
//生成的UUID是帶-的字符串,類似于:a5c8a5e8-df2b-4706-bea4-08d0939410e3
String?uuid?=?IdUtil.randomUUID();
//生成的是不帶-的字符串,類似于:b17f24ff026d40949c85a24f4f375d42
String?simpleUUID?=?IdUtil.simpleUUID();
Http 請求工具類
針對最為常用的 GET 和 POST 請求,HttpUtil 封裝了兩個方法,
HttpUtil.getHttpUtil.post
//?最簡單的HTTP請求,可以自動通過header等信息判斷編碼,不區(qū)分HTTP和HTTPS
String?result1?=?HttpUtil.get("https://www.baidu.com");
//?當無法識別頁面編碼的時候,可以自定義請求頁面的編碼
String?result2?=?HttpUtil.get("https://www.baidu.com",?CharsetUtil.CHARSET_UTF_8);
//可以單獨傳入http參數(shù),這樣參數(shù)會自動做URL編碼,拼接在URL中
HashMap?paramMap?=?new?HashMap<>();
paramMap.put("city",?"北京");
String?result3?=?HttpUtil.get("https://www.baidu.com",?paramMap);
緩存
Hutool 提供了常見的幾種緩存策略的實現(xiàn):
FIFO(first in first out) :先進先出策略。 LFU(least frequently used) :最少使用率策略。 LFU(least frequently used) :最少使用率策略。 定時緩存 :對被緩存的對象定義一個過期時間,當對象超過過期時間會被清理。 ......
FIFO(first in first out) 策略緩存使用:
Cache?fifoCache?=?CacheUtil.newFIFOCache(3);
//加入元素,每個元素可以設置其過期時長,DateUnit.SECOND.getMillis()代表每秒對應的毫秒數(shù),在此為3秒
fifoCache.put("key1",?"value1",?DateUnit.SECOND.getMillis()?*?3);
fifoCache.put("key2",?"value2",?DateUnit.SECOND.getMillis()?*?3);
fifoCache.put("key3",?"value3",?DateUnit.SECOND.getMillis()?*?3);
//由于緩存容量只有3,當加入第四個元素的時候,根據(jù)FIFO規(guī)則,最先放入的對象將被移除
fifoCache.put("key4",?"value4",?DateUnit.SECOND.getMillis()?*?3);
//value1為null
String?value1?=?fifoCache.get("key1");
控制臺打印封裝-Console
一般情況下,我們打印信息到控制臺小伙伴們應該再熟悉不過了!
System.out.println("Hello?World");
但是,這種方式不滿足很多場景的需要:
不支持參數(shù),對象打印需要拼接字符串 不能直接打印數(shù)組,需要手動調用 Arrays.toString
為此,Hutool 封裝了Console對象。
Console 對象的使用更加類似于 Javascript 的
console.log()方法,這也是借鑒了 JS 的一個語法糖。
String[]?a?=?{"java",?"c++",?"c"};
Console.log(a);//控制臺輸出:[java, c++, c]
Console.log("This?is?Console?log?for?{}.",?"test");//控制臺輸出:This is Console log for test.
參考資料
oshi: https://github.com/oshi/oshi
[2]EasyExcel: https://github.com/alibaba/easyexcel
[3]Hutool: https://github.com/looly/hutool
[4]JNA(Java Native Access): https://github.com/java-native-access/jna
閑聊
其實今天本來是準備更新一篇系統(tǒng)設計面試指南的,畢竟系統(tǒng)設計幾乎也是面試必問了,非常重要。?最近詢問這方面問題的小伙伴比較多。
文章大概要寫啥內容都構思好了,結果還是過于天真。因為涉及到的內容和知識點太多了。預計會在下周分享(如果中途沒出啥狀況的話)。

另外,上周日和我們大學的傳奇人物,研究生在華科,目前在華為的學長聊了一會。收獲確實不少,果然優(yōu)秀的人總有一些過人的地方(這周六應該會把自己的所得所獲分享出來)。
最近更新的一些好文章推薦:
往期推薦
文章有幫助可以點個「在看」或「分享」,都是支持,我都喜歡!
我是Guide哥,Java后端開發(fā),會一點前端知識,喜歡烹飪,自由的少年。一個三觀比主角還正的技術人。我們下期再見!
