SpringBoot—Hutool 之 Java开发必备基础工具

一、简单介绍

(1)简要概述

  1. Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。
  2. Hutool中的工具方法来自每个用户的精雕细琢,它涵盖了Java开发底层代码中的方方面面,它既是大型项目开发中解决小问题的利器,也是小型项目中的效率担当;
  3. Hutool是项目中 “util”包友好的替代,它节省了开发人员对项目中公用类和公用工具方法的封装时间,使开发专注于业务,同时可以最大限度的避免封装不完善带来的bug。

(2)核心组件

① hutool模块介绍
模块 介绍
hutool-aop JDK动态代理封装,提供非IOC下的切面支持
hutool-bloomFilter 布隆过滤,提供一些Hash算法的布隆过滤
hutool-cache 简单缓存实现
hutool-core 核心,包括Bean操作、日期、各种Util等
hutool-cron 定时任务模块,提供类Crontab表达式的定时任务
hutool-crypto 加密解密模块,提供对称、非对称和摘要算法封装
hutool-db JDBC封装后的数据操作,基于ActiveRecord思想
hutool-dfa 基于DFA模型的多关键字查找
hutool-extra 扩展模块,对第三方封装(模板引擎、邮件、Servlet、二维码、Emoji、FTP、分词等)
hutool-http 基于HttpUrlConnection的Http客户端封装
hutool-log 自动识别日志实现的日志门面
hutool-script 脚本执行封装,例如Javascript
hutool-setting 功能更强大的Setting配置文件和Properties封装
hutool-system 系统参数调用封装(JVM信息等)
hutool-json JSON实现
hutool-captcha 图片验证码实现
hutool-poi 针对POI中Excel和Word的封装
hutool-socket 基于Java的NIO和AIO的Socket封装
hutool-jwt JSON Web Token (JWT)封装实现

🌹 温馨提示:以根据需求对每个模块单独引入,也可以通过引入【hutool-all】方式引入所有模块。

② 常用核心处理类
工具类 解释说明
DateUtil 日期时间工具类(DateTime 日期时间对象)
ChineseDate 农历日期
LocalDateTimeUtil 本地日期时间工具类(JDK8)
TimeInterval 计时器工具类(可以计算方法或过程执行的时间。支持分组计时,方便对比时间。)
IoUtil.java IO流工具类,主要针对InputStream、OutputStream、Reader、Writer封装简化,并对NIO相关操作做封装简化。总体来说,Hutool对IO的封装,主要是工具层面,我们努力做到在便捷、性能和灵活之间找到最好的平衡点。

二、入门安装使用

(1)引入依赖

① maven 方式
<dependency>
 <groupId>cn.hutool</groupId>
 <artifactId>hutool-all</artifactId>
 <version>5.8.4</version>
</dependency>
② gradle 方式
implementation 'cn.hutool:hutool-all:5.8.4'
③ 直接下载 JAR 方式

repo1.maven.org/maven2/cn/h…

(2)使用示例

部分核心功能演示:

① 对象克隆
  1. 泛型克隆:① 实体类实现 Cloneable<T>; ② 对象调用clone方法;③ 见 testHutoolClone();
  2. 泛型克隆:① 实体类集成 CloneSupport<T>; ② 对象调用clone方法;③ 见 testHutoolClone2();
  3. 深拷贝(工具类深拷贝):① 实体类实现序列化;②直接使用 ObjectUtil.cloneByStream(obj); ② 见 testHutoolClone3();
import cn.hutool.core.clone.CloneRuntimeException;
import cn.hutool.core.clone.CloneSupport;
import cn.hutool.core.clone.Cloneable;
import cn.hutool.core.util.ObjectUtil;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.io.Serializable;
import java.util.Date;

