Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。
Hutool是项目中“util”包友好的替代,它节省了开发人员对项目中公用类和公用工具方法的封装时间,使开发专注于业务,同时可以最大限度的避免封装不完善带来的bug。
模块 介绍
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封装
Convert类
可以说是一个工具方法类,里面封装了针对Java常见类型的转换,用于简化类型转换。Convert类中大部分方法为toXXX,参数为Object,可以实现将任意可能的类型转换为指定类型。同时支持第二个参数defaultValue用于在转换失败时返回一个默认值。
int a = 1;
//aStr为"1"
String aStr = Convert.toStr(a);
long[] b = {1,2,3,4,5};
//bStr为:"[1, 2, 3, 4, 5]"
String bStr = Convert.toStr(b);
String[] b = { "1", "2", "3", "4" };
//结果为Integer数组
Integer[] intArray = Convert.toIntArray(b);
long[] c = {1,2,3,4,5};
//结果为Integer数组
Integer[] intArray2 = Convert.toIntArray(c);
日期转换
String str = "2012-12-12";
// 以前这样将字符串转为日期
Date parse = new SimpleDateFormat("yyyy-MM-dd").parse(str);
// 现在这样将字符串转为日期
Date date = Convert.toDate(str);
System.out.println(date);
String str1 = "2012/12/12";
Date date1 = Convert.toDate(str1);
System.out.println(date1);
集合转换
Object[] a = {"a", "你", "好", "", 1};
List<?> list = Convert.convert(List.class, a);
//从4.1.11开始可以这么用
List<?> lists = Convert.toList(a);
编码转换
String a = "我不是乱码";
//转换后result为乱码
// 将utf-8编码转为ISO_8859_1编码
String result = Convert.convertCharset(a, CharsetUtil.UTF_8, CharsetUtil.ISO_8859_1);
// 将ISO_8859_1编码转为utf-8编码
String raw = Convert.convertCharset(result, CharsetUtil.ISO_8859_1, "UTF-8");
Assert.assertEquals(raw, a);
时间转换
long a = 4535345;
//结果为:75
// 将毫秒转为秒
long minutes = Convert.convertTime(a, TimeUnit.MILLISECONDS, TimeUnit.MINUTES);
SpringUtil
在SpringBoot上加注解
@EnableSpringUtil
1、模拟HTTP请求
hutool提供了「HttpUtil」 和 「HttpRequest」 两个工具类都可用来模拟发送http请求,这两个用法大同小异这里只拿「HttpRequest」举例 「示例场景:」 在项目开发中Swagger可作为后端接口测试的良方,但在和别人对接,或使用别人提供的接口时常常需要后端自己去模拟请求发送,去校验接口
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
/**
* @author 遇见0和1
* @company lingStudy
* @create 2021-06-03 17:04
*/
@Slf4j
public class HttpTest {
/**
* putOnce:一次性Put 键值对,如果key已经存在抛出异常,如果键值中有null值,忽略
* putOpt:在键和值都为非空的情况下put到JSONObject中
*/
@Test
void postTest(){
JSONObject jsonObject = JSONUtil.createObj();// 或 JSONObject jsonObject = new JSONObject();
jsonObject.putOnce("customerTel","17563964456");
jsonObject.putOnce("remarks","备注1:我是HttpRequest测试请求!");
HttpResponse response = HttpRequest.post("http://127.0.0.1:9001/caiyun-record/saveRecord")
//设置请求头(可任意加)
.header("Content-Type", "application/json")
// 添加token
.header("Authorization","eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJ7E3NjJ9.9vgMKLpftjcXxmvViSyJDnBcXrO6c3bLlatwD83frAs")
//请求参数
.body(jsonObject.toString())
.execute();
log.info("请求响应结果:{}",response);
log.info("响应数据:{}",response.body());
}
@Test
void getTest(){
HttpResponse response = HttpRequest.get("http://127.0.0.1:9001/caiyun-record/login?paramData=I0CZZJYUBP9JixsyeDkhRnIfFgyXP-NaP1DiJ8_AWoY1eEeZN5BwF_HMSfb4wl6oE")
.execute();
log.info("get请求返回:{}",response.body());
}
}
2、JSONUtil 序列化
将一个对象序列化,也是后端开发中常遇到的,阿里以前挺火的 「fastjson」 「示例场景:」 返回给前端的token中要存对象时可将对象转为字符串,在拦截器中再将该字符串重新转为对象,若在登录后存的是该对象到session中,还可以在拦截器中通过判断session中的值是否为空,来解决「后端重启后session丢失」的问题。
//对象转字符串
String userInfoStr = JSONUtil.toJsonStr(userInfoDTO);
log.info("对象转字符串userInfoStr:{}", userInfoStr);
//生成token
String jwtToken = TokenUtil.createJwtToken(userInfoStr);
//字符串转对象
UserInfoDTO userInfo = JSONUtil.toBean(jti, UserInfoDTO.class);
request.getSession().setAttribute("userInfo",userInfo);
log.info("重设session后:{}",request.getSession().getAttribute("userInfo"));
List< Map >转List< Entity >
// HuTool
List<User> userList = JSONUtil.toList(new JSONArray(userMapList),User.class);
// 同fastjson
List<User> userList = JSON.parseObject(JSON.toJSONString(userMapList),new TypeReference<>() {});
3、BeanUtil:Map与javaBean的转换
「示例场景:」 面对POST或者一些参数较多的GET请求等,懒得新建参数对象,可用Map来接收前端传递的参数
@ApiOperation(value = "新增记录")
@ApiImplicitParams({
@ApiImplicitParam(paramType = "query", dataType = "String", name = "customerTel", value = "客户号码",required = true),
@ApiImplicitParam(paramType = "query", dataType = "String", name = "remarks", value = "备注")
})
@PostMapping("/saveRecord")
public ResultVo<Object> saveRecord(@ApiIgnore @RequestBody Map<String, Object> param){
log.info("新增登记记录 param:{}",param);
try {
HecaiyunRecord hecaiyunRecord = new HecaiyunRecord();
//将map赋值给HecaiyunRecord中与map的key对应的字段
BeanUtil.fillBeanWithMap(param,hecaiyunRecord,false);
UserInfoDTO userInfo = (UserInfoDTO) request.getSession().getAttribute("userInfo");
//用userInfo填充与hecaiyunRecord相同的字段
BeanUtils.copyProperties(userInfo,hecaiyunRecord);
//添加系统日志
sysLogService.saveSysLog(userInfo,request,"add","新增登记");
return recordService.saveRecord(hecaiyunRecord);
} catch (Exception e) {
log.error("新增登记记录失败");
e.printStackTrace();
throw new MyException(StatusEnum.ERROR);
}
}
「反过来:将 JavaBean 转为 Map」
User user = new User();
user.setAge(3);
user.setName("遇见0和1");
//将 user 转成map
Map<String, Object> map = BeanUtil.beanToMap(user);
//将userInfo对象复制给map,key保留userInfo中属性的驼峰形式不做下划线处理,不忽略userInfo中值为null的属性
BeanUtil.beanToMap(userInfo,map,false,false); //不会清空map (个人常用)
4、CaptchaUtil 生成图形验证码
「示例场景:」 图形验证码在登录时非常常见,Hutool也用几种类型的验证码,这里只举例个人常用的一种。
@ApiOperation(value = "获得图形验证码")
@GetMapping("/getCaptcha")
public void getCaptcha(HttpServletResponse response){
//生成验证码图片(定义图形的宽和高,验证码的位数,干扰线的条数)
//CircleCaptcha circleCaptcha = CaptchaUtil.createCircleCaptcha(200, 100, 4, 25);
CircleCaptcha circleCaptcha = CaptchaUtil.createCircleCaptcha(100, 50, 4, 25);
//告诉浏览器输出内容为jpeg类型的图片
response.setContentType("image/jpeg");
//禁止浏览器缓存
response.setHeader("Pragma","No-cache");
try {
ServletOutputStream outputStream = response.getOutputStream();
//图形验证码写出到流,也可以写出到文件如:circleCaptcha.write(“d:/circle25.jpeg”);
circleCaptcha.write(outputStream);
//从图形验证码图片中获取它的字符串验证码(获取字符串验证码要在图形验证码wirte写出后面才行,不然得到的值为null)
String captcha = circleCaptcha.getCode();
request.getSession().setAttribute("captcha",captcha);
log.info("生成的验证码:{}",captcha);
log.info("session id:{}",request.getSession().getId());
//关闭流
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
throw new MyException(StatusEnum.ERROR);
}
}
5、UserAgentUtil
「示例场景:」 系统操作日志里常常需要判断访问的是什么设备 「UserAgentUtil」 可以获取到服务的浏览器详细信息,也可以判断访问是不是移动设备。
//自己实现
public String isDevice(HttpServletRequest request){
String requestHeader = request.getHeader("user-agent");
//定义移动端请求的所有可能类型
String[] deviceArray = {"android", "iphone","ipod","ipad", "windows phone","mqqbrowser"};
//将字符串转换为小写
requestHeader = requestHeader.toLowerCase();
for (String device : deviceArray) {
if (requestHeader.contains(device)){
return "移动端";
}
}
return "PC端";
}
//使用UserAgentUtil
public String isDeviceHuTool(HttpServletRequest request){
String requestHeader = request.getHeader("user-agent");
UserAgent userAgent = UserAgentUtil.parse(requestHeader);
if (userAgent.isMobile()){
return "移动端";
}
return "PC端";
}
访问者的ip地址常常也是需要保存的一个数据,个人暂时没找到hutool对这个的支持,方便后面来抄作业,下面放一个搬来的获取ip的方法
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletRequest;
/**
* @author 遇见0和1
* @company lingStudy
* @create 2021-03-30 9:31
*/
@Slf4j
public class IPUtils {
/**
* 获取IP地址
*
* 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址
* 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址
*/
public static String getIpAddr(HttpServletRequest request) {
String ip = null;
try {
ip = request.getHeader("x-forwarded-for");
if (StrUtil.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (StrUtil.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (StrUtil.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (StrUtil.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StrUtil.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
} catch (Exception e) {
log.error("IPUtils ERROR:",e);
}
//对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
if(!StrUtil.isEmpty(ip) && ip.length() > 15) {
if(ip.indexOf(",") > 0) {
ip = ip.substring(0, ip.indexOf(","));
}
}
return ip;
}
}
6、FileUtil
「示例场景:」 文件上传下载在项目中也是一个常见并且重要的业务点,Hutool的「FileUtil」类对着方面也做了很好的支持。
@Value("${upload-file.img-path}")
private String imgPath;
@ApiOperation(value = "上传图片")
@PostMapping(value = "/uploadImg",headers = "content-type=multipart/form-data")
public ResultVo<Object> uploadFile(@ApiParam(value = "file") @RequestParam(value = "file" ,required = false) MultipartFile file){
if (file == null){
throw new MyException(StatusEnum.BUSINID);
}
if (!FileUtil.exist(imgPath)){
FileUtil.mkdir(imgPath);
}
//String fileName = UUID.randomUUID().toString() + "@" + multipartFile.getOriginalFilename();
log.info("原文件名:{}",file.getOriginalFilename());//包括扩展名
//文件扩展名
String suffix = Objects.requireNonNull(file.getOriginalFilename()).substring(file.getOriginalFilename().lastIndexOf(".") + 1);
String fileName = System.currentTimeMillis() + RandomUtil.randomNumbers(4) + "." +suffix;
try {
File file1 = FileUtil.writeBytes(file.getBytes(), imgPath + fileName);
log.info("file1:{}",file1);
return ResultVo.success();
} catch (IOException e) {
e.printStackTrace();
throw new MyException(StatusEnum.ERROR);
}
}
加密解密
加密分为三种:
- 「对称加密(symmetric)」:例如:AES、DES等
- 「非对称加密(asymmetric)」:例如:RSA、DSA等
- 「摘要加密(digest)」:例如:MD5、SHA-1、SHA-256、HMAC等
对常用到的算法,HuTool提供「SecureUtil」工具类用于快速实现加解密
// 对称加密
SecureUtil.aes
SecureUtil.des
// 摘要算法
SecureUtil.md5
SecureUtil.sha1
SecureUtil.hmac
SecureUtil.hmacMd5
SecureUtil.hmacSha1
// 非对称加密
SecureUtil.rsa
SecureUtil.dsa
// UUID
SecureUtil.simpleUUID 方法提供无“-”的UUID
// 密钥生成
SecureUtil.generateKey 针对对称加密生成密钥
SecureUtil.generateKeyPair 生成密钥对(用于非对称加密)
SecureUtil.generateSignature 生成签名(用于非对称加密)