
我们实际项目开发中是比较忌讳造轮子的,但是,自己在学习过程中造轮子绝对是对自己百利而无一害的!造轮子是一种特别能够提高自己系统编程能力的手段。
今天就分享几个我常用的开源工具库,希望对小伙伴们有帮助!
OSHI[1] :一款为 Java 语言提供的基于 JNA 的(本机)操作系统和硬件信息库。 EasyExcel[2] :一款快速、简单避免 OOM 的 java 处理 Excel 工具。 Hutool[3] : 一个非常实用的 Java 工具类库,对文件、流、加密解密、转码、正则、线程、XML 等 JDK 方法进行了封装。以下是较为详细一点的介绍,建议小伙伴们看完,方便自己快速上手,用在自己的项目中来提高生产效率。
...
介绍
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();
输出结果 (已过滤非必要数据)
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 - 解析到一条数据:{"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("[email protected]"); account.setUser("hutool"); account.setPass("q1w2e3"); MailUtil.send(account, CollUtil.newArrayList("[email protected]"), "测试", "邮件来自Hutool测试", false);
唯一 ID
在分布式环境中,唯一 ID 生成应用十分广泛,生成方法也多种多样,Hutool 针对一些常用生成策略做了简单封装。
...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.