/**
 * Hutool 工具部分功能示例
 * <pre>
 *     1.克隆功能
 *          1.1 泛型克隆:① 实体类实现 Cloneable&lt;T>; ② 对象调用clone方法;③ 见 testHutoolClone()
 *          1.2 泛型克隆:① 实体类集成 CloneSupport&lt;T>; ② 对象调用clone方法;③ 见 testHutoolClone2()
 *          1.3 深拷贝(工具类深拷贝):① 实体类实现序列化;②直接使用 ObjectUtil.cloneByStream(obj); ② 见 testHutoolClone3()
 *     2.
 * </pre>
 * @author zl
 * @date 2022-07-01 15:37
 */
public class HutoolDemo {

 public static void main(String[] args) {
 System.out.println("==============hutool 5.8.4=============");
 //testHutoolClone();
 //testHutoolClone2();
 testHutoolClone3();
 }

 private static void testHutoolClone() {
 // 初始对象
 UserEntity userEntity = UserEntity.builder().id(1).name("Drew").birthday(new Date()).build();
 // 克隆对象()
 UserEntity clone = userEntity.clone();
 // 修改克隆对象,判断是否深度克隆
 clone.setName("Mark");
 System.out.println("初始对象:" + userEntity);
 System.out.println("克隆对象(修改):" + clone);
 }

 private static void testHutoolClone2() {
 UserEntity2 userEntity2 = UserEntity2.builder().userId(2).userName("Bob").build();
 UserEntity2 clone2 = userEntity2.clone();
 clone2.setUserName("Baby");
 System.out.println("初始对象:" + userEntity2);
 System.out.println("克隆对象(修改):" + clone2);
 }

 private static void testHutoolClone3() {
 User user = User.builder().id(3).name("King").build();
 // 简化的克隆方法为  ObjectUtil.clone(obj) 也可
 User userClone = ObjectUtil.cloneByStream(user);
 userClone.setName("KingKong");
 System.out.println("初始对象:" + user);
 System.out.println("克隆对象(修改):" + userClone);
 }

}

@Data
@Builder
class UserEntity implements Cloneable<UserEntity> {
 private Integer id;
 private String name;
 private Date birthday;

 @Override
 public UserEntity clone() {
 try {
 return (UserEntity) super.clone();
 } catch (CloneNotSupportedException e) {
 throw new CloneRuntimeException(e);
 }
 }
}

@Data
@Builder
@EqualsAndHashCode(callSuper = true)
class UserEntity2 extends CloneSupport<UserEntity2> {
 private Integer userId;
 private String userName;
}

@Data
@Builder
class User implements Serializable {
 private Integer id;
 private String name;
}
② 数据类型转换
  1. 转字符串;
  2. 转日期;
  3. 转集合;
  4. 泛型转换成指定类型;
  5. 其他业务特殊需要转换;
package com.base.utils.docx;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.lang.hash.Number128;
import cn.hutool.core.util.CharsetUtil;
import lombok.Builder;
import lombok.Data;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Hutool 数据类型转换
 * <pre>
 *      1.转字符串;
 *      2.转日期;
 *      3.转集合;
 *      4.泛型转指定类型;(重点)
 *      5.其他转换;(重点)
 * </pre>
 *
 * @author zl
 * @date 2022-07-01 15:37
 */
public class HutoolDemo {

 public static void main(String[] args) {
 // 转字符串
 //testConvert();
 // 转日期
 //testConvertToDate();
 // 转集合
 //testConvertToList();
 // map转对象(重点)
 //testConvertMapToObj();
 // 泛型类型转换(重点)
 //testConvertTypeObj();
 // 其他转换(半角→全角、16进制、unicode→字符串、编码转换、金额大小写转换、时间单位转换、数字转换)
 testConvertOther();
 }

