不要重复造轮子?提高生产效率!3个常用的开源工具库分享
我们实际项目开发中是比较忌讳造轮子的,但是,自己在学习过程中造轮子绝对是对自己百利而无一害的!造轮子是一种特别能够提高自己系统编程能力的手段。
今天就分享几个我常用的开源工具库,希望对小伙伴们有帮助!
OSHI[1] :一款为 Java 语言提供的基于 JNA 的(本机)操作系统和硬件信息库。 EasyExcel[2] :一款快速、简单避免 OOM 的 java 处理 Excel 工具。 Hutool[3] : 一个非常实用的 Java 工具类库,对文件、流、加密解密、转码、正则、线程、XML 等 JDK 方法进行了封装。
以下是较为详细一点的介绍,建议小伙伴们看完,方便自己快速上手,用在自己的项目中来提高生产效率。
oshi
介绍
OSHI 是一款为 Java 语言提供的基于 JNA 的(本机)操作系统和硬件信息库。
JNA(Java Native Access)[4]是一个开源的 Java 框架,是 Sun 公司推出的一种调用本地方法的技术,是建立在经典的 JNI 基础之上的一个框架。之所以说它是 JNI 的替代者,是因为 JNA 大大简化了调用本地方法的过程,使用很方便,基本上不需要脱离 Java 环境就可以完成。
JNI(Java Native Interface) 是 JDK 提供的一个编程接口,它允许 Java 程序调用其他语言编写的程序或者代码库,其实 JDK 本身的实现也大量用到 JNI 技术来调用本地 C 程序库。
通过 OSHI ,我们不需要安装任何其他本机库,就能查看内存和 CPU 使用率、磁盘和分区使用情况、设备、传感器等信息。
OSHI 旨在提供一种跨平台的实现来检索系统信息,支持 Windows、Linux、MacOS、Unix 等主流操作系统。
官方是这样介绍 oshi 的:(翻译 Chrome 插件:Mate Translate):
使用 oshi 你可以轻松制作出项目常用的系统监控功能,如下图所示:
引入依赖
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
:
//系统信息
SystemInfo si = new SystemInfo();
//操作系统信息
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数
int physicalPackageCount = processor.getPhysicalPackageCount();
//获取物理核心数
int physicalProcessorCount = processor.getPhysicalProcessorCount();
EasyExcel
介绍
Java 解析、生成 Excel 常用的框架有 Apache poi、jxl ,但是这两个框架使用起来都不够优雅,并且非常耗内存,严重时会导致内存溢出。
怎么解决这个问题呢?
推荐你使用阿里开源的 EasyExcel。正如这个项目官网介绍的那样,这是一款快速、简单避免 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 导入导出实体对象)
@Data
public class DemoData {
private String string;
private Date date;
private Double doubleData;
}
监听器 (自定义 AnalysisEventListener
一次读取 5 条数据存储到数据库)
// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
public class DemoDataListener extends AnalysisEventListener<DemoData> {
private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class);
/**
* 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
*/
private static final int BATCH_COUNT = 5;
List<DemoData> list = new ArrayList<DemoData>();
/**
* 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
*/
private DemoDAO demoDAO;
public DemoDataListener() {
// 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
demoDAO = new DemoDAO();
}
/**
* 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
*
* @param demoDAO
*/
public DemoDataListener(DemoDAO demoDAO) {
this.demoDAO = demoDAO;
}
/**
* 这个每一条数据解析都会来调用
*
* @param data
* one row value. Is is same as {@link AnalysisContext#readRowHolder()}
* @param context
*/
@Override
public void invoke(DemoData data, AnalysisContext context) {
LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data));
list.add(data);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (list.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
list.clear();
}
}
/**
* 所有数据解析完成了 都会来调用
*
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
LOGGER.info("所有数据解析完成!");
}
/**
* 加上存储数据库
*/
private void saveData() {
LOGGER.info("{}条数据,开始存储数据库!", list.size());
demoDAO.save(list);
LOGGER.info("存储数据库成功!");
}
}
持久层 (mybatis 或者 jpa 来做都行)
/**
* 假设这个是你的DAO存储。当然还要这个类让spring管理,当然你不用需要存储,也不需要这个类。
**/
public class DemoDAO {
public void save(List<DemoData> list) {
// 如果是mybatis,尽量别直接调用多次insert,自己写一个mapper里面新增一个方法batchInsert,所有数据一次性插入
System.out.println(list);
}
}
读取数据
String fileName = "src/test/resources/demo/demo.xlsx";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();
输出结果 (已过滤非必要数据)
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 - 解析到一条数据:{"date":1577811661000,"doubleData":1.0,"string":"字符串0"}
2020-09-16 08:14:33.870 INFO [main] com.alibaba.easyexcel.test.demo.read.DemoDataListener:54 - 解析到一条数据:{"date":1577898061000,"doubleData":2.0,"string":"字符串1"}
2020-09-16 08:14:33.871 INFO [main] com.alibaba.easyexcel.test.demo.read.DemoDataListener:54 - 解析到一条数据:{"date":1577984461000,"doubleData":3.0,"string":"字符串2"}
2020-09-16 08:14:33.871 INFO [main] com.alibaba.easyexcel.test.demo.read.DemoDataListener:54 - 解析到一条数据:{"date":1578070861000,"doubleData":4.0,"string":"字符串3"}
2020-09-16 08:14:33.872 INFO [main] com.alibaba.easyexcel.test.demo.read.DemoDataListener:54 - 解析到一条数据:{"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条数据,开始存储数据库!
[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 - 存储数据库成功!
2020-09-16 08:14:33.875 INFO [main] com.alibaba.easyexcel.test.demo.read.DemoDataListener:54 - 解析到一条数据:{"date":1578243661000,"doubleData":6.0,"string":"字符串5"}
2020-09-16 08:14:33.875 INFO [main] com.alibaba.easyexcel.test.demo.read.DemoDataListener:54 - 解析到一条数据:{"date":1578330061000,"doubleData":7.0,"string":"字符串6"}
2020-09-16 08:14:33.876 INFO [main] com.alibaba.easyexcel.test.demo.read.DemoDataListener:54 - 解析到一条数据:{"date":1578416461000,"doubleData":8.0,"string":"字符串7"}
2020-09-16 08:14:33.876 INFO [main] com.alibaba.easyexcel.test.demo.read.DemoDataListener:54 - 解析到一条数据:{"date":1578502861000,"doubleData":9.0,"string":"字符串8"}
2020-09-16 08:14:33.876 INFO [main] com.alibaba.easyexcel.test.demo.read.DemoDataListener:54 - 解析到一条数据:{"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条数据,开始存储数据库!
[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 - 存储数据库成功!
2020-09-16 08:14:33.877 INFO [main] com.alibaba.easyexcel.test.demo.read.DemoDataListener:80 - 0条数据,开始存储数据库!
[]
2020-09-16 08:14:33.877 INFO [main] com.alibaba.easyexcel.test.demo.read.DemoDataListener:82 - 存储数据库成功!
2020-09-16 08:14:33.877 INFO [main] com.alibaba.easyexcel.test.demo.read.DemoDataListener:73 - 所有数据解析完成!
Process finished with exit code 0
Hutool
介绍
Hutool 是一个非常实用的 Java 工具类库,对文件、流、加密解密、转码、正则、线程、XML 等 JDK 方法进行了封装。
非常使用的开源工具类库,推荐小伙伴们在自己项目中使用。
官方是这样介绍 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 中发送邮件主要品依靠 javax.mail
包,但是由于使用比较繁琐,因此 Hutool 针对其做了封装。由于依赖第三方包,因此将此工具类归类到 extra 模块中。
实际项目中可以自定义邮箱配置,然后让配置保存在数据库,并在缓存中保存一份。
如果不想自定义配置的话,直接在配置文件中把邮箱配置写死就行了。
有了邮件的相关配置之后,定义邮件服务器之后即可发送邮件,非常方便:
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
在分布式环境中,唯一 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.get
HttpUtil.post
// 最简单的HTTP请求,可以自动通过header等信息判断编码,不区分HTTP和HTTPS
String result1 = HttpUtil.get("https://www.baidu.com");
// 当无法识别页面编码的时候,可以自定义请求页面的编码
String result2 = HttpUtil.get("https://www.baidu.com", CharsetUtil.CHARSET_UTF_8);
//可以单独传入http参数,这样参数会自动做URL编码,拼接在URL中
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("city", "北京");
String result3 = HttpUtil.get("https://www.baidu.com", paramMap);
缓存
Hutool 提供了常见的几种缓存策略的实现:
FIFO(first in first out) :先进先出策略。 LFU(least frequently used) :最少使用率策略。 LFU(least frequently used) :最少使用率策略。 定时缓存 :对被缓存的对象定义一个过期时间,当对象超过过期时间会被清理。 ......
FIFO(first in first out) 策略缓存使用:
Cache<String,String> fifoCache = CacheUtil.newFIFOCache(3);
//加入元素,每个元素可以设置其过期时长,DateUnit.SECOND.getMillis()代表每秒对应的毫秒数,在此为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,当加入第四个元素的时候,根据FIFO规则,最先放入的对象将被移除
fifoCache.put("key4", "value4", DateUnit.SECOND.getMillis() * 3);
//value1为null
String value1 = fifoCache.get("key1");
控制台打印封装-Console
一般情况下,我们打印信息到控制台小伙伴们应该再熟悉不过了!
System.out.println("Hello World");
但是,这种方式不满足很多场景的需要:
不支持参数,对象打印需要拼接字符串 不能直接打印数组,需要手动调用 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
闲聊
其实今天本来是准备更新一篇系统设计面试指南的,毕竟系统设计几乎也是面试必问了,非常重要。 最近询问这方面问题的小伙伴比较多。
文章大概要写啥内容都构思好了,结果还是过于天真。因为涉及到的内容和知识点太多了。预计会在下周分享(如果中途没出啥状况的话)。
另外,上周日和我们大学的传奇人物,研究生在华科,目前在华为的学长聊了一会。收获确实不少,果然优秀的人总有一些过人的地方(这周六应该会把自己的所得所获分享出来)。
最近更新的一些好文章推荐:
往期推荐
文章有帮助可以点个「在看」或「分享」,都是支持,我都喜欢!
我是Guide哥,Java后端开发,会一点前端知识,喜欢烹饪,自由的少年。一个三观比主角还正的技术人。我们下期再见!