https://www.hoshino.asia/archives/hutool

概述

由来

由于Hutool的原则是不依赖于其它配置文件,但是很多时候我们需要针对第三方非常棒的库做一些工具类化的支持,因此Hutoo-extra包主要用于支持第三方库的工具类。

介绍

现阶段扩展包括:

模板引擎封装工具类

Servlet封装

Jsch库封装(SSH和Sftp)

Apache Commons Net封装(FTP部分)

邮件封装

Zxing封装(二维码)

Servlet工具-ServletUtil

由来

最早Servlet相关的工具并不在Hutool的封装考虑范围内,但是后来很多人提出需要一个Servlet Cookie工具,于是我决定建立ServletUtil,这样工具的使用范围就不仅限于Cookie,还包括参数等等。

其实最早的Servlet封装来自于作者的一个MVC框架:Hulu,这个MVC框架对Servlet做了一层封装,使请求处理更加便捷。于是Hutool将Hulu中Request类和Response类中的方法封装于此。

使用

加入依赖

<dependency>
	<groupId>javax.servlet</groupId>
	<artifactId>javax.servlet-api</artifactId>
	<version>${servlet-api.version}</version>
	<!-- 此包一般在Servlet容器中都有提供 -->
	<scope>provided</scope>
</dependency>

方法

  • getParamMap 获得所有请求参数

  • fillBean 将请求参数转为Bean

  • getClientIP 获取客户端IP,支持从Nginx头部信息获取,也可以自定义头部信息获取位置

  • getHeadergetHeaderIgnoreCase 获得请求header中的信息

  • isIE 客户浏览器是否为IE

  • isMultipart 是否为Multipart类型表单,此类型表单用于文件上传

  • getCookie 获得指定的Cookie

  • readCookieMap 将cookie封装到Map里面

  • addCookie 设定返回给客户端的Cookie

  • write 返回数据给客户端

  • setHeader 设置响应的Header

二维码工具-QrCodeUtil

由来

由于大家对二维码的需求较多,对于二维码的生成和解析我认为应该作为简单的工具存在于Hutool中。考虑到自行实现的难度,因此Hutool针对被广泛接受的zxing库进行封装。而由于涉及第三方包,因此归类到extra模块中。

使用

引入zxing

考虑到Hutool的非强制依赖性,因此zxing需要用户自行引入:

<dependency>
	<groupId>com.google.zxing</groupId>
	<artifactId>core</artifactId>
	<version>${zxing.version}</version>
</dependency>

说明 zxing-3.5.1是此文档编写时的最新版本,理论上你引入的版本应与此版本一致或比这个版本新。

生成二维码

在此我们将Hutool主页的url生成为二维码,微信扫一扫可以看到H5主页哦:

// 生成指定url对应的二维码到文件,宽和高都是300像素
QrCodeUtil.generate("https://hutool.cn/", 300, 300, FileUtil.file("d:/qrcode.jpg"));

效果qrcode.jpg:

自定义参数(since 4.1.2)

  1. 基本参数设定

通过QrConfig可以自定义二维码的生成参数,例如长、宽、二维码的颜色、背景颜色、边距等参数,使用方法如下:

QrConfig config = new QrConfig(300, 300);
// 设置边距,即二维码和背景之间的边距
config.setMargin(3);
// 设置前景色,即二维码颜色(青色)
config.setForeColor(Color.CYAN.getRGB());
// 设置背景色(灰色)
config.setBackColor(Color.GRAY.getRGB());

// 生成二维码到文件,也可以到流
QrCodeUtil.generate("http://hutool.cn/", config, FileUtil.file("e:/qrcode.jpg"));

效果qrcode.jpg:

qrcodeCustom.jpg

  1. 附带logo小图标

QrCodeUtil.generate(//
	"http://hutool.cn/", //二维码内容
	QrConfig.create().setImg("e:/logo_small.jpg"), //附带logo
	FileUtil.file("e:/qrcodeWithLogo.jpg")//写出到的文件
);

效果如图:

qrcodeWithLogo.jpg

  1. 调整纠错级别

