我們實際項目開發(fā)中是比較忌諱造輪子的四敞,但是泛源,自己在學(xué)習(xí)過程中造輪子絕對是對自己百利而無一害的!造輪子是一種特別能夠提高自己系統(tǒng)編程能力的手段忿危。
今天就分享幾個我常用的開源工具庫达箍,希望對小伙伴們有幫助!
- OSHI[1] :一款為 Java 語言提供的基于 JNA 的(本機(jī))操作系統(tǒng)和硬件信息庫铺厨。
- EasyExcel[2] :一款快速缎玫、簡單避免 OOM 的 java 處理 Excel 工具。
- Hutool[3] : 一個非常實用的 Java 工具類庫解滓,對文件赃磨、流、加密解密洼裤、轉(zhuǎn)碼邻辉、正則、線程腮鞍、XML 等 JDK 方法進(jìn)行了封裝值骇。
以下是較為詳細(xì)一點的介紹,建議小伙伴們看完移国,方便自己快速上手吱瘩,用在自己的項目中來提高生產(chǎn)效率。
介紹
OSHI 是一款為 Java 語言提供的基于 JNA 的(本機(jī))操作系統(tǒng)和硬件信息庫。
JNA(Java Native Access)[4]是一個開源的 Java 框架裹芝,是 Sun 公司推出的一種調(diào)用本地方法的技術(shù)部逮,是建立在經(jīng)典的 JNI 基礎(chǔ)之上的一個框架。之所以說它是 JNI 的替代者嫂易,是因為 JNA 大大簡化了調(diào)用本地方法的過程兄朋,使用很方便,基本上不需要脫離 Java 環(huán)境就可以完成怜械。
JNI(Java Native Interface) 是 JDK 提供的一個編程接口颅和,它允許 Java 程序調(diào)用其他語言編寫的程序或者代碼庫,其實 JDK 本身的實現(xiàn)也大量用到 JNI 技術(shù)來調(diào)用本地 C 程序庫缕允。
通過 OSHI 峡扩,我們不需要安裝任何其他本機(jī)庫,就能查看內(nèi)存和 CPU 使用率障本、磁盤和分區(qū)使用情況教届、設(shè)備响鹃、傳感器等信息。
OSHI 旨在提供一種跨平臺的實現(xiàn)來檢索系統(tǒng)信息案训,支持 Windows买置、Linux、MacOS强霎、Unix 等主流操作系統(tǒng)忿项。
官方是這樣介紹 oshi 答:(翻譯 Chrome 插件:Mate Translate):
使用 oshi 你可以輕松制作出項目常用的系統(tǒng)監(jiān)控功能轩触,如下圖所示:
引入依賴
Maven
<!-- https://mvnrepository.com/artifact/com.github.oshi/oshi-core -->
<dependency>
<groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId>
<version>5.2.5</version>
</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 之后怕膛,我們就可以獲取硬件相關(guān)的信息了!
下面簡單演示一下獲取內(nèi)存和 CPU 相關(guān)信息秦踪。
1.獲取內(nèi)存相關(guān)信息
//內(nèi)存相關(guān)信息
GlobalMemory memory = hal.getMemory();
//獲取內(nèi)存總?cè)萘?String totalMemory = FormatUtil.formatBytes(memory.getTotal());
//獲取可用內(nèi)存的容量
String availableMemory = FormatUtil.formatBytes(memory.getAvailable());
有了內(nèi)存總?cè)萘亢蛢?nèi)存可用容量,你就可以計算出當(dāng)前內(nèi)存的利用率了掸茅。
2.獲取 CPU 相關(guān)信息
//CPU相關(guān)信息
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)雅景馁,并且非常耗內(nèi)存,嚴(yán)重時會導(dǎo)致內(nèi)存溢出逗鸣。
怎么解決這個問題呢合住?
推薦你使用阿里開源的 EasyExcel。正如這個項目官網(wǎng)介紹的那樣撒璧,這是一款快速透葛、簡單避免 OOM 的 java 處理 Excel 工具。
官方是這樣介紹 EasyExcel 答:
引入依賴
Maven
<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.6</version>
</dependency>
Gradle
// https://mvnrepository.com/artifact/com.alibaba/easyexcel
compile group: 'com.alibaba', name: 'easyexcel', version: '2.2.6'
功能演示
這里直接分享官方提供讀取 Excel 的例子(在實際項目中我對這部分做了簡單的封裝,涉及的地方比較多繁调,就不分享出來了)萨蚕。
實體對象 (Excel 導(dǎo)入導(dǎo)出實體對象)
@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可以構(gòu)造方法傳進(jìn)去
public class DemoDataListener extends AnalysisEventListener<DemoData> {
private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class);
/**
* 每隔5條存儲數(shù)據(jù)庫蹄胰,實際使用中可以3000條岳遥,然后清理list ,方便內(nèi)存回收
*/
private static final int BATCH_COUNT = 5;
List<DemoData> list = new ArrayList<DemoData>();
/**
* 假設(shè)這個是一個DAO裕寨,當(dāng)然有業(yè)務(wù)邏輯這個也可以是一個service浩蓉。當(dāng)然如果不用存儲這個對象沒用。 */
private DemoDAO demoDAO;
public DemoDataListener() {
// 這里是demo,所以隨便new一個妻往。實際使用如果到了spring,請使用下面的有參構(gòu)造函數(shù)
demoDAO = new DemoDAO();
}
/**
* 如果使用了spring,請使用這個構(gòu)造方法互艾。每次創(chuàng)建Listener的時候需要把spring管理的類傳進(jìn)來 * * @param demoDAO */
public DemoDataListener(DemoDAO demoDAO) {
this.demoDAO = demoDAO;
}
/**
* 這個每一條數(shù)據(jù)解析都會來調(diào)用 * * @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);
// 達(dá)到BATCH_COUNT了,需要去存儲一次數(shù)據(jù)庫讯泣,防止數(shù)據(jù)幾萬條數(shù)據(jù)在內(nèi)存纫普,容易OOM
if (list.size() >= BATCH_COUNT) {
saveData();
// 存儲完成清理 list
list.clear();
}
}
/**
* 所有數(shù)據(jù)解析完成了 都會來調(diào)用
*
* @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 來做都行)
/**
* 假設(shè)這個是你的DAO存儲假栓。當(dāng)然還要這個類讓spring管理,當(dāng)然你不用需要存儲霍掺,也不需要這個類匾荆。
**/
public class DemoDAO {
public void save(List<DemoData> list) {
// 如果是mybatis,盡量別直接調(diào)用多次insert,自己寫一個mapper里面新增一個方法batchInsert,所有數(shù)據(jù)一次性插入
System.out.println(list);
}
}
讀取數(shù)據(jù)
String fileName = "src/test/resources/demo/demo.xlsx";
// 這里 需要指定讀用哪個class去讀,然后讀取第一個sheet 文件流會自動關(guān)閉
EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();
輸出結(jié)果 (已過濾非必要數(shù)據(jù))
Hutool2020-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 工具類庫尚困,對文件蠢箩、流、加密解密事甜、轉(zhuǎn)碼谬泌、正則、線程逻谦、XML 等 JDK 方法進(jìn)行了封裝掌实。
非常實用的開源工具類庫,推薦小伙伴們在自己項目中使用邦马。
官方是這樣介紹 Hutool 答:
引入依賴
Maven
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.4.2</version>
</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ù)庫蛾扇,并在緩存中保存一份攘烛。
如果不想自定義配置的話,直接在配置文件中把郵箱配置寫死就行了镀首。
有了郵件的相關(guān)配置之后坟漱,定義郵件服務(wù)器之后即可發(fā)送郵件,非常方便:
MailAccount account = new MailAccount();
account.setHost("smtp.yeah.net");
account.setPort("25");
account.setAuth(true);
account.setFrom("hutool@yeah.net");
account.setUser("hutool");
account.setPass("q1w2e3");
MailUtil.send(account, CollUtil.newArrayList("hutool@foxmail.com"), "測試", "郵件來自Hutool測試", false);
唯一 ID
在分布式環(huán)境中更哄,唯一 ID 生成應(yīng)用十分廣泛芋齿,生成方法也多種多樣,Hutool 針對一些常用生成策略做了簡單封裝竖瘾。
Hutool 提供的唯一 ID 生成器的工具類捕传,涵蓋了:
- UUID
- ObjectId(MongoDB)
- Snowflake(Twitter)
拿 UUID 舉例!
Hutool 重寫java.util.UUID的邏輯扩劝,對應(yīng)類為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.get
- HttpUtil.post
// 最簡單的HTTP請求,可以自動通過header等信息判斷編碼趋观,不區(qū)分HTTP和HTTPS
String result1 = HttpUtil.get("https://www.baidu.com");
// 當(dāng)無法識別頁面編碼的時候扛禽,可以自定義請求頁面的編碼
String result2 = HttpUtil.get("https://www.baidu.com", CharsetUtil.CHARSET_UTF_8);
//可以單獨傳入http參數(shù),這樣參數(shù)會自動做URL編碼皱坛,拼接在URL中
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("city", "北京");
String result3 = HttpUtil.get("https://www.baidu.com", paramMap);
緩存
Hutool 提供了常見的幾種緩存策略的實現(xiàn):
- FIFO(first in first out) :先進(jìn)先出策略编曼。
- LFU(least frequently used) :最少使用率策略。
- LFU(least frequently used) :最少使用率策略剩辟。
- 定時緩存 :對被緩存的對象定義一個過期時間掐场,當(dāng)對象超過過期時間會被清理往扔。
- ......
FIFO(first in first out) 策略緩存使用:
Cache<String,String> fifoCache = CacheUtil.newFIFOCache(3);
//加入元素,每個元素可以設(shè)置其過期時長熊户,DateUnit.SECOND.getMillis()代表每秒對應(yīng)的毫秒數(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,當(dāng)加入第四個元素的時候嚷堡,根據(jù)FIFO規(guī)則蝗罗,最先放入的對象將被移除
fifoCache.put("key4", "value4", DateUnit.SECOND.getMillis() * 3);
//value1為null
String value1 = fifoCache.get("key1");
控制臺打印封裝-Console
一般情況下,我們打印信息到控制臺小伙伴們應(yīng)該再熟悉不過了麦到!
System.out.println("Hello World");
但是绿饵,這種方式不滿足很多場景的需要:
- 不支持參數(shù),對象打印需要拼接字符串
- 不能直接打印數(shù)組瓶颠,需要手動調(diào)用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.