 private static void testConvertOther() {
 // 1.半角 → 全角 (//结果为:"123456789")
 String sbc = Convert.toSBC("123456789");
 System.out.println("半角 → 全角: " + sbc);
 // 1.2 全角 → 半角("123456789")
 String dbc = Convert.toDBC("123456789");
 System.out.println("全角 → 半角: " + dbc);

 // 2.1 字符串→ 16进制字符
 //结果:"e68891e698afe4b880e4b8aae5b08fe5b08fe79a84e58fafe788b1e79a84e5ad97e7aca6e4b8b2"
 System.out.println("字符串→ 16进制字符: " + Convert.toHex("我是一个小小的可爱的字符串", CharsetUtil.CHARSET_UTF_8));
 // 2.2 16进制 → 字符串
 String hex = "e68891e698afe4b880e4b8aae5b08fe5b08fe79a84e58fafe788b1e79a84e5ad97e7aca6e4b8b2";
 //结果为:"我是一个小小的可爱的字符串"(注意:在4.1.11之后hexStrToStr将改名为hexToStr)
 System.out.println("16进制 → 字符串: " + Convert.hexToStr(hex, CharsetUtil.CHARSET_UTF_8));

 // 3.1 unicode → 字符串
 //结果为:"\\u6211\\u662f\\u4e00\\u4e2a\\u5c0f\\u5c0f\\u7684\\u53ef\\u7231\\u7684\\u5b57\\u7b26\\u4e32"
 String unicode = Convert.strToUnicode("我是一个小小的可爱的字符串");
 System.out.println("字符串 → unicode:" + unicode);
 //结果为:"我是一个小小的可爱的字符串"
 System.out.println("unicode → 字符串:" + Convert.unicodeToStr(unicode));

 // 4.编码转换(注意 经过测试,UTF-8编码后用GBK解码再用GBK编码后用UTF-8解码会存在某些中文转换失败的问题。)
 // 4.1 UTF-8 👉 ISO_8859_1
 String a = "我不是乱码";
 //转换后result为乱码
 String result = Convert.convertCharset(a, CharsetUtil.UTF_8, CharsetUtil.ISO_8859_1);
 String raw = Convert.convertCharset(result, CharsetUtil.ISO_8859_1, "UTF-8");
 System.out.println("编码转换:" + Objects.equals(raw, a));

 // 5.时间单位转换
 // 5.1 微秒 👉 分钟 (结果:75)
 System.out.println("时间单位转换:" + Convert.convertTime(4535345, TimeUnit.MILLISECONDS, TimeUnit.MINUTES));

 // 6.金额大小写转换(注意 转换为大写只能精确到分(小数点儿后两位),之后的数字会被忽略。)
 // 结果为:"陆万柒仟伍佰伍拾陆元叁角贰分"
 System.out.println("两位小数数据转金额大写:" + Convert.digitToChinese(67556.32));

 // 7.数字转换
 // 7.1 数字转英文表达
 // 结果:ONE HUNDRED AND TWENTY AND CENTS TWENTY THREE ONLY
 System.out.println("数字转英文表达(>1):" + Convert.numberToWord(120.23));
 // 结果:AND CENTS ONE ONLY
 System.out.println("数字转英文表达(<1):" + Convert.numberToWord(0.01));
 // 7.2 数字简化
 System.out.println("数字简化(12000👉1.2w):" + Convert.numberToSimple(12000)); // 1.2w
 // 7.3 数字转中文
 // 一万零八百八十九点七二
 System.out.println("数字转中文:" + Convert.numberToChinese(10889.72356, false));
 // 壹万贰仟陆佰伍拾叁
 System.out.println("金额大写:" + Convert.numberToChinese(12653, true));
 // 7.4 数字中文表示转换为数字
 System.out.println("数字中文表示转换为数字: " + Convert.chineseToNumber("一千零八十二"));// 1082

 // 8.原始类和包装类转换
 //去包装(结果为:int.class)
 Class<?> unWraped = Convert.unWrap(Integer.class);
 //包装(结果为:Long.class)
 Class<?> wraped = Convert.wrap(long.class);
 System.out.println(unWraped + " ------ " + wraped);
 }

 /**
 * 将复合类型的数组转换成指定同一类型的集合
 */
 private static void testConvertTypeObj() {
 Object[] a = {"a", "你", "好", "", 1, true, null, Collections.emptyList(), Collections.emptyMap()};
 List<String> list = Convert.convert(new TypeReference<List<String>>() {
 }, a);
 System.out.println("复合类型集合转指定类型集合:" + list);
 }