很多时候,二维码无法识别,这时就要调整纠错级别。纠错级别使用zxing的ErrorCorrectionLevel枚举封装,包括:L、M、Q、H几个参数,由低到高。低级别的像素块更大,可以远距离识别,但是遮挡就会造成无法识别。高级别则相反,像素块小,允许遮挡一定范围,但是像素块更密集。

QrConfig config = new QrConfig();
// 高纠错级别
config.setErrorCorrection(ErrorCorrectionLevel.H);
QrCodeUtil.generate("https://hutool.cn/", config, FileUtil.file("e:/qrcodeCustom.jpg"));

效果如图:

qrcodeH.jpg

识别二维码

// decode -> "http://hutool.cn/"
String decode = QrCodeUtil.decode(FileUtil.file("d:/qrcode.jpg"));

生成SVG矢量图二维码(since 5.8.6)

QrConfig qrConfig = QrConfig.create().setImg("d:/test/logo.png")
				.setForeColor(Color.blue)
				.setBackColor(Color.pink)
				.setRatio(8)
				.setErrorCorrection(ErrorCorrectionLevel.M)
				.setMargin(1);
		String svg = QrCodeUtil.generateAsSvg("https://hutool.cn/", qrConfig);

效果如图:

hutool_qr.png

生成Ascii Art字符画二维码(sincec 5.8.6)

QrConfig qrConfig = QrConfig.create()
				.setForeColor(Color.BLUE)
				.setBackColor(Color.MAGENTA)
				.setWidth(0)
				.setHeight(0).setMargin(1);
		String asciiArt = QrCodeUtil.generateAsAsciiArt("https://hutool.cn/",qrConfig);

生成的二维码字符画文本:

█▀▀▀▀▀▀▀█▀█▀█▀█▀█▀█▀▀▀▀▀▀▀█
█ █▀▀▀█ █▀▄▀▄ ▄▀ ▀█ █▀▀▀█ █
█ █   █ █▀█▄█▄▄▀▄ █ █   █ █
█ ▀▀▀▀▀ █▀█ █ ▄▀▄▀█ ▀▀▀▀▀ █
██▀██▀█▀██▄▄▄▀█ ▄▀▀██▀█▀█▀█
█▄▀▀  ▀▀ ▀▄▀█ ▀▀▀█████▀ ▀ █
█ ▄▄▀ ▄▀███▀ █▄█▄▀  ▀▄▄█▄▀█
██▀ ▀▀█▀█▄ ▀▄▀█▄██▄▀ ▀▀▄███
█ ▄▄▄▄█▀█▀  ▀█▀ ▀▀▀ ▀   ▄ █
█▀▀▀▀▀▀▀██▀  █▄ ▀ █▀█ █ █▄█
█ █▀▀▀█ █▀▀█▄▄▀█▄ ▀▀▀  █▀▀█
█ █   █ ███▄█▀█▄█▀█▄▄▀█▄▄▄█
█ ▀▀▀▀▀ █▄▄█   ▀█▀▄  ██▀▀ █
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀

打印到控制台的效果:

asscii_art_qr.png

邮件工具-MailUtil

概述

在Java中发送邮件主要依靠javax.mail包,但是由于使用比较繁琐,因此Hutool针对其做了封装。由于依赖第三方包,因此将此工具类归类到extra模块中。

使用

引入依赖

Hutool对所有第三方都是可选依赖,因此在使用MailUtil时需要自行引入第三方依赖。

<dependency>
	<groupId>com.sun.mail</groupId>
	<artifactId>javax.mail</artifactId>
	<version>${mail.version}</version>
</dependency>

说明 com.sun.mail是javax.mail升级后的版本,新版本包名做了变更。

邮件服务器配置

在classpath(在标准Maven项目中为src/main/resources)的config目录下新建mail.setting文件,最小配置内容如下,在此配置下,smtp服务器和用户名都将通过from参数识别:

# 发件人(必须正确,否则发送失败)
from = hutool@yeah.net
# 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助)
pass = q1w2e3

