Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。

Hutool中的工具方法来自于每个用户的精雕细琢,它涵盖了Java开发底层代码中的方方面面,它既是大型项目开发中解决小问题的利器,也是小型项目中的效率担当;

Hutool是项目中“util”包友好的替代,它节省了开发人员对项目中公用类和公用工具方法的封装时间,使开发专注于业务,同时可以最大限度的避免封装不完善带来的bug。

这是官方对它的介绍,简单点说,它通过一些封装,将原来略显复杂的API进一步优化,使得你在使用的时候能够更加方便快捷,当然语法也会比原来更加简单易懂。

包含组件

一个Java基础工具类,对文件、流、加密解密、转码、正则、线程、XML等JDK方法进行封装,组成各种Util工具类,同时提供以下组件:

模块 介绍
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的封装
hutool-socket 基于Java的NIO和AIO的Socket封装

可以根据需求对每个模块单独引入,也可以通过引入hutool-all方式引入所有模块。

安装

1、Maven项目

在项目的pom.xml的dependencies中加入以下内容:

<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.0.7</version>
</dependency>

2、非Maven项目

下载地址: https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.0.7/


下载hutool-all-X.X.X.jar即可。

下面对某几个组件的使用进行一个入门。

类型转换

1、常用类型转换

在传统的类型转换过程中,我们需要使用到包装类的valueof()方法,例如:

String s = "1234";
int num = Integer.valueOf(s);
double d = Double.valueOf(s);
float f = Float.valueOf(s);

但很显然实际情况并没有这么简单,在企业级的开发项目中,从前端传递过来的参数各式各样,类型繁多,我们如何知晓参数类型并作对应的转换呢?一般会先将所有参数转成String类型,如Web中的HttpServletRequest的getParamer()方法得到的数据类型就永远是String。转成String之后再将参数转成对应的数据类型,此时还需要考虑转换异常的问题,所以通常还需要在转换代码外面使用try-catch。

为了使转换过程变得轻松愉快,HuTool为我们提供了类型转换工具——Convert。

来看看使用Convert该如何进行转换:

String s = "1234";
int num = Convert.toInt(s);
double d = Convert.toDouble(s);
float f = Convert.toFloat(s);

首先在代码风格上,Convert作了一个统一,统一使用Convert类作为工具类进行类型转换,而无需使用每个类型对应的包装类。

当然了,Convert类的作用可远不止如此,比如:

String[] s = { "1", "2", "3", "4", "5" };
Integer[] intArray = Convert.toIntArray(s);
Double[] doubleArray = Convert.toDoubleArray(s);
Float[] floatArray = Convert.toFloatArray(s);
Character[] charArray = Convert.toCharArray(s);

将数组转换为任意类型的数组。

对于集合,Convert同样支持转换:

Object[] objs= {"hello","world","java",1};
List<?> list = Convert.toList(objs);

还有日期类型:

String s = "2019-12-07";
Date date = Convert.toDate(s);

关于日期的处理,HuTool为我们提供了专门的工具类,这个我们放到后面说。

2、其它类型转换

通过Convert的convert()方法也能够实现上述的所有操作,不信我们可以试一试:

String s = "1234";
int num = Convert.convert(Integer.class, s);
double d = Convert.convert(Double.class, s);
float f = Convert.convert(Float.class, s);

关于其它类型大家可以自己试一试,总之,通过convert()方法可以将任意类型转换为指定类型,但这种方法终归是有局限的,试问一下,我们如何将一个数组转换成List类型呢?

我们可以通过一个重载方法convert( TypeReference reference, Object value ),该方法需要一个TypeReference对象参数,我们就可以创建TypeReference对象并通过嵌套泛型来指定需要转换的类型,比如:

Object[] objs = { "hello", "world", "java"};
List<String> list = Convert.convert(new TypeReference<List<String>>() {}, objs);

Convert还提供了全角与半角符号之间的转换,比如:

//将全角符转为半角符
String s = "1,2,3,4,5";
String dbc = Convert.toDBC(s);
//将半角符转为全角符
String sbc = Convert.toSBC(dbc);

可以看看运行结果,更加直观:

3、编码转换