 /**
 * 通过Convert.convert(Class<T>, Object)方法可以将任意类型转换为指定类型
 */
 private static void testConvertMapToObj() {
 Map<String, Object> userMap = new HashMap<>(2);
 userMap.put("id", 1);
 userMap.put("name", "Halen");
 userMap.put("remark", "此map-key不存在于 user属性上,判断是否能赚成功?丢失映射,映射失败");

 User user = Convert.convert(User.class, userMap);
 System.out.println("map 👉 obj" + user);
 }

 private static void testConvertToTypeArr() {
 //结果为Integer数组
 Integer[] intArray = Convert.toIntArray(new String[]{"1", "2", "3", "4"});
 //结果为Integer数组
 Integer[] intArray2 = Convert.toIntArray(new Integer[]{1, 2, 3, 4, 5});
 }

 private static void testConvertToList() {
 // 1.纯数字数组转集合  [1, 2, 3, 4]
 System.out.println("数字数组 👉 集合:" + Convert.toList(new Integer[]{1, 2, 3, 4}));
 // 2.纯字符数组转集合  [one, two, three]
 System.out.println("字符数组 👉 集合:" + Convert.toList(new String[]{"one", "two", "three"}));
 // 3.对象数组转集合  [true, null, [], 1, {}, hi]
 System.out.println("复合集合 👉 集合:" + Convert.toList(new Object[]{true, null, Collections.emptyList(), 1, new HashMap<>(1), "hi"}));
 // 方法二:List<?> list = Convert.convert(List.class, a);
 }

 private static void testConvertToDate() {
 System.out.println("==============hutool 5.8.4 转日期=============");
 // 1.日期字符串转日期
 System.out.println("日期字符串 → 日期:" + Convert.toDate("2017-05-06"));
 // 1.1 如果字符串日期不符合日期格式,则使用默认日期进行处理
 System.out.println("转日期(转换异常使用默认值):" + Convert.toDate("2022-07-01 10:10:100", new Date()));

 // 2.date 转 localDateTime
 System.out.println("date 👉 localDateTime:" + Convert.toLocalDateTime(new Date()));
 // 2.1 date转localDateTime,带默认值
 System.out.println("date 👉 localDateTime(转换异常使用默认值):" + Convert.toLocalDateTime(new Date(), LocalDateTime.now()));

 // 3.转 LocalDateTime
 // 3.1 字符串转 LocalDateTime
 System.out.println("字符串 👉 localDatetime: " + Convert.toLocalDateTime("2017-05-06"));
 // 3.2 字符串转 LocalDateTime(转换异常使用默认值)
 System.out.println("字符串 👉 localDatetime(转换异常使用默认值): " + Convert.toLocalDateTime("2017-05-06 10:20:30", LocalDateTime.now()));
 }

 private static void testConvert() {
 System.out.println("==============hutool 5.8.4 转字符串=============");
 // 1.数字转字符串
 int num = 100_000;
 // 100000
 System.out.println("数字转字符串:" + Convert.toStr(num));

 // 2.数组转字符串
 int[] numArr = {1, 2, 3, 4, 5};
 // "[1, 2, 3, 4, 5]"
 System.out.println("数字数组转字符串:" + Convert.toStr(numArr));
 // "[1, 2, 3, 4, 5]"
 List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
 System.out.println("list集合转字符串:" + Convert.toStr(integerList));

 List<Object> objectList = Arrays.asList(null, true, "str", 0, new Arrays[]{}, 1, new HashMap<>(1));
 // "[null, true, str, 0, [Ljava.util.Arrays;@71e7a66b, 1, {}]"
 System.out.println("复合对象集合转字符串:" + Convert.toStr(objectList));

 // 3.map集合转字符串数组(set类似)
 Map<String, Integer> map1 = new HashMap<>(2);
 map1.put("one", 1);
 map1.put("two", 2);
 // "{two=2, one=1}"
 System.out.println("map转字符串:" + Convert.toStr(map1));
 }
}

@Data
@Builder
class User implements Serializable {
 private Integer id;
 private String name;
}

温馨提示:可以自定义转换策略的接口(ConverterRegistry)。