有时候一些非标准邮箱服务器(例如企业邮箱服务器)的smtp地址等信息并不与发件人后缀一致,端口也可能不同,此时Hutool可以提供完整的配置文件:

完整配置

# 邮件服务器的SMTP地址,可选,默认为smtp.<发件人邮箱后缀>
host = smtp.yeah.net
# 邮件服务器的SMTP端口,可选,默认25
port = 25
# 发件人(必须正确,否则发送失败)
from = hutool@yeah.net
# 用户名,默认为发件人邮箱前缀
user = hutool
# 密码(注意,某些邮箱需要为SMTP服务单独设置授权码,详情查看相关帮助)
pass = q1w2e3

注意
邮件服务器必须支持并打开SMTP协议,详细请查看相关帮助说明
配置文件的样例中提供的是我专门为测试邮件功能注册的yeah.net邮箱,帐号密码公开,供Hutool用户测试使用

发送邮件

  1. 发送普通文本邮件,最后一个参数可选是否添加多个附件:

MailUtil.send("hutool@foxmail.com", "测试", "邮件来自Hutool测试", false);
  1. 发送HTML格式的邮件并附带附件,最后一个参数可选是否添加多个附件:

MailUtil.send("hutool@foxmail.com", "测试", "<h1>邮件来自Hutool测试</h1>", true, FileUtil.file("d:/aaa.xml"));
  1. 群发邮件,可选HTML或普通文本,可选多个附件:

ArrayList<String> tos = CollUtil.newArrayList(
	"person1@bbb.com", 
	"person2@bbb.com", 
	"person3@bbb.com", 
	"person4@bbb.com");

MailUtil.send(tos, "测试", "邮件来自Hutool群发测试", false);

发送邮件非常简单,只需一个方法即可搞定其中按照参数顺序说明如下:

  1. tos: 对方的邮箱地址,可以是单个,也可以是多个(Collection表示)

  2. subject:标题

  3. content:邮件正文,可以是文本,也可以是HTML内容

  4. isHtml: 是否为HTML,如果是,那参数3识别为HTML内容

  5. files: 可选:附件,可以为多个或没有,将File对象加在最后一个可变参数中即可

其它

  1. 自定义邮件服务器

除了使用配置文件定义全局账号以外,MailUtil.send方法同时提供重载方法可以传入一个MailAccount对象,这个对象为一个普通Bean,记录了邮件服务器信息。

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);
  1. 使用SSL加密方式发送邮件 在使用QQ或Gmail邮箱时,需要强制开启SSL支持,此时我们只需修改配置文件即可:

# 发件人(必须正确,否则发送失败),“小磊”可以任意变更,<>内的地址必须唯一,以下方式也对
# from = hutool@yeah.net
from = 小磊<hutool@yeah.net>
# 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助)
pass = q1w2e3
# 使用SSL安全连接
sslEnable = true

在原先极简配置下只需加入sslEnable即可完成SSL连接,当然,这是最简单的配置,很多参数根据已有参数已设置为默认。

完整的配置文件如下:

# 邮件服务器的SMTP地址
host = smtp.yeah.net
# 邮件服务器的SMTP端口
port = 465
# 发件人(必须正确,否则发送失败)
from = hutool@yeah.net
# 用户名(注意:如果使用foxmail邮箱,此处user为qq号)
user = hutool
# 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助)
pass = q1w2e3
#使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。
starttlsEnable = true

# 使用SSL安全连接
sslEnable = true
# 指定实现javax.net.SocketFactory接口的类的名称,这个类将被用于创建SMTP的套接字
socketFactoryClass = javax.net.ssl.SSLSocketFactory
# 如果设置为true,未能创建一个套接字使用指定的套接字工厂类将导致使用java.net.Socket创建的套接字类, 默认值为true
socketFactoryFallback = true
# 指定的端口连接到使用的套接字工厂。如果没有设置,将使用默认端口465
socketFactoryPort = 465

# SMTP超时时长,单位毫秒,缺省值不超时
timeout = 0
# Socket连接超时值,单位毫秒,缺省值不超时
connectionTimeout = 0
  1. 针对QQ邮箱和Foxmail邮箱的说明