在一些场景下,比如表单提交,会将参数进行一个简单的加密,此时通常会使用16进制转换,当然了,我们在准备16进制转换的时候也不会自己去写,都是去百度找一个现成的。不过,有了HuTool就不需要了,它为我们提供了方法用于完成16进制的转换。

String s = "你好世界";
//转换为16进制字符串
String hex = Convert.toHex(s, CharsetUtil.CHARSET_UTF_8);
//转换为普通字符串
String str = Convert.hexToStr(hex, CharsetUtil.CHARSET_UTF_8);

运行结果:

e4bda0e5a5bde4b896e7958c
你好世界

注意编码对象要相同,这里都使用UTF-8编码,所以顺逆的转换过程都是成功的,如果编码不同,在转为普通字符串的时候就会出现乱码。

还有Unicode编码和字符串的转换:

String s = "你好世界";
//转换为Unicode编码
String unicode = Convert.strToUnicode(s);
//转换为普通字符串
String str = Convert.unicodeToStr(unicode);

运行结果:

\u4f60\u597d\u4e16\u754c
你好世界

Convert类还提供了convertCharset ()用于将字符串转换为指定编码的字符串,比如在处理表单数据时通常要处理乱码问题,如下:

String s = "你好世界";
//将字符串先转成乱码
String str = Convert.convertCharset(s, CharsetUtil.UTF_8, CharsetUtil.ISO_8859_1);
//处理乱码
String result = Convert.convertCharset(str, CharsetUtil.ISO_8859_1, CharsetUtil.UTF_8);
运行结果:
????????????
你好世界
还有金额大小写转换的功能:
double money = 2019.127;
String s = Convert.digitToChinese(money);
运行结果:
贰仟零壹拾玖元壹角叁分
4、自定义类型转换
Convert类的功能是不是非常强大呢?我们继续来看,对于数据类型转换,肯定是做不到包含所有数据类型的,因为Java面向对象的特性,但是HuTool提供了自定义类型转换。
ConverterRegistry converterRegistry = ConverterRegistry.getInstance();
converterRegistry.putCustom(Person.class, CustomConverter.class);
String[] str = { "20", "张三" };
Person person = converterRegistry.convert(Person.class, str);
System.out.println(person);
运行结果:
Person [age=20, name=张三]
该转换器将一个数组类型转换为了Person对象,它是如何实现的呢?(分三步)
  1. 自定义类实现Converter接口,并重写convert()方法
  2. 注册自定义的转换器
  3. 实现转换
