mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
Merge remote-tracking branch 'upstream/v5-dev' into v5-dev
This commit is contained in:
commit
e69aac1274
@ -4,7 +4,7 @@
|
||||
2. 请确认没有更改代码风格(如tab缩进)
|
||||
3. 新特性添加请确认注释完备,如有必要,请在src/test/java下添加Junit测试用例
|
||||
|
||||
### 修改描述(包括说明bug修复还是新特性添加)
|
||||
### 修改描述(包括说明bug修复或者添加新特性)
|
||||
|
||||
1. [bug修复] balabala……
|
||||
2. [新特性] balabala……
|
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -4,7 +4,7 @@
|
||||
2. 请确认没有更改代码风格(如tab缩进)
|
||||
3. 新特性添加请确认注释完备,如有必要,请在src/test/java下添加Junit测试用例
|
||||
|
||||
### 修改描述(包括说明bug修复还是新特性添加)
|
||||
### 修改描述(包括说明bug修复或者添加新特性)
|
||||
|
||||
1. [bug修复] balabala……
|
||||
2. [新特性] balabala……
|
@ -3,7 +3,7 @@
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
# 5.5.2 (2020-11-26)
|
||||
# 5.5.2 (2020-12-01)
|
||||
|
||||
### 新特性
|
||||
* 【crypto 】 KeyUtil增加重载,AES构造增加重载(issue#I25NNZ@Gitee)
|
||||
@ -28,6 +28,10 @@
|
||||
* 【core 】 修改IoUtil.read(Reader)逻辑默认关闭Reader
|
||||
* 【core 】 ZipUtil增加Zip方法(pr#222@Gitee)
|
||||
* 【all 】 增加Hutool.getAllUtils和printAllUtils方法
|
||||
* 【core 】 增加PunyCode(issue#1268@Gitee)
|
||||
* 【core 】 ArrayUtil增加isSorted方法(pr#1271@Github)
|
||||
* 【captcha】 增加GifCaptcha(pr#1273@Github)
|
||||
* 【core 】 增加SSLUtil、SSLContextBuilder
|
||||
|
||||
### Bug修复
|
||||
* 【cron 】 修复CronTimer可能死循环的问题(issue#1224@Github)
|
||||
@ -36,6 +40,8 @@
|
||||
* 【core 】 修复HexUtil.format问题(issue#I268XT@Gitee)
|
||||
* 【core 】 修复ZipUtil判断压缩文件是否位于压缩目录内的逻辑有误的问题(issue#1251@Github)
|
||||
* 【json 】 修复JSONObject.accumulate问题
|
||||
* 【core 】 修复部分xlsx文件sax方式解析空指针问题(issue#1265@Github)
|
||||
* 【core 】 修复PatternPool中邮编的正则(issue#1274@Github)
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
@ -65,7 +65,7 @@
|
||||
|
||||
Hutool,' Hútú '(Chinese Pinyin),On the one hand, it is simple and easy to understand, on the other hand, it means "hard to be confused".(note: confused means 'Hútú (糊涂)' in china )
|
||||
|
||||
### How Hutool is changing the way we coding
|
||||
### How Hutool is changing the way we code
|
||||
|
||||
The goal of **Hutool** is to use a simple function instead of a complex piece of code, thus avoiding the problem of "copy and paste" code as much as possible and revolutionizing the way we write code.
|
||||
|
||||
@ -182,7 +182,7 @@ Hutool welcomes anyone to contribute code to Hutool, but the author suffers from
|
||||
|
||||
1. Improve the comments, especially each new method should follow the Java documentation specification to indicate the method description, parameter description, return value description and other information, if necessary, please add unit tests, if you want, you can also add your name.
|
||||
2. Code indentation according to Eclipse.
|
||||
3. Newly added methods do not use third-party library methods,Unless the method tool is added to the '**extra module**'.
|
||||
3. Newly added methods do not use third-party library methods,Unless the method tool is add to the '**extra module**'.
|
||||
4. Please pull request to the `v5-dev` branch. Hutool uses a new branch after 5.x: `v5-master` is the master branch, which indicates the version of the central library that has been released, and this branch does not allow pr or modifications.
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
@ -55,7 +55,7 @@
|
||||
## 简介
|
||||
Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。
|
||||
|
||||
Hutool中的工具方法来自于每个用户的精雕细琢,它涵盖了Java开发底层代码中的方方面面,它既是大型项目开发中解决小问题的利器,也是小型项目中的效率担当;
|
||||
Hutool中的工具方法来自每个用户的精雕细琢,它涵盖了Java开发底层代码中的方方面面,它既是大型项目开发中解决小问题的利器,也是小型项目中的效率担当;
|
||||
|
||||
Hutool是项目中“util”包友好的替代,它节省了开发人员对项目中公用类和公用工具方法的封装时间,使开发专注于业务,同时可以最大限度的避免封装不完善带来的bug。
|
||||
|
||||
|
@ -13,9 +13,8 @@ public class JdkProxyFactory extends ProxyFactory {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T proxy(T target, Aspect aspect) {
|
||||
return (T) ProxyUtil.newProxyInstance(//
|
||||
return ProxyUtil.newProxyInstance(//
|
||||
target.getClass().getClassLoader(), //
|
||||
new JdkInterceptor(target, aspect), //
|
||||
target.getClass().getInterfaces());
|
||||
|
@ -33,14 +33,14 @@ public class IntMap implements BitMap, Serializable {
|
||||
public void add(long i) {
|
||||
int r = (int) (i / BitMap.MACHINE32);
|
||||
int c = (int) (i % BitMap.MACHINE32);
|
||||
ints[r] = (int) (ints[r] | (1 << c));
|
||||
ints[r] = ints[r] | (1 << c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(long i) {
|
||||
int r = (int) (i / BitMap.MACHINE32);
|
||||
int c = (int) (i % BitMap.MACHINE32);
|
||||
return ((int) ((ints[r] >>> c)) & 1) == 1;
|
||||
return ((ints[r] >>> c) & 1) == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -11,7 +11,7 @@ public class CaptchaUtil {
|
||||
/**
|
||||
* 创建线干扰的验证码,默认5位验证码,150条干扰线
|
||||
*
|
||||
* @param width 图片宽
|
||||
* @param width 图片宽
|
||||
* @param height 图片高
|
||||
* @return {@link LineCaptcha}
|
||||
*/
|
||||
@ -22,8 +22,8 @@ public class CaptchaUtil {
|
||||
/**
|
||||
* 创建线干扰的验证码
|
||||
*
|
||||
* @param width 图片宽
|
||||
* @param height 图片高
|
||||
* @param width 图片宽
|
||||
* @param height 图片高
|
||||
* @param codeCount 字符个数
|
||||
* @param lineCount 干扰线条数
|
||||
* @return {@link LineCaptcha}
|
||||
@ -35,7 +35,7 @@ public class CaptchaUtil {
|
||||
/**
|
||||
* 创建圆圈干扰的验证码,默认5位验证码,15个干扰圈
|
||||
*
|
||||
* @param width 图片宽
|
||||
* @param width 图片宽
|
||||
* @param height 图片高
|
||||
* @return {@link CircleCaptcha}
|
||||
* @since 3.2.3
|
||||
@ -47,9 +47,9 @@ public class CaptchaUtil {
|
||||
/**
|
||||
* 创建圆圈干扰的验证码
|
||||
*
|
||||
* @param width 图片宽
|
||||
* @param height 图片高
|
||||
* @param codeCount 字符个数
|
||||
* @param width 图片宽
|
||||
* @param height 图片高
|
||||
* @param codeCount 字符个数
|
||||
* @param circleCount 干扰圆圈条数
|
||||
* @return {@link CircleCaptcha}
|
||||
* @since 3.2.3
|
||||
@ -61,7 +61,7 @@ public class CaptchaUtil {
|
||||
/**
|
||||
* 创建扭曲干扰的验证码,默认5位验证码
|
||||
*
|
||||
* @param width 图片宽
|
||||
* @param width 图片宽
|
||||
* @param height 图片高
|
||||
* @return {@link ShearCaptcha}
|
||||
* @since 3.2.3
|
||||
@ -73,8 +73,8 @@ public class CaptchaUtil {
|
||||
/**
|
||||
* 创建扭曲干扰的验证码,默认5位验证码
|
||||
*
|
||||
* @param width 图片宽
|
||||
* @param height 图片高
|
||||
* @param width 图片宽
|
||||
* @param height 图片高
|
||||
* @param codeCount 字符个数
|
||||
* @param thickness 干扰线宽度
|
||||
* @return {@link ShearCaptcha}
|
||||
@ -83,4 +83,27 @@ public class CaptchaUtil {
|
||||
public static ShearCaptcha createShearCaptcha(int width, int height, int codeCount, int thickness) {
|
||||
return new ShearCaptcha(width, height, codeCount, thickness);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建GIF验证码
|
||||
*
|
||||
* @param width 宽
|
||||
* @param height 高
|
||||
* @return {@link GifCaptcha}
|
||||
*/
|
||||
public static GifCaptcha createGifCaptcha(int width, int height) {
|
||||
return new GifCaptcha(width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建GIF验证码
|
||||
*
|
||||
* @param width 宽
|
||||
* @param height 高
|
||||
* @param codeCount 字符个数
|
||||
* @return {@link GifCaptcha}
|
||||
*/
|
||||
public static GifCaptcha createGifCaptcha(int width, int height, int codeCount) {
|
||||
return new GifCaptcha(width, height, codeCount);
|
||||
}
|
||||
}
|
||||
|
218
hutool-captcha/src/main/java/cn/hutool/captcha/GifCaptcha.java
Normal file
218
hutool-captcha/src/main/java/cn/hutool/captcha/GifCaptcha.java
Normal file
@ -0,0 +1,218 @@
|
||||
package cn.hutool.captcha;
|
||||
|
||||
|
||||
import cn.hutool.core.img.gif.AnimatedGifEncoder;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
/**
|
||||
* Gif验证码类
|
||||
*
|
||||
* @author hsoftxl
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public class GifCaptcha extends AbstractCaptcha {
|
||||
private static final long serialVersionUID = 7091627304326538464L;
|
||||
|
||||
//量化器取样间隔 - 默认是10ms
|
||||
private int quality = 10;
|
||||
// 帧循环次数
|
||||
private int repeat = 0;
|
||||
//设置随机颜色时,最小的取色范围
|
||||
private int minColor = 0;
|
||||
//设置随机颜色时,最大的取色范围
|
||||
private int maxColor = 255;
|
||||
|
||||
|
||||
/**
|
||||
* 可以设置验证码宽度,高度的构造函数
|
||||
*
|
||||
* @param width 验证码宽度
|
||||
* @param height 验证码高度
|
||||
*/
|
||||
public GifCaptcha(int width, int height) {
|
||||
this(width, height, 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param width 验证码宽度
|
||||
* @param height 验证码高度
|
||||
* @param codeCount 验证码个数
|
||||
*/
|
||||
public GifCaptcha(int width, int height, int codeCount) {
|
||||
super(width, height, codeCount, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置图像的颜色量化(转换质量 由GIF规范允许的最大256种颜色)。
|
||||
* 低的值(最小值= 1)产生更好的颜色,但处理显著缓慢。
|
||||
* 10是默认,并产生良好的颜色而且有以合理的速度。
|
||||
* 值更大(大于20)不产生显著的改善速度
|
||||
*
|
||||
* @param quality 大于1
|
||||
* @return this
|
||||
*/
|
||||
public GifCaptcha setQuality(int quality) {
|
||||
if (quality < 1) {
|
||||
quality = 1;
|
||||
}
|
||||
this.quality = quality;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置GIF帧应该播放的次数。
|
||||
* 默认是 0; 0意味着无限循环。
|
||||
* 必须在添加的第一个图像之前被调用。
|
||||
*
|
||||
* @param repeat 必须大于等于0
|
||||
* @return this
|
||||
*/
|
||||
public GifCaptcha setRepeat(int repeat) {
|
||||
if (repeat >= 0) {
|
||||
this.repeat = repeat;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置验证码字符颜色
|
||||
*
|
||||
* @param maxColor 颜色
|
||||
* @return this
|
||||
*/
|
||||
public GifCaptcha setMaxColor(int maxColor) {
|
||||
this.maxColor = maxColor;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置验证码字符颜色
|
||||
*
|
||||
* @param minColor 颜色
|
||||
* @return this
|
||||
*/
|
||||
public GifCaptcha setMinColor(int minColor) {
|
||||
this.minColor = minColor;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createCode() {
|
||||
generateCode();
|
||||
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
||||
AnimatedGifEncoder gifEncoder = new AnimatedGifEncoder();// gif编码类
|
||||
//生成字符
|
||||
gifEncoder.start(out);
|
||||
gifEncoder.setQuality(quality);//设置量化器取样间隔
|
||||
// 帧延迟 (默认100)
|
||||
int delay = 100;
|
||||
gifEncoder.setDelay(delay);//设置帧延迟
|
||||
gifEncoder.setRepeat(repeat);//帧循环次数
|
||||
BufferedImage frame;
|
||||
char[] chars = code.toCharArray();
|
||||
Color[] fontColor = new Color[chars.length];
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
fontColor[i] = getRandomColor(minColor, maxColor);
|
||||
frame = graphicsImage(chars, fontColor, chars, i);
|
||||
gifEncoder.addFrame(frame);
|
||||
frame.flush();
|
||||
}
|
||||
gifEncoder.finish();
|
||||
this.imageBytes = out.toByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Image createImage(String code) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 画随机码图
|
||||
*
|
||||
* @param fontColor 随机字体颜色
|
||||
* @param words 字符数组
|
||||
* @param flag 透明度使用
|
||||
* @return BufferedImage
|
||||
*/
|
||||
private BufferedImage graphicsImage(char[] chars, Color[] fontColor, char[] words, int flag) {
|
||||
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||
//或得图形上下文
|
||||
Graphics2D g2d = image.createGraphics();
|
||||
//利用指定颜色填充背景
|
||||
g2d.setColor(ObjectUtil.defaultIfNull(this.background, Color.WHITE));
|
||||
g2d.fillRect(0, 0, width, height);
|
||||
AlphaComposite ac;
|
||||
// 字符的y坐标
|
||||
float y = (height >> 1) + (font.getSize() >> 1);
|
||||
float m = 1.0f * (width - (chars.length * font.getSize())) / chars.length;
|
||||
//字符的x坐标
|
||||
float x = Math.max(m / 2.0f, 2);
|
||||
g2d.setFont(font);
|
||||
// 指定透明度
|
||||
if (null != this.textAlpha) {
|
||||
g2d.setComposite(this.textAlpha);
|
||||
}
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getAlpha(chars.length, flag, i));
|
||||
g2d.setComposite(ac);
|
||||
g2d.setColor(fontColor[i]);
|
||||
g2d.drawOval(
|
||||
RandomUtil.randomInt(width),
|
||||
RandomUtil.randomInt(height),
|
||||
RandomUtil.randomInt(5, 30), 5 + RandomUtil.randomInt(5, 30)
|
||||
);//绘制椭圆边框
|
||||
g2d.drawString(words[i] + "", x + (font.getSize() + m) * i, y);
|
||||
}
|
||||
g2d.dispose();
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取透明度,从0到1,自动计算步长
|
||||
*
|
||||
* @return float 透明度
|
||||
*/
|
||||
private float getAlpha(int v, int i, int j) {
|
||||
int num = i + j;
|
||||
float r = (float) 1 / v;
|
||||
float s = (v + 1) * r;
|
||||
return num > v ? (num * r - s) : num * r;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过给定范围获得随机的颜色
|
||||
*
|
||||
* @return Color 获得随机的颜色
|
||||
*/
|
||||
private Color getRandomColor(int min, int max) {
|
||||
if (min > 255) {
|
||||
min = 255;
|
||||
}
|
||||
if (max > 255) {
|
||||
max = 255;
|
||||
}
|
||||
if (min < 0) {
|
||||
min = 0;
|
||||
}
|
||||
if (max < 0) {
|
||||
max = 0;
|
||||
}
|
||||
if (min > max) {
|
||||
min = 0;
|
||||
max = 255;
|
||||
}
|
||||
return new Color(
|
||||
RandomUtil.randomInt(min, max),
|
||||
RandomUtil.randomInt(min, max),
|
||||
RandomUtil.randomInt(min, max));
|
||||
}
|
||||
}
|
@ -1,11 +1,10 @@
|
||||
package cn.hutool.captcha;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import cn.hutool.captcha.generator.MathGenerator;
|
||||
import cn.hutool.core.lang.Console;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
@ -13,7 +12,6 @@ import java.awt.*;
|
||||
* 直线干扰验证码单元测试
|
||||
*
|
||||
* @author looly
|
||||
*
|
||||
*/
|
||||
public class CaptchaTest {
|
||||
|
||||
@ -102,4 +100,12 @@ public class CaptchaTest {
|
||||
// 验证图形验证码的有效性,返回boolean值
|
||||
captcha.verify("1234");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void GifCaptchaTest() {
|
||||
GifCaptcha captcha = CaptchaUtil.createGifCaptcha(200, 100, 4);
|
||||
captcha.write("d:/test/gif_captcha.gif");
|
||||
assert captcha.verify(captcha.getCode());
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ public class BeanPath implements Serializable{
|
||||
* </pre>
|
||||
*
|
||||
* @param expression 表达式
|
||||
* @return {@link BeanPath}
|
||||
* @return BeanPath
|
||||
*/
|
||||
public static BeanPath create(String expression) {
|
||||
return new BeanPath(expression);
|
||||
|
@ -1,10 +1,10 @@
|
||||
package cn.hutool.core.codec;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.Serializable;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
|
||||
/**
|
||||
* Base62编码解码实现,常用于短URL<br>
|
||||
* From https://github.com/seruco/base62
|
||||
@ -49,7 +49,7 @@ public class Base62Codec implements Serializable{
|
||||
/**
|
||||
* 创建GMP风格的Base62编码解码器对象
|
||||
*
|
||||
* @return {@link Base62Codec}
|
||||
* @return Base62Codec
|
||||
*/
|
||||
public static Base62Codec createGmp() {
|
||||
return new Base62Codec(GMP);
|
||||
@ -58,7 +58,7 @@ public class Base62Codec implements Serializable{
|
||||
/**
|
||||
* 创建Inverted风格的Base62编码解码器对象
|
||||
*
|
||||
* @return {@link Base62Codec}
|
||||
* @return Base62Codec
|
||||
*/
|
||||
public static Base62Codec createInverted() {
|
||||
return new Base62Codec(INVERTED);
|
||||
|
260
hutool-core/src/main/java/cn/hutool/core/codec/PunyCode.java
Normal file
260
hutool-core/src/main/java/cn/hutool/core/codec/PunyCode.java
Normal file
@ -0,0 +1,260 @@
|
||||
package cn.hutool.core.codec;
|
||||
|
||||
import cn.hutool.core.exceptions.UtilException;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
/**
|
||||
* Punycode是一个根据RFC 3492标准而制定的编码系统,主要用于把域名从地方语言所采用的Unicode编码转换成为可用于DNS系统的编码
|
||||
* <p>
|
||||
* 参考:https://blog.csdn.net/a19881029/article/details/18262671
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public class PunyCode {
|
||||
private static final int TMIN = 1;
|
||||
private static final int TMAX = 26;
|
||||
private static final int BASE = 36;
|
||||
private static final int INITIAL_N = 128;
|
||||
private static final int INITIAL_BIAS = 72;
|
||||
private static final int DAMP = 700;
|
||||
private static final int SKEW = 38;
|
||||
private static final char DELIMITER = '-';
|
||||
|
||||
public static final String PUNY_CODE_PREFIX = "xn--";
|
||||
|
||||
/**
|
||||
* 将内容编码为PunyCode
|
||||
*
|
||||
* @param input 字符串
|
||||
* @return PunyCode字符串
|
||||
* @throws UtilException 计算异常
|
||||
*/
|
||||
public static String encode(String input) throws UtilException {
|
||||
return encode(input, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将内容编码为PunyCode
|
||||
*
|
||||
* @param input 字符串
|
||||
* @param withPrefix 是否包含 "xn--"前缀
|
||||
* @return PunyCode字符串
|
||||
* @throws UtilException 计算异常
|
||||
*/
|
||||
public static String encode(String input, boolean withPrefix) throws UtilException {
|
||||
int n = INITIAL_N;
|
||||
int delta = 0;
|
||||
int bias = INITIAL_BIAS;
|
||||
StringBuilder output = new StringBuilder();
|
||||
// Copy all basic code points to the output
|
||||
final int length = input.length();
|
||||
int b = 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
char c = input.charAt(i);
|
||||
if (isBasic(c)) {
|
||||
output.append(c);
|
||||
b++;
|
||||
}
|
||||
}
|
||||
// Append delimiter
|
||||
if (b > 0) {
|
||||
output.append(DELIMITER);
|
||||
}
|
||||
int h = b;
|
||||
while (h < length) {
|
||||
int m = Integer.MAX_VALUE;
|
||||
// Find the minimum code point >= n
|
||||
for (int i = 0; i < length; i++) {
|
||||
final char c = input.charAt(i);
|
||||
if (c >= n && c < m) {
|
||||
m = c;
|
||||
}
|
||||
}
|
||||
if (m - n > (Integer.MAX_VALUE - delta) / (h + 1)) {
|
||||
throw new UtilException("OVERFLOW");
|
||||
}
|
||||
delta = delta + (m - n) * (h + 1);
|
||||
n = m;
|
||||
for (int j = 0; j < length; j++) {
|
||||
int c = input.charAt(j);
|
||||
if (c < n) {
|
||||
delta++;
|
||||
if (0 == delta) {
|
||||
throw new UtilException("OVERFLOW");
|
||||
}
|
||||
}
|
||||
if (c == n) {
|
||||
int q = delta;
|
||||
for (int k = BASE; ; k += BASE) {
|
||||
int t;
|
||||
if (k <= bias) {
|
||||
t = TMIN;
|
||||
} else if (k >= bias + TMAX) {
|
||||
t = TMAX;
|
||||
} else {
|
||||
t = k - bias;
|
||||
}
|
||||
if (q < t) {
|
||||
break;
|
||||
}
|
||||
output.append((char) digit2codepoint(t + (q - t) % (BASE - t)));
|
||||
q = (q - t) / (BASE - t);
|
||||
}
|
||||
output.append((char) digit2codepoint(q));
|
||||
bias = adapt(delta, h + 1, h == b);
|
||||
delta = 0;
|
||||
h++;
|
||||
}
|
||||
}
|
||||
delta++;
|
||||
n++;
|
||||
}
|
||||
|
||||
if(withPrefix){
|
||||
output.insert(0, PUNY_CODE_PREFIX);
|
||||
}
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 解码 PunyCode为字符串
|
||||
*
|
||||
* @param input PunyCode
|
||||
* @return 字符串
|
||||
* @throws UtilException 计算异常
|
||||
*/
|
||||
public static String decode(String input) throws UtilException {
|
||||
input = StrUtil.removePrefixIgnoreCase(input, PUNY_CODE_PREFIX);
|
||||
|
||||
int n = INITIAL_N;
|
||||
int i = 0;
|
||||
int bias = INITIAL_BIAS;
|
||||
StringBuilder output = new StringBuilder();
|
||||
int d = input.lastIndexOf(DELIMITER);
|
||||
if (d > 0) {
|
||||
for (int j = 0; j < d; j++) {
|
||||
final char c = input.charAt(j);
|
||||
if (isBasic(c)) {
|
||||
output.append(c);
|
||||
}
|
||||
}
|
||||
d++;
|
||||
} else {
|
||||
d = 0;
|
||||
}
|
||||
final int length = input.length();
|
||||
while (d < length) {
|
||||
int oldi = i;
|
||||
int w = 1;
|
||||
for (int k = BASE; ; k += BASE) {
|
||||
if (d == length) {
|
||||
throw new UtilException("BAD_INPUT");
|
||||
}
|
||||
int c = input.charAt(d++);
|
||||
int digit = codepoint2digit(c);
|
||||
if (digit > (Integer.MAX_VALUE - i) / w) {
|
||||
throw new UtilException("OVERFLOW");
|
||||
}
|
||||
i = i + digit * w;
|
||||
int t;
|
||||
if (k <= bias) {
|
||||
t = TMIN;
|
||||
} else if (k >= bias + TMAX) {
|
||||
t = TMAX;
|
||||
} else {
|
||||
t = k - bias;
|
||||
}
|
||||
if (digit < t) {
|
||||
break;
|
||||
}
|
||||
w = w * (BASE - t);
|
||||
}
|
||||
bias = adapt(i - oldi, output.length() + 1, oldi == 0);
|
||||
if (i / (output.length() + 1) > Integer.MAX_VALUE - n) {
|
||||
throw new UtilException("OVERFLOW");
|
||||
}
|
||||
n = n + i / (output.length() + 1);
|
||||
i = i % (output.length() + 1);
|
||||
output.insert(i, (char) n);
|
||||
i++;
|
||||
}
|
||||
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
private static int adapt(int delta, int numpoints, boolean first) {
|
||||
if (first) {
|
||||
delta = delta / DAMP;
|
||||
} else {
|
||||
delta = delta / 2;
|
||||
}
|
||||
delta = delta + (delta / numpoints);
|
||||
int k = 0;
|
||||
while (delta > ((BASE - TMIN) * TMAX) / 2) {
|
||||
delta = delta / (BASE - TMIN);
|
||||
k = k + BASE;
|
||||
}
|
||||
return k + ((BASE - TMIN + 1) * delta) / (delta + SKEW);
|
||||
}
|
||||
|
||||
private static boolean isBasic(char c) {
|
||||
return c < 0x80;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数字转为字符,对应关系为:
|
||||
* <pre>
|
||||
* 0 -> a
|
||||
* 1 -> b
|
||||
* ...
|
||||
* 25 -> z
|
||||
* 26 -> '0'
|
||||
* ...
|
||||
* 35 -> '9'
|
||||
* </pre>
|
||||
* @param d 输入字符
|
||||
* @return 转换后的字符
|
||||
* @throws UtilException 无效字符
|
||||
*/
|
||||
private static int digit2codepoint(int d) throws UtilException {
|
||||
Assert.checkBetween(d, 0, 35);
|
||||
if (d < 26) {
|
||||
// 0..25 : 'a'..'z'
|
||||
return d + 'a';
|
||||
} else if (d < 36) {
|
||||
// 26..35 : '0'..'9';
|
||||
return d - 26 + '0';
|
||||
} else {
|
||||
throw new UtilException("BAD_INPUT");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符转为数字,对应关系为:
|
||||
* <pre>
|
||||
* a -> 0
|
||||
* b -> 1
|
||||
* ...
|
||||
* z -> 25
|
||||
* '0' -> 26
|
||||
* ...
|
||||
* '9' -> 35
|
||||
* </pre>
|
||||
* @param c 输入字符
|
||||
* @return 转换后的字符
|
||||
* @throws UtilException 无效字符
|
||||
*/
|
||||
private static int codepoint2digit(int c) throws UtilException {
|
||||
if (c - '0' < 10) {
|
||||
// '0'..'9' : 26..35
|
||||
return c - '0' + 26;
|
||||
} else if (c - 'a' < 26) {
|
||||
// 'a'..'z' : 0..25
|
||||
return c - 'a';
|
||||
} else {
|
||||
throw new UtilException("BAD_INPUT");
|
||||
}
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ package cn.hutool.core.date;
|
||||
*/
|
||||
@Deprecated
|
||||
public class BetweenFormater extends BetweenFormatter {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public BetweenFormater(long betweenMs, Level level) {
|
||||
super(betweenMs, level);
|
||||
|
@ -11,7 +11,12 @@ import java.util.Date;
|
||||
|
||||
|
||||
/**
|
||||
* 农历日期工具,最大支持到2055年
|
||||
* 农历日期工具,最大支持到2055年,支持:
|
||||
*
|
||||
* <ul>
|
||||
* <li>通过公历日期构造获取对应农历</li>
|
||||
* <li>通过农历日期直接构造</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author zjw, looly
|
||||
* @since 5.1.1
|
||||
@ -36,9 +41,9 @@ public class ChineseDate {
|
||||
private boolean leap;
|
||||
|
||||
/**
|
||||
* 构造方法传入日期
|
||||
* 通过公历日期构造
|
||||
*
|
||||
* @param date 日期
|
||||
* @param date 公历日期
|
||||
*/
|
||||
public ChineseDate(Date date) {
|
||||
// 求出和1900年1月31日相差的天数
|
||||
|
@ -61,25 +61,17 @@ public class SystemClock {
|
||||
public static final SystemClock INSTANCE = new SystemClock(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 单例实例
|
||||
* @return 单例实例
|
||||
*/
|
||||
private static SystemClock instance() {
|
||||
return InstanceHolder.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 当前时间
|
||||
*/
|
||||
public static long now() {
|
||||
return instance().currentTimeMillis();
|
||||
return InstanceHolder.INSTANCE.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 当前时间字符串表现形式
|
||||
*/
|
||||
public static String nowDate() {
|
||||
return new Timestamp(instance().currentTimeMillis()).toString();
|
||||
return new Timestamp(InstanceHolder.INSTANCE.currentTimeMillis()).toString();
|
||||
}
|
||||
}
|
||||
|
@ -50,20 +50,20 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* 获得 {@link FastDateFormat} 实例,使用默认格式和地区
|
||||
* 获得 FastDateFormat实例,使用默认格式和地区
|
||||
*
|
||||
* @return {@link FastDateFormat}
|
||||
* @return FastDateFormat
|
||||
*/
|
||||
public static FastDateFormat getInstance() {
|
||||
return CACHE.getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得 {@link FastDateFormat} 实例,使用默认地区<br>
|
||||
* 获得 FastDateFormat 实例,使用默认地区<br>
|
||||
* 支持缓存
|
||||
*
|
||||
* @param pattern 使用{@link java.text.SimpleDateFormat} 相同的日期格式
|
||||
* @return {@link FastDateFormat}
|
||||
* @return FastDateFormat
|
||||
* @throws IllegalArgumentException 日期格式问题
|
||||
*/
|
||||
public static FastDateFormat getInstance(final String pattern) {
|
||||
@ -71,12 +71,12 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得 {@link FastDateFormat} 实例<br>
|
||||
* 获得 FastDateFormat 实例<br>
|
||||
* 支持缓存
|
||||
*
|
||||
* @param pattern 使用{@link java.text.SimpleDateFormat} 相同的日期格式
|
||||
* @param timeZone 时区{@link TimeZone}
|
||||
* @return {@link FastDateFormat}
|
||||
* @return FastDateFormat
|
||||
* @throws IllegalArgumentException 日期格式问题
|
||||
*/
|
||||
public static FastDateFormat getInstance(final String pattern, final TimeZone timeZone) {
|
||||
@ -84,12 +84,12 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得 {@link FastDateFormat} 实例<br>
|
||||
* 获得 FastDateFormat 实例<br>
|
||||
* 支持缓存
|
||||
*
|
||||
* @param pattern 使用{@link java.text.SimpleDateFormat} 相同的日期格式
|
||||
* @param locale {@link Locale} 日期地理位置
|
||||
* @return {@link FastDateFormat}
|
||||
* @return FastDateFormat
|
||||
* @throws IllegalArgumentException 日期格式问题
|
||||
*/
|
||||
public static FastDateFormat getInstance(final String pattern, final Locale locale) {
|
||||
@ -97,13 +97,13 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得 {@link FastDateFormat} 实例<br>
|
||||
* 获得 FastDateFormat 实例<br>
|
||||
* 支持缓存
|
||||
*
|
||||
* @param pattern 使用{@link java.text.SimpleDateFormat} 相同的日期格式
|
||||
* @param timeZone 时区{@link TimeZone}
|
||||
* @param locale {@link Locale} 日期地理位置
|
||||
* @return {@link FastDateFormat}
|
||||
* @return FastDateFormat
|
||||
* @throws IllegalArgumentException 日期格式问题
|
||||
*/
|
||||
public static FastDateFormat getInstance(final String pattern, final TimeZone timeZone, final Locale locale) {
|
||||
@ -112,48 +112,48 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* 获得 {@link FastDateFormat} 实例<br>
|
||||
* 获得 FastDateFormat 实例<br>
|
||||
* 支持缓存
|
||||
*
|
||||
* @param style date style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @return 本地化 {@link FastDateFormat}
|
||||
* @return 本地化 FastDateFormat
|
||||
*/
|
||||
public static FastDateFormat getDateInstance(final int style) {
|
||||
return CACHE.getDateInstance(style, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得 {@link FastDateFormat} 实例<br>
|
||||
* 获得 FastDateFormat 实例<br>
|
||||
* 支持缓存
|
||||
*
|
||||
* @param style date style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param locale {@link Locale} 日期地理位置
|
||||
* @return 本地化 {@link FastDateFormat}
|
||||
* @return 本地化 FastDateFormat
|
||||
*/
|
||||
public static FastDateFormat getDateInstance(final int style, final Locale locale) {
|
||||
return CACHE.getDateInstance(style, null, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得 {@link FastDateFormat} 实例<br>
|
||||
* 获得 FastDateFormat 实例<br>
|
||||
* 支持缓存
|
||||
*
|
||||
* @param style date style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeZone 时区{@link TimeZone}
|
||||
* @return 本地化 {@link FastDateFormat}
|
||||
* @return 本地化 FastDateFormat
|
||||
*/
|
||||
public static FastDateFormat getDateInstance(final int style, final TimeZone timeZone) {
|
||||
return CACHE.getDateInstance(style, timeZone, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得 {@link FastDateFormat} 实例<br>
|
||||
* 获得 FastDateFormat 实例<br>
|
||||
* 支持缓存
|
||||
*
|
||||
* @param style date style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeZone 时区{@link TimeZone}
|
||||
* @param locale {@link Locale} 日期地理位置
|
||||
* @return 本地化 {@link FastDateFormat}
|
||||
* @return 本地化 FastDateFormat
|
||||
*/
|
||||
public static FastDateFormat getDateInstance(final int style, final TimeZone timeZone, final Locale locale) {
|
||||
return CACHE.getDateInstance(style, timeZone, locale);
|
||||
@ -161,48 +161,48 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* 获得 {@link FastDateFormat} 实例<br>
|
||||
* 获得 FastDateFormat 实例<br>
|
||||
* 支持缓存
|
||||
*
|
||||
* @param style time style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @return 本地化 {@link FastDateFormat}
|
||||
* @return 本地化 FastDateFormat
|
||||
*/
|
||||
public static FastDateFormat getTimeInstance(final int style) {
|
||||
return CACHE.getTimeInstance(style, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得 {@link FastDateFormat} 实例<br>
|
||||
* 获得 FastDateFormat 实例<br>
|
||||
* 支持缓存
|
||||
*
|
||||
* @param style time style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param locale {@link Locale} 日期地理位置
|
||||
* @return 本地化 {@link FastDateFormat}
|
||||
* @return 本地化 FastDateFormat
|
||||
*/
|
||||
public static FastDateFormat getTimeInstance(final int style, final Locale locale) {
|
||||
return CACHE.getTimeInstance(style, null, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得 {@link FastDateFormat} 实例<br>
|
||||
* 获得 FastDateFormat 实例<br>
|
||||
* 支持缓存
|
||||
*
|
||||
* @param style time style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeZone optional time zone, overrides time zone of formatted time
|
||||
* @return 本地化 {@link FastDateFormat}
|
||||
* @return 本地化 FastDateFormat
|
||||
*/
|
||||
public static FastDateFormat getTimeInstance(final int style, final TimeZone timeZone) {
|
||||
return CACHE.getTimeInstance(style, timeZone, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得 {@link FastDateFormat} 实例<br>
|
||||
* 获得 FastDateFormat 实例<br>
|
||||
* 支持缓存
|
||||
*
|
||||
* @param style time style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeZone optional time zone, overrides time zone of formatted time
|
||||
* @param locale {@link Locale} 日期地理位置
|
||||
* @return 本地化 {@link FastDateFormat}
|
||||
* @return 本地化 FastDateFormat
|
||||
*/
|
||||
public static FastDateFormat getTimeInstance(final int style, final TimeZone timeZone, final Locale locale) {
|
||||
return CACHE.getTimeInstance(style, timeZone, locale);
|
||||
@ -210,52 +210,52 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter {
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/**
|
||||
* 获得 {@link FastDateFormat} 实例<br>
|
||||
* 获得 FastDateFormat 实例<br>
|
||||
* 支持缓存
|
||||
*
|
||||
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @return 本地化 {@link FastDateFormat}
|
||||
* @return 本地化 FastDateFormat
|
||||
*/
|
||||
public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle) {
|
||||
return CACHE.getDateTimeInstance(dateStyle, timeStyle, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得 {@link FastDateFormat} 实例<br>
|
||||
* 获得 FastDateFormat 实例<br>
|
||||
* 支持缓存
|
||||
*
|
||||
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param locale {@link Locale} 日期地理位置
|
||||
* @return 本地化 {@link FastDateFormat}
|
||||
* @return 本地化 FastDateFormat
|
||||
*/
|
||||
public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle, final Locale locale) {
|
||||
return CACHE.getDateTimeInstance(dateStyle, timeStyle, null, locale);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得 {@link FastDateFormat} 实例<br>
|
||||
* 获得 FastDateFormat 实例<br>
|
||||
* 支持缓存
|
||||
*
|
||||
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeZone 时区{@link TimeZone}
|
||||
* @return 本地化 {@link FastDateFormat}
|
||||
* @return 本地化 FastDateFormat
|
||||
*/
|
||||
public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle, final TimeZone timeZone) {
|
||||
return getDateTimeInstance(dateStyle, timeStyle, timeZone, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得 {@link FastDateFormat} 实例<br>
|
||||
* 获得 FastDateFormat 实例<br>
|
||||
* 支持缓存
|
||||
*
|
||||
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
|
||||
* @param timeZone 时区{@link TimeZone}
|
||||
* @param locale {@link Locale} 日期地理位置
|
||||
* @return 本地化 {@link FastDateFormat}
|
||||
* @return 本地化 FastDateFormat
|
||||
*/
|
||||
public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle, final TimeZone timeZone, final Locale locale) {
|
||||
return CACHE.getDateTimeInstance(dateStyle, timeStyle, timeZone, locale);
|
||||
|
@ -767,12 +767,11 @@ public class FileUtil extends PathUtil {
|
||||
final File[] files = directory.listFiles();
|
||||
if (ArrayUtil.isEmpty(files)) {
|
||||
// 空文件夹则删除之
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
directory.delete();
|
||||
} else {
|
||||
for (File childFile : files) {
|
||||
cleanEmpty(childFile);
|
||||
}
|
||||
return directory.delete();
|
||||
}
|
||||
|
||||
for (File childFile : files) {
|
||||
cleanEmpty(childFile);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -1666,7 +1665,7 @@ public class FileUtil extends PathUtil {
|
||||
* </pre>
|
||||
*
|
||||
* @param file 文件 {@link File}
|
||||
* @return 类型,文件的扩展名,未找到为<code>null</code>
|
||||
* @return 类型,文件的扩展名,未找到为{@code null}
|
||||
* @throws IORuntimeException IO异常
|
||||
* @see FileTypeUtil#getType(File)
|
||||
*/
|
||||
|
@ -3,6 +3,7 @@ package cn.hutool.core.io.checksum;
|
||||
import cn.hutool.core.io.checksum.crc16.CRC16Checksum;
|
||||
import cn.hutool.core.io.checksum.crc16.CRC16IBM;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.zip.Checksum;
|
||||
|
||||
/**
|
||||
@ -11,7 +12,7 @@ import java.util.zip.Checksum;
|
||||
* @author looly
|
||||
* @since 4.4.1
|
||||
*/
|
||||
public class CRC16 implements Checksum {
|
||||
public class CRC16 implements Checksum, Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final CRC16Checksum crc16;
|
||||
|
@ -7,6 +7,7 @@ package cn.hutool.core.io.checksum.crc16;
|
||||
* @since 5.3.10
|
||||
*/
|
||||
public class CRC16Ansi extends CRC16Checksum{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final int WC_POLY = 0xa001;
|
||||
|
||||
|
@ -8,6 +8,7 @@ package cn.hutool.core.io.checksum.crc16;
|
||||
* @since 5.3.10
|
||||
*/
|
||||
public class CRC16CCITT extends CRC16Checksum{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final int WC_POLY = 0x8408;
|
||||
|
||||
|
@ -7,6 +7,7 @@ package cn.hutool.core.io.checksum.crc16;
|
||||
* @since 5.3.10
|
||||
*/
|
||||
public class CRC16CCITTFalse extends CRC16Checksum{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final int WC_POLY = 0x1021;
|
||||
|
||||
|
@ -8,6 +8,7 @@ package cn.hutool.core.io.checksum.crc16;
|
||||
* @since 5.3.10
|
||||
*/
|
||||
public class CRC16DNP extends CRC16Checksum{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final int WC_POLY = 0xA6BC;
|
||||
|
||||
|
@ -8,6 +8,7 @@ package cn.hutool.core.io.checksum.crc16;
|
||||
* @since 5.3.10
|
||||
*/
|
||||
public class CRC16IBM extends CRC16Checksum{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final int WC_POLY = 0xa001;
|
||||
|
||||
|
@ -8,6 +8,7 @@ package cn.hutool.core.io.checksum.crc16;
|
||||
* @since 5.3.10
|
||||
*/
|
||||
public class CRC16Maxim extends CRC16Checksum{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final int WC_POLY = 0xa001;
|
||||
|
||||
|
@ -9,6 +9,7 @@ package cn.hutool.core.io.checksum.crc16;
|
||||
* @since 5.3.10
|
||||
*/
|
||||
public class CRC16Modbus extends CRC16Checksum{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final int WC_POLY = 0xa001;
|
||||
|
||||
|
@ -8,6 +8,7 @@ package cn.hutool.core.io.checksum.crc16;
|
||||
* @since 5.3.10
|
||||
*/
|
||||
public class CRC16USB extends CRC16Checksum{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final int WC_POLY = 0xa001;
|
||||
|
||||
|
@ -8,6 +8,7 @@ package cn.hutool.core.io.checksum.crc16;
|
||||
* @since 5.3.10
|
||||
*/
|
||||
public class CRC16X25 extends CRC16Checksum{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final int WC_POLY = 0x8408;
|
||||
|
||||
|
@ -8,6 +8,7 @@ package cn.hutool.core.io.checksum.crc16;
|
||||
* @since 5.3.10
|
||||
*/
|
||||
public class CRC16XModem extends CRC16Checksum{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// 0001 0000 0010 0001 (0, 5, 12)
|
||||
private static final int WC_POLY = 0x1021;
|
||||
|
@ -193,7 +193,7 @@ public class WatchMonitor extends WatchServer {
|
||||
*
|
||||
* @param uri URI
|
||||
* @param watcher {@link Watcher}
|
||||
* @return {@link WatchMonitor}
|
||||
* @return WatchMonitor
|
||||
*/
|
||||
public static WatchMonitor createAll(URI uri, Watcher watcher) {
|
||||
return createAll(Paths.get(uri), watcher);
|
||||
@ -204,7 +204,7 @@ public class WatchMonitor extends WatchServer {
|
||||
*
|
||||
* @param url URL
|
||||
* @param watcher {@link Watcher}
|
||||
* @return {@link WatchMonitor}
|
||||
* @return WatchMonitor
|
||||
*/
|
||||
public static WatchMonitor createAll(URL url, Watcher watcher) {
|
||||
try {
|
||||
@ -219,7 +219,7 @@ public class WatchMonitor extends WatchServer {
|
||||
*
|
||||
* @param file 被监听文件
|
||||
* @param watcher {@link Watcher}
|
||||
* @return {@link WatchMonitor}
|
||||
* @return WatchMonitor
|
||||
*/
|
||||
public static WatchMonitor createAll(File file, Watcher watcher) {
|
||||
return createAll(file.toPath(), watcher);
|
||||
@ -230,7 +230,7 @@ public class WatchMonitor extends WatchServer {
|
||||
*
|
||||
* @param path 路径
|
||||
* @param watcher {@link Watcher}
|
||||
* @return {@link WatchMonitor}
|
||||
* @return WatchMonitor
|
||||
*/
|
||||
public static WatchMonitor createAll(String path, Watcher watcher) {
|
||||
return createAll(Paths.get(path), watcher);
|
||||
@ -241,7 +241,7 @@ public class WatchMonitor extends WatchServer {
|
||||
*
|
||||
* @param path 路径
|
||||
* @param watcher {@link Watcher}
|
||||
* @return {@link WatchMonitor}
|
||||
* @return WatchMonitor
|
||||
*/
|
||||
public static WatchMonitor createAll(Path path, Watcher watcher) {
|
||||
final WatchMonitor watchMonitor = create(path, EVENTS_ALL);
|
||||
@ -348,7 +348,7 @@ public class WatchMonitor extends WatchServer {
|
||||
* 多个监听请使用{@link WatcherChain}
|
||||
*
|
||||
* @param watcher 监听
|
||||
* @return {@link WatchMonitor}
|
||||
* @return WatchMonitor
|
||||
*/
|
||||
public WatchMonitor setWatcher(Watcher watcher) {
|
||||
this.watcher = watcher;
|
||||
|
@ -63,9 +63,9 @@ public class PatternPool {
|
||||
public final static Pattern CITIZEN_ID = Pattern.compile("[1-9]\\d{5}[1-2]\\d{3}((0\\d)|(1[0-2]))(([012]\\d)|3[0-1])\\d{3}(\\d|X|x)");
|
||||
|
||||
/**
|
||||
* 邮编
|
||||
* 邮编,兼容港澳台
|
||||
*/
|
||||
public final static Pattern ZIP_CODE = Pattern.compile("[1-9]\\d{5}(?!\\d)");
|
||||
public final static Pattern ZIP_CODE = Pattern.compile("^(0[1-7]|1[0-356]|2[0-7]|3[0-6]|4[0-7]|5[0-7]|6[0-7]|7[0-5]|8[0-9]|9[0-8])\\d{4}|99907[78]$");
|
||||
/**
|
||||
* 生日
|
||||
*/
|
||||
|
@ -92,7 +92,7 @@ public class Validator {
|
||||
public final static Pattern PLATE_NUMBER = PatternPool.PLATE_NUMBER;
|
||||
|
||||
/**
|
||||
* 给定值是否为<code>true</code>
|
||||
* 给定值是否为{@code true}
|
||||
*
|
||||
* @param value 值
|
||||
* @return 是否为<code>true</code>
|
||||
@ -103,7 +103,7 @@ public class Validator {
|
||||
}
|
||||
|
||||
/**
|
||||
* 给定值是否不为<code>false</code>
|
||||
* 给定值是否不为{@code false}
|
||||
*
|
||||
* @param value 值
|
||||
* @return 是否不为<code>false</code>
|
||||
@ -114,7 +114,7 @@ public class Validator {
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查指定值是否为<code>true</code>
|
||||
* 检查指定值是否为{@code true}
|
||||
*
|
||||
* @param value 值
|
||||
* @param errorMsgTemplate 错误消息内容模板(变量使用{}表示)
|
||||
@ -131,7 +131,7 @@ public class Validator {
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查指定值是否为<code>false</code>
|
||||
* 检查指定值是否为{@code false}
|
||||
*
|
||||
* @param value 值
|
||||
* @param errorMsgTemplate 错误消息内容模板(变量使用{}表示)
|
||||
@ -148,7 +148,7 @@ public class Validator {
|
||||
}
|
||||
|
||||
/**
|
||||
* 给定值是否为<code>null</code>
|
||||
* 给定值是否为{@code null}
|
||||
*
|
||||
* @param value 值
|
||||
* @return 是否为<code>null</code>
|
||||
@ -158,7 +158,7 @@ public class Validator {
|
||||
}
|
||||
|
||||
/**
|
||||
* 给定值是否不为<code>null</code>
|
||||
* 给定值是否不为{@code null}
|
||||
*
|
||||
* @param value 值
|
||||
* @return 是否不为<code>null</code>
|
||||
@ -168,7 +168,7 @@ public class Validator {
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查指定值是否为<code>null</code>
|
||||
* 检查指定值是否为{@code null}
|
||||
*
|
||||
* @param <T> 被检查的对象类型
|
||||
* @param value 值
|
||||
@ -186,7 +186,7 @@ public class Validator {
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查指定值是否非<code>null</code>
|
||||
* 检查指定值是否非{@code null}
|
||||
*
|
||||
* @param <T> 被检查的对象类型
|
||||
* @param value 值
|
||||
|
@ -13,6 +13,7 @@ import java.util.Map;
|
||||
* @since 5.2.6
|
||||
*/
|
||||
public class BiMap<K, V> extends MapWrapper<K, V> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Map<V, K> inverse;
|
||||
|
||||
|
@ -296,7 +296,7 @@ public class NetUtil {
|
||||
* 获取指定名称的网卡信息
|
||||
*
|
||||
* @param name 网络接口名,例如Linux下默认是eth0
|
||||
* @return 网卡,未找到返回<code>null</code>
|
||||
* @return 网卡,未找到返回{@code null}
|
||||
* @since 5.0.7
|
||||
*/
|
||||
public static NetworkInterface getNetworkInterface(String name) {
|
||||
@ -321,7 +321,7 @@ public class NetUtil {
|
||||
/**
|
||||
* 获取本机所有网卡
|
||||
*
|
||||
* @return 所有网卡,异常返回<code>null</code>
|
||||
* @return 所有网卡,异常返回{@code null}
|
||||
* @since 3.0.1
|
||||
*/
|
||||
public static Collection<NetworkInterface> getNetworkInterfaces() {
|
||||
@ -425,11 +425,11 @@ public class NetUtil {
|
||||
/**
|
||||
* 获取本机网卡IP地址,这个地址为所有网卡中非回路地址的第一个<br>
|
||||
* 如果获取失败调用 {@link InetAddress#getLocalHost()}方法获取。<br>
|
||||
* 此方法不会抛出异常,获取失败将返回<code>null</code><br>
|
||||
* 此方法不会抛出异常,获取失败将返回{@code null}<br>
|
||||
* <p>
|
||||
* 参考:http://stackoverflow.com/questions/9481865/getting-the-ip-address-of-the-current-machine-using-java
|
||||
*
|
||||
* @return 本机网卡IP地址,获取失败返回<code>null</code>
|
||||
* @return 本机网卡IP地址,获取失败返回{@code null}
|
||||
* @since 3.0.7
|
||||
*/
|
||||
public static String getLocalhostStr() {
|
||||
@ -448,11 +448,11 @@ public class NetUtil {
|
||||
* 2. 如果无满足要求的地址,调用 {@link InetAddress#getLocalHost()} 获取地址
|
||||
* </pre>
|
||||
* <p>
|
||||
* 此方法不会抛出异常,获取失败将返回<code>null</code><br>
|
||||
* 此方法不会抛出异常,获取失败将返回{@code null}<br>
|
||||
* <p>
|
||||
* 见:https://github.com/looly/hutool/issues/428
|
||||
*
|
||||
* @return 本机网卡IP地址,获取失败返回<code>null</code>
|
||||
* @return 本机网卡IP地址,获取失败返回{@code null}
|
||||
* @since 3.0.1
|
||||
*/
|
||||
public static InetAddress getLocalhost() {
|
||||
@ -674,6 +674,7 @@ public class NetUtil {
|
||||
* @since 4.4.1
|
||||
* @deprecated 拼写错误,请使用{@link #isUnknown(String)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean isUnknow(String checkString) {
|
||||
return isUnknown(checkString);
|
||||
}
|
||||
|
@ -0,0 +1,146 @@
|
||||
package cn.hutool.core.net;
|
||||
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
/**
|
||||
* {@link SSLContext}构建器
|
||||
*
|
||||
* @author Looly
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public class SSLContextBuilder {
|
||||
|
||||
/**
|
||||
* Supports some version of SSL; may support other versions
|
||||
*/
|
||||
public static final String SSL = "SSL";
|
||||
/**
|
||||
* Supports SSL version 2 or later; may support other versions
|
||||
*/
|
||||
public static final String SSLv2 = "SSLv2";
|
||||
/**
|
||||
* Supports SSL version 3; may support other versions
|
||||
*/
|
||||
public static final String SSLv3 = "SSLv3";
|
||||
|
||||
/**
|
||||
* Supports some version of TLS; may support other versions
|
||||
*/
|
||||
public static final String TLS = "TLS";
|
||||
/**
|
||||
* Supports RFC 2246: TLS version 1.0 ; may support other versions
|
||||
*/
|
||||
public static final String TLSv1 = "TLSv1";
|
||||
/**
|
||||
* Supports RFC 4346: TLS version 1.1 ; may support other versions
|
||||
*/
|
||||
public static final String TLSv11 = "TLSv1.1";
|
||||
/**
|
||||
* Supports RFC 5246: TLS version 1.2 ; may support other versions
|
||||
*/
|
||||
public static final String TLSv12 = "TLSv1.2";
|
||||
|
||||
private String protocol = TLS;
|
||||
private KeyManager[] keyManagers;
|
||||
private TrustManager[] trustManagers;
|
||||
private SecureRandom secureRandom = new SecureRandom();
|
||||
|
||||
|
||||
/**
|
||||
* 创建 SSLContextBuilder
|
||||
*
|
||||
* @return SSLContextBuilder
|
||||
*/
|
||||
public static SSLContextBuilder create() {
|
||||
return new SSLContextBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置协议。例如TLS等
|
||||
*
|
||||
* @param protocol 协议
|
||||
* @return 自身
|
||||
*/
|
||||
public SSLContextBuilder setProtocol(String protocol) {
|
||||
if (StrUtil.isNotBlank(protocol)) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置信任信息
|
||||
*
|
||||
* @param trustManagers TrustManager列表
|
||||
* @return 自身
|
||||
*/
|
||||
public SSLContextBuilder setTrustManagers(TrustManager... trustManagers) {
|
||||
if (ArrayUtil.isNotEmpty(trustManagers)) {
|
||||
this.trustManagers = trustManagers;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 JSSE key managers
|
||||
*
|
||||
* @param keyManagers JSSE key managers
|
||||
* @return 自身
|
||||
*/
|
||||
public SSLContextBuilder setKeyManagers(KeyManager... keyManagers) {
|
||||
if (ArrayUtil.isNotEmpty(keyManagers)) {
|
||||
this.keyManagers = keyManagers;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 SecureRandom
|
||||
*
|
||||
* @param secureRandom SecureRandom
|
||||
* @return 自己
|
||||
*/
|
||||
public SSLContextBuilder setSecureRandom(SecureRandom secureRandom) {
|
||||
if (null != secureRandom) {
|
||||
this.secureRandom = secureRandom;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建{@link SSLContext}
|
||||
*
|
||||
* @return {@link SSLContext}
|
||||
* @throws NoSuchAlgorithmException 无此算法
|
||||
* @throws KeyManagementException Key管理异常
|
||||
*/
|
||||
public SSLContext build() throws NoSuchAlgorithmException, KeyManagementException {
|
||||
SSLContext sslContext = SSLContext.getInstance(protocol);
|
||||
sslContext.init(this.keyManagers, this.trustManagers, this.secureRandom);
|
||||
return sslContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建{@link SSLContext}
|
||||
*
|
||||
* @return {@link SSLContext}
|
||||
* @throws IORuntimeException 包装 GeneralSecurityException异常
|
||||
*/
|
||||
public SSLContext buildQuietly() throws IORuntimeException{
|
||||
try {
|
||||
return build();
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new IORuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
49
hutool-core/src/main/java/cn/hutool/core/net/SSLUtil.java
Normal file
49
hutool-core/src/main/java/cn/hutool/core/net/SSLUtil.java
Normal file
@ -0,0 +1,49 @@
|
||||
package cn.hutool.core.net;
|
||||
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
|
||||
/**
|
||||
* SSL(Secure Sockets Layer 安全套接字协议)相关工具封装
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public class SSLUtil {
|
||||
|
||||
/**
|
||||
* 创建{@link SSLContext}
|
||||
*
|
||||
* @param protocol SSL协议,例如TLS等
|
||||
* @param keyManager 密钥管理器,{@code null}表示无
|
||||
* @param trustManager 信任管理器, {@code null}表示无
|
||||
* @return {@link SSLContext}
|
||||
* @throws IORuntimeException 包装 GeneralSecurityException异常
|
||||
*/
|
||||
public static SSLContext createSSLContext(String protocol, KeyManager keyManager, TrustManager trustManager)
|
||||
throws IORuntimeException {
|
||||
return createSSLContext(protocol,
|
||||
keyManager == null ? null : new KeyManager[]{keyManager},
|
||||
trustManager == null ? null : new TrustManager[]{trustManager});
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建和初始化{@link SSLContext}
|
||||
*
|
||||
* @param protocol SSL协议,例如TLS等
|
||||
* @param keyManagers 密钥管理器,{@code null}表示无
|
||||
* @param trustManagers 信任管理器, {@code null}表示无
|
||||
* @return {@link SSLContext}
|
||||
* @throws IORuntimeException 包装 GeneralSecurityException异常
|
||||
*/
|
||||
public static SSLContext createSSLContext(String protocol, KeyManager[] keyManagers, TrustManager[] trustManagers) throws IORuntimeException {
|
||||
return SSLContextBuilder.create()
|
||||
.setProtocol(protocol)
|
||||
.setKeyManagers(keyManagers)
|
||||
.setTrustManagers(trustManagers).buildQuietly();
|
||||
}
|
||||
|
||||
}
|
@ -30,7 +30,7 @@ import java.util.function.Function;
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
public class ArrayUtil extends PrimitiveArrayUtil{
|
||||
public class ArrayUtil extends PrimitiveArrayUtil {
|
||||
|
||||
// ---------------------------------------------------------------------- isEmpty
|
||||
|
||||
@ -1761,4 +1761,89 @@ public class ArrayUtil extends PrimitiveArrayUtil{
|
||||
|
||||
return firstIndex;
|
||||
}
|
||||
|
||||
// O(n)时间复杂度检查数组是否有序
|
||||
|
||||
/**
|
||||
* 检查数组是否有序,即comparator.compare(array[i], array[i + 1]) <= 0,若传入空数组或空比较器,则返回false
|
||||
*
|
||||
* @param array 数组
|
||||
* @param comparator 比较器
|
||||
* @param <T> 数组元素类型
|
||||
* @return 数组是否有序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static <T> boolean isSorted(T[] array, Comparator<? super T> comparator) {
|
||||
if (array == null || comparator == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < array.length - 1; i++) {
|
||||
if (comparator.compare(array[i], array[i + 1]) > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数组是否升序,即array[i].compareTo(array[i + 1]) <= 0,若传入空数组,则返回false
|
||||
*
|
||||
* @param <T> 数组元素类型,该类型需要实现Comparable接口
|
||||
* @param array 数组
|
||||
* @return 数组是否升序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static <T extends Comparable<? super T>> boolean isSorted(T[] array) {
|
||||
return isSortedASC(array);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检查数组是否升序,即array[i].compareTo(array[i + 1]) <= 0,若传入空数组,则返回false
|
||||
*
|
||||
* @param <T> 数组元素类型,该类型需要实现Comparable接口
|
||||
* @param array 数组
|
||||
* @return 数组是否升序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static <T extends Comparable<? super T>> boolean isSortedASC(T[] array) {
|
||||
if (array == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < array.length - 1; i++) {
|
||||
if (array[i].compareTo(array[i + 1]) > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数组是否降序,即array[i].compareTo(array[i + 1]) >= 0,若传入空数组,则返回false
|
||||
*
|
||||
* @param <T> 数组元素类型,该类型需要实现Comparable接口
|
||||
* @param array 数组
|
||||
* @return 数组是否降序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static <T extends Comparable<? super T>> boolean isSortedDESC(T[] array) {
|
||||
if (array == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < array.length - 1; i++) {
|
||||
if (array[i].compareTo(array[i + 1]) < 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -2039,9 +2039,7 @@ public class PrimitiveArrayUtil {
|
||||
int j = Math.min(array.length, endIndexExclusive) - 1;
|
||||
long tmp;
|
||||
while (j > i) {
|
||||
tmp = array[j];
|
||||
array[j] = array[i];
|
||||
array[i] = tmp;
|
||||
swap(array, i, j);
|
||||
j--;
|
||||
i++;
|
||||
}
|
||||
@ -2076,9 +2074,7 @@ public class PrimitiveArrayUtil {
|
||||
int j = Math.min(array.length, endIndexExclusive) - 1;
|
||||
int tmp;
|
||||
while (j > i) {
|
||||
tmp = array[j];
|
||||
array[j] = array[i];
|
||||
array[i] = tmp;
|
||||
swap(array, i, j);
|
||||
j--;
|
||||
i++;
|
||||
}
|
||||
@ -2113,9 +2109,7 @@ public class PrimitiveArrayUtil {
|
||||
int j = Math.min(array.length, endIndexExclusive) - 1;
|
||||
short tmp;
|
||||
while (j > i) {
|
||||
tmp = array[j];
|
||||
array[j] = array[i];
|
||||
array[i] = tmp;
|
||||
swap(array, i, j);
|
||||
j--;
|
||||
i++;
|
||||
}
|
||||
@ -2150,9 +2144,7 @@ public class PrimitiveArrayUtil {
|
||||
int j = Math.min(array.length, endIndexExclusive) - 1;
|
||||
char tmp;
|
||||
while (j > i) {
|
||||
tmp = array[j];
|
||||
array[j] = array[i];
|
||||
array[i] = tmp;
|
||||
swap(array, i, j);
|
||||
j--;
|
||||
i++;
|
||||
}
|
||||
@ -2187,9 +2179,7 @@ public class PrimitiveArrayUtil {
|
||||
int j = Math.min(array.length, endIndexExclusive) - 1;
|
||||
byte tmp;
|
||||
while (j > i) {
|
||||
tmp = array[j];
|
||||
array[j] = array[i];
|
||||
array[i] = tmp;
|
||||
swap(array, i, j);
|
||||
j--;
|
||||
i++;
|
||||
}
|
||||
@ -2224,9 +2214,7 @@ public class PrimitiveArrayUtil {
|
||||
int j = Math.min(array.length, endIndexExclusive) - 1;
|
||||
double tmp;
|
||||
while (j > i) {
|
||||
tmp = array[j];
|
||||
array[j] = array[i];
|
||||
array[i] = tmp;
|
||||
swap(array, i, j);
|
||||
j--;
|
||||
i++;
|
||||
}
|
||||
@ -2261,9 +2249,7 @@ public class PrimitiveArrayUtil {
|
||||
int j = Math.min(array.length, endIndexExclusive) - 1;
|
||||
float tmp;
|
||||
while (j > i) {
|
||||
tmp = array[j];
|
||||
array[j] = array[i];
|
||||
array[i] = tmp;
|
||||
swap(array, i, j);
|
||||
j--;
|
||||
i++;
|
||||
}
|
||||
@ -2298,9 +2284,7 @@ public class PrimitiveArrayUtil {
|
||||
int j = Math.min(array.length, endIndexExclusive) - 1;
|
||||
boolean tmp;
|
||||
while (j > i) {
|
||||
tmp = array[j];
|
||||
array[j] = array[i];
|
||||
array[i] = tmp;
|
||||
swap(array, i, j);
|
||||
j--;
|
||||
i++;
|
||||
}
|
||||
@ -3019,4 +3003,396 @@ public class PrimitiveArrayUtil {
|
||||
array[index2] = tmp;
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数组是否升序,即array[i] <= array[i+1],若传入空数组,则返回false
|
||||
*
|
||||
* @param array 数组
|
||||
* @return 数组是否升序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static boolean isSorted(byte[] array) {
|
||||
return isSortedASC(array);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数组是否升序,即array[i] <= array[i+1],若传入空数组,则返回false
|
||||
*
|
||||
* @param array 数组
|
||||
* @return 数组是否升序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static boolean isSortedASC(byte[] array) {
|
||||
if (array == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < array.length - 1; i++) {
|
||||
if (array[i] > array[i + 1]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数组是否降序,即array[i] >= array[i+1],若传入空数组,则返回false
|
||||
*
|
||||
* @param array 数组
|
||||
* @return 数组是否降序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static boolean isSortedDESC(byte[] array) {
|
||||
if (array == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < array.length - 1; i++) {
|
||||
if (array[i] < array[i + 1]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数组是否升序,即array[i] <= array[i+1],若传入空数组,则返回false
|
||||
*
|
||||
* @param array 数组
|
||||
* @return 数组是否升序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static boolean isSorted(short[] array) {
|
||||
return isSortedASC(array);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数组是否升序,即array[i] <= array[i+1],若传入空数组,则返回false
|
||||
*
|
||||
* @param array 数组
|
||||
* @return 数组是否升序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static boolean isSortedASC(short[] array) {
|
||||
if (array == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < array.length - 1; i++) {
|
||||
if (array[i] > array[i + 1]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数组是否降序,即array[i] >= array[i+1],若传入空数组,则返回false
|
||||
*
|
||||
* @param array 数组
|
||||
* @return 数组是否降序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static boolean isSortedDESC(short[] array) {
|
||||
if (array == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < array.length - 1; i++) {
|
||||
if (array[i] < array[i + 1]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数组是否升序,即array[i] <= array[i+1],若传入空数组,则返回false
|
||||
*
|
||||
* @param array 数组
|
||||
* @return 数组是否升序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static boolean isSorted(char[] array) {
|
||||
return isSortedASC(array);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数组是否升序,即array[i] <= array[i+1],若传入空数组,则返回false
|
||||
*
|
||||
* @param array 数组
|
||||
* @return 数组是否升序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static boolean isSortedASC(char[] array) {
|
||||
if (array == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < array.length - 1; i++) {
|
||||
if (array[i] > array[i + 1]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数组是否降序,即array[i] >= array[i+1],若传入空数组,则返回false
|
||||
*
|
||||
* @param array 数组
|
||||
* @return 数组是否降序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static boolean isSortedDESC(char[] array) {
|
||||
if (array == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < array.length - 1; i++) {
|
||||
if (array[i] < array[i + 1]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数组是否升序,即array[i] <= array[i+1],若传入空数组,则返回false
|
||||
*
|
||||
* @param array 数组
|
||||
* @return 数组是否升序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static boolean isSorted(int[] array) {
|
||||
return isSortedASC(array);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数组是否升序,即array[i] <= array[i+1],若传入空数组,则返回false
|
||||
*
|
||||
* @param array 数组
|
||||
* @return 数组是否升序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static boolean isSortedASC(int[] array) {
|
||||
if (array == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < array.length - 1; i++) {
|
||||
if (array[i] > array[i + 1]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数组是否降序,即array[i] >= array[i+1],若传入空数组,则返回false
|
||||
*
|
||||
* @param array 数组
|
||||
* @return 数组是否降序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static boolean isSortedDESC(int[] array) {
|
||||
if (array == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < array.length - 1; i++) {
|
||||
if (array[i] < array[i + 1]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数组是否升序,即array[i] <= array[i+1],若传入空数组,则返回false
|
||||
*
|
||||
* @param array 数组
|
||||
* @return 数组是否升序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static boolean isSorted(long[] array) {
|
||||
return isSortedASC(array);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数组是否升序,即array[i] <= array[i+1],若传入空数组,则返回false
|
||||
*
|
||||
* @param array 数组
|
||||
* @return 数组是否升序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static boolean isSortedASC(long[] array) {
|
||||
if (array == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < array.length - 1; i++) {
|
||||
if (array[i] > array[i + 1]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数组是否降序,即array[i] >= array[i+1],若传入空数组,则返回false
|
||||
*
|
||||
* @param array 数组
|
||||
* @return 数组是否降序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static boolean isSortedDESC(long[] array) {
|
||||
if (array == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < array.length - 1; i++) {
|
||||
if (array[i] < array[i + 1]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数组是否升序,即array[i] <= array[i+1],若传入空数组,则返回false
|
||||
*
|
||||
* @param array 数组
|
||||
* @return 数组是否升序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static boolean isSorted(double[] array) {
|
||||
return isSortedASC(array);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数组是否升序,即array[i] <= array[i+1],若传入空数组,则返回false
|
||||
*
|
||||
* @param array 数组
|
||||
* @return 数组是否升序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static boolean isSortedASC(double[] array) {
|
||||
if (array == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < array.length - 1; i++) {
|
||||
if (array[i] > array[i + 1]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数组是否降序,即array[i] >= array[i+1],若传入空数组,则返回false
|
||||
*
|
||||
* @param array 数组
|
||||
* @return 数组是否降序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static boolean isSortedDESC(double[] array) {
|
||||
if (array == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < array.length - 1; i++) {
|
||||
if (array[i] < array[i + 1]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数组是否升序,即array[i] <= array[i+1],若传入空数组,则返回false
|
||||
*
|
||||
* @param array 数组
|
||||
* @return 数组是否升序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static boolean isSorted(float[] array) {
|
||||
return isSortedASC(array);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数组是否升序,即array[i] <= array[i+1],若传入空数组,则返回false
|
||||
*
|
||||
* @param array 数组
|
||||
* @return 数组是否升序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static boolean isSortedASC(float[] array) {
|
||||
if (array == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < array.length - 1; i++) {
|
||||
if (array[i] > array[i + 1]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查数组是否降序,即array[i] >= array[i+1],若传入空数组,则返回false
|
||||
*
|
||||
* @param array 数组
|
||||
* @return 数组是否降序
|
||||
* @author FengBaoheng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public static boolean isSortedDESC(float[] array) {
|
||||
if (array == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < array.length - 1; i++) {
|
||||
if (array[i] < array[i + 1]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
package cn.hutool.core.codec;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class PunyCodeTest {
|
||||
|
||||
@Test
|
||||
public void encodeDecodeTest(){
|
||||
String text = "Hutool编码器";
|
||||
String strPunyCode = PunyCode.encode(text);
|
||||
Assert.assertEquals("Hutool-ux9js33tgln", strPunyCode);
|
||||
String decode = PunyCode.decode("Hutool-ux9js33tgln");
|
||||
Assert.assertEquals(text, decode);
|
||||
decode = PunyCode.decode("xn--Hutool-ux9js33tgln");
|
||||
Assert.assertEquals(text, decode);
|
||||
}
|
||||
}
|
@ -51,6 +51,6 @@ public class VersionComparatorTest {
|
||||
public void equalsTest(){
|
||||
VersionComparator first = new VersionComparator();
|
||||
VersionComparator other = new VersionComparator();
|
||||
Assert.assertFalse(first.equals(other));
|
||||
Assert.assertNotEquals(first, other);
|
||||
}
|
||||
}
|
||||
|
@ -161,4 +161,30 @@ public class ValidatorTest {
|
||||
Assert.assertTrue(Validator.isUUID(IdUtil.randomUUID().toUpperCase()));
|
||||
Assert.assertTrue(Validator.isUUID(IdUtil.fastSimpleUUID().toUpperCase()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isZipCodeTest(){
|
||||
// 港
|
||||
boolean zipCode = Validator.isZipCode("999077");
|
||||
Assert.assertTrue(zipCode);
|
||||
// 澳
|
||||
zipCode = Validator.isZipCode("999078");
|
||||
Assert.assertTrue(zipCode);
|
||||
// 台(2020年3月起改用6位邮编,3+3)
|
||||
zipCode = Validator.isZipCode("822001");
|
||||
Assert.assertTrue(zipCode);
|
||||
|
||||
// 内蒙
|
||||
zipCode = Validator.isZipCode("016063");
|
||||
Assert.assertTrue(zipCode);
|
||||
// 山西
|
||||
zipCode = Validator.isZipCode("045246");
|
||||
Assert.assertTrue(zipCode);
|
||||
// 河北
|
||||
zipCode = Validator.isZipCode("066502");
|
||||
Assert.assertTrue(zipCode);
|
||||
// 北京
|
||||
zipCode = Validator.isZipCode("102629");
|
||||
Assert.assertTrue(zipCode);
|
||||
}
|
||||
}
|
||||
|
@ -377,4 +377,11 @@ public class ArrayUtilTest {
|
||||
i = ArrayUtil.lastIndexOfSub(null, b);
|
||||
Assert.assertEquals(-1, i);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reverseTest(){
|
||||
int[] a = {1,2,3,4};
|
||||
final int[] reverse = ArrayUtil.reverse(a);
|
||||
Assert.assertArrayEquals(new int[]{4,3,2,1}, reverse);
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,8 @@ public class EnumUtilTest {
|
||||
@Test
|
||||
public void getFieldNamesTest() {
|
||||
List<String> names = EnumUtil.getFieldNames(TestEnum.class);
|
||||
Assert.assertEquals(CollUtil.newArrayList("type", "name"), names);
|
||||
Assert.assertTrue(names.contains("type"));
|
||||
Assert.assertTrue(names.contains("name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -90,7 +90,7 @@ public class SM4 extends SymmetricCrypto{
|
||||
* @param iv 偏移向量,加盐
|
||||
*/
|
||||
public SM4(Mode mode, Padding padding, SecretKey key, byte[] iv) {
|
||||
this(mode, padding, key, ArrayUtil.isEmpty(iv) ? ((IvParameterSpec) null) : new IvParameterSpec(iv));
|
||||
this(mode, padding, key, ArrayUtil.isEmpty(iv) ? null : new IvParameterSpec(iv));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -137,7 +137,7 @@ public class SM4 extends SymmetricCrypto{
|
||||
public SM4(String mode, String padding, byte[] key, byte[] iv) {
|
||||
this(mode, padding,//
|
||||
SecureUtil.generateKey(ALGORITHM_NAME, key),//
|
||||
ArrayUtil.isEmpty(iv) ? ((IvParameterSpec) null) : new IvParameterSpec(iv));
|
||||
ArrayUtil.isEmpty(iv) ? null : new IvParameterSpec(iv));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,6 +65,7 @@ public class Column implements Serializable, Cloneable {
|
||||
* @return 列对象
|
||||
* @deprecated 请使用 {@link #create(Table, ResultSet)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static Column create(String tableName, ResultSet columnMetaRs) {
|
||||
return new Column(tableName, columnMetaRs);
|
||||
}
|
||||
|
@ -29,6 +29,6 @@ public class UpdateTest {
|
||||
int update = db.update(Entity.create("user").set("age", 88), Entity.create().set("name", "unitTestUser"));
|
||||
Assert.assertTrue(update > 0);
|
||||
Entity result2 = db.get("user", "name", "unitTestUser");
|
||||
Assert.assertSame(88, (int) result2.getInt("age"));
|
||||
Assert.assertSame(88, result2.getInt("age"));
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
package cn.hutool.extra.template.engine.beetl;
|
||||
|
||||
import cn.hutool.extra.template.AbstractTemplate;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.io.Writer;
|
||||
import java.util.Map;
|
||||
|
||||
import cn.hutool.extra.template.AbstractTemplate;
|
||||
|
||||
/**
|
||||
* Beetl模板实现
|
||||
*
|
||||
@ -21,7 +21,7 @@ public class BeetlTemplate extends AbstractTemplate implements Serializable{
|
||||
* 包装Beetl模板
|
||||
*
|
||||
* @param beetlTemplate Beetl的模板对象 {@link org.beetl.core.Template}
|
||||
* @return {@link BeetlTemplate}
|
||||
* @return BeetlTemplate
|
||||
*/
|
||||
public static BeetlTemplate wrap(org.beetl.core.Template beetlTemplate) {
|
||||
return (null == beetlTemplate) ? null : new BeetlTemplate(beetlTemplate);
|
||||
|
@ -260,7 +260,7 @@ public final class BeetlUtil {
|
||||
/**
|
||||
* 创建
|
||||
*
|
||||
* @return {@link ResourceLoaderBuilder}
|
||||
* @return ResourceLoaderBuilder
|
||||
*/
|
||||
public static ResourceLoaderBuilder create() {
|
||||
return new ResourceLoaderBuilder();
|
||||
@ -271,7 +271,7 @@ public final class BeetlUtil {
|
||||
*
|
||||
* @param matcher {@link Matcher} 匹配器
|
||||
* @param resourceLoader {@link ResourceLoader} 匹配时对应的资源加载器
|
||||
* @return {@link ResourceLoaderBuilder}
|
||||
* @return ResourceLoaderBuilder
|
||||
*/
|
||||
public ResourceLoaderBuilder add(Matcher matcher, ResourceLoader<?> resourceLoader) {
|
||||
compositeResourceLoader.addResourceLoader(matcher, resourceLoader);
|
||||
|
@ -20,9 +20,9 @@ public class EmojiUtilTest {
|
||||
@Test
|
||||
public void containsEmojiTest() {
|
||||
boolean containsEmoji = EmojiUtil.containsEmoji("测试一下是否包含EMOJ:😄");
|
||||
Assert.assertEquals(containsEmoji, true);
|
||||
Assert.assertTrue(containsEmoji);
|
||||
boolean notContainsEmoji = EmojiUtil.containsEmoji("不包含EMOJ:^_^");
|
||||
Assert.assertEquals(notContainsEmoji, false);
|
||||
Assert.assertFalse(notContainsEmoji);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package cn.hutool.extra.expression;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.lang.Console;
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.extra.expression.engine.aviator.AviatorEngine;
|
||||
@ -16,7 +17,7 @@ public class AviatorTest {
|
||||
|
||||
@Test
|
||||
public void simpleTest(){
|
||||
Foo foo = new Foo(100, 3.14f, new Date());
|
||||
Foo foo = new Foo(100, 3.14f, DateUtil.parseDate("2020-11-12"));
|
||||
ExpressionEngine engine = new AviatorEngine();
|
||||
String exp =
|
||||
"\"[foo i=\"+ foo.i + \", f=\" + foo.f + \", date.year=\" + (foo.date.year+1900) + \", date.month=\" + foo.date.month + \", bars[0].name=\" + #foo.bars[0].name + \"]\"";
|
||||
|
@ -1,5 +1,8 @@
|
||||
package cn.hutool.http;
|
||||
|
||||
import cn.hutool.core.lang.Console;
|
||||
import cn.hutool.core.util.CharUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@ -10,9 +13,6 @@ import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import cn.hutool.core.lang.Console;
|
||||
import cn.hutool.core.util.CharUtil;
|
||||
|
||||
/**
|
||||
* HTML过滤器,用于去除XSS(Cross Site Scripting) 漏洞隐患。
|
||||
*
|
||||
@ -74,11 +74,11 @@ public final class HTMLFilter {
|
||||
private final Map<String, Integer> vTagCounts = new HashMap<>();
|
||||
|
||||
/**
|
||||
* html elements which must always be self-closing (e.g. "<img />")
|
||||
* html elements which must always be self-closing (e.g. "<img />")
|
||||
**/
|
||||
private final String[] vSelfClosingTags;
|
||||
/**
|
||||
* html elements which must always have separate opening and closing tags (e.g. "<b></b>")
|
||||
* html elements which must always have separate opening and closing tags (e.g. "<b></b>")
|
||||
**/
|
||||
private final String[] vNeedClosingTags;
|
||||
/**
|
||||
@ -94,7 +94,7 @@ public final class HTMLFilter {
|
||||
**/
|
||||
private final String[] vAllowedProtocols;
|
||||
/**
|
||||
* tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />")
|
||||
* tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />")
|
||||
**/
|
||||
private final String[] vRemoveBlanks;
|
||||
/**
|
||||
@ -108,7 +108,8 @@ public final class HTMLFilter {
|
||||
private final boolean encodeQuotes;
|
||||
private boolean vDebug = false;
|
||||
/**
|
||||
* flag determining whether to try to make tags when presented with "unbalanced" angle brackets (e.g. "<b text </b>" becomes "<b> text </b>"). If set to false, unbalanced angle brackets will be
|
||||
* flag determining whether to try to make tags when presented with "unbalanced" angle brackets (e.g. "<b text </b>" becomes "<b> text </g>").
|
||||
* If set to false, unbalanced angle brackets will be
|
||||
* html escaped.
|
||||
*/
|
||||
private final boolean alwaysMakeTags;
|
||||
@ -452,7 +453,7 @@ public final class HTMLFilter {
|
||||
Matcher m = P_ENTITY.matcher(s);
|
||||
while (m.find()) {
|
||||
final String match = m.group(1);
|
||||
final int decimal = Integer.decode(match).intValue();
|
||||
final int decimal = Integer.decode(match);
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
@ -462,7 +463,7 @@ public final class HTMLFilter {
|
||||
m = P_ENTITY_UNICODE.matcher(s);
|
||||
while (m.find()) {
|
||||
final String match = m.group(1);
|
||||
final int decimal = Integer.valueOf(match, 16).intValue();
|
||||
final int decimal = Integer.parseInt(match, 16);
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
@ -472,7 +473,7 @@ public final class HTMLFilter {
|
||||
m = P_ENCODE.matcher(s);
|
||||
while (m.find()) {
|
||||
final String match = m.group(1);
|
||||
final int decimal = Integer.valueOf(match, 16).intValue();
|
||||
final int decimal = Integer.parseInt(match, 16);
|
||||
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
|
||||
}
|
||||
m.appendTail(buf);
|
||||
|
@ -1,63 +1,78 @@
|
||||
package cn.hutool.http.ssl;
|
||||
|
||||
import cn.hutool.core.net.SSLContextBuilder;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
/**
|
||||
* SSLSocketFactory构建器
|
||||
* @author Looly
|
||||
*
|
||||
* @author Looly
|
||||
* @see SSLContextBuilder
|
||||
*/
|
||||
public class SSLSocketFactoryBuilder{
|
||||
public class SSLSocketFactoryBuilder {
|
||||
|
||||
/** Supports some version of SSL; may support other versions */
|
||||
public static final String SSL = "SSL";
|
||||
/** Supports SSL version 2 or later; may support other versions */
|
||||
public static final String SSLv2 = "SSLv2";
|
||||
/** Supports SSL version 3; may support other versions */
|
||||
public static final String SSLv3 = "SSLv3";
|
||||
/**
|
||||
* Supports some version of SSL; may support other versions
|
||||
*/
|
||||
public static final String SSL = SSLContextBuilder.SSL;
|
||||
/**
|
||||
* Supports SSL version 2 or later; may support other versions
|
||||
*/
|
||||
public static final String SSLv2 = SSLContextBuilder.SSLv2;
|
||||
/**
|
||||
* Supports SSL version 3; may support other versions
|
||||
*/
|
||||
public static final String SSLv3 = SSLContextBuilder.SSLv3;
|
||||
|
||||
/** Supports some version of TLS; may support other versions */
|
||||
public static final String TLS = "TLS";
|
||||
/** Supports RFC 2246: TLS version 1.0 ; may support other versions */
|
||||
public static final String TLSv1 = "TLSv1";
|
||||
/** Supports RFC 4346: TLS version 1.1 ; may support other versions */
|
||||
public static final String TLSv11 = "TLSv1.1";
|
||||
/** Supports RFC 5246: TLS version 1.2 ; may support other versions */
|
||||
public static final String TLSv12 = "TLSv1.2";
|
||||
/**
|
||||
* Supports some version of TLS; may support other versions
|
||||
*/
|
||||
public static final String TLS = SSLContextBuilder.TLS;
|
||||
/**
|
||||
* Supports RFC 2246: TLS version 1.0 ; may support other versions
|
||||
*/
|
||||
public static final String TLSv1 = SSLContextBuilder.TLSv1;
|
||||
/**
|
||||
* Supports RFC 4346: TLS version 1.1 ; may support other versions
|
||||
*/
|
||||
public static final String TLSv11 = SSLContextBuilder.TLSv11;
|
||||
/**
|
||||
* Supports RFC 5246: TLS version 1.2 ; may support other versions
|
||||
*/
|
||||
public static final String TLSv12 = SSLContextBuilder.TLSv12;
|
||||
|
||||
private String protocol = TLS;
|
||||
private KeyManager[] keyManagers;
|
||||
private TrustManager[] trustManagers = {new DefaultTrustManager()};
|
||||
private SecureRandom secureRandom = new SecureRandom();
|
||||
SSLContextBuilder sslContextBuilder;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*/
|
||||
public SSLSocketFactoryBuilder() {
|
||||
this.sslContextBuilder = SSLContextBuilder.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 SSLSocketFactoryBuilder
|
||||
*
|
||||
* @return SSLSocketFactoryBuilder
|
||||
*/
|
||||
public static SSLSocketFactoryBuilder create(){
|
||||
public static SSLSocketFactoryBuilder create() {
|
||||
return new SSLSocketFactoryBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置协议
|
||||
*
|
||||
* @param protocol 协议
|
||||
* @return 自身
|
||||
*/
|
||||
public SSLSocketFactoryBuilder setProtocol(String protocol){
|
||||
if(StrUtil.isNotBlank(protocol)){
|
||||
this.protocol = protocol;
|
||||
}
|
||||
public SSLSocketFactoryBuilder setProtocol(String protocol) {
|
||||
this.sslContextBuilder.setProtocol(protocol);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -68,9 +83,7 @@ public class SSLSocketFactoryBuilder{
|
||||
* @return 自身
|
||||
*/
|
||||
public SSLSocketFactoryBuilder setTrustManagers(TrustManager... trustManagers) {
|
||||
if (ArrayUtil.isNotEmpty(trustManagers)) {
|
||||
this.trustManagers = trustManagers;
|
||||
}
|
||||
this.sslContextBuilder.setTrustManagers(trustManagers);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -81,33 +94,29 @@ public class SSLSocketFactoryBuilder{
|
||||
* @return 自身
|
||||
*/
|
||||
public SSLSocketFactoryBuilder setKeyManagers(KeyManager... keyManagers) {
|
||||
if (ArrayUtil.isNotEmpty(keyManagers)) {
|
||||
this.keyManagers = keyManagers;
|
||||
}
|
||||
this.sslContextBuilder.setKeyManagers(keyManagers);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 SecureRandom
|
||||
*
|
||||
* @param secureRandom SecureRandom
|
||||
* @return 自己
|
||||
*/
|
||||
public SSLSocketFactoryBuilder setSecureRandom(SecureRandom secureRandom){
|
||||
if(null != secureRandom){
|
||||
this.secureRandom = secureRandom;
|
||||
}
|
||||
public SSLSocketFactoryBuilder setSecureRandom(SecureRandom secureRandom) {
|
||||
this.sslContextBuilder.setSecureRandom(secureRandom);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建SSLSocketFactory
|
||||
*
|
||||
* @return SSLSocketFactory
|
||||
* @throws NoSuchAlgorithmException 无此算法
|
||||
* @throws KeyManagementException Key管理异常
|
||||
* @throws KeyManagementException Key管理异常
|
||||
*/
|
||||
public SSLSocketFactory build() throws NoSuchAlgorithmException, KeyManagementException{
|
||||
SSLContext sslContext = SSLContext.getInstance(protocol);
|
||||
sslContext.init(this.keyManagers, this.trustManagers, this.secureRandom);
|
||||
return sslContext.getSocketFactory();
|
||||
public SSLSocketFactory build() throws NoSuchAlgorithmException, KeyManagementException {
|
||||
return this.sslContextBuilder.build().getSocketFactory();
|
||||
}
|
||||
}
|
||||
|
@ -229,16 +229,20 @@ public class Excel07SaxReader extends DefaultHandler implements ExcelSaxReader<E
|
||||
*/
|
||||
@Override
|
||||
public void characters(char[] ch, int start, int length) {
|
||||
switch (this.curElementName){
|
||||
case v:
|
||||
// 得到单元格内容的值
|
||||
lastContent.append(ch, start, length);
|
||||
break;
|
||||
case f:
|
||||
// 得到单元格内容的值
|
||||
lastFormula.append(ch, start, length);
|
||||
break;
|
||||
final ElementName elementName = this.curElementName;
|
||||
if(null != elementName){
|
||||
switch (elementName){
|
||||
case v:
|
||||
// 得到单元格内容的值
|
||||
lastContent.append(ch, start, length);
|
||||
break;
|
||||
case f:
|
||||
// 得到单元格内容的值
|
||||
lastFormula.append(ch, start, length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 其它标签忽略
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------- Private method start
|
||||
|
Loading…
x
Reference in New Issue
Block a user