(1) QQ邮箱中SMTP密码是单独生成的授权码,而非你的QQ密码,至于怎么生成,见腾讯的帮助说明:什么是授权码,它又是如何设置?

使用帮助引导生成授权码后,配置如下即可:

pass = 你生成的授权码

(2) Foxmail邮箱本质上也是QQ邮箱的一种别名,你可以在你的QQ邮箱中设置一个foxmail邮箱,不过配置上有所区别。在Hutool中user属性默认提取你邮箱@前面的部分,但是对于foxmail邮箱是无效的,需要单独配置为与之绑定的qq号码或者XXXX@qq.comXXXX。即:

host = smtp.qq.com
from = XXXX@foxmail.com
user = foxmail邮箱对应的QQ号码或者qq邮箱@前面部分
...

(3) 阿里云邮箱的user是邮箱的完整地址,即xxx@aliyun.com

  1. 针对QQ邮箱(foxmail)PKIX path building failed错误(since 5.6.4)

部分用户反馈发送邮件时会遇到错误:

cn.hutool.extra.mail.MailException: MessagingException: Could not connect to SMTP host: smtp.qq.com, port: 465
...
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

这个错误可能是需要SSL验证造成的,我们可以手动跳过这个验证:

MailAccount mailAccount = new MailAccount();
mailAccount.setAuth(true);
mailAccount.setSslEnable(true);
...
MailSSLSocketFactory sf = new MailSSLSocketFactory();
sf.setTrustAllHosts(true);
mailAccount.setCustomProperty("mail.smtp.ssl.socketFactory", sf);

Mail mail = Mail.create(mailAccount)
    .setTos("xx@xx.com")
	.setTitle("邮箱验证")
	.setContent("您的验证码是:<h3>2333</h3>")
	.setHtml(true)
	.send();

cglib

Cglib工具-CglibUtil

介绍

CGLib (Code Generation Library) 是一个强大的,高性能,高质量的Code生成类库,通过此库可以完成动态代理、Bean拷贝等操作。

Hutool在5.4.1之后加入对Cglib的封装——CglibUtil,用于解决Bean拷贝的性能问题。

使用

引入Cglib

<dependency>
	<groupId>cglib</groupId>
	<artifactId>cglib</artifactId>
	<version>${cglib.version}</version>
	<scope>compile</scope>
</dependency>

使用

  1. Bean拷贝

首先我们定义两个Bean:

@Data
public class SampleBean {
	private String value;
}
@Data
public class OtherSampleBean {
	private String value;
}

@Data是Lombok的注解,请自行补充get和set方法,或者引入Lombok依赖

SampleBean bean = new SampleBean();
bean.setValue("Hello world");

OtherSampleBean otherBean = new OtherSampleBean();

CglibUtil.copy(bean, otherBean);

// 值为"Hello world"
otherBean.getValue();

当然,目标对象也可以省略,你可以传入一个class,让Hutool自动帮你实例化它:

OtherSampleBean otherBean2 = CglibUtil.copy(bean, OtherSampleBean.class);

// 值为"Hello world"
otherBean.getValue();

关于性能

Cglib的性能是目前公认最好的,其时间主要耗费在BeanCopier创建上,因此,Hutool根据传入Class不同,缓存了BeanCopier对象,使性能达到最好。

emoji

Emoji工具-EmojiUtil

由来

考虑到MySQL等数据库中普通的UTF8编码并不支持Emoji(只有utf8mb4支持),因此对于数据中的Emoji字符进行处理(转换、清除)变成一项必要工作。因此Hutool基于emoji-java库提供了Emoji工具实现。

此工具在Hutoo-4.2.1之后版本可用。

使用

加入依赖

<dependency>
	<groupId>com.vdurmont</groupId>
	<artifactId>emoji-java</artifactId>
	<version>4.0.0</version>
</dependency>

使用

  1. 转义Emoji字符

String alias = EmojiUtil.toAlias("😄");//:smile:
  1. 将转义的别名转为Emoji字符

String emoji = EmojiUtil.toUnicode(":smile:");//😄
  1. 将字符串中的Unicode Emoji字符转换为HTML表现形式