③ 日期时间
  1. Date、long、Calendar之间的相互转换;
  2. 字符串转日期;
  3. 格式化日期输出;
  4. 获取Date对象的某个部分;
  5. 开始和结束时间;
  6. 日期时间偏移;
  7. 日期时间差;
  8. 格式化时间差;
  9. 星座和属相;
  10. 其它;
//当前时间
Date date = DateUtil.date();
//当前时间
Date date2 = DateUtil.date(Calendar.getInstance());
//当前时间
Date date3 = DateUtil.date(System.currentTimeMillis());
//当前时间字符串,格式:yyyy-MM-dd HH:mm:ss
String now = DateUtil.now();
//当前日期字符串,格式:yyyy-MM-dd
String today= DateUtil.today();
【1】字符转日期

DateUtil.parse方法会自动识别一些常用格式,包括:

  • yyyy-MM-dd HH:mm:ss
  • yyyy/MM/dd HH:mm:ss
  • yyyy.MM.dd HH:mm:ss
  • yyyy年MM月dd日 HH时mm分ss秒
  • yyyy-MM-dd
  • yyyy/MM/dd
  • yyyy.MM.dd
  • HH:mm:ss
  • HH时mm分ss秒
  • yyyy-MM-dd HH:mm
  • yyyy-MM-dd HH:mm:ss.SSS
  • yyyyMMddHHmmss
  • yyyyMMddHHmmssSSS
  • yyyyMMdd
  • EEE, dd MMM yyyy HH:mm:ss z
  • EEE MMM dd HH:mm:ss zzz yyyy
  • yyyy-MM-dd'T'HH:mm:ss'Z'
  • yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
  • yyyy-MM-dd'T'HH:mm:ssZ
  • yyyy-MM-dd'T'HH:mm:ss.SSSZ

```java
Date date = DateUtil.parse("2017-03-01");
// 自定义日期格式化
Date date = DateUtil.parse("2017-03-01", "yyyy-MM-dd");
【2】格式化日期输出
Date date = DateUtil.parse("2017-03-01");
//(指定格式)结果 2017/03/01
String format = DateUtil.format(date, "yyyy/MM/dd");
//(默认格式)常用格式的格式化,结果:2017-03-01
String formatDate = DateUtil.formatDate(date);
//(自动格式化:年月日时分秒)结果:2017-03-01 00:00:00
String formatDateTime = DateUtil.formatDateTime(date);
//(自动格式化:时分秒)结果:00:00:00
String formatTime = DateUtil.formatTime(date);
【3】获取Date对象某个部分
Date date = DateUtil.date();
//获得【年的部分】
DateUtil.year(date);
//获得【月份,从0开始计数】
DateUtil.month(date);
//获得【月份枚举】
DateUtil.monthEnum(date);
【4】获取开始和结束时间
Date date = DateUtil.parse("2017-03-01 22:33:23");

//一天的开始,结果:2017-03-01 00:00:00
Date beginOfDay = DateUtil.beginOfDay(date);

//一天的结束,结果:2017-03-01 23:59:59
Date endOfDay = DateUtil.endOfDay(date);
【5】日期时间转移

日期或时间的偏移指针对某个日期增加或减少分、小时、天等等,达到日期变更的目的。Hutool也针对其做了大量封装

Date date = DateUtil.parse("2017-03-01 22:33:23");

//通用:(之后第三天)结果:2017-03-03 22:33:23
Date newDate = DateUtil.offset(date, DateField.DAY_OF_MONTH, 2);

//1.常用偏移(增加三天),结果:2017-03-04 22:33:23
DateTime newDate2 = DateUtil.offsetDay(date, 3);

//2.常用偏移(前三个小时的日期),结果:2017-03-01 19:33:23
DateTime newDate3 = DateUtil.offsetHour(date, -3);` </pre>

