Merge remote-tracking branch 'upstream/v5-dev' into v5-dev

This commit is contained in:
lzpeng723 2020-12-02 14:29:34 +08:00
commit e69aac1274
53 changed files with 1481 additions and 235 deletions

View File

@ -4,7 +4,7 @@
2. 请确认没有更改代码风格如tab缩进
3. 新特性添加请确认注释完备如有必要请在src/test/java下添加Junit测试用例
### 修改描述(包括说明bug修复还是新特性添加)
### 修改描述(包括说明bug修复或者添加新特性)
1. [bug修复] balabala……
2. [新特性] balabala……

View File

@ -4,7 +4,7 @@
2. 请确认没有更改代码风格如tab缩进
3. 新特性添加请确认注释完备如有必要请在src/test/java下添加Junit测试用例
### 修改描述(包括说明bug修复还是新特性添加)
### 修改描述(包括说明bug修复或者添加新特性)
1. [bug修复] balabala……
2. [新特性] balabala……

View File

@ -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 】 增加PunyCodeissue#1268@Gitee
* 【core 】 ArrayUtil增加isSorted方法pr#1271@Github
* 【captcha】 增加GifCaptchapr#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
-------------------------------------------------------------------------------------------------------------

View File

@ -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 methodsUnless the method tool is added to the '**extra module**'.
3. Newly added methods do not use third-party library methodsUnless 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.
-------------------------------------------------------------------------------

View File

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

View File

@ -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());

View File

@ -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

View File

@ -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);
}
}

View 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));
}
}

View File

@ -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());
}
}

View File

@ -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);

View File

@ -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);

View 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 -&gt; a
* 1 -&gt; b
* ...
* 25 -&gt; z
* 26 -&gt; '0'
* ...
* 35 -&gt; '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 -&gt; 0
* b -&gt; 1
* ...
* z -&gt; 25
* '0' -&gt; 26
* ...
* '9' -&gt; 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");
}
}
}

View File

@ -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);

View File

@ -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日相差的天数

View File

@ -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();
}
}

View File

@ -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);

View File

@ -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)
*/

View 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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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]$");
/**
* 生日
*/

View File

@ -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

View File

@ -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;

View File

@ -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);
}

View File

@ -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);
}
}
}

View 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();
}
}

View File

@ -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]) &lt;= 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]) &lt;= 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]) &lt;= 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]) &gt;= 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;
}
}

View File

@ -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] &lt;= array[i+1]若传入空数组则返回false
*
* @param array 数组
* @return 数组是否升序
* @author FengBaoheng
* @since 5.5.2
*/
public static boolean isSorted(byte[] array) {
return isSortedASC(array);
}
/**
* 检查数组是否升序即array[i] &lt;= 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] &gt;= 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] &lt;= array[i+1]若传入空数组则返回false
*
* @param array 数组
* @return 数组是否升序
* @author FengBaoheng
* @since 5.5.2
*/
public static boolean isSorted(short[] array) {
return isSortedASC(array);
}
/**
* 检查数组是否升序即array[i] &lt;= 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] &gt;= 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] &lt;= array[i+1]若传入空数组则返回false
*
* @param array 数组
* @return 数组是否升序
* @author FengBaoheng
* @since 5.5.2
*/
public static boolean isSorted(char[] array) {
return isSortedASC(array);
}
/**
* 检查数组是否升序即array[i] &lt;= 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] &gt;= 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] &lt;= array[i+1]若传入空数组则返回false
*
* @param array 数组
* @return 数组是否升序
* @author FengBaoheng
* @since 5.5.2
*/
public static boolean isSorted(int[] array) {
return isSortedASC(array);
}
/**
* 检查数组是否升序即array[i] &lt;= 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] &gt;= 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] &lt;= array[i+1]若传入空数组则返回false
*
* @param array 数组
* @return 数组是否升序
* @author FengBaoheng
* @since 5.5.2
*/
public static boolean isSorted(long[] array) {
return isSortedASC(array);
}
/**
* 检查数组是否升序即array[i] &lt;= 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] &gt;= 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] &lt;= array[i+1]若传入空数组则返回false
*
* @param array 数组
* @return 数组是否升序
* @author FengBaoheng
* @since 5.5.2
*/
public static boolean isSorted(double[] array) {
return isSortedASC(array);
}
/**
* 检查数组是否升序即array[i] &lt;= 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] &gt;= 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] &lt;= array[i+1]若传入空数组则返回false
*
* @param array 数组
* @return 数组是否升序
* @author FengBaoheng
* @since 5.5.2
*/
public static boolean isSorted(float[] array) {
return isSortedASC(array);
}
/**
* 检查数组是否升序即array[i] &lt;= 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] &gt;= 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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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));
}
/**

View File

@ -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);
}

View File

@ -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"));
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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 + \"]\"";

View File

@ -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. "&lt;img /&gt;")
**/
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. "&lt;b&gt;&lt;/b&gt;")
**/
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. "&lt;b&gt;&lt;/b&gt;" or "&lt;b /&gt;")
**/
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. "&lt;b text &lt;/b&gt;" becomes "&lt;b&gt; text &lt;/g&gt;").
* 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);

View File

@ -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();
}
}

View File

@ -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