String alias = EmojiUtil.toHtml("😄");//&#128102;

FTP

FTP客户端封装-Ftp

介绍

FTP客户端封装,此客户端基于Apache Commons Net

使用

引入依赖

<dependency>
	<groupId>commons-net</groupId>
	<artifactId>commons-net</artifactId>
	<version>${net.version}</version>
</dependency>

使用

//匿名登录(无需帐号密码的FTP服务器)
Ftp ftp = new Ftp("172.0.0.1");
//进入远程目录
ftp.cd("/opt/upload");
//上传本地文件
ftp.upload("/opt/upload", FileUtil.file("e:/test.jpg"));
//下载远程文件
ftp.download("/opt/upload", "test.jpg", FileUtil.file("e:/test2.jpg"));

//关闭连接
ftp.close();

主动模式与被动模式

  • PORT(主动模式)

FTP客户端连接到FTP服务器的21端口,发送用户名和密码登录,登录成功后要list列表或者读取数据时,客户端随机开放一个端口(1024以上),发送 PORT命令到FTP服务器,告诉服务器客户端采用主动模式并开放端口;FTP服务器收到PORT主动模式命令和端口号后,通过服务器的20端口和客户端开放的端口连接,发送数据。

  • PASV(被动模式)

FTP客户端连接到FTP服务器的21端口,发送用户名和密码登录,登录成功后要list列表或者读取数据时,发送PASV命令到FTP服务器, 服务器在本地随机开放一个端口(1024以上),然后把开放的端口告诉客户端, 客户端再连接到服务器开放的端口进行数据传输。

更多介绍见:https://www.cnblogs.com/huhaoshida/p/5412615.html

Ftp中默认是被动模式,需要切换则:

Ftp ftp = new Ftp("172.0.0.1");

//切换为主动模式
ftp.setMode(FtpMode.Active);

简易FTP服务器-SimpleFtpServer

介绍