针对当前时间,提供了简化的偏移方法(例如昨天、上周、上个月等):
 public static void main(String[] args) {
 //当前日期为:2022-07-01 21:41:12(2022-07-01)
 System.out.println("当前日期为:" + DateUtil.date() + "(" + DateUtil.today() + ")");
 //昨天日期为:2022-06-30 21:41:12
 System.out.println("昨天日期为:" + DateUtil.yesterday());
 //明天日期为:2022-07-02 21:41:12
 System.out.println("明天日期为:" + DateUtil.tomorrow());
 //上周星期日期为:2022-06-24 21:41:12
 System.out.println("上周星期日期为:" + DateUtil.lastWeek());
 //下周星期日期为:2022-07-08 21:41:12
 System.out.println("下周星期日期为:" + DateUtil.nextWeek());
 //上月当前日期为:2022-06-01 21:41:12
 System.out.println("上月当前日期为:" + DateUtil.lastMonth());
 //下月当前日期为:2022-08-01 21:41:12
 System.out.println("下月当前日期为:" + DateUtil.nextMonth());

 // JDK8 的 LocalDate 日期工具类
 //昨天
 String yesterdayStr = LocalDate.now().minusDays(1).atStartOfDay().atZone(ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
 System.out.println("yesterdayStr = " + yesterdayStr);
 //今天
 String todayStr = LocalDate.now().atStartOfDay().atZone(ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
 System.out.println("todayStr = " + todayStr);
 //明天
 String tomorrowStr = LocalDate.now().plusDays(1).atStartOfDay().atZone(ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
 System.out.println("tomorrowStr = " + tomorrowStr);
 //上个月
 String lastMonthStr = LocalDate.now().minusMonths(1).atStartOfDay().atZone(ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
 System.out.println("lastMonthStr = " + lastMonthStr);
 //下个月
 String nextMonthStr = LocalDate.now().plusMonths(1).atStartOfDay().atZone(ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
 System.out.println("nextMonthStr = " + nextMonthStr);
 //去年
 String lastYearStr = LocalDate.now().minusYears(1).atStartOfDay().atZone(ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
 System.out.println("lastYearStr = " + lastYearStr);
 //明年
 String nextYearStr = LocalDate.now().plusYears(1).atStartOfDay().atZone(ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
 System.out.println("nextYearStr = " + nextYearStr);
}
【6】日期时间差
/**
 * 有时候我们需要计算两个日期之间的时间差(相差天数、相差小时数等等),Hutool将此类方法封装为【between方法】:
 */
private static void testPeriods() {
 // 1.计算天数
 Date date1 = DateUtil.parse("2017-03-01 22:33:23");
 Date date2 = DateUtil.parse("2017-04-01 23:33:23");
 //相差一个月,31天
 System.out.println("日期时间差: " + DateUtil.between(date1, date2, DateUnit.DAY));

 // 2.计算相隔周数
 date1 = DateUtil.parse("2022-07-01");
 date2 = DateUtil.parse("2021-07-01");
 // 相隔周数:52
 System.out.println("相隔周数:" + DateUtil.between(date1, date2, DateUnit.WEEK));
 date1 =  DateUtil.parse("2022-07-01 10:23:26");
 date2 =  DateUtil.parse("2022-07-01 12:23:26");
 // 相隔小时数:2
 System.out.println("相隔小时数:" + DateUtil.between(date1, date2, DateUnit.HOUR));
 date1 =  DateUtil.parse("2022-07-01 10:00:26");
 date2 =  DateUtil.parse("2022-07-01 12:23:26");
 // 相隔分钟数:143
 System.out.println("相隔小时数:" + DateUtil.between(date1, date2, DateUnit.MINUTE));
 // 相隔毫秒数:8580000
 System.out.println("相隔毫秒数:" + DateUtil.between(date1, date2, DateUnit.MS));
}
【7】格式化时间差
import cn.hutool.core.date.BetweenFormatter;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Console;

private static void formartBetween() {
 Date date1 = DateUtil.parse("2022-07-01 10:00:26");
 Date date2 = DateUtil.parse("2022-07-01 12:23:26");
 // 相隔分钟数:8580000
 long between = DateUtil.between(date1, date2, DateUnit.MS);
 //Level.MINUTE表示精确到分
 String formatBetween = DateUtil.formatBetween(between, BetweenFormatter.Level.MINUTE);
 // 相隔小时数:8580000(2小时23分)
 System.out.println("相隔毫秒数:" + between + "(" + formatBetween + ")");
 //输出:2小时23分
 Console.log(formatBetween);
}
【8】星座、属相、年龄、平闰年
private static void testZodiac() {
 // 1.星座 + 属相
 String zodiac = DateUtil.getZodiac(Month.JANUARY.getValue(), 19);
 String chineseZodiac = DateUtil.getChineseZodiac(1994);
 // 输出   星座:摩羯座(属相:狗)
 System.out.println("星座:" + zodiac + "(属相:" + chineseZodiac + ")");

 // 2\. 年龄 + 是否闰年
 int ageOfNow = DateUtil.ageOfNow("1990-01-30");
 int yearNo = 2017;
 boolean leapYearFlag = DateUtil.isLeapYear(yearNo);
 // 输出  今天年龄:32,2017是否为闰年?false
 System.out.println("今天年龄:" + ageOfNow + "," + yearNo + "是否为闰年?" + leapYearFlag);
}
④ 字符串工具(StrUtil.java)

这个工具的用处类似于Apache Commons Lang中的StringUtil,常用的方法例如isBlank、isNotBlank、isEmpty、isNotEmpty。

【1】hasBlank 方法

就是给定一些字符串,如果一旦有空的就返回true,常用于判断好多字段是否有空的(例如web表单数据)。

这两个方法的区别是hasEmpty只判断是否为null或者空字符串(""),hasBlank则会把不可见字符也算做空,isEmpty和isBlank同理。

【2】removePrefix 方法

这两个是去掉字符串的前缀后缀的,例如去个文件名的扩展名啥。

String fileName = StrUtil.removeSuffix("pretty_girl.jpg", ".jpg");
//fileName -> pretty_girl

还有忽略大小写的 removePrefixIgnoreCaseremoveSuffixIgnoreCase 都比较实用。

【3】sub方法

不得不提一下这个方法,有人说String有了subString你还写它干啥,我想说subString方法越界啥的都会报异常,而使用 StrUtilsub就不会报错:

String str = "abcdefgh";
String strSub1 = StrUtil.sub(str, 2, 3); //strSub1 -> c
String strSub2 = StrUtil.sub(str, 2, -3); //strSub2 -> cde
String strSub3 = StrUtil.sub(str, 3, 2); //strSub2 -> c
【4】format方法

灵感来自slf4j,可以使用字符串模板代替字符串拼接。

String template = "{}爱{},就像老鼠爱大米";
String str = StrUtil.format(template, "我", "你"); //str -> 我爱你,就像老鼠爱大米
⑤ IdUtil

在分布式环境中,唯一ID生成应用十分广泛,生成方法也多种多样,Hutool针对一些常用生成策略做了简单封装。

唯一ID生成器的工具类,涵盖了:

  • UUID
  • ObjectId(MongoDB)
  • Snowflake(Twitter)
【1】UUID

UUID全称通用唯一识别码(universally unique identifier),JDK通过java.util.UUID提供了 Leach-Salz 变体的封装。在Hutool中,生成一个UUID字符串方法如下:

//生成的UUID是带-的字符串,类似于:a5c8a5e8-df2b-4706-bea4-08d0939410e3
String uuid = IdUtil.randomUUID();

//生成的是不带-的字符串,类似于:b17f24ff026d40949c85a24f4f375d42
String simpleUUID = IdUtil.simpleUUID();

说明 Hutool重写java.util.UUID的逻辑,对应类为cn.hutool.core.lang.UUID,使生成不带-的UUID字符串不再需要做字符替换,性能提升一倍左右。

【2】ObjectId

ObjectId是MongoDB数据库的一种唯一ID生成策略,是 UUID version1 的变种,Hutool针对此封装了cn.hutool.core.lang.ObjectId,快捷创建方法为:

//生成类似:5b9e306a4df4f8c54a39fb0c
String id = ObjectId.next();

//方法2:从Hutool-4.1.14开始提供
String id2 = IdUtil.objectId();
【3】Snowflake

分布式系统中,有一些需要使用全局唯一ID的场景,有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。Twitter的Snowflake 算法就是这种生成器。使用方法如下:

//参数1为终端ID
//参数2为数据中心ID
Snowflake snowflake = IdUtil.getSnowflake(1, 1);
long id = snowflake.nextId();

//简单使用
long id = IdUtil.getSnowflakeNextId();
String id = snowflake.getSnowflakeNextIdStr();
⑥ 随机工具类(RandomUtil.java)

RandomUtil主要针对JDK中Random对象做封装,严格来说,Java产生的随机数都是伪随机数,因此Hutool封装后产生的随机结果也是伪随机结果。不过这种随机结果对于大多数情况已经够用。

RandomUtil.randomInt 获得指定范围内的随机数 例如我们想产生一个[10, 100)的随机数,则:

int c = RandomUtil.randomInt(10, 100);

RandomUtil.randomBytes 随机bytes,一般用于密码或者salt生成

byte[] c = RandomUtil.randomBytes(10);

RandomUtil.randomEle 随机获得列表中的元素。

RandomUtil.randomEleSet 随机获得列表中的一定量的不重复元素,返回Set

Set<Integer> set = RandomUtil.randomEleSet(CollUtil.newArrayList(1, 2, 3, 4, 5, 6), 2);
⑦ 对象JSON 工具(JSONUtil.java)

JSONUtil是针对JSONObject和JSONArray的静态快捷方法集合。

【1】JSON字符串创建

JSONUtil.toJsonStr可以将任意对象(Bean、Map、集合等)直接转换为JSON字符串。如果对象是有序的Map等对象,则转换后的JSON字符串也是有序的。

SortedMap<Object, Object> sortedMap = new TreeMap<Object, Object>() {
 private static final long serialVersionUID = 1L;
 {
 put("attributes", "a");
 put("b", "b");
 put("c", "c");
}};

JSONUtil.toJsonStr(sortedMap); // 输出结果:{"attributes":"a","b":"b","c":"c"}
// 如果我们想获得格式化后的JSON,则:
JSONUtil.toJsonPrettyStr(sortedMap);
//{
//    "attributes": "a",
//    "b": "b",
//    "c": "c"
//}
【2】JSON 字符串解析
String html = "{\"name\":\"Something must have been changed since you leave\"}";
JSONObject jsonObject = JSONUtil.parseObj(html);
jsonObject.getStr("name");
【3】 XML字符串转换为JSON
String s = "<sfzh>123</sfzh><sfz>456</sfz><name>aa</name><gender>1</gender>";
JSONObject json = JSONUtil.parseFromXml(s);

json.get("sfzh");
json.get("name");
【4】 JSON转换为XML
final JSONObject put = JSONUtil.createObj()
 .set("aaa", "你好")
 .set("键2", "test");

// <aaa>你好</aaa><键2>test</键2>
final String s = JSONUtil.toXmlStr(put);
【5】JSON转Bean

我们先定义两个较为复杂的Bean(包含泛型)

@Data
public class ADT {
 private List<String> BookingCode;
}

@Data
public class Price {
 private List<List<ADT>> ADT;
}
String json = "{\"ADT\":[[{\"BookingCode\":[\"N\",\"N\"]}]]}";

Price price = JSONUtil.toBean(json, Price.class);
price.getADT().get(0).get(0).getBookingCode().get(0);

当然,上面只是列举了Hutool的一部分功能,更多功能可以去它官网:www.hutool.cn查看。

总体来说,Hutool目前封装的这些工具类,确实非常好用,可以节省我们重复造轮子的时间,少写很多代码,帮助我们提升开发效率。
转自:https://juejin.cn/post/7363555404130811904

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,233评论 6 495
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,357评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,831评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,313评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,417评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,470评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,482评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,265评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,708评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,997评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,176评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,827评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,503评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,150评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,391评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,034评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,063评论 2 352

推荐阅读更多精彩内容