From efc4ca63a282b94fbeb55bff78033810cceb6e44 Mon Sep 17 00:00:00 2001
From: Looly
Date: Fri, 5 Jan 2024 09:06:31 +0800
Subject: [PATCH 01/26] add constructor
---
.../hutool/swing/captcha/CaptchaUtil.java | 16 ++++----
.../hutool/swing/captcha/CircleCaptcha.java | 16 +++++++-
.../hutool/swing/captcha/GifCaptcha.java | 38 +++++++++++++++----
.../hutool/swing/captcha/LineCaptcha.java | 16 +++++++-
.../hutool/swing/captcha/ShearCaptcha.java | 16 +++++++-
.../hutool/swing/captcha/CaptchaTest.java | 18 ++++-----
.../hutool/swing/captcha/CaptchaUtilTest.java | 2 +-
7 files changed, 94 insertions(+), 28 deletions(-)
diff --git a/hutool-swing/src/main/java/org/dromara/hutool/swing/captcha/CaptchaUtil.java b/hutool-swing/src/main/java/org/dromara/hutool/swing/captcha/CaptchaUtil.java
index 395e8cc62..9acac1258 100644
--- a/hutool-swing/src/main/java/org/dromara/hutool/swing/captcha/CaptchaUtil.java
+++ b/hutool-swing/src/main/java/org/dromara/hutool/swing/captcha/CaptchaUtil.java
@@ -27,7 +27,7 @@ public class CaptchaUtil {
* @param height 图片高
* @return {@link LineCaptcha}
*/
- public static LineCaptcha createLineCaptcha(final int width, final int height) {
+ public static LineCaptcha ofLineCaptcha(final int width, final int height) {
return new LineCaptcha(width, height);
}
@@ -40,7 +40,7 @@ public class CaptchaUtil {
* @param lineCount 干扰线条数
* @return {@link LineCaptcha}
*/
- public static LineCaptcha createLineCaptcha(final int width, final int height, final int codeCount, final int lineCount) {
+ public static LineCaptcha ofLineCaptcha(final int width, final int height, final int codeCount, final int lineCount) {
return new LineCaptcha(width, height, codeCount, lineCount);
}
@@ -52,7 +52,7 @@ public class CaptchaUtil {
* @return {@link CircleCaptcha}
* @since 3.2.3
*/
- public static CircleCaptcha createCircleCaptcha(final int width, final int height) {
+ public static CircleCaptcha ofCircleCaptcha(final int width, final int height) {
return new CircleCaptcha(width, height);
}
@@ -66,7 +66,7 @@ public class CaptchaUtil {
* @return {@link CircleCaptcha}
* @since 3.2.3
*/
- public static CircleCaptcha createCircleCaptcha(final int width, final int height, final int codeCount, final int circleCount) {
+ public static CircleCaptcha ofCircleCaptcha(final int width, final int height, final int codeCount, final int circleCount) {
return new CircleCaptcha(width, height, codeCount, circleCount);
}
@@ -78,7 +78,7 @@ public class CaptchaUtil {
* @return {@link ShearCaptcha}
* @since 3.2.3
*/
- public static ShearCaptcha createShearCaptcha(final int width, final int height) {
+ public static ShearCaptcha ofShearCaptcha(final int width, final int height) {
return new ShearCaptcha(width, height);
}
@@ -92,7 +92,7 @@ public class CaptchaUtil {
* @return {@link ShearCaptcha}
* @since 3.3.0
*/
- public static ShearCaptcha createShearCaptcha(final int width, final int height, final int codeCount, final int thickness) {
+ public static ShearCaptcha ofShearCaptcha(final int width, final int height, final int codeCount, final int thickness) {
return new ShearCaptcha(width, height, codeCount, thickness);
}
@@ -103,7 +103,7 @@ public class CaptchaUtil {
* @param height 高
* @return {@link GifCaptcha}
*/
- public static GifCaptcha createGifCaptcha(final int width, final int height) {
+ public static GifCaptcha ofGifCaptcha(final int width, final int height) {
return new GifCaptcha(width, height);
}
@@ -115,7 +115,7 @@ public class CaptchaUtil {
* @param codeCount 字符个数
* @return {@link GifCaptcha}
*/
- public static GifCaptcha createGifCaptcha(final int width, final int height, final int codeCount) {
+ public static GifCaptcha ofGifCaptcha(final int width, final int height, final int codeCount) {
return new GifCaptcha(width, height, codeCount);
}
}
diff --git a/hutool-swing/src/main/java/org/dromara/hutool/swing/captcha/CircleCaptcha.java b/hutool-swing/src/main/java/org/dromara/hutool/swing/captcha/CircleCaptcha.java
index d650f0016..57bbbe604 100644
--- a/hutool-swing/src/main/java/org/dromara/hutool/swing/captcha/CircleCaptcha.java
+++ b/hutool-swing/src/main/java/org/dromara/hutool/swing/captcha/CircleCaptcha.java
@@ -14,6 +14,8 @@ package org.dromara.hutool.swing.captcha;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.core.util.RandomUtil;
+import org.dromara.hutool.swing.captcha.generator.CodeGenerator;
+import org.dromara.hutool.swing.captcha.generator.RandomGenerator;
import org.dromara.hutool.swing.img.color.ColorUtil;
import org.dromara.hutool.swing.img.GraphicsUtil;
@@ -63,7 +65,19 @@ public class CircleCaptcha extends AbstractCaptcha {
* @param interfereCount 验证码干扰元素个数
*/
public CircleCaptcha(final int width, final int height, final int codeCount, final int interfereCount) {
- super(width, height, codeCount, interfereCount);
+ this(width, height, new RandomGenerator(codeCount), interfereCount);
+ }
+
+ /**
+ * 构造
+ *
+ * @param width 图片宽
+ * @param height 图片高
+ * @param generator 验证码生成器
+ * @param interfereCount 验证码干扰元素个数
+ */
+ public CircleCaptcha(final int width, final int height, final CodeGenerator generator, final int interfereCount) {
+ super(width, height, generator, interfereCount);
}
@Override
diff --git a/hutool-swing/src/main/java/org/dromara/hutool/swing/captcha/GifCaptcha.java b/hutool-swing/src/main/java/org/dromara/hutool/swing/captcha/GifCaptcha.java
index 9af10552e..a63aec5ce 100644
--- a/hutool-swing/src/main/java/org/dromara/hutool/swing/captcha/GifCaptcha.java
+++ b/hutool-swing/src/main/java/org/dromara/hutool/swing/captcha/GifCaptcha.java
@@ -16,6 +16,8 @@ package org.dromara.hutool.swing.captcha;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.core.util.RandomUtil;
import com.madgag.gif.fmsware.AnimatedGifEncoder;
+import org.dromara.hutool.swing.captcha.generator.CodeGenerator;
+import org.dromara.hutool.swing.captcha.generator.RandomGenerator;
import java.awt.AlphaComposite;
import java.awt.Color;
@@ -59,7 +61,29 @@ public class GifCaptcha extends AbstractCaptcha {
* @param codeCount 验证码个数
*/
public GifCaptcha(final int width, final int height, final int codeCount) {
- super(width, height, codeCount, 10);
+ this(width, height, codeCount, 10);
+ }
+
+ /**
+ * @param width 验证码宽度
+ * @param height 验证码高度
+ * @param codeCount 验证码个数
+ * @param interfereCount 干扰个数
+ */
+ public GifCaptcha(final int width, final int height, final int codeCount, final int interfereCount) {
+ this(width, height, new RandomGenerator(codeCount), interfereCount);
+ }
+
+ /**
+ * 构造
+ *
+ * @param width 图片宽
+ * @param height 图片高
+ * @param generator 验证码生成器
+ * @param interfereCount 验证码干扰元素个数
+ */
+ public GifCaptcha(final int width, final int height, final CodeGenerator generator, final int interfereCount) {
+ super(width, height, generator, interfereCount);
}
/**
@@ -178,9 +202,9 @@ public class GifCaptcha extends AbstractCaptcha {
g2d.setComposite(ac);
g2d.setColor(fontColor[i]);
g2d.drawOval(
- RandomUtil.randomInt(width),
- RandomUtil.randomInt(height),
- RandomUtil.randomInt(5, 30), 5 + RandomUtil.randomInt(5, 30)
+ 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);
}
@@ -223,8 +247,8 @@ public class GifCaptcha extends AbstractCaptcha {
max = 255;
}
return new Color(
- RandomUtil.randomInt(min, max),
- RandomUtil.randomInt(min, max),
- RandomUtil.randomInt(min, max));
+ RandomUtil.randomInt(min, max),
+ RandomUtil.randomInt(min, max),
+ RandomUtil.randomInt(min, max));
}
}
diff --git a/hutool-swing/src/main/java/org/dromara/hutool/swing/captcha/LineCaptcha.java b/hutool-swing/src/main/java/org/dromara/hutool/swing/captcha/LineCaptcha.java
index 37458a8c0..022de5e65 100644
--- a/hutool-swing/src/main/java/org/dromara/hutool/swing/captcha/LineCaptcha.java
+++ b/hutool-swing/src/main/java/org/dromara/hutool/swing/captcha/LineCaptcha.java
@@ -14,6 +14,8 @@ package org.dromara.hutool.swing.captcha;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.core.util.RandomUtil;
+import org.dromara.hutool.swing.captcha.generator.CodeGenerator;
+import org.dromara.hutool.swing.captcha.generator.RandomGenerator;
import org.dromara.hutool.swing.img.color.ColorUtil;
import org.dromara.hutool.swing.img.GraphicsUtil;
@@ -53,7 +55,19 @@ public class LineCaptcha extends AbstractCaptcha {
* @param lineCount 干扰线条数
*/
public LineCaptcha(final int width, final int height, final int codeCount, final int lineCount) {
- super(width, height, codeCount, lineCount);
+ this(width, height, new RandomGenerator(codeCount), lineCount);
+ }
+
+ /**
+ * 构造
+ *
+ * @param width 图片宽
+ * @param height 图片高
+ * @param generator 验证码生成器
+ * @param interfereCount 验证码干扰元素个数
+ */
+ public LineCaptcha(final int width, final int height, final CodeGenerator generator, final int interfereCount) {
+ super(width, height, generator, interfereCount);
}
// -------------------------------------------------------------------- Constructor end
diff --git a/hutool-swing/src/main/java/org/dromara/hutool/swing/captcha/ShearCaptcha.java b/hutool-swing/src/main/java/org/dromara/hutool/swing/captcha/ShearCaptcha.java
index 0e08863d5..cd7d35137 100644
--- a/hutool-swing/src/main/java/org/dromara/hutool/swing/captcha/ShearCaptcha.java
+++ b/hutool-swing/src/main/java/org/dromara/hutool/swing/captcha/ShearCaptcha.java
@@ -14,6 +14,8 @@ package org.dromara.hutool.swing.captcha;
import org.dromara.hutool.core.util.ObjUtil;
import org.dromara.hutool.core.util.RandomUtil;
+import org.dromara.hutool.swing.captcha.generator.CodeGenerator;
+import org.dromara.hutool.swing.captcha.generator.RandomGenerator;
import org.dromara.hutool.swing.img.color.ColorUtil;
import org.dromara.hutool.swing.img.GraphicsUtil;
@@ -63,7 +65,19 @@ public class ShearCaptcha extends AbstractCaptcha {
* @param thickness 干扰线宽度
*/
public ShearCaptcha(final int width, final int height, final int codeCount, final int thickness) {
- super(width, height, codeCount, thickness);
+ this(width, height, new RandomGenerator(codeCount), thickness);
+ }
+
+ /**
+ * 构造
+ *
+ * @param width 图片宽
+ * @param height 图片高
+ * @param generator 验证码生成器
+ * @param interfereCount 验证码干扰元素个数
+ */
+ public ShearCaptcha(final int width, final int height, final CodeGenerator generator, final int interfereCount) {
+ super(width, height, generator, interfereCount);
}
@Override
diff --git a/hutool-swing/src/test/java/org/dromara/hutool/swing/captcha/CaptchaTest.java b/hutool-swing/src/test/java/org/dromara/hutool/swing/captcha/CaptchaTest.java
index 81362a26b..1bc990670 100644
--- a/hutool-swing/src/test/java/org/dromara/hutool/swing/captcha/CaptchaTest.java
+++ b/hutool-swing/src/test/java/org/dromara/hutool/swing/captcha/CaptchaTest.java
@@ -30,7 +30,7 @@ public class CaptchaTest {
@Test
public void lineCaptchaTest1() {
// 定义图形验证码的长和宽
- final LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200, 100);
+ final LineCaptcha lineCaptcha = CaptchaUtil.ofLineCaptcha(200, 100);
Assertions.assertNotNull(lineCaptcha.getCode());
Assertions.assertTrue(lineCaptcha.verify(lineCaptcha.getCode()));
}
@@ -39,7 +39,7 @@ public class CaptchaTest {
@Disabled
public void lineCaptchaTest3() {
// 定义图形验证码的长和宽
- final LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200, 70, 4, 15);
+ final LineCaptcha lineCaptcha = CaptchaUtil.ofLineCaptcha(200, 70, 4, 15);
lineCaptcha.setBackground(Color.yellow);
lineCaptcha.write("f:/test/captcha/tellow.png");
}
@@ -48,7 +48,7 @@ public class CaptchaTest {
@Disabled
public void lineCaptchaWithMathTest() {
// 定义图形验证码的长和宽
- final LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200, 80);
+ final LineCaptcha lineCaptcha = CaptchaUtil.ofLineCaptcha(200, 80);
lineCaptcha.setGenerator(new MathGenerator());
lineCaptcha.setTextAlpha(0.8f);
lineCaptcha.write("f:/captcha/math.png");
@@ -59,7 +59,7 @@ public class CaptchaTest {
public void lineCaptchaTest2() {
// 定义图形验证码的长和宽
- final LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200, 100);
+ final LineCaptcha lineCaptcha = CaptchaUtil.ofLineCaptcha(200, 100);
// LineCaptcha lineCaptcha = new LineCaptcha(200, 100, 4, 150);
// 图形验证码写出,可以写出到文件,也可以写出到流
lineCaptcha.write("f:/captcha/line.png");
@@ -79,7 +79,7 @@ public class CaptchaTest {
public void circleCaptchaTest() {
// 定义图形验证码的长和宽
- final CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(200, 100, 4, 20);
+ final CircleCaptcha captcha = CaptchaUtil.ofCircleCaptcha(200, 100, 4, 20);
// CircleCaptcha captcha = new CircleCaptcha(200, 100, 4, 20);
// 图形验证码写出,可以写出到文件,也可以写出到流
captcha.write("f:/captcha/circle.png");
@@ -92,7 +92,7 @@ public class CaptchaTest {
public void shearCaptchaTest() {
// 定义图形验证码的长和宽
- final ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(203, 100, 4, 4);
+ final ShearCaptcha captcha = CaptchaUtil.ofShearCaptcha(203, 100, 4, 4);
// ShearCaptcha captcha = new ShearCaptcha(200, 100, 4, 4);
// 图形验证码写出,可以写出到文件,也可以写出到流
captcha.write("f:/captcha/shear.png");
@@ -116,7 +116,7 @@ public class CaptchaTest {
@Disabled
public void ShearCaptchaWithMathTest() {
// 定义图形验证码的长和宽
- final ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(200, 45, 4, 4);
+ final ShearCaptcha captcha = CaptchaUtil.ofShearCaptcha(200, 45, 4, 4);
captcha.setGenerator(new MathGenerator());
// ShearCaptcha captcha = new ShearCaptcha(200, 100, 4, 4);
// 图形验证码写出,可以写出到文件,也可以写出到流
@@ -128,7 +128,7 @@ public class CaptchaTest {
@Test
@Disabled
public void GifCaptchaTest() {
- final GifCaptcha captcha = CaptchaUtil.createGifCaptcha(200, 100, 4);
+ final GifCaptcha captcha = CaptchaUtil.ofGifCaptcha(200, 100, 4);
captcha.write("d:/test/gif_captcha.gif");
assert captcha.verify(captcha.getCode());
}
@@ -136,7 +136,7 @@ public class CaptchaTest {
@Test
@Disabled
public void bgTest(){
- final LineCaptcha captcha = CaptchaUtil.createLineCaptcha(200, 100, 4, 1);
+ final LineCaptcha captcha = CaptchaUtil.ofLineCaptcha(200, 100, 4, 1);
captcha.setBackground(Color.WHITE);
captcha.write("d:/test/test.jpg");
}
diff --git a/hutool-swing/src/test/java/org/dromara/hutool/swing/captcha/CaptchaUtilTest.java b/hutool-swing/src/test/java/org/dromara/hutool/swing/captcha/CaptchaUtilTest.java
index 2920d721c..77917d974 100644
--- a/hutool-swing/src/test/java/org/dromara/hutool/swing/captcha/CaptchaUtilTest.java
+++ b/hutool-swing/src/test/java/org/dromara/hutool/swing/captcha/CaptchaUtilTest.java
@@ -21,7 +21,7 @@ public class CaptchaUtilTest {
@Disabled
public void createTest() {
for(int i = 0; i < 1; i++) {
- CaptchaUtil.createShearCaptcha(320, 240);
+ CaptchaUtil.ofShearCaptcha(320, 240);
}
}
}
From 69206406d7e2da5c75bf4ced393e17bd3074b0de Mon Sep 17 00:00:00 2001
From: Looly
Date: Fri, 5 Jan 2024 12:00:24 +0800
Subject: [PATCH 02/26] fix code
---
.../dromara/hutool/core/xml/XmlConstants.java | 30 +++++++
.../hutool/json/mapper/JSONObjectMapper.java | 3 +-
.../hutool/json/xml/JSONXMLParser.java | 47 +++++-----
.../dromara/hutool/json/xml/JSONXMLUtil.java | 62 ++-----------
.../dromara/hutool/json/xml/ParseConfig.java | 88 +++++++++++++++++++
.../dromara/hutool/json/xml/XMLTokener.java | 36 ++++----
6 files changed, 172 insertions(+), 94 deletions(-)
create mode 100644 hutool-json/src/main/java/org/dromara/hutool/json/xml/ParseConfig.java
diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/xml/XmlConstants.java b/hutool-core/src/main/java/org/dromara/hutool/core/xml/XmlConstants.java
index 01977d2ed..b77d2af83 100755
--- a/hutool-core/src/main/java/org/dromara/hutool/core/xml/XmlConstants.java
+++ b/hutool-core/src/main/java/org/dromara/hutool/core/xml/XmlConstants.java
@@ -12,6 +12,8 @@
package org.dromara.hutool.core.xml;
+import org.dromara.hutool.core.text.CharUtil;
+
import java.util.regex.Pattern;
/**
@@ -30,6 +32,10 @@ public class XmlConstants {
* 字符串常量:XML And 符转义 {@code "&" -> "&"}
*/
public static final String AMP = "&";
+ /**
+ * The Character '&'.
+ */
+ public static final Character C_AMP = CharUtil.AMP;
/**
* 字符串常量:XML 双引号转义 {@code """ -> "\""}
@@ -40,17 +46,41 @@ public class XmlConstants {
* 字符串常量:XML 单引号转义 {@code "&apos" -> "'"}
*/
public static final String APOS = "'";
+ /**
+ * The Character '''.
+ */
+ public static final Character C_APOS = CharUtil.SINGLE_QUOTE;
/**
* 字符串常量:XML 小于号转义 {@code "<" -> "<"}
*/
public static final String LT = "<";
+ /**
+ * The Character '<'.
+ */
+ public static final Character C_LT = '<';
+
/**
* 字符串常量:XML 大于号转义 {@code ">" -> ">"}
*/
public static final String GT = ">";
+ /**
+ * The Character '>'.
+ */
+ public static final Character C_GT = '>';
+
+ /**
+ * The Character '!'.
+ */
+ public static final Character C_BANG = '!';
+
+ /**
+ * The Character '?'.
+ */
+ public static final Character C_QUEST = '?';
+
/**
* 在XML中无效的字符 正则
*/
diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONObjectMapper.java b/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONObjectMapper.java
index ba6508dae..a102aa19f 100644
--- a/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONObjectMapper.java
+++ b/hutool-json/src/main/java/org/dromara/hutool/json/mapper/JSONObjectMapper.java
@@ -29,6 +29,7 @@ import org.dromara.hutool.json.JSONTokener;
import org.dromara.hutool.json.xml.JSONXMLUtil;
import org.dromara.hutool.json.serialize.GlobalSerializeMapping;
import org.dromara.hutool.json.serialize.JSONSerializer;
+import org.dromara.hutool.json.xml.ParseConfig;
import java.io.InputStream;
import java.io.Reader;
@@ -170,7 +171,7 @@ public class JSONObjectMapper {
final String jsonStr = StrUtil.trim(source);
if (StrUtil.startWith(jsonStr, '<')) {
// 可能为XML
- JSONXMLUtil.toJSONObject(jsonObject, jsonStr, false);
+ JSONXMLUtil.toJSONObject(jsonStr, jsonObject, ParseConfig.of());
return;
}
mapFromTokener(new JSONTokener(StrUtil.trim(source), jsonObject.config()), jsonObject);
diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/xml/JSONXMLParser.java b/hutool-json/src/main/java/org/dromara/hutool/json/xml/JSONXMLParser.java
index addf574d7..dc8f579e3 100644
--- a/hutool-json/src/main/java/org/dromara/hutool/json/xml/JSONXMLParser.java
+++ b/hutool-json/src/main/java/org/dromara/hutool/json/xml/JSONXMLParser.java
@@ -12,7 +12,9 @@
package org.dromara.hutool.json.xml;
+import org.dromara.hutool.core.text.CharUtil;
import org.dromara.hutool.core.text.StrUtil;
+import org.dromara.hutool.core.xml.XmlConstants;
import org.dromara.hutool.json.JSONException;
import org.dromara.hutool.json.JSONObject;
import org.dromara.hutool.json.mapper.JSONValueMapper;
@@ -29,28 +31,28 @@ public class JSONXMLParser {
* 转换XML为JSONObject
* 转换过程中一些信息可能会丢失,JSON中无法区分节点和属性,相同的节点将被处理为JSONArray。
*
- * @param jo JSONObject
* @param xmlStr XML字符串
- * @param keepStrings 如果为{@code true},则值保持String类型,不转换为数字或boolean
+ * @param jo JSONObject
+ * @param parseConfig 解析选项
* @throws JSONException 解析异常
*/
- public static void parseJSONObject(final JSONObject jo, final String xmlStr, final boolean keepStrings) throws JSONException {
+ public static void parseJSONObject(final String xmlStr, final JSONObject jo, final ParseConfig parseConfig) throws JSONException {
final XMLTokener x = new XMLTokener(xmlStr, jo.config());
while (x.more() && x.skipPast("<")) {
- parse(x, jo, null, keepStrings);
+ parse(x, jo, null, parseConfig);
}
}
/**
- * Scan the content following the named tag, attaching it to the context.
+ * 扫描XML内容,并解析到JSONObject中。
*
- * @param x The XMLTokener containing the source string.
- * @param context The JSONObject that will include the new material.
- * @param name The tag name.
- * @return true if the close tag is processed.
+ * @param x {@link XMLTokener}
+ * @param context {@link JSONObject}
+ * @param name 标签名,null表示从根标签开始解析
+ * @return {@code true}表示解析完成
* @throws JSONException JSON异常
*/
- private static boolean parse(final XMLTokener x, final JSONObject context, final String name, final boolean keepStrings) throws JSONException {
+ private static boolean parse(final XMLTokener x, final JSONObject context, final String name, final ParseConfig parseConfig) throws JSONException {
final char c;
int i;
final JSONObject jsonobject;
@@ -60,7 +62,7 @@ public class JSONXMLParser {
token = x.nextToken();
- if (token == JSONXMLUtil.BANG) {
+ if (token == XmlConstants.C_BANG) {
c = x.next();
if (c == '-') {
if (x.next() == '-') {
@@ -86,19 +88,19 @@ public class JSONXMLParser {
token = x.nextMeta();
if (token == null) {
throw x.syntaxError("Missing '>' after ' 0);
return false;
- } else if (token == JSONXMLUtil.QUEST) {
+ } else if (token == XmlConstants.C_QUEST) {
//
x.skipPast("?>");
return false;
- } else if (token == JSONXMLUtil.SLASH) {
+ } else if (token == Character.valueOf(CharUtil.SLASH)) {
// Close tag
@@ -109,7 +111,7 @@ public class JSONXMLParser {
if (!token.equals(name)) {
throw x.syntaxError("Mismatched " + name + " and " + token);
}
- if (x.nextToken() != JSONXMLUtil.GT) {
+ if (x.nextToken() != XmlConstants.C_GT) {
throw x.syntaxError("Misshaped close tag");
}
return true;
@@ -123,6 +125,7 @@ public class JSONXMLParser {
tagName = (String) token;
token = null;
jsonobject = new JSONObject();
+ final boolean keepStrings = parseConfig.isKeepStrings();
for (; ; ) {
if (token == null) {
token = x.nextToken();
@@ -132,7 +135,7 @@ public class JSONXMLParser {
if (token instanceof String) {
string = (String) token;
token = x.nextToken();
- if (token == JSONXMLUtil.EQ) {
+ if (token == Character.valueOf(CharUtil.EQUAL)) {
token = x.nextToken();
if (!(token instanceof String)) {
throw x.syntaxError("Missing value");
@@ -143,9 +146,9 @@ public class JSONXMLParser {
jsonobject.append(string, "");
}
- } else if (token == JSONXMLUtil.SLASH) {
+ } else if (token == Character.valueOf(CharUtil.SLASH)) {
// Empty tag <.../>
- if (x.nextToken() != JSONXMLUtil.GT) {
+ if (x.nextToken() != XmlConstants.C_GT) {
throw x.syntaxError("Misshaped tag");
}
if (!jsonobject.isEmpty()) {
@@ -155,7 +158,7 @@ public class JSONXMLParser {
}
return false;
- } else if (token == JSONXMLUtil.GT) {
+ } else if (token == XmlConstants.C_GT) {
// Content, between <...> and
for (; ; ) {
token = x.nextContent();
@@ -170,9 +173,9 @@ public class JSONXMLParser {
jsonobject.append("content", keepStrings ? token : JSONValueMapper.toJsonValue(string));
}
- } else if (token == JSONXMLUtil.LT) {
+ } else if (token == XmlConstants.C_LT) {
// Nested element
- if (parse(x, jsonobject, tagName, keepStrings)) {
+ if (parse(x, jsonobject, tagName, parseConfig)) {
if (jsonobject.isEmpty()) {
context.append(tagName, StrUtil.EMPTY);
} else if (jsonobject.size() == 1 && jsonobject.get("content") != null) {
diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/xml/JSONXMLUtil.java b/hutool-json/src/main/java/org/dromara/hutool/json/xml/JSONXMLUtil.java
index 13de4624a..083a2a56a 100644
--- a/hutool-json/src/main/java/org/dromara/hutool/json/xml/JSONXMLUtil.java
+++ b/hutool-json/src/main/java/org/dromara/hutool/json/xml/JSONXMLUtil.java
@@ -12,7 +12,6 @@
package org.dromara.hutool.json.xml;
-import org.dromara.hutool.core.text.CharUtil;
import org.dromara.hutool.json.JSONException;
import org.dromara.hutool.json.JSONObject;
@@ -25,51 +24,6 @@ import org.dromara.hutool.json.JSONObject;
*/
public class JSONXMLUtil {
- /**
- * The Character '&'.
- */
- public static final Character AMP = CharUtil.AMP;
-
- /**
- * The Character '''.
- */
- public static final Character APOS = CharUtil.SINGLE_QUOTE;
-
- /**
- * The Character '!'.
- */
- public static final Character BANG = '!';
-
- /**
- * The Character '='.
- */
- public static final Character EQ = '=';
-
- /**
- * The Character '>'.
- */
- public static final Character GT = '>';
-
- /**
- * The Character '<'.
- */
- public static final Character LT = '<';
-
- /**
- * The Character '?'.
- */
- public static final Character QUEST = '?';
-
- /**
- * The Character '"'.
- */
- public static final Character QUOT = CharUtil.DOUBLE_QUOTES;
-
- /**
- * The Character '/'.
- */
- public static final Character SLASH = CharUtil.SLASH;
-
/**
* 转换XML为JSONObject
* 转换过程中一些信息可能会丢失,JSON中无法区分节点和属性,相同的节点将被处理为JSONArray。
@@ -80,7 +34,7 @@ public class JSONXMLUtil {
* @throws JSONException Thrown if there is an errors while parsing the string
*/
public static JSONObject toJSONObject(final String string) throws JSONException {
- return toJSONObject(string, false);
+ return toJSONObject(string, ParseConfig.of());
}
/**
@@ -89,13 +43,13 @@ public class JSONXMLUtil {
* Content text may be placed in a "content" member. Comments, prologs, DTDs, and {@code <[ [ ]]>} are ignored.
* All values are converted as strings, for 1, 01, 29.0 will not be coerced to numbers but will instead be the exact value as seen in the XML document.
*
- * @param string The source string.
- * @param keepStrings If true, then values will not be coerced into boolean or numeric values and will instead be left as strings
+ * @param string XML字符串
+ * @param parseConfig XML解析选项
* @return A JSONObject containing the structured data from the XML string.
* @throws JSONException Thrown if there is an errors while parsing the string
*/
- public static JSONObject toJSONObject(final String string, final boolean keepStrings) throws JSONException {
- return toJSONObject(new JSONObject(), string, keepStrings);
+ public static JSONObject toJSONObject(final String string, final ParseConfig parseConfig) throws JSONException {
+ return toJSONObject(string, new JSONObject(), parseConfig);
}
/**
@@ -104,13 +58,13 @@ public class JSONXMLUtil {
*
* @param jo JSONObject
* @param xmlStr XML字符串
- * @param keepStrings 如果为{@code true},则值保持String类型,不转换为数字或boolean
+ * @param parseConfig XML解析选项
* @return A JSONObject 解析后的JSON对象,与传入的jo为同一对象
* @throws JSONException 解析异常
* @since 5.3.1
*/
- public static JSONObject toJSONObject(final JSONObject jo, final String xmlStr, final boolean keepStrings) throws JSONException {
- JSONXMLParser.parseJSONObject(jo, xmlStr, keepStrings);
+ public static JSONObject toJSONObject(final String xmlStr, final JSONObject jo, final ParseConfig parseConfig) throws JSONException {
+ JSONXMLParser.parseJSONObject(xmlStr, jo, parseConfig);
return jo;
}
diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/xml/ParseConfig.java b/hutool-json/src/main/java/org/dromara/hutool/json/xml/ParseConfig.java
new file mode 100644
index 000000000..fbe4e1b51
--- /dev/null
+++ b/hutool-json/src/main/java/org/dromara/hutool/json/xml/ParseConfig.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2024. looly(loolly@aliyun.com)
+ * Hutool is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * https://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+
+package org.dromara.hutool.json.xml;
+
+import java.io.Serializable;
+
+/**
+ * XML解析为JSON的可选选项
+ * 参考:https://github.com/stleary/JSON-java/blob/master/src/main/java/org/json/ParserConfiguration.java
+ *
+ * @author AylwardJ, Looly
+ */
+public class ParseConfig implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 默认最大嵌套深度
+ */
+ public static final int DEFAULT_MAXIMUM_NESTING_DEPTH = 512;
+
+ /**
+ * 创建ParseConfig
+ *
+ * @return ParseConfig
+ */
+ public static ParseConfig of() {
+ return new ParseConfig();
+ }
+
+ /**
+ * 是否保持值为String类型,如果为{@code false},则尝试转换为对应类型(numeric, boolean, string)
+ */
+ private boolean keepStrings;
+ /**
+ * 最大嵌套深度,用于解析时限制解析层级,当大于这个层级时抛出异常,-1表示无限制
+ */
+ private int maxNestingDepth;
+
+ /**
+ * 是否保持值为String类型,如果为{@code false},则尝试转换为对应类型(numeric, boolean, string)
+ *
+ * @return 是否保持值为String类型
+ */
+ public boolean isKeepStrings() {
+ return keepStrings;
+ }
+
+ /**
+ * 设置是否保持值为String类型,如果为{@code false},则尝试转换为对应类型(numeric, boolean, string)
+ *
+ * @param keepStrings 是否保持值为String类型
+ * @return this
+ */
+ public ParseConfig setKeepStrings(final boolean keepStrings) {
+ this.keepStrings = keepStrings;
+ return this;
+ }
+
+ /**
+ * 获取最大嵌套深度,用于解析时限制解析层级,当大于这个层级时抛出异常,-1表示无限制
+ *
+ * @return 最大嵌套深度
+ */
+ public int getMaxNestingDepth() {
+ return maxNestingDepth;
+ }
+
+ /**
+ * 设置最大嵌套深度,用于解析时限制解析层级,当大于这个层级时抛出异常,-1表示无限制
+ *
+ * @param maxNestingDepth 最大嵌套深度
+ * @return this
+ */
+ public ParseConfig setMaxNestingDepth(final int maxNestingDepth) {
+ this.maxNestingDepth = maxNestingDepth;
+ return this;
+ }
+}
diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/xml/XMLTokener.java b/hutool-json/src/main/java/org/dromara/hutool/json/xml/XMLTokener.java
index 3569fba5f..d3eb34bb8 100644
--- a/hutool-json/src/main/java/org/dromara/hutool/json/xml/XMLTokener.java
+++ b/hutool-json/src/main/java/org/dromara/hutool/json/xml/XMLTokener.java
@@ -12,6 +12,8 @@
package org.dromara.hutool.json.xml;
+import org.dromara.hutool.core.text.CharUtil;
+import org.dromara.hutool.core.xml.XmlConstants;
import org.dromara.hutool.json.JSONConfig;
import org.dromara.hutool.json.JSONException;
import org.dromara.hutool.json.JSONTokener;
@@ -31,11 +33,11 @@ public class XMLTokener extends JSONTokener {
static {
entity = new java.util.HashMap<>(8);
- entity.put("amp", JSONXMLUtil.AMP);
- entity.put("apos", JSONXMLUtil.APOS);
- entity.put("gt", JSONXMLUtil.GT);
- entity.put("lt", JSONXMLUtil.LT);
- entity.put("quot", JSONXMLUtil.QUOT);
+ entity.put("amp", XmlConstants.C_AMP);
+ entity.put("apos", XmlConstants.C_APOS);
+ entity.put("gt", XmlConstants.C_GT);
+ entity.put("lt", XmlConstants.C_LT);
+ entity.put("quot", CharUtil.DOUBLE_QUOTES);
}
/**
@@ -89,7 +91,7 @@ public class XMLTokener extends JSONTokener {
return null;
}
if (c == '<') {
- return JSONXMLUtil.LT;
+ return XmlConstants.C_LT;
}
sb = new StringBuilder();
for (; ; ) {
@@ -175,17 +177,17 @@ public class XMLTokener extends JSONTokener {
case 0:
throw syntaxError("Misshaped meta tag");
case '<':
- return JSONXMLUtil.LT;
+ return XmlConstants.C_LT;
case '>':
- return JSONXMLUtil.GT;
+ return XmlConstants.C_GT;
case '/':
- return JSONXMLUtil.SLASH;
+ return CharUtil.SLASH;
case '=':
- return JSONXMLUtil.EQ;
+ return CharUtil.EQUAL;
case '!':
- return JSONXMLUtil.BANG;
+ return XmlConstants.C_BANG;
case '?':
- return JSONXMLUtil.QUEST;
+ return XmlConstants.C_QUEST;
case '"':
case '\'':
q = c;
@@ -242,15 +244,15 @@ public class XMLTokener extends JSONTokener {
case '<':
throw syntaxError("Misplaced '<'");
case '>':
- return JSONXMLUtil.GT;
+ return XmlConstants.C_GT;
case '/':
- return JSONXMLUtil.SLASH;
+ return CharUtil.SLASH;
case '=':
- return JSONXMLUtil.EQ;
+ return CharUtil.EQUAL;
case '!':
- return JSONXMLUtil.BANG;
+ return XmlConstants.C_BANG;
case '?':
- return JSONXMLUtil.QUEST;
+ return XmlConstants.C_QUEST;
// Quoted string
From 30fafaa5de4a2ec7f08eaa5f4eb25d1076bf7c19 Mon Sep 17 00:00:00 2001
From: Looly
Date: Fri, 5 Jan 2024 12:36:23 +0800
Subject: [PATCH 03/26] =?UTF-8?q?=E5=A2=9E=E5=8A=A0ParseConfig=EF=BC=8C?=
=?UTF-8?q?=E9=80=9A=E8=BF=87=E5=A2=9E=E5=8A=A0maxNestingDepth=E5=8F=82?=
=?UTF-8?q?=E6=95=B0=E9=81=BF=E5=85=8DStackOverflowError=E9=97=AE=E9=A2=98?=
=?UTF-8?q?=EF=BC=8C=E4=BF=AE=E5=A4=8DCVE-2022-45688=E6=BC=8F=E6=B4=9E?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../hutool/json/xml/JSONXMLParser.java | 22 ++++++++++++++-----
.../dromara/hutool/json/xml/ParseConfig.java | 2 +-
.../hutool/json/xml/Issue2748Test.java | 18 +++++++++++++++
3 files changed, 35 insertions(+), 7 deletions(-)
create mode 100644 hutool-json/src/test/java/org/dromara/hutool/json/xml/Issue2748Test.java
diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/xml/JSONXMLParser.java b/hutool-json/src/main/java/org/dromara/hutool/json/xml/JSONXMLParser.java
index dc8f579e3..524829c4a 100644
--- a/hutool-json/src/main/java/org/dromara/hutool/json/xml/JSONXMLParser.java
+++ b/hutool-json/src/main/java/org/dromara/hutool/json/xml/JSONXMLParser.java
@@ -39,20 +39,23 @@ public class JSONXMLParser {
public static void parseJSONObject(final String xmlStr, final JSONObject jo, final ParseConfig parseConfig) throws JSONException {
final XMLTokener x = new XMLTokener(xmlStr, jo.config());
while (x.more() && x.skipPast("<")) {
- parse(x, jo, null, parseConfig);
+ parse(x, jo, null, parseConfig, 0);
}
}
/**
* 扫描XML内容,并解析到JSONObject中。
*
- * @param x {@link XMLTokener}
- * @param context {@link JSONObject}
- * @param name 标签名,null表示从根标签开始解析
+ * @param x {@link XMLTokener}
+ * @param context {@link JSONObject}
+ * @param name 标签名,null表示从根标签开始解析
+ * @param parseConfig 解析选项
+ * @param currentNestingDepth 当前层级
* @return {@code true}表示解析完成
* @throws JSONException JSON异常
*/
- private static boolean parse(final XMLTokener x, final JSONObject context, final String name, final ParseConfig parseConfig) throws JSONException {
+ private static boolean parse(final XMLTokener x, final JSONObject context, final String name,
+ final ParseConfig parseConfig, final int currentNestingDepth) throws JSONException {
final char c;
int i;
final JSONObject jsonobject;
@@ -175,7 +178,14 @@ public class JSONXMLParser {
} else if (token == XmlConstants.C_LT) {
// Nested element
- if (parse(x, jsonobject, tagName, parseConfig)) {
+ // issue#2748 of CVE-2022-45688
+ final int maxNestingDepth = parseConfig.getMaxNestingDepth();
+ if (maxNestingDepth > -1 && currentNestingDepth >= maxNestingDepth) {
+ throw x.syntaxError("Maximum nesting depth of " + maxNestingDepth + " reached");
+ }
+
+ // Nested element
+ if (parse(x, jsonobject, tagName, parseConfig, currentNestingDepth + 1)) {
if (jsonobject.isEmpty()) {
context.append(tagName, StrUtil.EMPTY);
} else if (jsonobject.size() == 1 && jsonobject.get("content") != null) {
diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/xml/ParseConfig.java b/hutool-json/src/main/java/org/dromara/hutool/json/xml/ParseConfig.java
index fbe4e1b51..d1fd7b33c 100644
--- a/hutool-json/src/main/java/org/dromara/hutool/json/xml/ParseConfig.java
+++ b/hutool-json/src/main/java/org/dromara/hutool/json/xml/ParseConfig.java
@@ -44,7 +44,7 @@ public class ParseConfig implements Serializable {
/**
* 最大嵌套深度,用于解析时限制解析层级,当大于这个层级时抛出异常,-1表示无限制
*/
- private int maxNestingDepth;
+ private int maxNestingDepth = -1;
/**
* 是否保持值为String类型,如果为{@code false},则尝试转换为对应类型(numeric, boolean, string)
diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/xml/Issue2748Test.java b/hutool-json/src/test/java/org/dromara/hutool/json/xml/Issue2748Test.java
new file mode 100644
index 000000000..8093101cd
--- /dev/null
+++ b/hutool-json/src/test/java/org/dromara/hutool/json/xml/Issue2748Test.java
@@ -0,0 +1,18 @@
+package org.dromara.hutool.json.xml;
+
+import org.dromara.hutool.core.text.StrUtil;
+import org.dromara.hutool.json.JSONException;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class Issue2748Test {
+
+ @Test
+ void toJSONObjectTest() {
+ final String s = StrUtil.repeat("", 600);
+
+ Assertions.assertThrows(JSONException.class, () -> {
+ JSONXMLUtil.toJSONObject(s, ParseConfig.of().setMaxNestingDepth(512));
+ });
+ }
+}
From 9992d776da73880288f944c3394e75778623a28c Mon Sep 17 00:00:00 2001
From: Looly
Date: Sat, 6 Jan 2024 02:20:49 +0800
Subject: [PATCH 04/26] add Cipher
---
.../org/dromara/hutool/crypto/Cipher.java | 57 ++++++++
.../dromara/hutool/crypto/CipherWrapper.java | 136 ------------------
.../org/dromara/hutool/crypto/JceCipher.java | 134 +++++++++++++++++
.../java/org/dromara/hutool/crypto/Mode.java | 7 +-
.../crypto/asymmetric/AsymmetricCrypto.java | 37 +++--
.../dromara/hutool/crypto/bc/BCCipher.java | 96 +++++++++++++
.../org/dromara/hutool/crypto/bc/BCUtil.java | 71 +++++++--
.../crypto/symmetric/SymmetricCrypto.java | 44 +++---
8 files changed, 404 insertions(+), 178 deletions(-)
create mode 100644 hutool-crypto/src/main/java/org/dromara/hutool/crypto/Cipher.java
delete mode 100644 hutool-crypto/src/main/java/org/dromara/hutool/crypto/CipherWrapper.java
create mode 100644 hutool-crypto/src/main/java/org/dromara/hutool/crypto/JceCipher.java
create mode 100644 hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/Cipher.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/Cipher.java
new file mode 100644
index 000000000..a88795ac8
--- /dev/null
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/Cipher.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2024. looly(loolly@aliyun.com)
+ * Hutool is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * https://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+
+package org.dromara.hutool.crypto;
+
+/**
+ * 密码接口,提供统一的API,用于兼容和统一JCE和BouncyCastle等库的操作
+ *
+ * @author Looly
+ * @since 6.0.0
+ */
+public interface Cipher {
+
+ /**
+ * 获取算法名称
+ *
+ * @return 算法名称
+ */
+ String getAlgorithmName();
+
+ /**
+ * 获取块大小,当为Stream方式加密时返回0
+ *
+ * @return 块大小
+ */
+ int getBlockSize();
+
+ /**
+ * 初始化模式和参数
+ *
+ * @param mode 模式,如加密模式或解密模式
+ * @param parameters Cipher所需参数,包括Key、Random、IV等信息
+ */
+ void init(CipherMode mode, Parameters parameters);
+
+ /**
+ * 执行运算,可以是加密运算或解密运算
+ *
+ * @param data 被处理的数据
+ * @return 运算结果
+ */
+ byte[] process(byte[] data);
+
+ /**
+ * Cipher所需参数,包括Key、Random、IV等信息
+ */
+ interface Parameters { }
+}
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/CipherWrapper.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/CipherWrapper.java
deleted file mode 100644
index 7a4077932..000000000
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/CipherWrapper.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (c) 2023 looly(loolly@aliyun.com)
- * Hutool is licensed under Mulan PSL v2.
- * You can use this software according to the terms and conditions of the Mulan PSL v2.
- * You may obtain a copy of Mulan PSL v2 at:
- * https://license.coscl.org.cn/MulanPSL2
- * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
- * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
- * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
- * See the Mulan PSL v2 for more details.
- */
-
-package org.dromara.hutool.crypto;
-
-import org.dromara.hutool.core.lang.wrapper.Wrapper;
-
-import javax.crypto.Cipher;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.SecureRandom;
-import java.security.spec.AlgorithmParameterSpec;
-
-/**
- * {@link Cipher}包装类,提供初始化模式等额外方法
- * 包装之后可提供自定义或默认的:
- *
- * - {@link AlgorithmParameterSpec}
- * - {@link SecureRandom}
- *
- *
- * @author looly
- * @since 5.7.17
- */
-public class CipherWrapper implements Wrapper {
-
- private final Cipher cipher;
- /**
- * 算法参数
- */
- private AlgorithmParameterSpec params;
- /**
- * 随机数生成器,可自定义随机数种子
- */
- private SecureRandom random;
-
- /**
- * 构造
- *
- * @param algorithm 算法名称
- */
- public CipherWrapper(final String algorithm) {
- this(SecureUtil.createCipher(algorithm));
- }
-
- /**
- * 构造
- *
- * @param cipher {@link Cipher}
- */
- public CipherWrapper(final Cipher cipher) {
- this.cipher = cipher;
- }
-
- /**
- * 获取{@link AlgorithmParameterSpec}
- * 在某些算法中,需要特别的参数,例如在ECIES中,此处为IESParameterSpec
- *
- * @return {@link AlgorithmParameterSpec}
- */
- public AlgorithmParameterSpec getParams() {
- return this.params;
- }
-
- /**
- * 设置 {@link AlgorithmParameterSpec},通常用于加盐或偏移向量
- *
- * @param params {@link AlgorithmParameterSpec}
- * @return this
- */
- public CipherWrapper setParams(final AlgorithmParameterSpec params) {
- this.params = params;
- return this;
- }
-
- /**
- * 设置随机数生成器,可自定义随机数种子
- *
- * @param random 随机数生成器,可自定义随机数种子
- * @return this
- */
- public CipherWrapper setRandom(final SecureRandom random) {
- this.random = random;
- return this;
- }
-
- /**
- * 获取被包装的{@link Cipher}
- *
- * @return {@link Cipher}
- */
- @Override
- public Cipher getRaw() {
- return this.cipher;
- }
-
- /**
- * 初始化{@link Cipher}为加密或者解密模式
- *
- * @param mode 模式,见{@link Cipher#ENCRYPT_MODE} 或 {@link Cipher#DECRYPT_MODE}
- * @param key 密钥
- * @return this
- * @throws InvalidKeyException 无效key
- * @throws InvalidAlgorithmParameterException 无效算法
- */
- public CipherWrapper initMode(final int mode, final Key key)
- throws InvalidKeyException, InvalidAlgorithmParameterException {
- final Cipher cipher = this.cipher;
- final AlgorithmParameterSpec params = this.params;
- final SecureRandom random = this.random;
- if (null != params) {
- if (null != random) {
- cipher.init(mode, key, params, random);
- } else {
- cipher.init(mode, key, params);
- }
- } else {
- if (null != random) {
- cipher.init(mode, key, random);
- } else {
- cipher.init(mode, key);
- }
- }
- return this;
- }
-}
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/JceCipher.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/JceCipher.java
new file mode 100644
index 000000000..ca92856e8
--- /dev/null
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/JceCipher.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2024. looly(loolly@aliyun.com)
+ * Hutool is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * https://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+
+package org.dromara.hutool.crypto;
+
+import org.dromara.hutool.core.lang.Assert;
+import org.dromara.hutool.core.lang.wrapper.Wrapper;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * 提供{@link javax.crypto.Cipher}的方法包装
+ *
+ * @author Looly
+ */
+public class JceCipher implements Cipher, Wrapper {
+
+ private final javax.crypto.Cipher cipher;
+
+ /**
+ * 构造
+ *
+ * @param algorithm 算法名称
+ */
+ public JceCipher(final String algorithm) {
+ this(SecureUtil.createCipher(algorithm));
+ }
+
+ /**
+ * 构造
+ *
+ * @param cipher {@link javax.crypto.Cipher}
+ */
+ public JceCipher(final javax.crypto.Cipher cipher) {
+ this.cipher = cipher;
+ }
+
+ @Override
+ public javax.crypto.Cipher getRaw() {
+ return this.cipher;
+ }
+
+ @Override
+ public String getAlgorithmName() {
+ return this.cipher.getAlgorithm();
+ }
+
+ @Override
+ public int getBlockSize() {
+ return this.cipher.getBlockSize();
+ }
+
+ @Override
+ public void init(final CipherMode mode, final Parameters parameters) {
+ Assert.isInstanceOf(JceParameters.class, parameters, "Only support JceParameters!");
+
+ try {
+ init(mode.getValue(), (JceParameters) parameters);
+ } catch (final InvalidAlgorithmParameterException | InvalidKeyException e) {
+ throw new CryptoException(e);
+ }
+ }
+
+ /**
+ * 执行初始化参数操作
+ *
+ * @param mode 模式
+ * @param jceParameters {@link JceParameters}
+ * @throws InvalidAlgorithmParameterException 无效算法参数
+ * @throws InvalidKeyException 无效key
+ */
+ public void init(final int mode, final JceParameters jceParameters) throws InvalidAlgorithmParameterException, InvalidKeyException {
+ final javax.crypto.Cipher cipher = this.cipher;
+ if (null != jceParameters.parameterSpec) {
+ if (null != jceParameters.random) {
+ cipher.init(mode, jceParameters.key, jceParameters.parameterSpec, jceParameters.random);
+ } else {
+ cipher.init(mode, jceParameters.key, jceParameters.parameterSpec);
+ }
+ } else {
+ if (null != jceParameters.random) {
+ cipher.init(mode, jceParameters.key, jceParameters.random);
+ } else {
+ cipher.init(mode, jceParameters.key);
+ }
+ }
+ }
+
+ @Override
+ public byte[] process(final byte[] data) {
+ return new byte[0];
+ }
+
+ /**
+ * JCE的{@link AlgorithmParameterSpec} 参数包装
+ */
+ public static class JceParameters implements Parameters {
+ private final Key key;
+ /**
+ * 算法参数
+ */
+ private final AlgorithmParameterSpec parameterSpec;
+ /**
+ * 随机数生成器,可自定义随机数种子
+ */
+ private final SecureRandom random;
+
+ /**
+ * 构造
+ *
+ * @param key 密钥
+ * @param parameterSpec {@link AlgorithmParameterSpec}
+ * @param random 自定义随机数生成器
+ */
+ public JceParameters(final Key key, final AlgorithmParameterSpec parameterSpec, final SecureRandom random) {
+ this.key = key;
+ this.parameterSpec = parameterSpec;
+ this.random = random;
+ }
+ }
+}
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/Mode.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/Mode.java
index 7ef557bae..87e592bfb 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/Mode.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/Mode.java
@@ -54,5 +54,10 @@ public enum Mode {
/**
* Propagating Cipher Block
*/
- PCBC
+ PCBC,
+ /**
+ * GCM 全称为 Galois/Counter Mode。G是指GMAC,C是指CTR。
+ * 它在 CTR 加密的基础上增加 GMAC 的特性,解决了 CTR 不能对加密消息进行完整性校验的问题。
+ */
+ GCM
}
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/asymmetric/AsymmetricCrypto.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/asymmetric/AsymmetricCrypto.java
index b050f6bf8..1731a0b62 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/asymmetric/AsymmetricCrypto.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/asymmetric/AsymmetricCrypto.java
@@ -14,10 +14,7 @@ package org.dromara.hutool.crypto.asymmetric;
import org.dromara.hutool.core.codec.binary.Base64;
import org.dromara.hutool.core.io.stream.FastByteArrayOutputStream;
-import org.dromara.hutool.crypto.CipherWrapper;
-import org.dromara.hutool.crypto.CryptoException;
-import org.dromara.hutool.crypto.KeyUtil;
-import org.dromara.hutool.crypto.SecureUtil;
+import org.dromara.hutool.crypto.*;
import org.dromara.hutool.crypto.symmetric.SymmetricAlgorithm;
import javax.crypto.BadPaddingException;
@@ -51,8 +48,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
/**
* Cipher负责完成加密或解密工作
*/
- protected CipherWrapper cipherWrapper;
-
+ protected JceCipher cipher;
/**
* 加密的块大小
*/
@@ -61,6 +57,15 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
* 解密的块大小
*/
protected int decryptBlockSize = -1;
+
+ /**
+ * 算法参数
+ */
+ private AlgorithmParameterSpec algorithmParameterSpec;
+ /**
+ * 自定义随机数
+ */
+ private SecureRandom random;
// ------------------------------------------------------------------ Constructor start
/**
@@ -209,7 +214,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
* @since 5.4.3
*/
public AlgorithmParameterSpec getAlgorithmParameterSpec() {
- return this.cipherWrapper.getParams();
+ return this.algorithmParameterSpec;
}
/**
@@ -217,10 +222,11 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
* 在某些算法中,需要特别的参数,例如在ECIES中,此处为IESParameterSpec
*
* @param algorithmParameterSpec {@link AlgorithmParameterSpec}
- * @since 5.4.3
+ * @return this
*/
- public void setAlgorithmParameterSpec(final AlgorithmParameterSpec algorithmParameterSpec) {
- this.cipherWrapper.setParams(algorithmParameterSpec);
+ public AsymmetricCrypto setAlgorithmParameterSpec(final AlgorithmParameterSpec algorithmParameterSpec) {
+ this.algorithmParameterSpec = algorithmParameterSpec;
+ return this;
}
/**
@@ -231,7 +237,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
* @since 5.7.17
*/
public AsymmetricCrypto setRandom(final SecureRandom random) {
- this.cipherWrapper.setRandom(random);
+ this.random = random;
return this;
}
@@ -301,7 +307,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
* @since 5.4.3
*/
public Cipher getCipher() {
- return this.cipherWrapper.getRaw();
+ return this.cipher.getRaw();
}
/**
@@ -310,7 +316,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
* @since 4.5.2
*/
protected void initCipher() {
- this.cipherWrapper = new CipherWrapper(this.algorithm);
+ this.cipher = new JceCipher(this.algorithm);
}
/**
@@ -376,6 +382,9 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
* @throws InvalidKeyException 异常KEY错误
*/
private Cipher initMode(final int mode, final Key key) throws InvalidAlgorithmParameterException, InvalidKeyException {
- return this.cipherWrapper.initMode(mode, key).getRaw();
+ final JceCipher cipher = this.cipher;
+ cipher.init(mode,
+ new JceCipher.JceParameters(key, this.algorithmParameterSpec, this.random));
+ return cipher.getRaw();
}
}
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java
new file mode 100644
index 000000000..ad51cd410
--- /dev/null
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2024. looly(loolly@aliyun.com)
+ * Hutool is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * https://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+
+package org.dromara.hutool.crypto.bc;
+
+import org.bouncycastle.crypto.BufferedBlockCipher;
+import org.bouncycastle.crypto.CipherParameters;
+import org.dromara.hutool.core.lang.Assert;
+import org.dromara.hutool.crypto.Cipher;
+import org.dromara.hutool.crypto.CipherMode;
+import org.dromara.hutool.crypto.CryptoException;
+
+/**
+ * 基于BouncyCastle库的{@link BufferedBlockCipher}封装的加密解密实现
+ *
+ * @author Looly, changhr2013
+ */
+public class BCCipher implements Cipher {
+
+ /**
+ * {@link BufferedBlockCipher},包含engine、mode、padding
+ */
+ private final BufferedBlockCipher blockCipher;
+
+ /**
+ * 构造
+ *
+ * @param blockCipher {@link BufferedBlockCipher}
+ */
+ public BCCipher(final BufferedBlockCipher blockCipher) {
+ this.blockCipher = blockCipher;
+ }
+
+ @Override
+ public String getAlgorithmName() {
+ return this.blockCipher.getUnderlyingCipher().getAlgorithmName();
+ }
+
+ @Override
+ public int getBlockSize() {
+ return this.blockCipher.getBlockSize();
+ }
+
+ @Override
+ public void init(final CipherMode mode, final Parameters parameters) {
+ Assert.isInstanceOf(BCParameters.class, parameters, "Only support BCParameters!");
+ this.blockCipher.init(mode == CipherMode.encrypt, ((BCParameters) parameters).parameters);
+ }
+
+ @Override
+ public byte[] process(final byte[] data) {
+ final byte[] out;
+ try {
+ final BufferedBlockCipher cipher = this.blockCipher;
+ final int updateOutputSize = cipher.getOutputSize(data.length);
+ final byte[] buf = new byte[updateOutputSize];
+ int len = cipher.processBytes(data, 0, data.length, buf, 0);
+ len += cipher.doFinal(buf, len);
+ out = new byte[len];
+ System.arraycopy(buf, 0, out, 0, len);
+ } catch (final Exception e) {
+ throw new CryptoException("encrypt/decrypt process exception.", e);
+ }
+ return out;
+ }
+
+ /**
+ * BouncyCastle库的{@link CipherParameters}封装
+ *
+ * @author Looly
+ */
+ public static class BCParameters implements Parameters {
+ /**
+ * 算法的参数
+ */
+ private final CipherParameters parameters;
+
+ /**
+ * 构造
+ *
+ * @param parameters {@link CipherParameters}
+ */
+ public BCParameters(final CipherParameters parameters) {
+ this.parameters = parameters;
+ }
+ }
+}
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCUtil.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCUtil.java
index f392fe8fe..9455bbb26 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCUtil.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCUtil.java
@@ -15,10 +15,19 @@ package org.dromara.hutool.crypto.bc;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.crypto.BlockCipher;
+import org.bouncycastle.crypto.BufferedBlockCipher;
+import org.bouncycastle.crypto.DefaultBufferedBlockCipher;
+import org.bouncycastle.crypto.modes.*;
+import org.bouncycastle.crypto.paddings.ISO10126d2Padding;
+import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
+import org.bouncycastle.crypto.paddings.ZeroBytePadding;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.dromara.hutool.core.io.IORuntimeException;
+import org.dromara.hutool.crypto.Mode;
+import org.dromara.hutool.crypto.Padding;
import java.io.IOException;
import java.security.PrivateKey;
@@ -41,10 +50,10 @@ public class BCUtil {
*/
public static ECDomainParameters toDomainParams(final ECParameterSpec parameterSpec) {
return new ECDomainParameters(
- parameterSpec.getCurve(),
- parameterSpec.getG(),
- parameterSpec.getN(),
- parameterSpec.getH());
+ parameterSpec.getCurve(),
+ parameterSpec.getG(),
+ parameterSpec.getN(),
+ parameterSpec.getH());
}
/**
@@ -67,10 +76,10 @@ public class BCUtil {
*/
public static ECDomainParameters toDomainParams(final X9ECParameters x9ECParameters) {
return new ECDomainParameters(
- x9ECParameters.getCurve(),
- x9ECParameters.getG(),
- x9ECParameters.getN(),
- x9ECParameters.getH()
+ x9ECParameters.getCurve(),
+ x9ECParameters.getG(),
+ x9ECParameters.getN(),
+ x9ECParameters.getH()
);
}
@@ -81,7 +90,7 @@ public class BCUtil {
* @return PKCS#1格式私钥
* @since 5.5.9
*/
- public static byte[] toPkcs1(final PrivateKey privateKey){
+ public static byte[] toPkcs1(final PrivateKey privateKey) {
final PrivateKeyInfo pkInfo = PrivateKeyInfo.getInstance(privateKey.getEncoded());
try {
return pkInfo.parsePrivateKey().toASN1Primitive().getEncoded();
@@ -97,13 +106,53 @@ public class BCUtil {
* @return PKCS#1格式公钥
* @since 5.5.9
*/
- public static byte[] toPkcs1(final PublicKey publicKey){
+ public static byte[] toPkcs1(final PublicKey publicKey) {
final SubjectPublicKeyInfo spkInfo = SubjectPublicKeyInfo
- .getInstance(publicKey.getEncoded());
+ .getInstance(publicKey.getEncoded());
try {
return spkInfo.parsePublicKey().getEncoded();
} catch (final IOException e) {
throw new IORuntimeException(e);
}
}
+
+ /**
+ * 将{@link BlockCipher}包装为指定mode和padding的{@link BufferedBlockCipher}
+ *
+ * @param cipher {@link BlockCipher}
+ * @param mode 模式
+ * @param padding 补码方式
+ * @return {@link BufferedBlockCipher},无对应Cipher返回{@code null}
+ * @since 6.0.0
+ */
+ public static BufferedBlockCipher wrap(BlockCipher cipher, final Mode mode, final Padding padding) {
+ switch (mode) {
+ case CBC:
+ cipher = CBCBlockCipher.newInstance(cipher);
+ break;
+ case CFB:
+ cipher = CFBBlockCipher.newInstance(cipher, cipher.getBlockSize() * 8);
+ break;
+ case CTR:
+ cipher = SICBlockCipher.newInstance(cipher);
+ break;
+ case OFB:
+ cipher = new OFBBlockCipher(cipher, cipher.getBlockSize() * 8);
+ case CTS:
+ return new CTSBlockCipher(cipher);
+ }
+
+ switch (padding) {
+ case NoPadding:
+ return new DefaultBufferedBlockCipher(cipher);
+ case PKCS5Padding:
+ return new PaddedBufferedBlockCipher(cipher);
+ case ZeroPadding:
+ return new PaddedBufferedBlockCipher(cipher, new ZeroBytePadding());
+ case ISO10126Padding:
+ return new PaddedBufferedBlockCipher(cipher, new ISO10126d2Padding());
+ }
+
+ return null;
+ }
}
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/symmetric/SymmetricCrypto.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/symmetric/SymmetricCrypto.java
index 38cea58af..3de82962a 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/symmetric/SymmetricCrypto.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/symmetric/SymmetricCrypto.java
@@ -52,7 +52,15 @@ import java.util.concurrent.locks.ReentrantLock;
public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor, Serializable {
private static final long serialVersionUID = 1L;
- private CipherWrapper cipherWrapper;
+ private JceCipher cipher;
+ /**
+ * 算法参数
+ */
+ private AlgorithmParameterSpec algorithmParameterSpec;
+ /**
+ * 自定义随机数
+ */
+ private SecureRandom random;
/**
* SecretKey 负责保存对称密钥
*/
@@ -157,7 +165,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
this.isZeroPadding = true;
}
- this.cipherWrapper = new CipherWrapper(algorithm);
+ this.cipher = new JceCipher(algorithm);
return this;
}
@@ -176,17 +184,17 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
* @return 加密或解密
*/
public Cipher getCipher() {
- return cipherWrapper.getRaw();
+ return cipher.getRaw();
}
/**
- * 设置 {@link AlgorithmParameterSpec},通常用于加盐或偏移向量
+ * 设置{@link AlgorithmParameterSpec},通常用于加盐或偏移向量
*
- * @param params {@link AlgorithmParameterSpec}
- * @return 自身
+ * @param algorithmParameterSpec {@link AlgorithmParameterSpec}
+ * @return this
*/
- public SymmetricCrypto setParams(final AlgorithmParameterSpec params) {
- this.cipherWrapper.setParams(params);
+ public SymmetricCrypto setAlgorithmParameterSpec(final AlgorithmParameterSpec algorithmParameterSpec) {
+ this.algorithmParameterSpec = algorithmParameterSpec;
return this;
}
@@ -197,7 +205,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
* @return 自身
*/
public SymmetricCrypto setIv(final IvParameterSpec iv) {
- return setParams(iv);
+ return setAlgorithmParameterSpec(iv);
}
/**
@@ -218,7 +226,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
* @since 5.7.17
*/
public SymmetricCrypto setRandom(final SecureRandom random) {
- this.cipherWrapper.setRandom(random);
+ this.random = random;
return this;
}
@@ -263,7 +271,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
* @since 5.6.8
*/
public byte[] update(final byte[] data) {
- final Cipher cipher = cipherWrapper.getRaw();
+ final Cipher cipher = this.cipher.getRaw();
lock.lock();
try {
return cipher.update(paddingDataWithZero(data, cipher.getBlockSize()));
@@ -417,8 +425,8 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
*/
private SymmetricCrypto initParams(final String algorithm, AlgorithmParameterSpec paramsSpec) {
if (null == paramsSpec) {
- byte[] iv = Opt.ofNullable(cipherWrapper)
- .map(CipherWrapper::getRaw).map(Cipher::getIV).get();
+ byte[] iv = Opt.ofNullable(cipher)
+ .map(JceCipher::getRaw).map(Cipher::getIV).get();
// 随机IV
if (StrUtil.startWithIgnoreCase(algorithm, "PBE")) {
@@ -435,7 +443,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
}
}
- return setParams(paramsSpec);
+ return setAlgorithmParameterSpec(paramsSpec);
}
/**
@@ -455,10 +463,14 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
.getKeyAndIV(secretKey.getEncoded(), salt);
secretKey = KeyUtil.generateKey(algorithm, keyAndIV[0]);
if(ArrayUtil.isNotEmpty(keyAndIV[1])){
- this.cipherWrapper.setParams(new IvParameterSpec(keyAndIV[1]));
+ setAlgorithmParameterSpec(new IvParameterSpec(keyAndIV[1]));
}
}
- return this.cipherWrapper.initMode(mode, secretKey).getRaw();
+
+ final JceCipher cipher = this.cipher;
+ cipher.init(mode,
+ new JceCipher.JceParameters(secretKey, this.algorithmParameterSpec, this.random));
+ return cipher.getRaw();
}
/**
From e621069a18b14965b2290f2393bd4211bd39d905 Mon Sep 17 00:00:00 2001
From: Looly
Date: Mon, 8 Jan 2024 17:42:13 +0800
Subject: [PATCH 05/26] fix dependency
---
hutool-extra/pom.xml | 10 +++++++++-
hutool-poi/pom.xml | 10 ++++++++++
2 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/hutool-extra/pom.xml b/hutool-extra/pom.xml
index 6231d4545..1ef2aec1b 100755
--- a/hutool-extra/pom.xml
+++ b/hutool-extra/pom.xml
@@ -39,7 +39,7 @@
3.1.2.RELEASE
1.6.2
0.1.55
- 0.37.0
+ 0.38.0
3.5.2
3.9.0
5.1.1
@@ -204,6 +204,14 @@
slf4j-api
org.slf4j
+
+ bcpkix-jdk18on
+ org.bouncycastle
+
+
+ bcprov-jdk18on
+ org.bouncycastle
+
true
diff --git a/hutool-poi/pom.xml b/hutool-poi/pom.xml
index 01f1c32b6..e5a712ce9 100755
--- a/hutool-poi/pom.xml
+++ b/hutool-poi/pom.xml
@@ -55,6 +55,16 @@
ofdrw-full
2.2.4
compile
+
+
+ bcpkix-jdk15on
+ org.bouncycastle
+
+
+ bcprov-jdk15on
+ org.bouncycastle
+
+
true
From ae4d15de46e7bb9cb60ba102b6629374ce4a6623 Mon Sep 17 00:00:00 2001
From: Looly
Date: Mon, 8 Jan 2024 18:02:18 +0800
Subject: [PATCH 06/26] update dependency
---
hutool-crypto/pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hutool-crypto/pom.xml b/hutool-crypto/pom.xml
index 0428e92fa..0e84aaa11 100755
--- a/hutool-crypto/pom.xml
+++ b/hutool-crypto/pom.xml
@@ -31,7 +31,7 @@
org.dromara.hutool.crypto
- 1.76
+ 1.77
From ab6c3b3efcca6b16e3e943eefde4f56d25c718f3 Mon Sep 17 00:00:00 2001
From: Looly
Date: Mon, 8 Jan 2024 18:05:52 +0800
Subject: [PATCH 07/26] fix code
---
.../main/java/org/dromara/hutool/crypto/bc/BCCipher.java | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java
index ad51cd410..876d226ee 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java
@@ -15,6 +15,7 @@ package org.dromara.hutool.crypto.bc;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.CipherParameters;
import org.dromara.hutool.core.lang.Assert;
+import org.dromara.hutool.core.lang.wrapper.Wrapper;
import org.dromara.hutool.crypto.Cipher;
import org.dromara.hutool.crypto.CipherMode;
import org.dromara.hutool.crypto.CryptoException;
@@ -24,13 +25,18 @@ import org.dromara.hutool.crypto.CryptoException;
*
* @author Looly, changhr2013
*/
-public class BCCipher implements Cipher {
+public class BCCipher implements Cipher, Wrapper {
/**
* {@link BufferedBlockCipher},包含engine、mode、padding
*/
private final BufferedBlockCipher blockCipher;
+ @Override
+ public BufferedBlockCipher getRaw() {
+ return this.blockCipher;
+ }
+
/**
* 构造
*
From 10979681260f4aa9c33eac04052ac239713d3678 Mon Sep 17 00:00:00 2001
From: Looly
Date: Mon, 8 Jan 2024 18:06:04 +0800
Subject: [PATCH 08/26] fix code
---
.../java/org/dromara/hutool/crypto/bc/BCCipher.java | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java
index 876d226ee..40c5f53a5 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java
@@ -32,11 +32,6 @@ public class BCCipher implements Cipher, Wrapper {
*/
private final BufferedBlockCipher blockCipher;
- @Override
- public BufferedBlockCipher getRaw() {
- return this.blockCipher;
- }
-
/**
* 构造
*
@@ -46,6 +41,11 @@ public class BCCipher implements Cipher, Wrapper {
this.blockCipher = blockCipher;
}
+ @Override
+ public BufferedBlockCipher getRaw() {
+ return this.blockCipher;
+ }
+
@Override
public String getAlgorithmName() {
return this.blockCipher.getUnderlyingCipher().getAlgorithmName();
From 8455f76110329b969b4f65254319cb96554472ce Mon Sep 17 00:00:00 2001
From: Looly
Date: Mon, 8 Jan 2024 18:06:56 +0800
Subject: [PATCH 09/26] fix code
---
.../src/main/java/org/dromara/hutool/crypto/JceCipher.java | 2 +-
.../src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/JceCipher.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/JceCipher.java
index ca92856e8..85d70ac3e 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/JceCipher.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/JceCipher.java
@@ -45,7 +45,7 @@ public class JceCipher implements Cipher, Wrapper {
* @param cipher {@link javax.crypto.Cipher}
*/
public JceCipher(final javax.crypto.Cipher cipher) {
- this.cipher = cipher;
+ this.cipher = Assert.notNull(cipher);
}
@Override
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java
index 40c5f53a5..34a05db0b 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java
@@ -38,7 +38,7 @@ public class BCCipher implements Cipher, Wrapper {
* @param blockCipher {@link BufferedBlockCipher}
*/
public BCCipher(final BufferedBlockCipher blockCipher) {
- this.blockCipher = blockCipher;
+ this.blockCipher = Assert.notNull(blockCipher);
}
@Override
From a5b5497bf5aedb54a581fa015ede6e422184e34d Mon Sep 17 00:00:00 2001
From: Looly
Date: Mon, 8 Jan 2024 18:16:21 +0800
Subject: [PATCH 10/26] fix code
---
hutool-json/pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hutool-json/pom.xml b/hutool-json/pom.xml
index f80f9801c..3400bafb4 100755
--- a/hutool-json/pom.xml
+++ b/hutool-json/pom.xml
@@ -31,7 +31,7 @@
org.dromara.hutool.json
- 1.76
+ 1.77
0.12.3
From 6fba25ad7d08642015f6983f16fe845b5228a1ea Mon Sep 17 00:00:00 2001
From: Looly
Date: Mon, 8 Jan 2024 19:03:27 +0800
Subject: [PATCH 11/26] add methods
---
.../org/dromara/hutool/crypto/KeyUtil.java | 18 ++++++++++++++++++
.../dromara/hutool/crypto/bc/ECKeyUtil.java | 6 ++++++
2 files changed, 24 insertions(+)
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/KeyUtil.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/KeyUtil.java
index be4eb5a98..43784426e 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/KeyUtil.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/KeyUtil.java
@@ -64,6 +64,7 @@ public class KeyUtil {
public static final int DEFAULT_KEY_SIZE = 1024;
// region ----- generateKey
+
/**
* 生成 {@link SecretKey},仅用于对称加密和摘要算法密钥生成
*
@@ -196,7 +197,24 @@ public class KeyUtil {
}
// endregion
+ /**
+ * 检查{@link KeyPair} 是否为空,空的条件是:
+ *
+ * - keyPair本身为{@code null}
+ * - {@link KeyPair#getPrivate()}和{@link KeyPair#getPublic()}都为{@code null}
+ *
+ *
+ * @param keyPair 密钥对
+ * @return 是否为空
+ */
// region ----- keyPair
+ public static boolean isEmpty(final KeyPair keyPair) {
+ if (null == keyPair) {
+ return false;
+ }
+ return null != keyPair.getPrivate() || null != keyPair.getPublic();
+ }
+
/**
* 生成RSA私钥,仅用于非对称加密
* 采用PKCS#8规范,此规范定义了私钥信息语法和加密私钥语法
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/ECKeyUtil.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/ECKeyUtil.java
index 040c614c4..864d88824 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/ECKeyUtil.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/ECKeyUtil.java
@@ -435,6 +435,9 @@ public class ECKeyUtil {
* @since 5.5.9
*/
public static ECPrivateKeyParameters decodePrivateKeyParams(final byte[] privateKeyBytes) {
+ if (null == privateKeyBytes) {
+ return null;
+ }
try {
// 尝试D值
return toSm2PrivateParams(privateKeyBytes);
@@ -468,6 +471,9 @@ public class ECKeyUtil {
* @since 5.5.9
*/
public static ECPublicKeyParameters decodePublicKeyParams(final byte[] publicKeyBytes) {
+ if(null == publicKeyBytes){
+ return null;
+ }
try {
// 尝试Q值
return toSm2PublicParams(publicKeyBytes);
From 46febc3d05b6f4a29509c51b63e84ada7f5f1ef3 Mon Sep 17 00:00:00 2001
From: Looly
Date: Mon, 8 Jan 2024 21:57:53 +0800
Subject: [PATCH 12/26] fix code
---
.../org/dromara/hutool/crypto/Cipher.java | 57 +++++++-
.../org/dromara/hutool/crypto/CipherMode.java | 8 +-
.../org/dromara/hutool/crypto/JceCipher.java | 32 ++++-
.../crypto/asymmetric/AsymmetricCrypto.java | 28 ++--
.../dromara/hutool/crypto/bc/BCCipher.java | 132 +++++++++++++++---
.../crypto/symmetric/SymmetricCrypto.java | 36 ++---
.../hutool/crypto/bc/BCCipherTest.java | 28 ++++
.../crypto/symmetric/SymmetricTest.java | 4 +-
8 files changed, 252 insertions(+), 73 deletions(-)
create mode 100644 hutool-crypto/src/test/java/org/dromara/hutool/crypto/bc/BCCipherTest.java
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/Cipher.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/Cipher.java
index a88795ac8..6709cfb84 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/Cipher.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/Cipher.java
@@ -12,6 +12,10 @@
package org.dromara.hutool.crypto;
+import org.bouncycastle.crypto.BufferedBlockCipher;
+
+import java.util.Arrays;
+
/**
* 密码接口,提供统一的API,用于兼容和统一JCE和BouncyCastle等库的操作
*
@@ -30,7 +34,7 @@ public interface Cipher {
/**
* 获取块大小,当为Stream方式加密时返回0
*
- * @return 块大小
+ * @return 块大小,-1表示非块加密
*/
int getBlockSize();
@@ -42,16 +46,59 @@ public interface Cipher {
*/
void init(CipherMode mode, Parameters parameters);
+ /**
+ * 根据输入长度,获取输出长度,输出长度与算法相关
+ * 输出长度只针对本次输入关联,即len长度的数据对应输出长度加doFinal的长度
+ *
+ * @param len 输入长度
+ * @return 输出长度,-1表示非块加密
+ */
+ int getOutputSize(int len);
+
/**
* 执行运算,可以是加密运算或解密运算
*
- * @param data 被处理的数据
- * @return 运算结果
+ * @param in 输入数据
+ * @param inOff 输入数据开始位置
+ * @param len 被处理数据长度
+ * @param out 输出数据
+ * @param outOff 输出数据开始位置
+ * @return 处理长度
*/
- byte[] process(byte[] data);
+ int process(byte[] in, int inOff, int len, byte[] out, int outOff);
+
+ /**
+ * 处理最后一块数据
+ * 当{@link #process(byte[], int, int, byte[], int)}处理完数据后非完整块数据,此方法用于处理块中剩余的bytes
+ * 如加密数据要求128bit,即16byes的整数,单数处理数据后为15bytes,此时根据padding方式不同,可填充剩余1byte为指定值(如填充0)
+ * 当对数据进行分段加密时,需要首先多次执行process方法,在最后一块数据处理完后执行此方法。
+ *
+ * @param out 经过process执行过运算的结果数据
+ * @param outOff 数据处理开始位置
+ * @return 处理长度
+ */
+ int doFinal(byte[] out, int outOff);
+
+ /**
+ * 处理数据,并返回最终结果
+ *
+ * @param in 输入数据
+ * @return 结果数据
+ */
+ default byte[] processFinal(final byte[] in) {
+ final byte[] buf = new byte[getOutputSize(in.length)];
+ int len = process(in, 0, in.length, buf, 0);
+ len += doFinal(buf, len);
+
+ if (len == buf.length) {
+ return buf;
+ }
+ return Arrays.copyOfRange(buf, 0, len);
+ }
/**
* Cipher所需参数,包括Key、Random、IV等信息
*/
- interface Parameters { }
+ interface Parameters {
+ }
}
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/CipherMode.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/CipherMode.java
index c94eb2336..4e2317261 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/CipherMode.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/CipherMode.java
@@ -24,19 +24,19 @@ public enum CipherMode {
/**
* 加密模式
*/
- encrypt(Cipher.ENCRYPT_MODE),
+ ENCRYPT(Cipher.ENCRYPT_MODE),
/**
* 解密模式
*/
- decrypt(Cipher.DECRYPT_MODE),
+ DECRYPT(Cipher.DECRYPT_MODE),
/**
* 包装模式
*/
- wrap(Cipher.WRAP_MODE),
+ WRAP(Cipher.WRAP_MODE),
/**
* 拆包模式
*/
- unwrap(Cipher.UNWRAP_MODE);
+ UNWRAP(Cipher.UNWRAP_MODE);
/**
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/JceCipher.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/JceCipher.java
index 85d70ac3e..d4dbd5c07 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/JceCipher.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/JceCipher.java
@@ -15,6 +15,7 @@ package org.dromara.hutool.crypto;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.lang.wrapper.Wrapper;
+import javax.crypto.ShortBufferException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
@@ -63,6 +64,11 @@ public class JceCipher implements Cipher, Wrapper {
return this.cipher.getBlockSize();
}
+ @Override
+ public int getOutputSize(final int len) {
+ return this.cipher.getOutputSize(len);
+ }
+
@Override
public void init(final CipherMode mode, final Parameters parameters) {
Assert.isInstanceOf(JceParameters.class, parameters, "Only support JceParameters!");
@@ -100,8 +106,30 @@ public class JceCipher implements Cipher, Wrapper {
}
@Override
- public byte[] process(final byte[] data) {
- return new byte[0];
+ public int process(final byte[] in, final int inOff, final int len, final byte[] out, final int outOff) {
+ try {
+ return this.cipher.update(in, inOff, len, out, outOff);
+ } catch (final ShortBufferException e) {
+ throw new CryptoException(e);
+ }
+ }
+
+ @Override
+ public int doFinal(final byte[] out, final int outOff) {
+ try {
+ return this.cipher.doFinal(out, outOff);
+ } catch (final Exception e) {
+ throw new CryptoException(e);
+ }
+ }
+
+ @Override
+ public byte[] processFinal(final byte[] data) {
+ try {
+ return this.cipher.doFinal(data);
+ } catch (final Exception e) {
+ throw new CryptoException(e);
+ }
}
/**
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/asymmetric/AsymmetricCrypto.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/asymmetric/AsymmetricCrypto.java
index 1731a0b62..5542d8395 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/asymmetric/AsymmetricCrypto.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/asymmetric/AsymmetricCrypto.java
@@ -21,8 +21,6 @@ import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import java.io.IOException;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
import java.security.Key;
import java.security.PrivateKey;
import java.security.PublicKey;
@@ -149,8 +147,8 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
*/
public AsymmetricCrypto(final String algorithm, final byte[] privateKey, final byte[] publicKey) {
this(algorithm, //
- KeyUtil.generatePrivateKey(algorithm, privateKey), //
- KeyUtil.generatePublicKey(algorithm, publicKey)//
+ KeyUtil.generatePrivateKey(algorithm, privateKey), //
+ KeyUtil.generatePublicKey(algorithm, publicKey)//
);
}
@@ -255,7 +253,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
final Key key = getKeyByType(keyType);
lock.lock();
try {
- final Cipher cipher = initMode(Cipher.ENCRYPT_MODE, key);
+ final JceCipher cipher = initMode(CipherMode.ENCRYPT, key);
if (this.encryptBlockSize < 0) {
// 在引入BC库情况下,自动获取块大小
@@ -280,7 +278,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
final Key key = getKeyByType(keyType);
lock.lock();
try {
- final Cipher cipher = initMode(Cipher.DECRYPT_MODE, key);
+ final JceCipher cipher = initMode(CipherMode.DECRYPT, key);
if (this.decryptBlockSize < 0) {
// 在引入BC库情况下,自动获取块大小
@@ -352,9 +350,10 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
* @throws BadPaddingException padding错误异常
* @throws IOException IO异常,不会被触发
*/
+ @SuppressWarnings("resource")
private byte[] doFinalWithBlock(final byte[] data, final int maxBlockSize) throws IllegalBlockSizeException, BadPaddingException, IOException {
final int dataLength = data.length;
- @SuppressWarnings("resource") final FastByteArrayOutputStream out = new FastByteArrayOutputStream();
+ final FastByteArrayOutputStream out = new FastByteArrayOutputStream();
int offSet = 0;
// 剩余长度
@@ -373,18 +372,15 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
}
/**
- * 初始化{@link Cipher}的模式,如加密模式或解密模式
+ * 初始化{@link JceCipher}的模式,如加密模式或解密模式
*
- * @param mode 模式,可选{@link Cipher#ENCRYPT_MODE}或者{@link Cipher#DECRYPT_MODE}
+ * @param mode 模式,可选{@link CipherMode#ENCRYPT}或者{@link CipherMode#DECRYPT}
* @param key 密钥
- * @return {@link Cipher}
- * @throws InvalidAlgorithmParameterException 异常算法错误
- * @throws InvalidKeyException 异常KEY错误
+ * @return {@link JceCipher}
*/
- private Cipher initMode(final int mode, final Key key) throws InvalidAlgorithmParameterException, InvalidKeyException {
+ private JceCipher initMode(final CipherMode mode, final Key key) {
final JceCipher cipher = this.cipher;
- cipher.init(mode,
- new JceCipher.JceParameters(key, this.algorithmParameterSpec, this.random));
- return cipher.getRaw();
+ cipher.init(mode, new JceCipher.JceParameters(key, this.algorithmParameterSpec, this.random));
+ return cipher;
}
}
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java
index 34a05db0b..44f4eccfd 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java
@@ -14,6 +14,9 @@ package org.dromara.hutool.crypto.bc;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.StreamCipher;
+import org.bouncycastle.crypto.modes.AEADBlockCipher;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.lang.wrapper.Wrapper;
import org.dromara.hutool.crypto.Cipher;
@@ -21,16 +24,31 @@ import org.dromara.hutool.crypto.CipherMode;
import org.dromara.hutool.crypto.CryptoException;
/**
- * 基于BouncyCastle库的{@link BufferedBlockCipher}封装的加密解密实现
+ * 基于BouncyCastle库封装的加密解密实现,包装包括:
+ *
+ * - {@link BufferedBlockCipher}
+ * - {@link StreamCipher}
+ * - {@link AEADBlockCipher}
+ *
*
* @author Looly, changhr2013
*/
-public class BCCipher implements Cipher, Wrapper {
+public class BCCipher implements Cipher, Wrapper
*
+ *
+ * MacEngineFactory
+ * ||(创建)
+ * MacEngine----------------(包装)-----------------> Mac
+ * _____|_______________ |
+ * / \ HMac
+ * JCEMacEngine BCMacEngine
+ * / \
+ * BCHMacEngine CBCBlockCipherMacEngine
+ * |
+ * SM4MacEngine
+ *
+ *
+ * 通过MacEngine,封装支持了BouncyCastle和JCE实现的一些MAC算法,通过MacEngineFactory自动根据算法名称创建对应对象。
+ *
* @author Looly
* @since 4.5.13
*/
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/digest/otp/package-info.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/digest/otp/package-info.java
index 29e540aac..695306155 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/digest/otp/package-info.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/digest/otp/package-info.java
@@ -21,6 +21,12 @@
* Truncate:是一个函数,就是怎么截取加密后的串,并取加密后串的哪些字段组成一个数字。
*
*
+ * 实现包括:
+ *
+ * - HMAC-based one-time passwords (HOTP) 基于HMAC算法一次性密码生成器
+ * - time-based one-time passwords (TOTP) 基于时间戳算法的一次性密码生成器
+ *
+ *
* @author looly
*/
package org.dromara.hutool.crypto.digest.otp;
diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSWrapper.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSWrapper.java
index 1109de772..21177f3b3 100644
--- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSWrapper.java
+++ b/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSWrapper.java
@@ -14,7 +14,7 @@ package org.dromara.hutool.db.ds;
import org.dromara.hutool.core.exception.CloneException;
import org.dromara.hutool.core.io.IoUtil;
-import org.dromara.hutool.core.lang.wrapper.Wrapper;
+import org.dromara.hutool.core.lang.wrapper.SimpleWrapper;
import javax.sql.DataSource;
import java.io.Closeable;
@@ -34,9 +34,8 @@ import java.util.logging.Logger;
* @author looly
* @since 4.3.2
*/
-public class DSWrapper implements Wrapper, DataSource, Closeable, Cloneable {
+public class DSWrapper extends SimpleWrapper implements DataSource, Closeable, Cloneable {
- private final DataSource ds;
private final String driver;
/**
@@ -57,7 +56,7 @@ public class DSWrapper implements Wrapper, DataSource, Closeable, Cl
* @param driver 数据库驱动类名
*/
public DSWrapper(final DataSource ds, final String driver) {
- this.ds = ds;
+ super(ds);
this.driver = driver;
}
@@ -70,65 +69,56 @@ public class DSWrapper implements Wrapper, DataSource, Closeable, Cl
return this.driver;
}
- /**
- * 获取原始的数据源
- *
- * @return 原始数据源
- */
- @Override
- public DataSource getRaw() {
- return this.ds;
- }
-
@Override
public PrintWriter getLogWriter() throws SQLException {
- return ds.getLogWriter();
+ return getRaw().getLogWriter();
}
@Override
public void setLogWriter(final PrintWriter out) throws SQLException {
- ds.setLogWriter(out);
+ getRaw().setLogWriter(out);
}
@Override
public void setLoginTimeout(final int seconds) throws SQLException {
- ds.setLoginTimeout(seconds);
+ getRaw().setLoginTimeout(seconds);
}
@Override
public int getLoginTimeout() throws SQLException {
- return ds.getLoginTimeout();
+ return getRaw().getLoginTimeout();
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
- return ds.getParentLogger();
+ return getRaw().getParentLogger();
}
@Override
public T unwrap(final Class iface) throws SQLException {
- return ds.unwrap(iface);
+ return getRaw().unwrap(iface);
}
@Override
public boolean isWrapperFor(final Class> iface) throws SQLException {
- return ds.isWrapperFor(iface);
+ return getRaw().isWrapperFor(iface);
}
@Override
public Connection getConnection() throws SQLException {
- return ds.getConnection();
+ return getRaw().getConnection();
}
@Override
public Connection getConnection(final String username, final String password) throws SQLException {
- return ds.getConnection(username, password);
+ return getRaw().getConnection(username, password);
}
@Override
public void close() {
- if (this.ds instanceof AutoCloseable) {
- IoUtil.closeQuietly((AutoCloseable) this.ds);
+ final DataSource ds = getRaw();
+ if (ds instanceof AutoCloseable) {
+ IoUtil.closeQuietly((AutoCloseable) ds);
}
}
From 9ae587cd595b32c803a90b8af51e3c6e79fefc04 Mon Sep 17 00:00:00 2001
From: Looly
Date: Mon, 8 Jan 2024 23:42:36 +0800
Subject: [PATCH 14/26] fix code
---
.../src/main/java/org/dromara/hutool/crypto/SignUtil.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/SignUtil.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/SignUtil.java
index b728bfc80..78ebbfc25 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/SignUtil.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/SignUtil.java
@@ -31,7 +31,7 @@ import java.util.Map;
* 签名工具类
* 封装包括:
*
- * - 非堆成签名,签名算法支持见{@link SignAlgorithm}
+ * - 非对称签名,签名算法支持见{@link SignAlgorithm}
* - 对称签名,支持Map类型参数排序后签名
* - 摘要签名,支持Map类型参数排序后签名,签名方法见:{@link DigestAlgorithm}
*
From 94dc35a2e0dac725dc2d9c54dba2c3f62435c42e Mon Sep 17 00:00:00 2001
From: Looly
Date: Mon, 8 Jan 2024 23:52:58 +0800
Subject: [PATCH 15/26] fix code
---
.../org/dromara/hutool/crypto/digest/mac/package-info.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/digest/mac/package-info.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/digest/mac/package-info.java
index b6401766c..0ca816ff1 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/digest/mac/package-info.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/digest/mac/package-info.java
@@ -22,7 +22,7 @@
* HMAC 可以与任何迭代散列函数捆绑使用。MD5 和 SHA-1 就是这种散列函数。HMAC 还可以使用一个用于计算和确认消息鉴别值的密钥。
*
*
- *
+ * {@code
* MacEngineFactory
* ||(创建)
* MacEngine----------------(包装)-----------------> Mac
@@ -33,7 +33,7 @@
* BCHMacEngine CBCBlockCipherMacEngine
* |
* SM4MacEngine
- *
+ * }
*
* 通过MacEngine,封装支持了BouncyCastle和JCE实现的一些MAC算法,通过MacEngineFactory自动根据算法名称创建对应对象。
*
From 4a545e3f1a7c86c0a4848c305533c63f0f27e002 Mon Sep 17 00:00:00 2001
From: Looly
Date: Tue, 9 Jan 2024 21:55:36 +0800
Subject: [PATCH 16/26] =?UTF-8?q?=E4=BF=AE=E5=A4=8DUserInfo=E4=B8=AD?=
=?UTF-8?q?=E7=94=A8=E6=88=B7=E5=90=8D=E5=8A=A0/=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../java/org/dromara/hutool/extra/management/UserInfo.java | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/hutool-extra/src/main/java/org/dromara/hutool/extra/management/UserInfo.java b/hutool-extra/src/main/java/org/dromara/hutool/extra/management/UserInfo.java
index a3293e8da..0e4786986 100644
--- a/hutool-extra/src/main/java/org/dromara/hutool/extra/management/UserInfo.java
+++ b/hutool-extra/src/main/java/org/dromara/hutool/extra/management/UserInfo.java
@@ -31,8 +31,11 @@ public class UserInfo implements Serializable{
private final String USER_LANGUAGE;
private final String USER_COUNTRY;
+ /**
+ * 构造
+ */
public UserInfo(){
- USER_NAME = fixPath(SystemUtil.get("user.name", false));
+ USER_NAME = SystemUtil.get("user.name", false);
USER_HOME = fixPath(SystemUtil.get("user.home", false));
USER_DIR = fixPath(SystemUtil.get("user.dir", false));
JAVA_IO_TMPDIR = fixPath(SystemUtil.get("java.io.tmpdir", false));
From 64c1dc554b48d342eb652379d7940679617d0644 Mon Sep 17 00:00:00 2001
From: Looly
Date: Tue, 9 Jan 2024 23:04:16 +0800
Subject: [PATCH 17/26] add BoundSql
---
.../org/dromara/hutool/db/StatementUtil.java | 2 +-
.../org/dromara/hutool/db/sql/BoundSql.java | 65 +++++++++++++++++++
.../org/dromara/hutool/db/sql/NamedSql.java | 38 +++++------
.../dromara/hutool/db/sql/SqlExecutor.java | 6 +-
.../hutool/db/sql/StatementBuilder.java | 2 +-
.../org/dromara/hutool/db/NamedSqlTest.java | 16 ++---
6 files changed, 93 insertions(+), 36 deletions(-)
create mode 100644 hutool-db/src/main/java/org/dromara/hutool/db/sql/BoundSql.java
diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/StatementUtil.java b/hutool-db/src/main/java/org/dromara/hutool/db/StatementUtil.java
index 449109869..68a32f881 100644
--- a/hutool-db/src/main/java/org/dromara/hutool/db/StatementUtil.java
+++ b/hutool-db/src/main/java/org/dromara/hutool/db/StatementUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023 looly(loolly@aliyun.com)
+ * Copyright (c) 2023-2024. looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/sql/BoundSql.java b/hutool-db/src/main/java/org/dromara/hutool/db/sql/BoundSql.java
new file mode 100644
index 000000000..bf063e57e
--- /dev/null
+++ b/hutool-db/src/main/java/org/dromara/hutool/db/sql/BoundSql.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2024. looly(loolly@aliyun.com)
+ * Hutool is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * https://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+
+package org.dromara.hutool.db.sql;
+
+import java.util.List;
+
+/**
+ * 参数绑定的SQL封装,用于表示SQL语句模板('?'表示参数占位符)和参数值的封装
+ * SQL中的'?'占位符必须和params列表中的参数值一一对应
+ *
+ * @author Looly
+ */
+public class BoundSql {
+
+ protected String sql;
+ protected final List params;
+
+ /**
+ * 构造
+ *
+ * @param sql SQL语句,参数占位符使用'?'表示
+ * @param params 参数列表,每个参数对应一个'?'
+ */
+ public BoundSql(final String sql, final List params) {
+ this.sql = sql;
+ this.params = params;
+ }
+
+ /**
+ * 获取SQL
+ *
+ * @return SQL
+ */
+ public String getSql() {
+ return this.sql;
+ }
+
+ /**
+ * 获取参数列表,按照占位符顺序
+ *
+ * @return 参数列表
+ */
+ public List getParams() {
+ return this.params;
+ }
+
+ /**
+ * 获取参数列表,按照占位符顺序
+ *
+ * @return 参数数组
+ */
+ public Object[] getParamArray() {
+ return this.params.toArray(new Object[0]);
+ }
+}
diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/sql/NamedSql.java b/hutool-db/src/main/java/org/dromara/hutool/db/sql/NamedSql.java
index 68b763f8e..db442abdf 100644
--- a/hutool-db/src/main/java/org/dromara/hutool/db/sql/NamedSql.java
+++ b/hutool-db/src/main/java/org/dromara/hutool/db/sql/NamedSql.java
@@ -12,13 +12,12 @@
package org.dromara.hutool.db.sql;
+import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.text.StrUtil;
-import org.dromara.hutool.core.array.ArrayUtil;
import java.util.Collection;
import java.util.LinkedList;
-import java.util.List;
import java.util.Map;
/**
@@ -33,12 +32,12 @@ import java.util.Map;
* @author looly
* @since 4.0.10
*/
-public class NamedSql {
+public class NamedSql extends BoundSql {
private static final char[] NAME_START_CHARS = {':', '@', '?'};
- private String sql;
- private final List params;
+ private final String namedSql;
+ private final Map paramMap;
/**
* 构造
@@ -47,35 +46,28 @@ public class NamedSql {
* @param paramMap 名和参数的对应Map
*/
public NamedSql(final String namedSql, final Map paramMap) {
- this.params = new LinkedList<>();
+ super(null, new LinkedList<>());
+ this.namedSql = namedSql;
+ this.paramMap = paramMap;
parse(namedSql, paramMap);
}
/**
- * 获取SQL
+ * 获取原始地带名称占位符的SQL语句
*
- * @return SQL
+ * @return 名称占位符的SQL
*/
- public String getSql() {
- return this.sql;
+ public String getNamedSql() {
+ return namedSql;
}
/**
- * 获取参数列表,按照占位符顺序
+ * 获取原始参数名和参数值对应关系参数表
*
- * @return 参数数组
+ * @return 参数名和参数值对应关系参数表
*/
- public Object[] getParams() {
- return this.params.toArray(new Object[0]);
- }
-
- /**
- * 获取参数列表,按照占位符顺序
- *
- * @return 参数列表
- */
- public List getParamList() {
- return this.params;
+ public Map getParamMap() {
+ return paramMap;
}
/**
diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/sql/SqlExecutor.java b/hutool-db/src/main/java/org/dromara/hutool/db/sql/SqlExecutor.java
index a4245d661..90f6361f8 100644
--- a/hutool-db/src/main/java/org/dromara/hutool/db/sql/SqlExecutor.java
+++ b/hutool-db/src/main/java/org/dromara/hutool/db/sql/SqlExecutor.java
@@ -44,7 +44,7 @@ public class SqlExecutor {
*/
public static int execute(final Connection conn, final String sql, final Map paramMap) throws DbRuntimeException {
final NamedSql namedSql = new NamedSql(sql, paramMap);
- return execute(conn, namedSql.getSql(), namedSql.getParams());
+ return execute(conn, namedSql.getSql(), namedSql.getParamArray());
}
/**
@@ -125,7 +125,7 @@ public class SqlExecutor {
*/
public static Long executeForGeneratedKey(final Connection conn, final String sql, final Map paramMap) throws DbRuntimeException {
final NamedSql namedSql = new NamedSql(sql, paramMap);
- return executeForGeneratedKey(conn, namedSql.getSql(), namedSql.getParams());
+ return executeForGeneratedKey(conn, namedSql.getSql(), namedSql.getParamArray());
}
/**
@@ -241,7 +241,7 @@ public class SqlExecutor {
*/
public static T query(final Connection conn, final String sql, final RsHandler rsh, final Map paramMap) throws DbRuntimeException {
final NamedSql namedSql = new NamedSql(sql, paramMap);
- return query(conn, namedSql.getSql(), rsh, namedSql.getParams());
+ return query(conn, namedSql.getSql(), rsh, namedSql.getParamArray());
}
/**
diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/sql/StatementBuilder.java b/hutool-db/src/main/java/org/dromara/hutool/db/sql/StatementBuilder.java
index 521342b75..1eb0b930a 100644
--- a/hutool-db/src/main/java/org/dromara/hutool/db/sql/StatementBuilder.java
+++ b/hutool-db/src/main/java/org/dromara/hutool/db/sql/StatementBuilder.java
@@ -200,7 +200,7 @@ public class StatementBuilder implements Builder {
// 检查参数是否为命名方式的参数
final NamedSql namedSql = new NamedSql(sql, Convert.toMap(String.class, Object.class, params[0]));
sql = namedSql.getSql();
- params = namedSql.getParams();
+ params = namedSql.getParamArray();
}
sqlLog.log(sql, ArrayUtil.isEmpty(params) ? null : params);
diff --git a/hutool-db/src/test/java/org/dromara/hutool/db/NamedSqlTest.java b/hutool-db/src/test/java/org/dromara/hutool/db/NamedSqlTest.java
index bbee47be0..0253facb3 100644
--- a/hutool-db/src/test/java/org/dromara/hutool/db/NamedSqlTest.java
+++ b/hutool-db/src/test/java/org/dromara/hutool/db/NamedSqlTest.java
@@ -36,8 +36,8 @@ public class NamedSqlTest {
final NamedSql namedSql = new NamedSql(sql, paramMap);
//未指定参数原样输出
Assertions.assertEquals("select * from table where id=@id and name = ? and nickName = ?", namedSql.getSql());
- Assertions.assertEquals("张三", namedSql.getParams()[0]);
- Assertions.assertEquals("小豆豆", namedSql.getParams()[1]);
+ Assertions.assertEquals("张三", namedSql.getParamArray()[0]);
+ Assertions.assertEquals("小豆豆", namedSql.getParamArray()[1]);
}
@Test
@@ -54,9 +54,9 @@ public class NamedSqlTest {
final NamedSql namedSql = new NamedSql(sql, paramMap);
Assertions.assertEquals("select * from table where id=? and name = ? and nickName = ?", namedSql.getSql());
//指定了null参数的依旧替换,参数值为null
- Assertions.assertNull(namedSql.getParams()[0]);
- Assertions.assertEquals("张三", namedSql.getParams()[1]);
- Assertions.assertEquals("小豆豆", namedSql.getParams()[2]);
+ Assertions.assertNull(namedSql.getParamArray()[0]);
+ Assertions.assertEquals("张三", namedSql.getParamArray()[1]);
+ Assertions.assertEquals("小豆豆", namedSql.getParamArray()[2]);
}
@Test
@@ -92,9 +92,9 @@ public class NamedSqlTest {
final NamedSql namedSql = new NamedSql(sql, paramMap);
Assertions.assertEquals("select * from user where id in (?,?,?)", namedSql.getSql());
- Assertions.assertEquals(1, namedSql.getParams()[0]);
- Assertions.assertEquals(2, namedSql.getParams()[1]);
- Assertions.assertEquals(3, namedSql.getParams()[2]);
+ Assertions.assertEquals(1, namedSql.getParamArray()[0]);
+ Assertions.assertEquals(2, namedSql.getParamArray()[1]);
+ Assertions.assertEquals(3, namedSql.getParamArray()[2]);
}
@Test
From ebf1632f3654db96ff600697dec89f1ec66a35e7 Mon Sep 17 00:00:00 2001
From: Looly
Date: Tue, 9 Jan 2024 23:15:52 +0800
Subject: [PATCH 18/26] fix code
---
.../core/lang/wrapper/SimpleWrapper.java | 3 ++-
.../org/dromara/hutool/crypto/JceCipher.java | 14 ++++++-------
.../hutool/crypto/digest/Digester.java | 2 +-
.../hutool/crypto/digest/mac/BCMacEngine.java | 10 +++++-----
.../crypto/digest/mac/JCEMacEngine.java | 12 +++++------
.../org/dromara/hutool/db/ds/DSWrapper.java | 20 +++++++++----------
6 files changed, 31 insertions(+), 30 deletions(-)
diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/lang/wrapper/SimpleWrapper.java b/hutool-core/src/main/java/org/dromara/hutool/core/lang/wrapper/SimpleWrapper.java
index c67ba52e7..a1d199af2 100644
--- a/hutool-core/src/main/java/org/dromara/hutool/core/lang/wrapper/SimpleWrapper.java
+++ b/hutool-core/src/main/java/org/dromara/hutool/core/lang/wrapper/SimpleWrapper.java
@@ -13,7 +13,8 @@
package org.dromara.hutool.core.lang.wrapper;
/**
- * 简单包装对象
+ * 简单包装对象
+ * 通过继承此类,可以直接使用被包装的对象,用于简化和统一封装。
*
* @param 被包装对象类型
* @author looly
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/JceCipher.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/JceCipher.java
index 689c95695..11625d35c 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/JceCipher.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/JceCipher.java
@@ -49,17 +49,17 @@ public class JceCipher extends SimpleWrapper implements Cip
@Override
public String getAlgorithmName() {
- return getRaw().getAlgorithm();
+ return this.raw.getAlgorithm();
}
@Override
public int getBlockSize() {
- return getRaw().getBlockSize();
+ return this.raw.getBlockSize();
}
@Override
public int getOutputSize(final int len) {
- return getRaw().getOutputSize(len);
+ return this.raw.getOutputSize(len);
}
@Override
@@ -82,7 +82,7 @@ public class JceCipher extends SimpleWrapper implements Cip
* @throws InvalidKeyException 无效key
*/
public void init(final int mode, final JceParameters jceParameters) throws InvalidAlgorithmParameterException, InvalidKeyException {
- final javax.crypto.Cipher cipher = getRaw();
+ final javax.crypto.Cipher cipher = this.raw;
if (null != jceParameters.parameterSpec) {
if (null != jceParameters.random) {
cipher.init(mode, jceParameters.key, jceParameters.parameterSpec, jceParameters.random);
@@ -101,7 +101,7 @@ public class JceCipher extends SimpleWrapper implements Cip
@Override
public int process(final byte[] in, final int inOff, final int len, final byte[] out, final int outOff) {
try {
- return getRaw().update(in, inOff, len, out, outOff);
+ return this.raw.update(in, inOff, len, out, outOff);
} catch (final ShortBufferException e) {
throw new CryptoException(e);
}
@@ -110,7 +110,7 @@ public class JceCipher extends SimpleWrapper implements Cip
@Override
public int doFinal(final byte[] out, final int outOff) {
try {
- return getRaw().doFinal(out, outOff);
+ return this.raw.doFinal(out, outOff);
} catch (final Exception e) {
throw new CryptoException(e);
}
@@ -119,7 +119,7 @@ public class JceCipher extends SimpleWrapper implements Cip
@Override
public byte[] processFinal(final byte[] data) {
try {
- return getRaw().doFinal(data);
+ return this.raw.doFinal(data);
} catch (final Exception e) {
throw new CryptoException(e);
}
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/digest/Digester.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/digest/Digester.java
index d17e1a87b..7af85dcee 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/digest/Digester.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/digest/Digester.java
@@ -253,7 +253,7 @@ public class Digester extends SimpleWrapper implements Serializab
// 加盐在末尾,自动忽略空盐值
result = doDigest(data, this.salt);
} else if (ArrayUtil.isNotEmpty(this.salt)) {
- final MessageDigest digest = getRaw();
+ final MessageDigest digest = this.raw;
// 加盐在中间
digest.update(data, 0, this.saltPosition);
digest.update(this.salt);
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/digest/mac/BCMacEngine.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/digest/mac/BCMacEngine.java
index c60a78caa..92e27103e 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/digest/mac/BCMacEngine.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/digest/mac/BCMacEngine.java
@@ -41,29 +41,29 @@ public class BCMacEngine extends SimpleWrapper implements MacEngine {
@Override
public void update(final byte[] in, final int inOff, final int len) {
- getRaw().update(in, inOff, len);
+ this.raw.update(in, inOff, len);
}
@Override
public byte[] doFinal() {
final byte[] result = new byte[getMacLength()];
- getRaw().doFinal(result, 0);
+ this.raw.doFinal(result, 0);
return result;
}
@Override
public void reset() {
- getRaw().reset();
+ this.raw.reset();
}
@Override
public int getMacLength() {
- return getRaw().getMacSize();
+ return this.raw.getMacSize();
}
@Override
public String getAlgorithm() {
- return getRaw().getAlgorithmName();
+ return this.raw.getAlgorithmName();
}
/**
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/digest/mac/JCEMacEngine.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/digest/mac/JCEMacEngine.java
index 4ab8fa997..2b3695c0e 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/digest/mac/JCEMacEngine.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/digest/mac/JCEMacEngine.java
@@ -70,32 +70,32 @@ public class JCEMacEngine extends SimpleWrapper implements MacEngine {
@Override
public void update(final byte[] in) {
- getRaw().update(in);
+ this.raw.update(in);
}
@Override
public void update(final byte[] in, final int inOff, final int len) {
- getRaw().update(in, inOff, len);
+ this.raw.update(in, inOff, len);
}
@Override
public byte[] doFinal() {
- return getRaw().doFinal();
+ return this.raw.doFinal();
}
@Override
public void reset() {
- getRaw().reset();
+ this.raw.reset();
}
@Override
public int getMacLength() {
- return getRaw().getMacLength();
+ return this.raw.getMacLength();
}
@Override
public String getAlgorithm() {
- return getRaw().getAlgorithm();
+ return this.raw.getAlgorithm();
}
/**
diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSWrapper.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSWrapper.java
index 21177f3b3..2490387ca 100644
--- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSWrapper.java
+++ b/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSWrapper.java
@@ -71,52 +71,52 @@ public class DSWrapper extends SimpleWrapper implements DataSource,
@Override
public PrintWriter getLogWriter() throws SQLException {
- return getRaw().getLogWriter();
+ return this.raw.getLogWriter();
}
@Override
public void setLogWriter(final PrintWriter out) throws SQLException {
- getRaw().setLogWriter(out);
+ this.raw.setLogWriter(out);
}
@Override
public void setLoginTimeout(final int seconds) throws SQLException {
- getRaw().setLoginTimeout(seconds);
+ this.raw.setLoginTimeout(seconds);
}
@Override
public int getLoginTimeout() throws SQLException {
- return getRaw().getLoginTimeout();
+ return this.raw.getLoginTimeout();
}
@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
- return getRaw().getParentLogger();
+ return this.raw.getParentLogger();
}
@Override
public T unwrap(final Class iface) throws SQLException {
- return getRaw().unwrap(iface);
+ return this.raw.unwrap(iface);
}
@Override
public boolean isWrapperFor(final Class> iface) throws SQLException {
- return getRaw().isWrapperFor(iface);
+ return this.raw.isWrapperFor(iface);
}
@Override
public Connection getConnection() throws SQLException {
- return getRaw().getConnection();
+ return this.raw.getConnection();
}
@Override
public Connection getConnection(final String username, final String password) throws SQLException {
- return getRaw().getConnection(username, password);
+ return this.raw.getConnection(username, password);
}
@Override
public void close() {
- final DataSource ds = getRaw();
+ final DataSource ds = this.raw;
if (ds instanceof AutoCloseable) {
IoUtil.closeQuietly((AutoCloseable) ds);
}
From 8205a8b03a1d7909b62b8955047d25aa4d5dfec6 Mon Sep 17 00:00:00 2001
From: Looly
Date: Wed, 10 Jan 2024 00:48:21 +0800
Subject: [PATCH 19/26] add filter
---
.../org/dromara/hutool/db/StatementUtil.java | 32 ++-----
.../db/dialect/impl/AnsiSqlDialect.java | 8 +-
.../java/org/dromara/hutool/db/ds/DSPool.java | 2 +
.../org/dromara/hutool/db/sql/BoundSql.java | 46 +++++++++-
.../org/dromara/hutool/db/sql/NamedSql.java | 10 +--
.../hutool/db/sql/StatementBuilder.java | 87 +++++++++----------
.../hutool/db/sql/filter/SqlFilter.java | 34 ++++++++
.../hutool/db/sql/filter/SqlLogFilter.java | 55 ++++++++++++
.../hutool/db/sql/filter/package-info.java | 18 ++++
9 files changed, 208 insertions(+), 84 deletions(-)
create mode 100644 hutool-db/src/main/java/org/dromara/hutool/db/sql/filter/SqlFilter.java
create mode 100644 hutool-db/src/main/java/org/dromara/hutool/db/sql/filter/SqlLogFilter.java
create mode 100644 hutool-db/src/main/java/org/dromara/hutool/db/sql/filter/package-info.java
diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/StatementUtil.java b/hutool-db/src/main/java/org/dromara/hutool/db/StatementUtil.java
index 68a32f881..679faed72 100644
--- a/hutool-db/src/main/java/org/dromara/hutool/db/StatementUtil.java
+++ b/hutool-db/src/main/java/org/dromara/hutool/db/StatementUtil.java
@@ -12,14 +12,15 @@
package org.dromara.hutool.db;
+import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.collection.iter.ArrayIter;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.db.handler.ResultSetUtil;
import org.dromara.hutool.db.handler.RsHandler;
import org.dromara.hutool.db.sql.SqlBuilder;
-import org.dromara.hutool.db.sql.SqlLog;
import org.dromara.hutool.db.sql.StatementBuilder;
import org.dromara.hutool.db.sql.StatementWrapper;
+import org.dromara.hutool.db.sql.filter.SqlLogFilter;
import java.sql.*;
import java.util.Collection;
@@ -87,7 +88,7 @@ public class StatementUtil {
return StatementBuilder.of()
.setConnection(conn)
.setReturnGeneratedKey(returnGeneratedKey)
- .setSqlLog(SqlLog.INSTANCE)
+ .setSqlFilter(SqlLogFilter.INSTANCE)
.setSql(sql)
.setParams(params)
.build();
@@ -120,29 +121,10 @@ public class StatementUtil {
return StatementBuilder.of()
.setConnection(conn)
.setReturnGeneratedKey(false)
- .setSqlLog(SqlLog.INSTANCE)
+ .setSqlFilter(SqlLogFilter.INSTANCE)
.setSql(sql)
- .buildForBatch(paramsBatch);
- }
-
- /**
- * 创建批量操作的{@link PreparedStatement}
- *
- * @param conn 数据库连接
- * @param sql SQL语句,使用"?"做为占位符
- * @param fields 字段列表,用于获取对应值
- * @param entities "?"对应参数批次列表
- * @return {@link PreparedStatement}
- * @since 4.6.7
- */
- public static PreparedStatement prepareStatementForBatch(final Connection conn, final String sql,
- final Iterable fields, final Entity... entities) {
- return StatementBuilder.of()
- .setConnection(conn)
- .setReturnGeneratedKey(false)
- .setSqlLog(SqlLog.INSTANCE)
- .setSql(sql)
- .buildForBatch(fields, entities);
+ .setParams(ArrayUtil.ofArray(paramsBatch, Object.class))
+ .buildForBatch();
}
/**
@@ -158,7 +140,7 @@ public class StatementUtil {
public static CallableStatement prepareCall(final Connection conn, final String sql, final Object... params) throws SQLException {
return StatementBuilder.of()
.setConnection(conn)
- .setSqlLog(SqlLog.INSTANCE)
+ .setSqlFilter(SqlLogFilter.INSTANCE)
.setSql(sql)
.setParams(params)
.buildForCall();
diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/AnsiSqlDialect.java b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/AnsiSqlDialect.java
index fdc6ff605..567307a31 100644
--- a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/AnsiSqlDialect.java
+++ b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/AnsiSqlDialect.java
@@ -53,21 +53,21 @@ public class AnsiSqlDialect implements Dialect {
}
@Override
- public PreparedStatement psForInsert(final Connection conn, final Entity entity) throws SQLException {
+ public PreparedStatement psForInsert(final Connection conn, final Entity entity) {
final SqlBuilder insert = SqlBuilder.of(quoteWrapper).insert(entity, this.dialectName());
return StatementUtil.prepareStatement(conn, insert);
}
@Override
- public PreparedStatement psForInsertBatch(final Connection conn, final Entity... entities) throws SQLException {
+ public PreparedStatement psForInsertBatch(final Connection conn, final Entity... entities) {
if (ArrayUtil.isEmpty(entities)) {
throw new DbRuntimeException("Entities for batch insert is empty !");
}
// 批量,根据第一行数据结构生成SQL占位符
final SqlBuilder insert = SqlBuilder.of(quoteWrapper).insert(entities[0], this.dialectName());
final Set fields = CollUtil.remove(entities[0].keySet(), StrUtil::isBlank);
- return StatementUtil.prepareStatementForBatch(conn, insert.build(), fields, entities);
+ return StatementUtil.prepareStatementForBatch(conn, insert.build(), entities);
}
@Override
@@ -116,7 +116,7 @@ public class AnsiSqlDialect implements Dialect {
}
@Override
- public PreparedStatement psForPage(final Connection conn, SqlBuilder sqlBuilder, final Page page) throws SQLException {
+ public PreparedStatement psForPage(final Connection conn, SqlBuilder sqlBuilder, final Page page) {
// 根据不同数据库在查询SQL语句基础上包装其分页的语句
if (null != page) {
sqlBuilder = wrapPageSql(sqlBuilder.orderBy(page.getOrders()), page);
diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSPool.java b/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSPool.java
index 20cc1aa0b..90cef3077 100644
--- a/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSPool.java
+++ b/hutool-db/src/main/java/org/dromara/hutool/db/ds/DSPool.java
@@ -19,6 +19,7 @@ import org.dromara.hutool.core.map.SafeConcurrentHashMap;
import org.dromara.hutool.core.spi.SpiUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.db.DbRuntimeException;
+import org.dromara.hutool.db.DbUtil;
import org.dromara.hutool.db.GlobalDbConfig;
import org.dromara.hutool.db.driver.DriverUtil;
import org.dromara.hutool.log.LogUtil;
@@ -89,6 +90,7 @@ public class DSPool implements Closeable {
*/
public DSPool(final Setting setting, final DSFactory factory) {
this.setting = null != setting ? setting : GlobalDbConfig.createDbSetting();
+ DbUtil.setShowSqlGlobal(this.setting);
this.factory = null != factory ? factory : SpiUtil.loadFirstAvailable(DSFactory.class);
this.pool = new SafeConcurrentHashMap<>();
}
diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/sql/BoundSql.java b/hutool-db/src/main/java/org/dromara/hutool/db/sql/BoundSql.java
index bf063e57e..1801c08c7 100644
--- a/hutool-db/src/main/java/org/dromara/hutool/db/sql/BoundSql.java
+++ b/hutool-db/src/main/java/org/dromara/hutool/db/sql/BoundSql.java
@@ -12,6 +12,7 @@
package org.dromara.hutool.db.sql;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -22,8 +23,13 @@ import java.util.List;
*/
public class BoundSql {
- protected String sql;
- protected final List params;
+ private String sql;
+ private List params;
+
+ /**
+ * 构造
+ */
+ public BoundSql() {}
/**
* 构造
@@ -45,6 +51,17 @@ public class BoundSql {
return this.sql;
}
+ /**
+ * 设置SQL语句
+ *
+ * @param sql SQL语句
+ * @return this
+ */
+ public BoundSql setSql(final String sql) {
+ this.sql = sql;
+ return this;
+ }
+
/**
* 获取参数列表,按照占位符顺序
*
@@ -62,4 +79,29 @@ public class BoundSql {
public Object[] getParamArray() {
return this.params.toArray(new Object[0]);
}
+
+ /**
+ * 设置参数列表
+ *
+ * @param params 参数列表
+ * @return this
+ */
+ public BoundSql setParams(final List params) {
+ this.params = params;
+ return this;
+ }
+
+ /**
+ * 增加参数
+ *
+ * @param paramValue 参数值
+ * @return this
+ */
+ public BoundSql addParam(final Object paramValue){
+ if(null == this.params){
+ this.params = new ArrayList<>();
+ }
+ this.params.add(paramValue);
+ return this;
+ }
}
diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/sql/NamedSql.java b/hutool-db/src/main/java/org/dromara/hutool/db/sql/NamedSql.java
index db442abdf..9ba5354a8 100644
--- a/hutool-db/src/main/java/org/dromara/hutool/db/sql/NamedSql.java
+++ b/hutool-db/src/main/java/org/dromara/hutool/db/sql/NamedSql.java
@@ -17,7 +17,6 @@ import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.text.StrUtil;
import java.util.Collection;
-import java.util.LinkedList;
import java.util.Map;
/**
@@ -46,7 +45,6 @@ public class NamedSql extends BoundSql {
* @param paramMap 名和参数的对应Map
*/
public NamedSql(final String namedSql, final Map paramMap) {
- super(null, new LinkedList<>());
this.namedSql = namedSql;
this.paramMap = paramMap;
parse(namedSql, paramMap);
@@ -78,7 +76,7 @@ public class NamedSql extends BoundSql {
*/
private void parse(final String namedSql, final Map paramMap) {
if (MapUtil.isEmpty(paramMap)) {
- this.sql = namedSql;
+ setSql(namedSql);
return;
}
@@ -116,7 +114,7 @@ public class NamedSql extends BoundSql {
replaceVar(nameStartChar, name, sqlBuilder, paramMap);
}
- this.sql = sqlBuilder.toString();
+ setSql(sqlBuilder.toString());
}
/**
@@ -155,11 +153,11 @@ public class NamedSql extends BoundSql {
sqlBuilder.append(',');
}
sqlBuilder.append('?');
- this.params.add(ArrayUtil.get(paramValue, i));
+ addParam(ArrayUtil.get(paramValue, i));
}
} else {
sqlBuilder.append('?');
- this.params.add(paramValue);
+ addParam(paramValue);
}
} else {
// 无变量对应值,原样输出
diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/sql/StatementBuilder.java b/hutool-db/src/main/java/org/dromara/hutool/db/sql/StatementBuilder.java
index 1eb0b930a..c60aa6d8d 100644
--- a/hutool-db/src/main/java/org/dromara/hutool/db/sql/StatementBuilder.java
+++ b/hutool-db/src/main/java/org/dromara/hutool/db/sql/StatementBuilder.java
@@ -13,17 +13,19 @@
package org.dromara.hutool.db.sql;
import org.dromara.hutool.core.array.ArrayUtil;
+import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.collection.iter.ArrayIter;
import org.dromara.hutool.core.convert.Convert;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.lang.builder.Builder;
-import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.db.DbRuntimeException;
import org.dromara.hutool.db.Entity;
+import org.dromara.hutool.db.sql.filter.SqlFilter;
import java.sql.*;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
/**
@@ -44,20 +46,19 @@ public class StatementBuilder implements Builder {
return new StatementBuilder();
}
- private SqlLog sqlLog;
+ private final BoundSql boundSql = new BoundSql();
private Connection connection;
- private String sql;
- private Object[] params;
private boolean returnGeneratedKey = true;
+ private SqlFilter sqlFilter;
/**
* 设置SQL日志
*
- * @param sqlLog {@link SqlLog}
+ * @param sqlFilter {@link SqlFilter}
* @return this
*/
- public StatementBuilder setSqlLog(final SqlLog sqlLog) {
- this.sqlLog = sqlLog;
+ public StatementBuilder setSqlFilter(final SqlFilter sqlFilter) {
+ this.sqlFilter = sqlFilter;
return this;
}
@@ -79,7 +80,7 @@ public class StatementBuilder implements Builder {
* @return this
*/
public StatementBuilder setSql(final String sql) {
- this.sql = StrUtil.trim(sql);
+ this.boundSql.setSql(sql);
return this;
}
@@ -90,7 +91,7 @@ public class StatementBuilder implements Builder {
* @return this
*/
public StatementBuilder setParams(final Object... params) {
- this.params = params;
+ this.boundSql.setParams(ListUtil.of(params));
return this;
}
@@ -105,6 +106,11 @@ public class StatementBuilder implements Builder {
return this;
}
+ /**
+ * 构建{@link StatementWrapper}
+ *
+ * @return {@link StatementWrapper},{@code null}表示不执行
+ */
@Override
public StatementWrapper build() {
try {
@@ -117,48 +123,29 @@ public class StatementBuilder implements Builder {
/**
* 创建批量操作的{@link StatementWrapper}
*
- * @param paramsBatch "?"对应参数批次列表
- * @return {@link StatementWrapper}
+ * @return {@link StatementWrapper},{@code null}表示不执行
* @throws DbRuntimeException SQL异常
*/
- public StatementWrapper buildForBatch(final Iterable paramsBatch) throws DbRuntimeException {
+ public StatementWrapper buildForBatch() throws DbRuntimeException {
+ final String sql = this.boundSql.getSql();
Assert.notBlank(sql, "Sql String must be not blank!");
+ final List paramsBatch = this.boundSql.getParams();
- sqlLog.log(sql, paramsBatch);
+ sqlFilter.filter(this.connection, this.boundSql, this.returnGeneratedKey);
final StatementWrapper ps;
try {
ps = StatementWrapper.of(connection.prepareStatement(sql));
final Map nullTypeMap = new HashMap<>();
- for (final Object[] params : paramsBatch) {
- ps.fillParams(new ArrayIter<>(params), nullTypeMap);
- ps.addBatch();
- }
- } catch (final SQLException e) {
- throw new DbRuntimeException(e);
- }
- return ps;
- }
-
- /**
- * 创建批量操作的{@link StatementWrapper}
- *
- * @param fields 字段列表,用于获取对应值
- * @param entities "?"对应参数批次列表
- * @return {@link StatementWrapper}
- * @throws DbRuntimeException SQL异常
- */
- public StatementWrapper buildForBatch(final Iterable fields, final Entity... entities) throws DbRuntimeException {
- Assert.notBlank(sql, "Sql String must be not blank!");
-
- sqlLog.logForBatch(sql);
-
- final StatementWrapper ps;
- try {
- ps = StatementWrapper.of(connection.prepareStatement(sql));
- final Map nullTypeMap = new HashMap<>();
- for (final Entity entity : entities) {
- ps.fillParams(MapUtil.valuesOfKeys(entity, fields), nullTypeMap);
+ for (final Object params : paramsBatch) {
+ if (null == params) {
+ continue;
+ }
+ if (ArrayUtil.isArray(params)) {
+ ps.fillParams(new ArrayIter<>(params), nullTypeMap);
+ } else if (params instanceof Entity) {
+ ps.fillParams(((Entity) params).values(), nullTypeMap);
+ }
ps.addBatch();
}
} catch (final SQLException e) {
@@ -170,12 +157,15 @@ public class StatementBuilder implements Builder {
/**
* 创建存储过程或函数调用的{@link StatementWrapper}
*
- * @return StatementWrapper
+ * @return StatementWrapper,{@code null}表示不执行
* @since 6.0.0
*/
public CallableStatement buildForCall() {
+ final String sql = this.boundSql.getSql();
+ final Object[] params = this.boundSql.getParamArray();
Assert.notBlank(sql, "Sql String must be not blank!");
- sqlLog.log(sql, ArrayUtil.isEmpty(params) ? null : params);
+
+ sqlFilter.filter(this.connection, this.boundSql, this.returnGeneratedKey);
try {
return (CallableStatement) StatementWrapper
@@ -190,20 +180,23 @@ public class StatementBuilder implements Builder {
/**
* 构建{@link StatementWrapper}
*
- * @return {@link StatementWrapper}
+ * @return {@link StatementWrapper},{@code null}表示不执行
* @throws SQLException SQL异常
*/
private StatementWrapper _build() throws SQLException {
+ String sql = this.boundSql.getSql();
+ Object[] params = this.boundSql.getParamArray();
Assert.notBlank(sql, "Sql String must be not blank!");
if (ArrayUtil.isNotEmpty(params) && 1 == params.length && params[0] instanceof Map) {
// 检查参数是否为命名方式的参数
- final NamedSql namedSql = new NamedSql(sql, Convert.toMap(String.class, Object.class, params[0]));
+ final NamedSql namedSql = new NamedSql(sql, Convert.toMap(String.class, Object.class, params[0]));
sql = namedSql.getSql();
params = namedSql.getParamArray();
}
- sqlLog.log(sql, ArrayUtil.isEmpty(params) ? null : params);
+ sqlFilter.filter(this.connection, this.boundSql, this.returnGeneratedKey);
+
final PreparedStatement ps;
if (returnGeneratedKey && StrUtil.startWithIgnoreCase(sql, "insert")) {
// 插入默认返回主键
diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/sql/filter/SqlFilter.java b/hutool-db/src/main/java/org/dromara/hutool/db/sql/filter/SqlFilter.java
new file mode 100644
index 000000000..5a06a5445
--- /dev/null
+++ b/hutool-db/src/main/java/org/dromara/hutool/db/sql/filter/SqlFilter.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2024. looly(loolly@aliyun.com)
+ * Hutool is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * https://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+
+package org.dromara.hutool.db.sql.filter;
+
+import org.dromara.hutool.db.sql.BoundSql;
+
+import java.sql.Connection;
+import java.util.List;
+
+/**
+ * SQL拦截器
+ */
+public interface SqlFilter {
+
+ /**
+ * 过滤
+ *
+ * @param conn {@link Connection}
+ * @param boundSql {@link BoundSql},包含SQL语句和参数,
+ * 可通过{@link BoundSql#setSql(String)}和{@link BoundSql#setParams(List)} 自定义SQL和参数
+ * @param returnGeneratedKey 是否自动生成主键
+ */
+ void filter(Connection conn, BoundSql boundSql, boolean returnGeneratedKey);
+}
diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/sql/filter/SqlLogFilter.java b/hutool-db/src/main/java/org/dromara/hutool/db/sql/filter/SqlLogFilter.java
new file mode 100644
index 000000000..53ec08480
--- /dev/null
+++ b/hutool-db/src/main/java/org/dromara/hutool/db/sql/filter/SqlLogFilter.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2024. looly(loolly@aliyun.com)
+ * Hutool is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * https://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+
+package org.dromara.hutool.db.sql.filter;
+
+import org.dromara.hutool.core.lang.Console;
+import org.dromara.hutool.db.sql.BoundSql;
+import org.dromara.hutool.db.sql.SqlLog;
+
+import java.sql.Connection;
+
+/**
+ * SQL打印拦截器
+ *
+ * @author Looly
+ */
+public class SqlLogFilter implements SqlFilter {
+
+ /**
+ * 单例
+ */
+ public static final SqlLogFilter INSTANCE = new SqlLogFilter();
+
+ private final SqlLog sqlLog;
+
+ /**
+ * 构造,使用默认SqlLog
+ */
+ public SqlLogFilter() {
+ this(SqlLog.INSTANCE);
+ }
+
+ /**
+ * 构造
+ *
+ * @param sqlLog {@link SqlLog}
+ */
+ public SqlLogFilter(final SqlLog sqlLog) {
+ this.sqlLog = sqlLog;
+ }
+
+ @Override
+ public void filter(final Connection conn, final BoundSql boundSql, final boolean returnGeneratedKey) {
+ sqlLog.log(boundSql.getSql(), boundSql.getParams());
+ }
+}
diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/sql/filter/package-info.java b/hutool-db/src/main/java/org/dromara/hutool/db/sql/filter/package-info.java
new file mode 100644
index 000000000..e1ee60e95
--- /dev/null
+++ b/hutool-db/src/main/java/org/dromara/hutool/db/sql/filter/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2024. looly(loolly@aliyun.com)
+ * Hutool is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * https://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+
+/**
+ * 提供SQL过滤器封装
+ *
+ * @author Looly
+ */
+package org.dromara.hutool.db.sql.filter;
From c60f30361e2090cd2155de7f8de1703fe96e4681 Mon Sep 17 00:00:00 2001
From: Looly
Date: Wed, 10 Jan 2024 11:57:38 +0800
Subject: [PATCH 20/26] fix code
---
.../hutool/db/dialect/impl/OracleDialect.java | 32 ++++++++++++++++---
1 file changed, 28 insertions(+), 4 deletions(-)
diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/OracleDialect.java b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/OracleDialect.java
index 06f822a46..de67b8612 100644
--- a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/OracleDialect.java
+++ b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/OracleDialect.java
@@ -12,6 +12,7 @@
package org.dromara.hutool.db.dialect.impl;
+import org.dromara.hutool.core.text.StrPool;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.db.Page;
import org.dromara.hutool.db.dialect.DialectName;
@@ -25,6 +26,10 @@ import org.dromara.hutool.db.sql.SqlBuilder;
public class OracleDialect extends AnsiSqlDialect {
private static final long serialVersionUID = 6122761762247483015L;
+ private static final String DEFAULT_TABLE_ALIAS = "table_alias_";
+ private static final String DEFAULT_ROW_ALIAS = "row_";
+ private static final String DEFAULT_ROWNUM_ALIAS = "rownum_";
+
/**
* 检查字段值是否为Oracle自增字段,自增字段以`.nextval`结尾
*
@@ -36,6 +41,9 @@ public class OracleDialect extends AnsiSqlDialect {
return (value instanceof CharSequence) && StrUtil.endWithIgnoreCase(value.toString(), ".nextval");
}
+ /**
+ * 构造
+ */
public OracleDialect() {
//Oracle所有字段名用双引号包围,防止字段名或表名与系统关键字冲突
//wrapper = new Wrapper('"');
@@ -44,11 +52,27 @@ public class OracleDialect extends AnsiSqlDialect {
@Override
protected SqlBuilder wrapPageSql(final SqlBuilder find, final Page page) {
final int[] startEnd = page.getStartEnd();
+
+ // 检查别名,避免重名
+ final String sql = find.toString();
+ String tableAlias = DEFAULT_TABLE_ALIAS;
+ while (sql.contains(tableAlias)) {
+ tableAlias += StrPool.UNDERLINE;
+ }
+ String rowAlias = DEFAULT_ROW_ALIAS;
+ while (sql.contains(rowAlias)) {
+ rowAlias += StrPool.UNDERLINE;
+ }
+ String rownumAlias = DEFAULT_ROWNUM_ALIAS;
+ while (sql.contains(rownumAlias)) {
+ rownumAlias += StrPool.UNDERLINE;
+ }
+
return find
- .insertPreFragment("SELECT * FROM ( SELECT row_.*, rownum rownum_ from ( ")
- .append(" ) row_ where rownum <= ").append(startEnd[1])//
- .append(") table_alias_")//
- .append(" where table_alias_.rownum_ > ").append(startEnd[0]);//
+ .insertPreFragment("SELECT * FROM ( SELECT " + rowAlias + ".*, rownum " + rownumAlias + " from ( ")
+ .append(" ) row_ where rownum <= ").append(startEnd[1])//
+ .append(") ").append(tableAlias)//
+ .append(" where ").append(tableAlias).append(".rownum_ > ").append(startEnd[0]);//
}
@Override
From 5345e4cc615a7760ddca583a2d9ff520d7d0d565 Mon Sep 17 00:00:00 2001
From: dazer007
Date: Wed, 10 Jan 2024 07:37:43 +0000
Subject: [PATCH 21/26] =?UTF-8?q?!1148=20hutool6.x=20StrUtil=E5=A2=9E?=
=?UTF-8?q?=E5=8A=A0=E6=8B=86=E5=88=86=E6=B3=A8=E9=87=8A=20*=20hutoolv6=20?=
=?UTF-8?q?=E5=AF=B9StrUtil=E6=8B=86=E5=88=86=E7=9A=84=E7=B1=BB=EF=BC=8C?=
=?UTF-8?q?=E8=BF=9B=E8=A1=8C=E6=B3=A8=E9=87=8A=EF=BC=8C=E8=BE=BE=E5=88=B0?=
=?UTF-8?q?=E4=BB=A3=E7=A0=81=E8=87=AA=E8=AF=B4=E6=98=8E=E7=9A=84=E7=9B=AE?=
=?UTF-8?q?=E7=9A=84=EF=BC=8C=E5=87=8F=E5=B0=91=E5=92=A8=E8=AF=A2=E9=87=8F?=
=?UTF-8?q?=E3=80=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../java/org/dromara/hutool/core/compress/ZipUtil.java | 3 ++-
.../main/java/org/dromara/hutool/core/text/StrUtil.java | 8 ++++++++
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/compress/ZipUtil.java b/hutool-core/src/main/java/org/dromara/hutool/core/compress/ZipUtil.java
index 1afb561c8..a947041ac 100644
--- a/hutool-core/src/main/java/org/dromara/hutool/core/compress/ZipUtil.java
+++ b/hutool-core/src/main/java/org/dromara/hutool/core/compress/ZipUtil.java
@@ -33,6 +33,7 @@ import org.dromara.hutool.core.util.ObjUtil;
import java.io.*;
import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystem;
import java.nio.file.*;
import java.util.ArrayList;
@@ -726,7 +727,7 @@ public class ZipUtil {
* Gzip压缩处理
*
* @param content 被压缩的字符串
- * @param charset 编码
+ * @param charset 编码 {@link StandardCharsets#UTF_8}、 {@link CharsetUtil#UTF_8}
* @return 压缩后的字节流
* @throws HutoolException IO异常
*/
diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/text/StrUtil.java b/hutool-core/src/main/java/org/dromara/hutool/core/text/StrUtil.java
index fb52e0b62..ebb26bae8 100644
--- a/hutool-core/src/main/java/org/dromara/hutool/core/text/StrUtil.java
+++ b/hutool-core/src/main/java/org/dromara/hutool/core/text/StrUtil.java
@@ -15,6 +15,7 @@ package org.dromara.hutool.core.text;
import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.func.FunctionPool;
import org.dromara.hutool.core.text.placeholder.StrFormatter;
+import org.dromara.hutool.core.text.split.SplitUtil;
import org.dromara.hutool.core.util.CharsetUtil;
import java.io.StringReader;
@@ -27,6 +28,13 @@ import java.util.Map;
* 字符串工具类
* 此工具主要针对单个字符串的操作
*
+ * 本工具类,v6.x进行了拆分。
+ * 字符串分割split参考:{@link SplitUtil}
+ * 多字符串判空hasBlank参考:{@link ArrayUtil}
+ *
+ * @see SplitUtil#split(CharSequence, CharSequence) 对字符串分割
+ * @see ArrayUtil#hasBlank(CharSequence...) 对多个字符串判空
+ *
* @author Looly
*/
public class StrUtil extends CharSequenceUtil implements StrPool {
From 037d53794d30f8171e429b8567b867d7bab7ad61 Mon Sep 17 00:00:00 2001
From: Looly
Date: Wed, 10 Jan 2024 16:43:48 +0800
Subject: [PATCH 22/26] fix code
---
.../hutool/db/dialect/impl/AnsiSqlDialect.java | 5 ++---
.../hutool/db/dialect/impl/PhoenixDialect.java | 3 +++
.../db/dialect/impl/SqlServer2012Dialect.java | 16 +++++++++-------
.../hutool/db/dialect/impl/Sqlite3Dialect.java | 7 +++++--
.../dromara/hutool/db/sql/StatementBuilder.java | 12 +++++++++++-
5 files changed, 30 insertions(+), 13 deletions(-)
diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/AnsiSqlDialect.java b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/AnsiSqlDialect.java
index 567307a31..64bb94fe2 100644
--- a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/AnsiSqlDialect.java
+++ b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/AnsiSqlDialect.java
@@ -66,7 +66,6 @@ public class AnsiSqlDialect implements Dialect {
}
// 批量,根据第一行数据结构生成SQL占位符
final SqlBuilder insert = SqlBuilder.of(quoteWrapper).insert(entities[0], this.dialectName());
- final Set fields = CollUtil.remove(entities[0].keySet(), StrUtil::isBlank);
return StatementUtil.prepareStatementForBatch(conn, insert.build(), entities);
}
@@ -100,12 +99,12 @@ public class AnsiSqlDialect implements Dialect {
}
@Override
- public PreparedStatement psForFind(final Connection conn, final Query query) throws SQLException {
+ public PreparedStatement psForFind(final Connection conn, final Query query) {
return psForPage(conn, query);
}
@Override
- public PreparedStatement psForPage(final Connection conn, final Query query) throws SQLException {
+ public PreparedStatement psForPage(final Connection conn, final Query query) {
Assert.notNull(query, "query must be not null !");
if (ArrayUtil.hasBlank(query.getTableNames())) {
throw new DbRuntimeException("Table name must be not empty !");
diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/PhoenixDialect.java b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/PhoenixDialect.java
index ebfa95146..0d9966ab0 100644
--- a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/PhoenixDialect.java
+++ b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/PhoenixDialect.java
@@ -29,6 +29,9 @@ import java.sql.SQLException;
public class PhoenixDialect extends AnsiSqlDialect {
private static final long serialVersionUID = 1L;
+ /**
+ * 构造
+ */
public PhoenixDialect() {
// wrapper = new Wrapper('"');
}
diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/SqlServer2012Dialect.java b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/SqlServer2012Dialect.java
index fd98c9ebf..b879b0195 100644
--- a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/SqlServer2012Dialect.java
+++ b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/SqlServer2012Dialect.java
@@ -21,15 +21,17 @@ import org.dromara.hutool.db.sql.QuoteWrapper;
/**
* SQLServer2012 方言
*
- * @author loolly
- *
+ * @author Looly
*/
public class SqlServer2012Dialect extends AnsiSqlDialect {
private static final long serialVersionUID = -37598166015777797L;
+ /**
+ * 构造
+ */
public SqlServer2012Dialect() {
//双引号和中括号适用,双引号更广泛
- quoteWrapper = new QuoteWrapper('"');
+ quoteWrapper = new QuoteWrapper('"');
}
@Override
@@ -39,10 +41,10 @@ public class SqlServer2012Dialect extends AnsiSqlDialect {
find.append(" order by current_timestamp");
}
return find.append(" offset ")
- .append(page.getStartPosition())//
- .append(" row fetch next ")//row和rows同义词
- .append(page.getPageSize())//
- .append(" row only");//
+ .append(page.getStartPosition())//
+ .append(" row fetch next ")//row和rows同义词
+ .append(page.getPageSize())//
+ .append(" row only");//
}
@Override
diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/Sqlite3Dialect.java b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/Sqlite3Dialect.java
index d8209e501..fc9217b2f 100644
--- a/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/Sqlite3Dialect.java
+++ b/hutool-db/src/main/java/org/dromara/hutool/db/dialect/impl/Sqlite3Dialect.java
@@ -17,12 +17,15 @@ import org.dromara.hutool.db.sql.QuoteWrapper;
/**
* SqlLite3方言
- * @author loolly
*
+ * @author Looly
*/
-public class Sqlite3Dialect extends AnsiSqlDialect{
+public class Sqlite3Dialect extends AnsiSqlDialect {
private static final long serialVersionUID = -3527642408849291634L;
+ /**
+ * 构造
+ */
public Sqlite3Dialect() {
quoteWrapper = new QuoteWrapper('[', ']');
}
diff --git a/hutool-db/src/main/java/org/dromara/hutool/db/sql/StatementBuilder.java b/hutool-db/src/main/java/org/dromara/hutool/db/sql/StatementBuilder.java
index c60aa6d8d..91d6d0845 100644
--- a/hutool-db/src/main/java/org/dromara/hutool/db/sql/StatementBuilder.java
+++ b/hutool-db/src/main/java/org/dromara/hutool/db/sql/StatementBuilder.java
@@ -18,6 +18,7 @@ import org.dromara.hutool.core.collection.iter.ArrayIter;
import org.dromara.hutool.core.convert.Convert;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.lang.builder.Builder;
+import org.dromara.hutool.core.map.MapUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.db.DbRuntimeException;
import org.dromara.hutool.db.Entity;
@@ -27,6 +28,7 @@ import java.sql.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* {@link PreparedStatement}构建器,构建结果为{@link StatementWrapper}
@@ -137,6 +139,7 @@ public class StatementBuilder implements Builder {
try {
ps = StatementWrapper.of(connection.prepareStatement(sql));
final Map nullTypeMap = new HashMap<>();
+ Set keys = null;
for (final Object params : paramsBatch) {
if (null == params) {
continue;
@@ -144,7 +147,14 @@ public class StatementBuilder implements Builder {
if (ArrayUtil.isArray(params)) {
ps.fillParams(new ArrayIter<>(params), nullTypeMap);
} else if (params instanceof Entity) {
- ps.fillParams(((Entity) params).values(), nullTypeMap);
+ final Entity entity = (Entity) params;
+ // 对于多Entity批量插入的情况,为防止数据不对齐,故按照首行提供键值对筛选。
+ if(null == keys){
+ keys = entity.keySet();
+ ps.fillParams(entity.values(), nullTypeMap);
+ } else{
+ ps.fillParams(MapUtil.valuesOfKeys(entity, keys), nullTypeMap);
+ }
}
ps.addBatch();
}
From f341b9ed7a83a54e2a08d4635540ab0a8b159c4f Mon Sep 17 00:00:00 2001
From: Looly
Date: Thu, 11 Jan 2024 12:08:46 +0800
Subject: [PATCH 23/26] =?UTF-8?q?=E4=BF=AE=E5=A4=8DNumberUtil.toBigDecimal?=
=?UTF-8?q?=E6=96=B9=E6=B3=95=E6=8A=A5StackOverflowError(CVE-2023-51080)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../hutool/core/math/NumberParser.java | 1 +
.../dromara/hutool/core/math/NumberUtil.java | 6 ++--
.../hutool/core/math/Issue3423Test.java | 28 +++++++++++++++++++
.../org/dromara/hutool/cron/CronConfig.java | 3 ++
hutool-db/README.md | 2 +-
5 files changed, 36 insertions(+), 4 deletions(-)
create mode 100644 hutool-core/src/test/java/org/dromara/hutool/core/math/Issue3423Test.java
diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/math/NumberParser.java b/hutool-core/src/main/java/org/dromara/hutool/core/math/NumberParser.java
index 9038c4685..3c8779b23 100644
--- a/hutool-core/src/main/java/org/dromara/hutool/core/math/NumberParser.java
+++ b/hutool-core/src/main/java/org/dromara/hutool/core/math/NumberParser.java
@@ -297,6 +297,7 @@ public class NumberParser {
// issue#I79VS7
numberStr = StrUtil.subSuf(numberStr, 1);
}
+
try {
final NumberFormat format = NumberFormat.getInstance(locale);
if (format instanceof DecimalFormat) {
diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/math/NumberUtil.java b/hutool-core/src/main/java/org/dromara/hutool/core/math/NumberUtil.java
index e81fd333e..561a86959 100644
--- a/hutool-core/src/main/java/org/dromara/hutool/core/math/NumberUtil.java
+++ b/hutool-core/src/main/java/org/dromara/hutool/core/math/NumberUtil.java
@@ -898,12 +898,12 @@ public class NumberUtil extends NumberValidator {
}
// Float、Double等有精度问题,转换为字符串后再转换
- return toBigDecimal(number.toString());
+ return new BigDecimal(number.toString());
}
/**
* 数字转{@link BigDecimal}
- * null或""或空白符转换为0
+ * null或""或"NaN"或空白符转换为0
*
* @param numberStr 数字字符串
* @return {@link BigDecimal}
@@ -927,7 +927,7 @@ public class NumberUtil extends NumberValidator {
/**
* 数字转{@link BigInteger}
- * null转换为0
+ * null或"NaN"转换为0
*
* @param number 数字
* @return {@link BigInteger}
diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/math/Issue3423Test.java b/hutool-core/src/test/java/org/dromara/hutool/core/math/Issue3423Test.java
new file mode 100644
index 000000000..9579a300f
--- /dev/null
+++ b/hutool-core/src/test/java/org/dromara/hutool/core/math/Issue3423Test.java
@@ -0,0 +1,28 @@
+package org.dromara.hutool.core.math;
+
+import org.dromara.hutool.core.lang.Console;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.text.ParseException;
+
+public class Issue3423Test {
+ @Test
+ public void toBigDecimalOfNaNTest() {
+ final BigDecimal naN = NumberUtil.toBigDecimal("NaN");
+ Assertions.assertEquals(BigDecimal.ZERO, naN);
+ }
+
+ @Test
+ @Disabled
+ public void toBigDecimalOfNaNTest2() throws ParseException {
+ final NumberFormat format = NumberFormat.getInstance();
+ ((DecimalFormat) format).setParseBigDecimal(true);
+ final Number naN = format.parse("NaN");
+ Console.log(naN.getClass());
+ }
+}
diff --git a/hutool-cron/src/main/java/org/dromara/hutool/cron/CronConfig.java b/hutool-cron/src/main/java/org/dromara/hutool/cron/CronConfig.java
index 47fbe1a6b..1df148ebf 100644
--- a/hutool-cron/src/main/java/org/dromara/hutool/cron/CronConfig.java
+++ b/hutool-cron/src/main/java/org/dromara/hutool/cron/CronConfig.java
@@ -31,6 +31,9 @@ public class CronConfig {
*/
protected boolean matchSecond;
+ /**
+ * 构造
+ */
public CronConfig(){
}
diff --git a/hutool-db/README.md b/hutool-db/README.md
index 603876838..97d7fd3bb 100644
--- a/hutool-db/README.md
+++ b/hutool-db/README.md
@@ -28,7 +28,7 @@
### SQL相关工具(sql)
提供SQL相关功能,包括SQL变量替换(NamedSql),通过对象完成SQL构建(SqlBuilder)等。
-`SqlSqlExecutor`提供SQL执行的静态方法。
+`SqlExecutor`提供SQL执行的静态方法。
### 数据库元信息(meta)
通过`MetaUtil`提供数据库表、字段等信息的读取操作。
From fe2516b646940560975e63eae8788c6e5f070728 Mon Sep 17 00:00:00 2001
From: Looly
Date: Thu, 11 Jan 2024 13:31:10 +0800
Subject: [PATCH 24/26] fix cron
---
.../main/java/org/dromara/hutool/cron/CronTimer.java | 10 ++++++++--
hutool-cron/src/test/resources/config/cron.setting | 2 +-
hutool-db/pom.xml | 2 +-
hutool-extra/pom.xml | 8 ++++----
hutool-log/pom.xml | 4 ++--
5 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/hutool-cron/src/main/java/org/dromara/hutool/cron/CronTimer.java b/hutool-cron/src/main/java/org/dromara/hutool/cron/CronTimer.java
index 085f01818..3ad60d746 100644
--- a/hutool-cron/src/main/java/org/dromara/hutool/cron/CronTimer.java
+++ b/hutool-cron/src/main/java/org/dromara/hutool/cron/CronTimer.java
@@ -13,6 +13,7 @@
package org.dromara.hutool.cron;
import org.dromara.hutool.core.date.DateUnit;
+import org.dromara.hutool.core.lang.Console;
import org.dromara.hutool.core.thread.ThreadUtil;
import org.dromara.hutool.log.Log;
@@ -63,9 +64,14 @@ public class CronTimer extends Thread implements Serializable {
//等待直到下一个时间点,如果被中断直接退出Timer
break;
}
+
//执行点,时间记录为执行开始的时间,而非结束时间
- thisTime = System.currentTimeMillis();
- spawnLauncher(thisTime);
+ spawnLauncher(nextTime);
+
+ // issue#3460 采用叠加方式,确保正好是1分钟或1秒,避免sleep晚醒问题
+ // 此处无需校验,因为每次循环都是sleep与上触发点的时间差。
+ // 当上一次晚醒后,本次会减少sleep时间,保证误差在一个unit内,并不断修正。
+ thisTime = nextTime;
} else{
// 非正常时间重新计算(issue#1224@Github)
thisTime = System.currentTimeMillis();
diff --git a/hutool-cron/src/test/resources/config/cron.setting b/hutool-cron/src/test/resources/config/cron.setting
index 4e2860de9..62faca9fc 100644
--- a/hutool-cron/src/test/resources/config/cron.setting
+++ b/hutool-cron/src/test/resources/config/cron.setting
@@ -8,7 +8,7 @@
# demo.org.dromara.hutool.cron.TestJob.doTest = */1 * * * * *
-[org.dromara.hutool.cron.demo]=
+[org.dromara.hutool.cron.demo]
# 6位表达式在秒匹配模式下可用,此处表示每秒执行一次
# TestJob.doTest = */1 * * * * *
# 5位表达式在分匹配模式下可用,此处表示每分钟执行一次
diff --git a/hutool-db/pom.xml b/hutool-db/pom.xml
index bab350310..188744420 100755
--- a/hutool-db/pom.xml
+++ b/hutool-db/pom.xml
@@ -38,7 +38,7 @@
1.2.21
4.0.3
- 3.43.0.0
+ 3.44.1.0
2.5.2
diff --git a/hutool-extra/pom.xml b/hutool-extra/pom.xml
index 1ef2aec1b..0febf0c07 100755
--- a/hutool-extra/pom.xml
+++ b/hutool-extra/pom.xml
@@ -32,7 +32,7 @@
org.dromara.hutool.extra
2.3
- 3.15.8.RELEASE
+ 3.15.12.RELEASE
1.4.2
2.3.32
5.1.3
@@ -415,7 +415,7 @@
com.rnkrsoft.bopomofo4j
bopomofo4j
- 1.0.0
+ 1.0.1
true
@@ -496,7 +496,7 @@
org.apache.commons
commons-compress
- 1.24.0
+ 1.25.0
compile
true
@@ -504,7 +504,7 @@
com.github.oshi
oshi-core
- 6.4.5
+ 6.4.10
provided
diff --git a/hutool-log/pom.xml b/hutool-log/pom.xml
index db948322f..4a93b8e20 100755
--- a/hutool-log/pom.xml
+++ b/hutool-log/pom.xml
@@ -32,10 +32,10 @@
org.dromara.hutool.log
2.0.9
- 1.4.13
+ 1.4.14
1.2.17
2.20.0
- 1.2
+ 1.3.0
1.3.6
2.6.2
From 71fc0173f08a62365670be80536a9158c2c06dd7 Mon Sep 17 00:00:00 2001
From: Looly
Date: Thu, 11 Jan 2024 13:52:52 +0800
Subject: [PATCH 25/26] fix test
---
.../test/java/org/dromara/hutool/cron/demo/DeamonMainTest.java | 2 +-
.../src/test/java/org/dromara/hutool/cron/demo/TestJob2.java | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/hutool-cron/src/test/java/org/dromara/hutool/cron/demo/DeamonMainTest.java b/hutool-cron/src/test/java/org/dromara/hutool/cron/demo/DeamonMainTest.java
index c7f982aff..40188baed 100644
--- a/hutool-cron/src/test/java/org/dromara/hutool/cron/demo/DeamonMainTest.java
+++ b/hutool-cron/src/test/java/org/dromara/hutool/cron/demo/DeamonMainTest.java
@@ -19,7 +19,7 @@ import org.dromara.hutool.cron.task.InvokeTask;
public class DeamonMainTest {
public static void main(final String[] args) {
// 测试守护线程是否对作业线程有效
- CronUtil.schedule("*/2 * * * * *", new InvokeTask("demo.org.dromara.hutool.cron.TestJob.doWhileTest"));
+ CronUtil.schedule("*/2 * * * * *", new InvokeTask("org.dromara.hutool.cron.demo.TestJob.doWhileTest"));
// 当为守护线程时,stop方法调用后doWhileTest里的循环输出将终止,表示作业线程正常结束
// 当非守护线程时,stop方法调用后,不再产生新的作业,原作业正常执行。
CronUtil.setMatchSecond(true);
diff --git a/hutool-cron/src/test/java/org/dromara/hutool/cron/demo/TestJob2.java b/hutool-cron/src/test/java/org/dromara/hutool/cron/demo/TestJob2.java
index 00a7e20d7..b3baf4197 100644
--- a/hutool-cron/src/test/java/org/dromara/hutool/cron/demo/TestJob2.java
+++ b/hutool-cron/src/test/java/org/dromara/hutool/cron/demo/TestJob2.java
@@ -14,6 +14,7 @@ package org.dromara.hutool.cron.demo;
import java.util.concurrent.TimeUnit;
+import org.dromara.hutool.core.date.DateUtil;
import org.dromara.hutool.core.lang.Console;
import org.dromara.hutool.core.thread.ThreadUtil;
@@ -29,7 +30,7 @@ public class TestJob2 {
* 执行定时任务内容
*/
public void doTest() {
- Console.log("TestJob2.doTest开始执行……");
+ Console.log("TestJob2.doTest开始执行…… at [{}]", DateUtil.formatNow());
ThreadUtil.sleep(20, TimeUnit.SECONDS);
Console.log("延迟20s打印testJob2");
}
From 6a3aece4dedfd3b0228300b9167d80aff7dd9e08 Mon Sep 17 00:00:00 2001
From: Looly
Date: Thu, 11 Jan 2024 14:24:15 +0800
Subject: [PATCH 26/26] prepare M11
---
CHANGELOG.md | 2 +-
README-EN.md | 6 +++---
README.md | 6 +++---
bin/version.txt | 2 +-
docs/js/version.js | 2 +-
hutool-all/pom.xml | 2 +-
hutool-bom/pom.xml | 2 +-
hutool-core/pom.xml | 2 +-
hutool-cron/pom.xml | 2 +-
hutool-crypto/pom.xml | 2 +-
hutool-db/pom.xml | 2 +-
hutool-extra/pom.xml | 2 +-
hutool-http/pom.xml | 2 +-
hutool-json/pom.xml | 2 +-
hutool-log/pom.xml | 2 +-
hutool-poi/pom.xml | 2 +-
hutool-setting/pom.xml | 2 +-
hutool-socket/pom.xml | 2 +-
hutool-swing/pom.xml | 2 +-
pom.xml | 2 +-
20 files changed, 24 insertions(+), 24 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6afff4a3c..9a6601673 100755
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,7 +3,7 @@
-------------------------------------------------------------------------------------------------------------
-# 6.0.0-M10 (2023-12-28)
+# 6.0.0-M11 (2024-01-11)
### 计划实现
* 【poi 】 Markdown相关(如HTML转换等),基于commonmark-java
diff --git a/README-EN.md b/README-EN.md
index c71a5d51f..20a0901ae 100755
--- a/README-EN.md
+++ b/README-EN.md
@@ -144,18 +144,18 @@ We provide the T-Shirt and Sweater with Hutool Logo, please visit the shop:
org.dromara.hutool
hutool-all
- 6.0.0-M10
+ 6.0.0-M11
```
### 🍐Gradle
```
-implementation 'org.dromara.hutool:hutool-all:6.0.0-M10'
+implementation 'org.dromara.hutool:hutool-all:6.0.0-M11'
```
## 📥Download
-- [Maven Repo](https://repo1.maven.org/maven2/cn/hutool/hutool-all/6.0.0-M10/)
+- [Maven Repo](https://repo1.maven.org/maven2/cn/hutool/hutool-all/6.0.0-M11/)
> 🔔️note:
> Hutool 5.x supports JDK8+ and is not tested on Android platforms, and cannot guarantee that all tool classes or tool methods are available.
diff --git a/README.md b/README.md
index b2cc82c74..f65dccc66 100755
--- a/README.md
+++ b/README.md
@@ -139,21 +139,21 @@
org.dromara.hutool
hutool-all
- 6.0.0-M10
+ 6.0.0-M11
```
### 🍐Gradle
```
-implementation 'org.dromara.hutool:hutool-all:6.0.0-M10'
+implementation 'org.dromara.hutool:hutool-all:6.0.0-M11'
```
### 📥下载jar
点击以下链接,下载`hutool-all-X.X.X.jar`即可:
-- [Maven中央库](https://repo1.maven.org/maven2/org/dromara/hutool/hutool-all/6.0.0-M10/)
+- [Maven中央库](https://repo1.maven.org/maven2/org/dromara/hutool/hutool-all/6.0.0-M11/)
> 🔔️注意
> Hutool 6.x支持JDK8+,对Android平台没有测试,不能保证所有工具类或工具方法可用。
diff --git a/bin/version.txt b/bin/version.txt
index 76f9249ad..bdfaba25f 100644
--- a/bin/version.txt
+++ b/bin/version.txt
@@ -1 +1 @@
-6.0.0-M10
+6.0.0-M11
diff --git a/docs/js/version.js b/docs/js/version.js
index 2221a2e15..afee3da9a 100755
--- a/docs/js/version.js
+++ b/docs/js/version.js
@@ -1 +1 @@
-var version = '6.0.0-M10'
\ No newline at end of file
+var version = '6.0.0-M11'
\ No newline at end of file
diff --git a/hutool-all/pom.xml b/hutool-all/pom.xml
index d7a896e56..1317ca64f 100755
--- a/hutool-all/pom.xml
+++ b/hutool-all/pom.xml
@@ -21,7 +21,7 @@
org.dromara.hutool
hutool-parent
- 6.0.0-M10
+ 6.0.0-M11
hutool-all
diff --git a/hutool-bom/pom.xml b/hutool-bom/pom.xml
index 231002101..411a1ff45 100755
--- a/hutool-bom/pom.xml
+++ b/hutool-bom/pom.xml
@@ -21,7 +21,7 @@
org.dromara.hutool
hutool-parent
- 6.0.0-M10
+ 6.0.0-M11
hutool-bom
diff --git a/hutool-core/pom.xml b/hutool-core/pom.xml
index f83eb80fb..8c247ce36 100755
--- a/hutool-core/pom.xml
+++ b/hutool-core/pom.xml
@@ -21,7 +21,7 @@
org.dromara.hutool
hutool-parent
- 6.0.0-M10
+ 6.0.0-M11
hutool-core
diff --git a/hutool-cron/pom.xml b/hutool-cron/pom.xml
index d7a4bd4f7..4c4f7350a 100755
--- a/hutool-cron/pom.xml
+++ b/hutool-cron/pom.xml
@@ -21,7 +21,7 @@
org.dromara.hutool
hutool-parent
- 6.0.0-M10
+ 6.0.0-M11
hutool-cron
diff --git a/hutool-crypto/pom.xml b/hutool-crypto/pom.xml
index 0e84aaa11..e82c73ae0 100755
--- a/hutool-crypto/pom.xml
+++ b/hutool-crypto/pom.xml
@@ -21,7 +21,7 @@
org.dromara.hutool
hutool-parent
- 6.0.0-M10
+ 6.0.0-M11
hutool-crypto
diff --git a/hutool-db/pom.xml b/hutool-db/pom.xml
index 188744420..36cfd6d7a 100755
--- a/hutool-db/pom.xml
+++ b/hutool-db/pom.xml
@@ -21,7 +21,7 @@
org.dromara.hutool
hutool-parent
- 6.0.0-M10
+ 6.0.0-M11
hutool-db
diff --git a/hutool-extra/pom.xml b/hutool-extra/pom.xml
index 0febf0c07..37b93a30a 100755
--- a/hutool-extra/pom.xml
+++ b/hutool-extra/pom.xml
@@ -21,7 +21,7 @@
org.dromara.hutool
hutool-parent
- 6.0.0-M10
+ 6.0.0-M11
hutool-extra
diff --git a/hutool-http/pom.xml b/hutool-http/pom.xml
index 1955090ce..41686d9f7 100755
--- a/hutool-http/pom.xml
+++ b/hutool-http/pom.xml
@@ -21,7 +21,7 @@
org.dromara.hutool
hutool-parent
- 6.0.0-M10
+ 6.0.0-M11
hutool-http
diff --git a/hutool-json/pom.xml b/hutool-json/pom.xml
index 3400bafb4..dbbedfa36 100755
--- a/hutool-json/pom.xml
+++ b/hutool-json/pom.xml
@@ -21,7 +21,7 @@
org.dromara.hutool
hutool-parent
- 6.0.0-M10
+ 6.0.0-M11
hutool-json
diff --git a/hutool-log/pom.xml b/hutool-log/pom.xml
index 4a93b8e20..f27b2477c 100755
--- a/hutool-log/pom.xml
+++ b/hutool-log/pom.xml
@@ -21,7 +21,7 @@
org.dromara.hutool
hutool-parent
- 6.0.0-M10
+ 6.0.0-M11
hutool-log
diff --git a/hutool-poi/pom.xml b/hutool-poi/pom.xml
index e5a712ce9..5448ddeeb 100755
--- a/hutool-poi/pom.xml
+++ b/hutool-poi/pom.xml
@@ -21,7 +21,7 @@
org.dromara.hutool
hutool-parent
- 6.0.0-M10
+ 6.0.0-M11
hutool-poi
diff --git a/hutool-setting/pom.xml b/hutool-setting/pom.xml
index 613367242..da628335f 100755
--- a/hutool-setting/pom.xml
+++ b/hutool-setting/pom.xml
@@ -21,7 +21,7 @@
org.dromara.hutool
hutool-parent
- 6.0.0-M10
+ 6.0.0-M11
hutool-setting
diff --git a/hutool-socket/pom.xml b/hutool-socket/pom.xml
index c259cf477..d6e763c4f 100755
--- a/hutool-socket/pom.xml
+++ b/hutool-socket/pom.xml
@@ -21,7 +21,7 @@
org.dromara.hutool
hutool-parent
- 6.0.0-M10
+ 6.0.0-M11
hutool-socket
diff --git a/hutool-swing/pom.xml b/hutool-swing/pom.xml
index 185754e1c..e0e0783d9 100755
--- a/hutool-swing/pom.xml
+++ b/hutool-swing/pom.xml
@@ -21,7 +21,7 @@
org.dromara.hutool
hutool-parent
- 6.0.0-M10
+ 6.0.0-M11
hutool-swing
diff --git a/pom.xml b/pom.xml
index 6666b0cb9..8c8c95408 100755
--- a/pom.xml
+++ b/pom.xml
@@ -20,7 +20,7 @@
org.dromara.hutool
hutool-parent
- 6.0.0-M10
+ 6.0.0-M11
hutool
Hutool是一个功能丰富且易用的Java工具库,通过诸多实用工具类的使用,旨在帮助开发者快速、便捷地完成各类开发任务。这些封装的工具涵盖了字符串、数字、集合、编码、日期、文件、IO、加密、数据库JDBC、JSON、HTTP客户端等一系列操作,可以满足各种不同的开发需求。