先定义一个Person类:
public class Person {
<span class="token keyword">private</span> <span class="token keyword">int</span> age<span class="token punctuation">;</span>
<span class="token keyword">private</span> String name<span class="token punctuation">;</span><span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">getAge</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">return</span> age<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setAge</span><span class="token punctuation">(</span><span class="token keyword">int</span> age<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>age <span class="token operator">=</span> age<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token keyword">public</span> String <span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">return</span> name<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setName</span><span class="token punctuation">(</span>String name<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> String <span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">return</span> <span class="token string">"Person [age="</span> <span class="token operator">+</span> age <span class="token operator">+</span> <span class="token string">", name="</span> <span class="token operator">+</span> name <span class="token operator">+</span> <span class="token string">"]"</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

然后自定义类实现Converter接口,并重写方法:

public class CustomConverter implements Converter<Person> {
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> Person <span class="token function">convert</span><span class="token punctuation">(</span>Object value<span class="token punctuation">,</span> Person person<span class="token punctuation">)</span> <span class="token keyword">throws</span> IllegalArgumentException <span class="token punctuation">{</span>person <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Person</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>String<span class="token punctuation">[</span><span class="token punctuation">]</span> str <span class="token operator">=</span> Convert<span class="token punctuation">.</span><span class="token function">toStrArray</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span>person<span class="token punctuation">.</span><span class="token function">setAge</span><span class="token punctuation">(</span>Convert<span class="token punctuation">.</span><span class="token function">toInt</span><span class="token punctuation">(</span>str<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>person<span class="token punctuation">.</span><span class="token function">setName</span><span class="token punctuation">(</span>str<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">return</span> person<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

该方法将传递过来的数据封装成Person对象并返回,实现类型转换。

接着注册自定义的转换器:

ConverterRegistry converterRegistry = ConverterRegistry.getInstance();
converterRegistry.putCustom(Person.class, CustomConverter.class);

现在就可以使用我们的转换器了,也就是刚刚的代码:

String[] str = { "20", "张三" };
Person person = converterRegistry.convert(Person.class, str);
System.out.println(person);

需要转换的数据是什么样式的,完全由你自定义的转换器决定,非常灵活,可根据自己的需求随意定制。

日期时间处理

对于日期时间的处理,Java提供了Date类和Calendar类,但就是因为有了更多的选择,使得日期时间转换的操作变得混乱和复杂,为此,HuTool提供了DateUtil工具。

1、Date、long、Calendar的相互转换

使用DateUtil可以实现Date、long和Calendar之间的相互转换,如下:

// Calendar转为Date
Date date = DateUtil.date(Calendar.getInstance());
// long转为Date
Date date2 = DateUtil.date(System.currentTimeMillis());
// Date转为Calendar
Calendar calendar = DateUtil.calendar(date);
// long转为Calendar
Calendar calendar2 = DateUtil.calendar(System.currentTimeMillis());

2、日期字符串转换为Date

String s = "2019-12-07";
DateTime dateTime = DateUtil.parse(s);
System.out.println(dateTime);

运行结果:

2019-12-07 00:00:00

该方法能够将日期字符串转换为Date类型,它能够自动识别以下格式的字符串:

  1. yyyy-MM-dd HH:mm:ss
  2. yyyy-MM-dd
  3. HH:mm:ss
  4. yyyy-MM-dd HH:mm
  5. yyyy-MM-dd HH:mm:ss.SSS

3、格式化日期

格式化日期很简单,和Java的API没什么区别。

String s = "2019-12-07";
DateTime date = DateUtil.parse(s);

String dateStr = DateUtil.format(date, “yyyy/MM/dd”);
System.out.println(dateStr);
String dateStr2 = DateUtil.formatDate(date);
System.out.println(dateStr2);
String dateStr3 = DateUtil.formatDateTime(date);
System.out.println(dateStr3);
String dateStr4 = DateUtil.formatTime(date);
System.out.println(dateStr4);

通过format()方法可以将日期字符串转换为指定的格式,不过,DateUtil提供了其它的一些方法来作为常用的日期格式转换,看运行结果即可:

2019/12/07
2019-12-07
2019-12-07 00:00:00
00:00:00

4、获取年、月、日

对于年、月、日的获取,DateUtil也提供了非常简便的获取方式:

// 获取当前日期时间
DateTime date = DateUtil.date();
System.out.println(date);
// 获取年
int year = DateUtil.year(date);
System.out.println(year);
// 获取月  从0开始
int month = DateUtil.month(date);
System.out.println(month);

运行结果:

2019-12-07 21:45:42
2019
11

5、日期时间偏移量

对于日期时间的偏移,DateUtil同样能够很方便地实现,如下:

String s = "2019-12-06 21:46:00";
DateTime date = DateUtil.parse(s);

// 日期往后偏移一天
DateTime dateTime = DateUtil.offset(date, DateField.DAY_OF_MONTH, 1);
System.out.println(dateTime);

// 日期往后偏移两天
DateTime dateTime2 = DateUtil.offsetDay(dateTime, 2);
System.out.println(dateTime2);

// 日期往后偏移一个小时
DateTime dateTime3 = DateUtil.offsetHour(date, 1);
System.out.println(dateTime3);

运行结果:

2019-12-07 21:46:00
2019-12-09 21:46:00
2019-12-06 22:46:00

关于日期时间的偏移,通过offset()方法即可实现,该方法的第二个参数可传入偏移的单位,不过DateUtil还提供了一些比较常用的偏移方法,比如偏移天数、偏移小时。

对于与当前十分接近的日期时间,DateUtil也提供了一些较为常用的方法,比如昨天、明天、上周、下周、上个月、下个月等:

DateTime yesrerday = DateUtil.yesterday();
System.out.println(yesrerday);

DateTime tomorrow = DateUtil.tomorrow();
System.out.println(tomorrow);

DateTime lastMonth = DateUtil.lastMonth();
System.out.println(lastMonth);

DateTime nextMonth = DateUtil.nextMonth();
System.out.println(nextMonth);

DateTime lastWeek = DateUtil.lastWeek();
System.out.println(lastWeek);

DateTime nextWeek = DateUtil.nextWeek();
System.out.println(nextWeek);

运行结果:

2019-12-06 22:02:29
2019-12-08 22:02:29
2019-11-07 22:02:29
2020-01-07 22:02:29
2019-11-30 22:02:29
2019-12-14 22:02:29

6、计算日期时间差

String s1 = "2019-12-06 22:15:00";
DateTime date1 = DateUtil.parse(s1);
String s2 = "2019-12-08 22:15:00";
DateTime date2 = DateUtil.parse(s2);
// 计算相差的天数
long day = DateUtil.between(date1, date2, DateUnit.DAY);
System.out.println(day);
// 计算相差的小时数
long hour = DateUtil.between(date1, date2, DateUnit.HOUR);
System.out.println(hour);

运行结果:

2
48

对于两个日期时间的差值,通过between()方法能够很轻松地得到,该方法的第三个参数是需要计算的差值的单位。

7、计时器

DateUtil类还封装了计时器功能,用过传统的Timer计时器的同学就会知道,Timer计时器略显复杂,而DateUtil的封装则恰到好处。

TimeInterval timer = DateUtil.timer();
// 延迟2秒
Thread.sleep(2000);
// 花费的时间,单位:毫秒
long interval = timer.interval();
System.out.println(interval);
// 花费的时间,单位:分
long intervalMinute = timer.intervalMinute();
System.out.println(intervalMinute);

运行结果:

2000
0

还有很多其它的方法,篇幅有限,就不一一例举了。

8、其它

考虑到一些比较常见的场景,例如计算一个人的年龄,判断给定年份是否为闰年,DateUtil也给出了相应的解决办法。

int age = DateUtil.ageOfNow("1999-08-08");
System.out.println(age);
boolean leapYear = DateUtil.isLeapYear(2019);
System.out.println(leapYear);

运行结果:

20
false

IO操作

IO操作是Java中比较重要的操作之一,为此,Java提供了InputStream、OutputStream、Reader、Writer等接口,而实现类又非常的多,往往选择一多,我们就不知道该如何选择,而HuTool为我们封装了一系列的工具类。

FileUtil(文件操作工具类)

既然是IO流,那就离不开文件操作,HuTool为我们提供了FileUtil工具类用来解决大部分的文件操作问题。

对于文件操作的方法,有Linux基础的同学肯定非常熟悉,开源项目的作者努力将方法名与Linux保持一致,比如创建文件的方法不是createFile()而是touch()。

File[] files = FileUtil.ls("E:");
for (File file : files) {System.out.println(file);
}

运行结果:

E:\$RECYCLE.BIN
E:\androidSdk
E:\androidstudio
E:\b2631f36a0808f7d3cab19543d645e63
E:\flutter
E:\Java
E:\MailMasterData
E:\QLDownload
E:\QQPCmg
E:\QQPCmgr
E:\qycache
E:\System Volume Information
E:\test.txt
E:\Tool
E:\迅雷下载

ls()方法会列出给定路径下的所有目录和文件。

FileUtil.touch("E:/test/hello.txt");

touch()方法用于创建文件,如果父目录不存在也自动创建,比如这里的hello.txt文件,倘若E盘下没有test目录,则会先创建test文件夹,再在test目录下创建hello.txt文件。

其它方法也如上所示使用,就不一一演示了:

  • mkdir 创建目录,会递归创建每层目录
  • del 删除文件或目录(递归删除,不判断是否为空),这个方法相当于Linux的delete命令
  • copy 拷贝文件或目录

注意:对于del()方法,它会直接删除目录而不判断其是否为空,所以请谨慎使用。

IOUtil(IO工具类)

第二个便是IOUtil,该工具类主要针对输入输出流的一个封装。

1、文件复制

针对文件复制操作,IOUtil能够很轻松地完成。

BufferedInputStream inputStream = FileUtil.getInputStream("C:/Users/Administrator/Desktop/eclipseworkspace/HuToolDemo/src/com/wwj/test/TestDemo.java");
BufferedOutputStream outputStream = FileUtil.getOutputStream("E:/test.txt");
long copySize = IoUtil.copy(inputStream, outputStream, IoUtil.DEFAULT_BUFFER_SIZE);

这里就复制了一下当前的java文件并将其保存至E盘下的test.txt文件中。

2、读流写流

读流写流也是IO操作中使用频率非常高的操作,它跟传统的方式没有太大区别,只不过对调用者进行了统一。

BufferedInputStream inputStream = FileUtil.getInputStream("C:\\Users\\Administrator\\Desktop\\eclipseworkspace\\HuToolDemo\\src\\com\\wwj\\test\\TestDemo.Java");
BufferedOutputStream outputStream = FileUtil.getOutputStream("E:\\test.txt");
int len = -1;
byte[] buffer = new byte[1024];
while ((len = inputStream.read(buffer)) != -1) {outputStream.write(buffer, 0, len);
}
IoUtil.close(inputStream);
IoUtil.close(outputStream);

下面列出关于读写流操作相关的方法:

  • readBytes 返回byte数组(读取图片等)
  • readHex 读取16进制字符串
  • readObj 读取序列化对象(反序列化)
  • readLines 按行读取

对于写流操作,IoUtil提供了两个write()的重载方法,当然也可以直接使用输出流的write()方法,而事实上,IoUtil的write()方法也是这么做的。

我们再来看看IoUtil如何读写图片,对于图片的读写操作,它提供了readBytes()方法,使用该方法读写图片简直不要太简单:

BufferedInputStream inputStream = FileUtil.getInputStream("C:\\Users\\Administrator\\Desktop\\eclipseworkspace\\HuToolDemo\\默认图表.png");
BufferedOutputStream outputStream = FileUtil.getOutputStream("E:\\test.png");
byte[] bytes = IoUtil.readBytes(inputStream);
outputStream.write(bytes);
IoUtil.close(inputStream);
IoUtil.close(outputStream);

这样即可完成图片的读写。

IoUtil还提供了一些其它方法用于简化编程,比如:toStream()方法用于将某些对象转换为流对象;writeObjects()方法用于将可序列化对象序列化后写入到流中。

3、释放流资源

IO操作中的一个好习惯就是用完哪个流就关掉哪个流,而关闭操作会面临两个问题:

  • 被关闭的对象为空
  • 对象关闭失败

而IoUtil提供的close()方法则很好地解决了这些问题,我们只需将要关闭的流传入close()方法即可。

FileTypeUtil(文件类型判断工具类)

FileTypeUtil是一个判断文件类型的工具类,它并不是通过文件的扩展名来确定文件类型,而是通过读取文件的首部几个二进制位来判断。

File file = FileUtil.file("C:\\Users\\Administrator\\Desktop\\eclipseworkspace\\HuToolDemo\\默认图表.png");
String type = FileTypeUtil.getType(file);
Console.log(type);

运行结果:

png

FileReader(文件读取)

虽然FileUtil已经提供了关于文件读写的API,但是根据职责分离原则,HuTool还是为我们提供了FileReader类专门读取文件。

在JDK中同样提供了FileReader类,但并不好用,HuTool正是对它进行的一个升级。

FileReader fileReader = new FileReader("test.properties");
String result = fileReader.readString();
System.out.println(result);

运行结果:

username=root
password=123456

该类还提供了一些常用的方法帮助文件读取:

  • readBytes
  • readString
  • readLines

文件写入(FileWriter)

有文件读取,肯定就会有文件写入,使用方法和FileReader是一样的,这里就不做代码演示了。

写入方式分为追加和覆盖两种模式,追加的话可以用append()方法,覆盖可以用write()方法;当然你也可以直接使用write()方法,并将写入模式作为第二个参数传入。

资源访问

在Java开发中,资源访问是比较常见的操作,例如在操作数据库、整合框架的时候,需要频繁地访问配置文件,通常我们会将配置文件放在类路径下,方便访问:

InputStream in = TestDemo.class.getResource("test.properties").openStream();

对于资源访问这种频繁而且麻烦的操作,HuTool对其进行了封装。

ClassPathResource resource = new ClassPathResource("test.properties");
Properties properties = new Properties();
properties.load(resource.getStream());
Console.log(properties);

运行结果:

{password=123456, username=root}

当然,对于资源访问的封装远不止如此,这个放到后面说。

最后

以上内容只是HuTool项目的冰山一角,我将在下篇相关文章中继续介绍该项目下封装的一些工具类。

                                </div><link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-b6c3c6d139.css" rel="stylesheet"><div class="more-toolbox"><div class="left-toolbox"><ul class="toolbox-list"><li class="tool-item tool-active is-like "><a href="javascript:;"><svg class="icon" aria-hidden="true"><use xlink:href="#csdnc-thumbsup"></use></svg><span class="name">点赞</span><span class="count">83</span></a></li><li class="tool-item tool-active is-collection "><a href="javascript:;" data-report-click="{&quot;mod&quot;:&quot;popu_824&quot;}"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-csdnc-Collection-G"></use></svg><span class="name">收藏</span></a></li><li class="tool-item tool-active is-share"><a href="javascript:;"><svg class="icon" aria-hidden="true"><use xlink:href="#icon-csdnc-fenxiang"></use></svg>分享</a></li><!--打赏开始--><!--打赏结束--><li class="tool-item tool-more"><a><svg t="1575545411852" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M179.176 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5718"></path><path d="M509.684 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5719"></path><path d="M846.175 499.222m-113.245 0a113.245 113.245 0 1 0 226.49 0 113.245 113.245 0 1 0-226.49 0Z" p-id="5720"></path></svg></a><ul class="more-box"><li class="item"><a class="article-report">文章举报</a></li></ul></li></ul></div></div><div class="person-messagebox"><div class="left-message"><a href="https://blog.csdn.net/qq_42453117"><img src="https://profile.csdnimg.cn/F/B/3/3_qq_42453117" class="avatar_pic" username="qq_42453117"><img src="https://g.csdnimg.cn/static/user-reg-year/1x/2.png" class="user-years"></a></div><div class="middle-message"><div class="title"><span class="tit"><a href="https://blog.csdn.net/qq_42453117" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}" target="_blank">~wangweijun</a></span><span class="flag expert"><a href="https://blog.csdn.net/home/help.html#classicfication" target="_blank"><svg class="icon" aria-hidden="true"><use xlink:href="#csdnc-blogexpert"></use></svg>博客专家</a></span></div><div class="text"><span>发布了95 篇原创文章</span> · <span>获赞 8014</span> · <span>访问量 43万+</span></div></div><div class="right-message"><a href="https://bbs.csdn.net/forums/p-qq_42453117" target="_blank" class="btn btn-sm btn-red-hollow bt-button personal-messageboard">他的留言板</a><a class="btn btn-sm  bt-button personal-watch" data-report-click="{&quot;mod&quot;:&quot;popu_379&quot;}">关注</a></div></div></div>

Hutool你值得拥有,吃相不要太难看相关推荐

  1. 记录一次关于百度网盘打开提示页面不存在的问题(吃相不要太难看)

    前言 近日辉哥博客交流群内有成员发现自己的域名跳转到百度网盘提示页面不存在,群内网页根据真实情况进行了多次讨论,最终找到问题所在! 前因 该用户日常使用中分享百度网盘的链接在自己网站上进行跳转,可是怎 ...

  2. 5G概念被热炒,运营商吃相不要太难看 1

    5G自提出以来就受到了极大的关注,各大厂商也争先恐后入场展开角逐.最近随着商用降临,这一概念被媒体炒得火热,各大运营商更是铆足了劲,都想抢首发,甚至为此打起了嘴战. 近日,T-Mobile的首席技术官 ...

  3. 真是「狗」了,知乎「吃相」太难看了

    loonggg 读完需要 7 分钟 速读仅需 3 分钟 大家好,我是校长. 最近我发现一件事,感觉知乎作为一个知识类问答创作平台,真的是一点也不尊重创作者,或许知乎刚上市吧,需要赚钱回报股东,提振市值 ...

  4. 听说CN域名要付费开启隐私保护了,48元/年?吃相是不是太难看了?

    最近看到西部数码一则公告,称根据注册局规定,CN域名要付费开启隐私保护了,48元/年. 我不仅感慨:Web都快完犊子了,企业站能给客户带来的效益越来越小了,你一个域名还要增加客户的额外运营成本,怎么滴 ...

  5. 怒怼某自媒体培训机构,吃相不要太难看了!!!

    首先说明,这篇博客非技术,纯粹是吐槽+点名怼某个培训机构.下面就开喷了,各位看官误笑... 首先说说事情的起因:今天快下班时候,一个同事拿着手机找我,上面显示的是某软件测试培训机构的一篇文章,标题和U ...

  6. 怒怼某些自媒体培训机构,吃相不要太难看了!!!

    首先说明,这篇博客非技术,纯粹是吐槽+点名怼某个培训机构.下面就开喷了,各位看官误笑... 2019年7月1日更新 又是培训机构洗稿子,不过这次变成了鲁德!!! 复制黏贴发自己公众号好歹要点脸征求下原 ...

  7. 丰巢的吃相到底难看在哪呢?

    loonggg 读完需要 5 分钟 速读仅需 2 分钟 最近丰巢快递柜超时收费的话题上热搜了,成了全民讨论的话题.一时间,网上反对,抗议的声浪很大,那丰巢的吃相到底难看在哪呢?大部分人抗议,反对的原因 ...

  8. 吃相难看!《人民日报》再评视频网站套路:消磨观众信任,必将引火烧身

    最近,IP大剧<庆余年>正在热播,不少人加入追剧行列,在各个社交网络平台上引起一波又一波的讨论,可见其受欢迎程度. 随着该剧大火,腾讯视频的骚操作也跟上来了.12月11日上午,腾讯视频官方 ...

  9. VIP看剧也要找好友砍一刀!网友喊话优酷:吃相越来越难看了

    4月20日消息,超前点播被叫停之后,视频网站"圈钱"又有了新套路,这次的主角是优酷. 近日,优酷新剧<我叫赵甲第>热播,但其播放方式却引发争议.优酷VIP用户在VIP会 ...

  10. 响铃:一年一度的盛典套餐,吃相如何更优雅?

    [首发创业邦] 又是一年年终时,各大媒体.互联网公司暗自捣鼓的年终盛典大餐纷纷报上了菜名:阿里"双11晚会".爱奇艺"尖叫之夜".一下科技"放肆一下· ...

最新文章

  1. 谷歌BERT预训练源码解析(一):训练数据生成
  2. jpa多表关联查询_JPA【关联查询篇】
  3. python coroutine_笔记-python-coroutine
  4. Bootstrap4+MySQL前后端综合实训-Day01-AM【实训安排、HBuilder下载及使用、双飞翼布局(圣杯布局)案例、CSS在线手册、flex布局中的对齐方式】
  5. 再次携号转网_潍坊一小伙欲携号转网屡被拒 联通客服:试运营状态不支持携转...
  6. ab plc编程软件_三菱PLC原装和高仿怎么区分?仿真和编程软件一样吗?
  7. Java面试之什么是GCRoots,能做什么?
  8. xcode4.3.2 arc模式下导入非arc的文件 转
  9. 佛祖保佑,永无BUG
  10. day25-python之继承组合
  11. Android项目文件的目录结构(1)
  12. sshv2 mitm工具SSH MITM v2.1的使用记录
  13. Android航海航线地图,Alfa的航海大时代航线介绍 全航线跑商路线详解
  14. 云原生架构下的 API 网关实践: Kong (三)
  15. Ubunt14.04搭建opengrok环境
  16. presenting view controller
  17. BUUCTF Reverse/findKey
  18. 虚拟机下的ROS无法打开笔记本摄像头
  19. 钱多多软件制作第一天
  20. web与web服务器的概念理解

热门文章

  1. python+appium+夜神模拟器APP自动化测试
  2. 摄影光学与镜头pdf_摄影摄像基础pdf
  3. 五子棋AI第二篇 AB剪枝和启发搜索(Java)
  4. vnc远程连接,5个步骤教你如何轻松实现vnc远程连接
  5. 软件测试中的80/20原则
  6. 高薪程序员面试题精讲系列55之你了解红黑树吗?说说它的底层结构吧
  7. 计算机主机检测不到耳机,win10电脑检测不到耳机的原因及处理方法
  8. 简析FUP LB5CM/LB6CM 落地式低速大容量冷冻离心机
  9. python处理图片像素_Python 处理图片像素点的实例
  10. 某三甲医院大数据平台建设应用与实践