Hutool基于 [Apache FtpServer](http://mina.apache.org/ftpserver-project/)封装了一个简易的FTP服务端组件,主要用于在一些测试场景或小并发应用场景下使用。

使用

引入FtpServer

<dependency>
	<groupId>org.apache.ftpserver</groupId>
	<artifactId>ftpserver-core</artifactId>
	<version>1.1.1</version>
</dependency>

使用

  • 开启匿名FTP服务:

SimpleFtpServer
	.create()
	// 此目录必须存在
	.addAnonymous("d:/test/ftp/")
	.start();

此时就可以通过资源管理器访问:

ftp://localhost
  • 自定义用户

BaseUser user = new BaseUser();
user.setName("username");
user.setPassword("123");
user.setHomeDirectory("d:/test/user/");

SimpleFtpServer
	.create()
	.addUser(user)
	.start();

Jsch封装

SFTP封装-Sftp

介绍

SFTP是Secure File Transfer Protocol的缩写,安全文件传送协议。可以为传输文件提供一种安全的加密方法。

SFTP 为 SSH的一部份,是一种传输文件到服务器的安全方式。SFTP是使用加密传输认证信息和数据,所以,使用SFTP是非常安全的。

但是,由于这种传输方式使用了加密/解密技术,所以传输效率比普通的FTP要低得多,如果您对网络安全性要求更高时,可以使用SFTP代替FTP。

使用

引入jsch

<dependency>
	<groupId>com.jcraft</groupId>
	<artifactId>jsch</artifactId>
	<version>${jsch.version}</version>
</dependency>

使用

Sftp sftp= JschUtil.createSftp("172.0.0.1", 22, "root", "123456");
//进入远程目录
sftp.cd("/opt/upload");
//上传本地文件
sftp.put("e:/test.jpg", "/opt/upload");
//下载远程文件
sftp.get("/opt/upload/test.jpg", "e:/test2.jpg");

//关闭连接
sftp.close();

Jsch工具-JschUtil

由来

此工具最早来自于我的早期项目:Common-tools,当时是为了解决在存在堡垒机(跳板机)环境时无法穿透堡垒机访问内部主机端口问题,于是辗转找到了jsch库。为了更加便捷的、且容易理解的方式使用此库,因此有了JschUtil

使用

引入jsch

<dependency>
	<groupId>com.jcraft</groupId>
	<artifactId>jsch</artifactId>
	<version>${jsch.version}</version>
</dependency>

说明 截止本文档撰写完毕,jsch的最新版为0.1.55,理论上应引入的版本应大于或等于此版本。

使用

ssh连接到远程主机

//新建会话,此会话用于ssh连接到跳板机(堡垒机),此处为10.1.1.1:22
Session session = JschUtil.getSession("10.1.1.1", 22, "test", "123456");

端口映射

//新建会话,此会话用于ssh连接到跳板机(堡垒机),此处为10.1.1.1:22
Session session = JschUtil.getSession("10.1.1.1", 22, "test", "123456");

// 将堡垒机保护的内网8080端口映射到localhost,我们就可以通过访问http://localhost:8080/访问内网服务了
JschUtil.bindPort(session, "172.20.12.123", 8080, 8080);

其它方法

  • generateLocalPort 生成一个本地端口(从10001开始尝试,找到一个未被使用的本地端口)

  • unBindPort 解绑端口映射

  • openAndBindPortToLocal 快捷方法,将连接到跳板机和绑定远程主机端口到本地使用一个方法搞定

  • close 关闭SSH会话

Spring

Spring工具-SpringUtil

由来

使用Spring Boot时,通过依赖注入获取bean是非常方便的,但是在工具化的应用场景下,想要动态获取bean就变得非常困难,于是Hutool封装了Spring中Bean获取的工具类——SpringUtil。

使用

注册SpringUtil

  1. 使用ComponentScan注册类

// 扫描cn.hutool.extra.spring包下所有类并注册之
@ComponentScan(basePackages={"cn.hutool.extra.spring"})
  1. 使用Import导入

@Import(cn.hutool.extra.spring.SpringUtil.class)

获取指定Bean

  1. 定义一个Bean

@Data
public static class Demo2{
	private long id;
	private String name;

	@Bean(name="testDemo")
	public Demo2 generateDemo() {
		Demo2 demo = new Demo2();
		demo.setId(12345);
		demo.setName("test");
		return demo;
	}
}
  1. 获取Bean

final Demo2 testDemo = SpringUtil.getBean("testDemo");

中文分词

中文分词封装-TokenizerUtil

介绍

现阶段,应用于搜索引擎和自然语言处理的中文分词库五花八门,使用方式各不统一,虽然有适配于Lucene和Elasticsearch的插件,但是我们想在多个库之间选择更换时,依旧有学习时间。

Hutool针对常见中文分词库做了统一接口封装,即定义一套规范,隔离各个库的差异,做到一段代码,随意更换。

Hutool现在封装的引擎有:

注意 此工具和模块从Hutool-4.4.0开始支持。

原理

类似于Java日志门面的思想,Hutool将分词引擎的渲染抽象为三个概念:

  • TokenizerEngine 分词引擎,用于封装分词库对象

  • Result 分词结果接口定义,用于抽象对文本分词的结果,实现了Iterator和Iterable接口,用于遍历分词

  • Word 表示分词中的一个词,既分词后的单词,可以获取单词文本、起始位置和结束位置等信息

通过实现这三个接口,用户便可抛开分词库的差异,实现多文本分词。

Hutool同时会通过TokenizerFactory根据用户引入的分词库的jar来自动选择用哪个库实现分词

使用

解析文本并分词

//自动根据用户引入的分词库的jar来自动选择使用的引擎
TokenizerEngine engine = TokenizerUtil.createEngine();

//解析文本
String text = "这两个方法的区别在于返回值";
Result result = engine.parse(text);
//输出:这 两个 方法 的 区别 在于 返回 值
String resultStr = CollUtil.join((Iterator<Word>)result, " ");

当你引入Ansj,会自动路由到Ansj的库去实现分词,引入HanLP则会路由到HanLP,依此类推。

也就是说,使用Hutool之后,无论你用任何一种分词库,代码不变。

自定义模板引擎

此处以HanLP为例:

TokenizerEngine engine = new HanLPEngine();

//解析文本
String text = "这两个方法的区别在于返回值";
Result result = engine.parse(text);
//输出:这 两个 方法 的 区别 在于 返回 值
String resultStr = CollUtil.join((Iterator<Word>)result, " ");

压缩

压缩封装-CompressUtil

介绍

虽然Hutool基于JDK提供了ZipUtil用于压缩或解压ZIP相关文件,但是对于7zip、tar等格式的压缩依旧无法处理,于是基于commons-compress做了进一步封装:CompressUtil

此工具支持的格式有:

对于流式压缩支持:

  • GZIP

  • BZIP2

  • XZ

  • PACK200

  • SNAPPY_FRAMED

  • LZ4_BLOCK

  • LZ4_FRAMED

  • ZSTANDARD

  • DEFLATE

对于归档文件支持:

  • AR

  • CPIO

  • JAR

  • TAR

  • ZIP

  • 7z

对于归档文件,Hutool提供了两个通用接口:

  • Archiver 数据归档,提供打包工作,如增加文件到压缩包等

  • Extractor 归档数据解包,用于解压或者提取压缩文件

使用

首先引入commons-compress

<dependency>
	<groupId>org.apache.commons</groupId>
	<artifactId>commons-compress</artifactId>
	<version>1.24</version>
</dependency>

压缩文件

我们以7Zip为例:

final File file = FileUtil.file("d:/test/compress/test.7z");
CompressUtil.createArchiver(CharsetUtil.CHARSET_UTF_8, ArchiveStreamFactory.SEVEN_Z, file)
	.add(FileUtil.file("d:/test/someFiles"));
	.finish()
	.close();

其中ArchiveStreamFactory.SEVEN_Z就是自定义的压缩格式,可以自行选择

add方法支持文件和目录,多个文件/目录多次调用add方法即可。

有时候我们不想把目录下所有的文件放到压缩包,这时候可以使用add方法的第二个参数Filter,此接口用于过滤不需要加入的文件。

CompressUtil.createArchiver(CharsetUtil.CHARSET_UTF_8, ArchiveStreamFactory.SEVEN_Z, zipFile)
	.add(FileUtil.file("d:/Java/apache-maven-3.6.3"), (file)->{
		if("invalid".equals(file.getName())){
			return false;
		}
		return true;
	})
	.finish().close();

解压文件

我们以7Zip为例:

Extractor extractor = 	CompressUtil.createExtractor(
		CharsetUtil.defaultCharset(),
		FileUtil.file("d:/test/compress/test.7z"));

extractor.extract(FileUtil.file("d:/test/compress/test2/"));

拼音

拼音工具-PinyinUtil

介绍

拼音工具类在旧版本的Hutool中在core包中,但是发现自己实现相关功能需要庞大的字典,放在core包中便是累赘。

于是为了方便,Hutool封装了拼音的门面,用于兼容以下拼音库:

  1. TinyPinyin

  2. JPinyin

  3. Pinyin4j

和其它门面模块类似,采用SPI方式识别所用的库。例如你想用Pinyin4j,只需引入jar,Hutool即可自动识别。

使用

引入库

以下为Hutool支持的拼音库的pom坐标,你可以选择任意一个引入项目中,如果引入多个,Hutool会按照以上顺序选择第一个使用。

<dependency>
	<groupId>io.github.biezhi</groupId>
	<artifactId>TinyPinyin</artifactId>
	<version>2.0.3.RELEASE</version>
</dependency>
<dependency>
	<groupId>com.belerweb</groupId>
	<artifactId>pinyin4j</artifactId>
	<version>2.5.1</version>
</dependency>
<dependency>
	<groupId>com.github.stuxuhai</groupId>
	<artifactId>jpinyin</artifactId>
	<version>1.1.8</version>
</dependency>

使用

  1. 获取拼音

// "ni hao"
String pinyin = PinyinUtil.getPinyin("你好", " ");

这里定义的分隔符为空格,你也可以按照需求自定义分隔符,亦或者使用""代表无分隔符。

  1. 获取拼音首字母

// "h, s, d, y, g"
String result = PinyinUtil.getFirstLetter("H是第一个", ", ");
  1. 自定义拼音库(拼音引擎)

Pinyin4jEngine engine = new Pinyin4jEngine();

// "ni hao h"
String pinyin = engine.getPinyin("你好h", " ");

表达式引擎

表达式引擎封装-ExpressionUtil

介绍

与模板引擎类似,Hutool针对较为流行的表达式计算引擎封装为门面模式,提供统一的API,去除差异。 现有的引擎实现有:

使用

首先引入我们需要的模板引擎,引入后,Hutool借助SPI机制可自动识别使用,我们以Aviator为例:

<dependency>
	<groupId>com.googlecode.aviator</groupId>
	<artifactId>aviator</artifactId>
	<version>5.3.3</version>
</dependency>

执行表达式

final Dict dict = Dict.create()
		.set("a", 100.3)
		.set("b", 45)
		.set("c", -199.100);

// -143.8
final Object eval = ExpressionUtil.eval("a-(b-c)", dict);

自定义引擎执行

如果项目中引入多个引擎,我们想选择某个引擎执行,则可以:

ExpressionEngine engine = new JexlEngine();

final Dict dict = Dict.create()
		.set("a", 100.3)
		.set("b", 45)
		.set("c", -199.100);

// -143.8
final Object eval = engine.eval("a-(b-c)", dict);

创建自定义引擎

引擎的核心就是实现ExpressionEngine接口,此接口只有一个方法:eval

我们实现此接口后,在项目的META-INF/services/下创建spi文件cn.hutool.extra.expression.ExpressionEngine

com.yourProject.XXXXEngine

这样就可以直接调用ExpressionUtil.eval执行表达式了。

模板引擎

模板引擎封装-TemplateUtil

介绍

随着前后端分离的流行,JSP技术和模板引擎慢慢变得不再那么重要,但是在某些场景中(例如邮件模板、页面静态化等)依旧无可替代,但是各种模板引擎语法大相径庭,使用方式也不尽相同,学习成本很高。Hutool旨在封装各个引擎的共性,使用户只关注模板语法即可,减少学习成本。

Hutool现在封装的引擎有:

原理

类似于Java日志门面的思想,Hutool将模板引擎的渲染抽象为两个概念:

  • TemplateEngine 模板引擎,用于封装模板对象,配置各种配置

  • Template 模板对象,用于配合参数渲染产生内容

通过实现这两个接口,用户便可抛开模板实现,从而渲染模板。Hutool同时会通过TemplateFactory根据用户引入的模板引擎库的jar来自动选择用哪个引擎来渲染

使用

从字符串模板渲染内容

//自动根据用户引入的模板引擎库的jar来自动选择使用的引擎
//TemplateConfig为模板引擎的选项,可选内容有字符编码、模板路径、模板加载方式等,默认通过模板字符串渲染
TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig());

//假设我们引入的是Beetl引擎,则:
Template template = engine.getTemplate("Hello ${name}");
//Dict本质上为Map,此处可用Map
String result = template.render(Dict.create().set("name", "Hutool"));
//输出:Hello Hutool

也就是说,使用Hutool之后,无论你用任何一种模板引擎,代码不变(只变更模板内容)。

从classpath查找模板渲染

只需修改TemplateConfig配置文件内容即可更换(这里以Velocity为例):

TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("templates", ResourceMode.CLASSPATH));
Template template = engine.getTemplate("velocity_test.vtl");
String result = template.render(Dict.create().set("name", "Hutool"));

其它方式查找模板

查找模板的方式由ResourceMode定义,包括:

  • CLASSPATH 从ClassPath加载模板

  • FILE 从File本地目录加载模板

  • WEB_ROOT 从WebRoot目录加载模板

  • STRING 从模板文本加载模板

  • COMPOSITE 复合加载模板(分别从File、ClassPath、Web-root、String方式尝试查找模板)

Ciallo~(∠・ω< )⌒☆