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

This commit is contained in:
achao 2021-12-09 20:15:58 +08:00
commit 43b33c81e3
41 changed files with 410 additions and 202 deletions

View File

@ -3,7 +3,13 @@
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------
# 5.7.17 (2021-12-06) # 5.7.18 (2021-12-09)
### 🐣新特性
### 🐞Bug修复
-------------------------------------------------------------------------------------------------------------
# 5.7.17 (2021-12-09)
### 🐣新特性 ### 🐣新特性
* 【core 】 增加AsyncUtilpr#457@Gitee * 【core 】 增加AsyncUtilpr#457@Gitee
@ -33,6 +39,10 @@
* 【core 】 NumberUtil增加isOdd、isEven方法pr#474@Gitee * 【core 】 NumberUtil增加isOdd、isEven方法pr#474@Gitee
* 【http 】 增加HttpGlobalConfig.setBoundary删除MultipartBody.BOUNDARY和getContentTypeissue#I4KSLY@Gitee * 【http 】 增加HttpGlobalConfig.setBoundary删除MultipartBody.BOUNDARY和getContentTypeissue#I4KSLY@Gitee
* 【core 】 DateTime增加setMinimalDaysInFirstWeekissue#1988@Github * 【core 】 DateTime增加setMinimalDaysInFirstWeekissue#1988@Github
* 【db 】 Db增加query重载可支持自定义PreparedStatement从而支持游标issue#I4JXWN@Gitee
* 【cache 】 CacheObj增加getExpiredTime等方法issue#I4LE80@Gitee
* 【extra 】 Ftp增加backToPwd方法issue#2004@Github
* 【core 】 CollStreamUtil修改集合中null处理问题pr#478@Gitee
* *
### 🐞Bug修复 ### 🐞Bug修复
* 【core 】 修复FileResource构造fileName参数无效问题issue#1942@Github * 【core 】 修复FileResource构造fileName参数无效问题issue#1942@Github
@ -43,10 +53,12 @@
* 【poi 】 修复SoapClient参数未使用问题 * 【poi 】 修复SoapClient参数未使用问题
* 【core 】 修复HashUtil.cityHash128参数未使用问题 * 【core 】 修复HashUtil.cityHash128参数未使用问题
* 【core 】 修复DateUtil.formatChineseDate显示问题issue#I4KK5F@Gitee * 【core 】 修复DateUtil.formatChineseDate显示问题issue#I4KK5F@Gitee
* 【poi 】 修复CellUtil.setCellValuestyle空导致值无法写入问题issue#1995@Github * 【poi 】 修复CellUtil.setCellValueStyle空导致值无法写入问题issue#1995@Github
* 【poi 】 修复CellUtil.setComment参数设置错误问题 * 【poi 】 修复CellUtil.setComment参数设置错误问题
* 【core 】 修复QueryBuilder解析路径导致的错误issue#1989@Github * 【core 】 修复QueryBuilder解析路径导致的错误issue#1989@Github
* 【core 】 修复DateTime.between中DateUnit无效问题 * 【core 】 修复DateTime.between中DateUnit无效问题
* 【poi 】 修复StyleUtil.getFormat非static问题issue#I4LGNP@Gitee
* 【crypto 】 修复SM2.getD返回bytes包含符号位的问题issue#2001@Github
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------

View File

@ -142,18 +142,18 @@ We provide the T-Shirt and Sweater with Hutool Logo, please visit the shop
<dependency> <dependency>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId> <artifactId>hutool-all</artifactId>
<version>5.7.17</version> <version>5.7.18</version>
</dependency> </dependency>
``` ```
### 🍐Gradle ### 🍐Gradle
``` ```
implementation 'cn.hutool:hutool-all:5.7.17' implementation 'cn.hutool:hutool-all:5.7.18'
``` ```
## 📥Download ## 📥Download
- [Maven Repo](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.7.17/) - [Maven Repo](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.7.18/)
> 🔔note: > 🔔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. > Hutool 5.x supports JDK8+ and is not tested on Android platforms, and cannot guarantee that all tool classes or tool methods are available.

View File

@ -142,20 +142,20 @@ Hutool的存在就是为了减少代码搜索成本避免网络上参差不
<dependency> <dependency>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId> <artifactId>hutool-all</artifactId>
<version>5.7.17</version> <version>5.7.18</version>
</dependency> </dependency>
``` ```
### 🍐Gradle ### 🍐Gradle
``` ```
implementation 'cn.hutool:hutool-all:5.7.17' implementation 'cn.hutool:hutool-all:5.7.18'
``` ```
### 📥下载jar ### 📥下载jar
点击以下链接,下载`hutool-all-X.X.X.jar`即可: 点击以下链接,下载`hutool-all-X.X.X.jar`即可:
- [Maven中央库](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.7.17/) - [Maven中央库](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.7.18/)
> 🔔️注意 > 🔔️注意
> Hutool 5.x支持JDK8+对Android平台没有测试不能保证所有工具类或工具方法可用。 > Hutool 5.x支持JDK8+对Android平台没有测试不能保证所有工具类或工具方法可用。

View File

@ -1 +1 @@
5.7.17 5.7.18

View File

@ -1 +1 @@
var version = '5.7.17' var version = '5.7.18'

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version> <version>5.7.18-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-all</artifactId> <artifactId>hutool-all</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version> <version>5.7.18-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-aop</artifactId> <artifactId>hutool-aop</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version> <version>5.7.18-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-bloomFilter</artifactId> <artifactId>hutool-bloomFilter</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version> <version>5.7.18-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-bom</artifactId> <artifactId>hutool-bom</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version> <version>5.7.18-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-cache</artifactId> <artifactId>hutool-cache</artifactId>

View File

@ -1,26 +1,35 @@
package cn.hutool.cache.impl; package cn.hutool.cache.impl;
import cn.hutool.core.date.DateUtil;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
/** /**
* 缓存对象 * 缓存对象
* @author Looly
* *
* @param <K> Key类型 * @param <K> Key类型
* @param <V> Value类型 * @param <V> Value类型
* @author Looly
*/ */
public class CacheObj<K, V> implements Serializable{ public class CacheObj<K, V> implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
protected final K key; protected final K key;
protected final V obj; protected final V obj;
/** 上次访问时间 */ /**
* 上次访问时间
*/
protected volatile long lastAccess; protected volatile long lastAccess;
/** 访问次数 */ /**
* 访问次数
*/
protected AtomicLong accessCount = new AtomicLong(); protected AtomicLong accessCount = new AtomicLong();
/** 对象存活时长0表示永久存活*/ /**
* 对象存活时长0表示永久存活
*/
protected final long ttl; protected final long ttl;
/** /**
@ -39,6 +48,7 @@ public class CacheObj<K, V> implements Serializable{
/** /**
* 获取键 * 获取键
*
* @return * @return
* @since 4.0.10 * @since 4.0.10
*/ */
@ -48,6 +58,7 @@ public class CacheObj<K, V> implements Serializable{
/** /**
* 获取值 * 获取值
*
* @return * @return
* @since 4.0.10 * @since 4.0.10
*/ */
@ -55,6 +66,39 @@ public class CacheObj<K, V> implements Serializable{
return this.obj; return this.obj;
} }
/**
* 获取对象存活时长即超时总时长0表示无限
*
* @return 对象存活时长
* @since 5.7.17
*/
public long getTtl() {
return this.ttl;
}
/**
* 获取过期时间返回{@code null}表示永不过期
*
* @return 此对象的过期时间返回{@code null}表示永不过期
* @since 5.7.17
*/
public Date getExpiredTime(){
if(this.ttl > 0){
return DateUtil.date(this.lastAccess + this.ttl);
}
return null;
}
/**
* 获取上次访问时间
*
* @return 上次访问时间
* @since 5.7.17
*/
public long getLastAccess() {
return this.lastAccess;
}
@Override @Override
public String toString() { public String toString() {
return "CacheObj [key=" + key + ", obj=" + obj + ", lastAccess=" + lastAccess + ", accessCount=" + accessCount + ", ttl=" + ttl + "]"; return "CacheObj [key=" + key + ", obj=" + obj + ", lastAccess=" + lastAccess + ", accessCount=" + accessCount + ", ttl=" + ttl + "]";
@ -66,7 +110,7 @@ public class CacheObj<K, V> implements Serializable{
* @return 是否过期 * @return 是否过期
*/ */
protected boolean isExpired() { protected boolean isExpired() {
if(this.ttl > 0) { if (this.ttl > 0) {
// 此处不考虑时间回拨 // 此处不考虑时间回拨
return (System.currentTimeMillis() - this.lastAccess) > this.ttl; return (System.currentTimeMillis() - this.lastAccess) > this.ttl;
} }
@ -81,7 +125,7 @@ public class CacheObj<K, V> implements Serializable{
* @since 4.0.10 * @since 4.0.10
*/ */
protected V get(boolean isUpdateLastAccess) { protected V get(boolean isUpdateLastAccess) {
if(isUpdateLastAccess) { if (isUpdateLastAccess) {
lastAccess = System.currentTimeMillis(); lastAccess = System.currentTimeMillis();
} }
accessCount.getAndIncrement(); accessCount.getAndIncrement();

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version> <version>5.7.18-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-captcha</artifactId> <artifactId>hutool-captcha</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version> <version>5.7.18-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-core</artifactId> <artifactId>hutool-core</artifactId>

View File

@ -5,7 +5,14 @@ import cn.hutool.core.lang.Opt;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.stream.StreamUtil; import cn.hutool.core.stream.StreamUtil;
import java.util.*; import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -48,8 +55,7 @@ public class CollStreamUtil {
if (CollUtil.isEmpty(collection)) { if (CollUtil.isEmpty(collection)) {
return Collections.emptyMap(); return Collections.emptyMap();
} }
return StreamUtil.of(collection, isParallel) return toMap(collection, (v)-> Opt.ofNullable(v).map(key).get(), Function.identity(), isParallel);
.collect(HashMap::new, (HashMap<K, V> m, V v) -> m.put(Opt.ofNullable(v).map(key).get(), v), HashMap::putAll);
} }
/** /**
@ -82,7 +88,8 @@ public class CollStreamUtil {
if (CollUtil.isEmpty(collection)) { if (CollUtil.isEmpty(collection)) {
return Collections.emptyMap(); return Collections.emptyMap();
} }
return StreamUtil.of(collection, isParallel).collect(HashMap::new, (HashMap<K, V> m, E v) -> m.put(key.apply(v), value.apply(v)), HashMap::putAll); return StreamUtil.of(collection, isParallel)
.collect(HashMap::new, (m, v) -> m.put(key.apply(v), value.apply(v)), HashMap::putAll);
} }

View File

@ -16,7 +16,6 @@ import java.util.Stack;
*/ */
public class Calculator { public class Calculator {
private final Stack<String> postfixStack = new Stack<>();// 后缀式栈 private final Stack<String> postfixStack = new Stack<>();// 后缀式栈
private final Stack<Character> opStack = new Stack<>();// 运算符栈
private final int[] operatPriority = new int[]{0, 3, 2, 1, -1, 1, 0, 2};// 运用运算符ASCII码-40做索引的运算符优先级 private final int[] operatPriority = new int[]{0, 3, 2, 1, -1, 1, 0, 2};// 运用运算符ASCII码-40做索引的运算符优先级
/** /**
@ -26,39 +25,7 @@ public class Calculator {
* @return 计算结果 * @return 计算结果
*/ */
public static double conversion(String expression) { public static double conversion(String expression) {
final Calculator cal = new Calculator(); return (new Calculator()).calculate(expression);
expression = transform(expression);
return cal.calculate(expression);
}
/**
* 将表达式中负数的符号更改
*
* @param expression 例如-2+-1*(-3E-2)-(-1) 被转为 ~2+~1*(~3E~2)-(~1)
* @return 转换后的字符串
*/
private static String transform(String expression) {
expression = StrUtil.cleanBlank(expression);
expression = StrUtil.removeSuffix(expression, "=");
final char[] arr = expression.toCharArray();
for (int i = 0; i < arr.length; i++) {
if (arr[i] == '-') {
if (i == 0) {
arr[i] = '~';
} else {
char c = arr[i - 1];
if (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == 'E' || c == 'e') {
arr[i] = '~';
}
}
}
}
if (arr[0] == '~' || (arr.length > 1 && arr[1] == '(')) {
arr[0] = '-';
return "0" + new String(arr);
} else {
return new String(arr);
}
} }
/** /**
@ -68,15 +35,16 @@ public class Calculator {
* @return 计算结果 * @return 计算结果
*/ */
public double calculate(String expression) { public double calculate(String expression) {
prepare(transform(expression));
Stack<String> resultStack = new Stack<>(); Stack<String> resultStack = new Stack<>();
prepare(expression);
Collections.reverse(postfixStack);// 将后缀式栈反转 Collections.reverse(postfixStack);// 将后缀式栈反转
String firstValue, secondValue, currentValue;// 参与计算的第一个值第二个值和算术运算符 String firstValue, secondValue, currentOp;// 参与计算的第一个值第二个值和算术运算符
while (false == postfixStack.isEmpty()) { while (false == postfixStack.isEmpty()) {
currentValue = postfixStack.pop(); currentOp = postfixStack.pop();
if (false == isOperator(currentValue.charAt(0))) {// 如果不是运算符则存入操作数栈中 if (false == isOperator(currentOp.charAt(0))) {// 如果不是运算符则存入操作数栈中
currentValue = currentValue.replace("~", "-"); currentOp = currentOp.replace("~", "-");
resultStack.push(currentValue); resultStack.push(currentOp);
} else {// 如果是运算符则从操作数栈中取两个值和该数值一起参与运算 } else {// 如果是运算符则从操作数栈中取两个值和该数值一起参与运算
secondValue = resultStack.pop(); secondValue = resultStack.pop();
firstValue = resultStack.pop(); firstValue = resultStack.pop();
@ -85,7 +53,7 @@ public class Calculator {
firstValue = firstValue.replace("~", "-"); firstValue = firstValue.replace("~", "-");
secondValue = secondValue.replace("~", "-"); secondValue = secondValue.replace("~", "-");
BigDecimal tempResult = calculate(firstValue, secondValue, currentValue.charAt(0)); BigDecimal tempResult = calculate(firstValue, secondValue, currentOp.charAt(0));
resultStack.push(tempResult.toString()); resultStack.push(tempResult.toString());
} }
} }
@ -98,6 +66,7 @@ public class Calculator {
* @param expression 表达式 * @param expression 表达式
*/ */
private void prepare(String expression) { private void prepare(String expression) {
final Stack<Character> opStack = new Stack<>();
opStack.push(',');// 运算符放入栈底元素逗号此符号优先级最低 opStack.push(',');// 运算符放入栈底元素逗号此符号优先级最低
char[] arr = expression.toCharArray(); char[] arr = expression.toCharArray();
int currentIndex = 0;// 当前字符的位置 int currentIndex = 0;// 当前字符的位置
@ -152,7 +121,7 @@ public class Calculator {
* *
* @param cur 下标 * @param cur 下标
* @param peek peek * @param peek peek
* @return 优先级 * @return 优先级如果cur高或相等返回true否则false
*/ */
private boolean compare(char cur, char peek) {// 如果是peek优先级高于cur返回true默认都是peek优先级要低 private boolean compare(char cur, char peek) {// 如果是peek优先级高于cur返回true默认都是peek优先级要低
final int offset = 40; final int offset = 40;
@ -199,4 +168,34 @@ public class Calculator {
} }
return result; return result;
} }
/**
* 将表达式中负数的符号更改
*
* @param expression 例如-2+-1*(-3E-2)-(-1) 被转为 ~2+~1*(~3E~2)-(~1)
* @return 转换后的字符串
*/
private static String transform(String expression) {
expression = StrUtil.cleanBlank(expression);
expression = StrUtil.removeSuffix(expression, "=");
final char[] arr = expression.toCharArray();
for (int i = 0; i < arr.length; i++) {
if (arr[i] == '-') {
if (i == 0) {
arr[i] = '~';
} else {
char c = arr[i - 1];
if (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == 'E' || c == 'e') {
arr[i] = '~';
}
}
}
}
if (arr[0] == '~' || (arr.length > 1 && arr[1] == '(')) {
arr[0] = '-';
return "0" + new String(arr);
} else {
return new String(arr);
}
}
} }

View File

@ -20,6 +20,8 @@ import java.util.Map;
* <pre> * <pre>
* key1=v1&amp;key2=&amp;key3=v3 * key1=v1&amp;key2=&amp;key3=v3
* </pre> * </pre>
* 查询封装分为解析查询字符串和构建查询字符串解析可通过charset为null来自定义是否decode编码后的内容<br>
* 构建则通过charset是否为null是否encode参数键值对
* *
* @author looly * @author looly
* @since 5.3.1 * @since 5.3.1

View File

@ -514,20 +514,20 @@ public class XmlUtil {
* *
* @param doc XML文档 * @param doc XML文档
* @param path 文件路径绝对路径或相对ClassPath路径不存在会自动创建 * @param path 文件路径绝对路径或相对ClassPath路径不存在会自动创建
* @param charset 自定义XML文件的编码如果为{@code null} 读取XML文档中的编码否则默认UTF-8 * @param charsetName 自定义XML文件的编码如果为{@code null} 读取XML文档中的编码否则默认UTF-8
*/ */
public static void toFile(Document doc, String path, String charset) { public static void toFile(Document doc, String path, String charsetName) {
if (StrUtil.isBlank(charset)) { if (StrUtil.isBlank(charsetName)) {
charset = doc.getXmlEncoding(); charsetName = doc.getXmlEncoding();
} }
if (StrUtil.isBlank(charset)) { if (StrUtil.isBlank(charsetName)) {
charset = CharsetUtil.UTF_8; charsetName = CharsetUtil.UTF_8;
} }
BufferedWriter writer = null; BufferedWriter writer = null;
try { try {
writer = FileUtil.getWriter(path, charset, false); writer = FileUtil.getWriter(path, CharsetUtil.charset(charsetName), false);
write(doc, writer, charset, INDENT_DEFAULT); write(doc, writer, charsetName, INDENT_DEFAULT);
} finally { } finally {
IoUtil.close(writer); IoUtil.close(writer);
} }
@ -783,10 +783,10 @@ public class XmlUtil {
*/ */
public static Element getElement(Element element, String tagName) { public static Element getElement(Element element, String tagName) {
final NodeList nodeList = element.getElementsByTagName(tagName); final NodeList nodeList = element.getElementsByTagName(tagName);
if (nodeList == null || nodeList.getLength() < 1) { final int length = nodeList.getLength();
if (length < 1) {
return null; return null;
} }
int length = nodeList.getLength();
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
Element childEle = (Element) nodeList.item(i); Element childEle = (Element) nodeList.item(i);
if (childEle == null || childEle.getParentNode() == element) { if (childEle == null || childEle.getParentNode() == element) {
@ -1499,22 +1499,20 @@ public class XmlUtil {
*/ */
private void examineNode(Node node, boolean attributesOnly) { private void examineNode(Node node, boolean attributesOnly) {
final NamedNodeMap attributes = node.getAttributes(); final NamedNodeMap attributes = node.getAttributes();
if (null != attributes) { final int length = attributes.getLength();
for (int i = 0; i < attributes.getLength(); i++) { for (int i = 0; i < length; i++) {
Node attribute = attributes.item(i); Node attribute = attributes.item(i);
storeAttribute(attribute); storeAttribute(attribute);
}
} }
if (false == attributesOnly) { if (false == attributesOnly) {
final NodeList childNodes = node.getChildNodes(); final NodeList childNodes = node.getChildNodes();
if (null != childNodes) { Node item;
Node item; final int childLength = childNodes.getLength();
for (int i = 0; i < childNodes.getLength(); i++) { for (int i = 0; i < childLength; i++) {
item = childNodes.item(i); item = childNodes.item(i);
if (item.getNodeType() == Node.ELEMENT_NODE) if (item.getNodeType() == Node.ELEMENT_NODE)
examineNode(item, false); examineNode(item, false);
}
} }
} }
} }

View File

@ -130,4 +130,11 @@ public class UrlQueryTest {
final String a = UrlQuery.of(MapUtil.of("a ", " ")).build(CharsetUtil.CHARSET_UTF_8); final String a = UrlQuery.of(MapUtil.of("a ", " ")).build(CharsetUtil.CHARSET_UTF_8);
Assert.assertEquals("a%20=%20", a); Assert.assertEquals("a%20=%20", a);
} }
@Test
public void parsePercentTest(){
String queryStr = "a%2B=ccc";
final UrlQuery query = UrlQuery.of(queryStr, null);
Assert.assertEquals(queryStr, query.toString());
}
} }

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version> <version>5.7.18-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-cron</artifactId> <artifactId>hutool-cron</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version> <version>5.7.18-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-crypto</artifactId> <artifactId>hutool-crypto</artifactId>

View File

@ -19,7 +19,9 @@ import org.bouncycastle.crypto.signers.DSAEncoding;
import org.bouncycastle.crypto.signers.PlainDSAEncoding; import org.bouncycastle.crypto.signers.PlainDSAEncoding;
import org.bouncycastle.crypto.signers.SM2Signer; import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.crypto.signers.StandardDSAEncoding; import org.bouncycastle.crypto.signers.StandardDSAEncoding;
import org.bouncycastle.util.BigIntegers;
import java.math.BigInteger;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.PublicKey; import java.security.PublicKey;
@ -519,7 +521,27 @@ public class SM2 extends AbstractAsymmetricCrypto<SM2> {
* @since 5.5.9 * @since 5.5.9
*/ */
public byte[] getD() { public byte[] getD() {
return this.privateKeyParams.getD().toByteArray(); return BigIntegers.asUnsignedByteArray(getDBigInteger());
}
/**
* 获得私钥D值编码后的私钥
*
* @return D值
* @since 5.7.17
*/
public String getDHex() {
return getDBigInteger().toString(16);
}
/**
* 获得私钥D值
*
* @return D值
* @since 5.7.17
*/
public BigInteger getDBigInteger() {
return this.privateKeyParams.getD();
} }
/** /**

View File

@ -311,4 +311,14 @@ public class SM2Test {
byte[] dec = sm2.decrypt(data, KeyType.PrivateKey); byte[] dec = sm2.decrypt(data, KeyType.PrivateKey);
Assert.assertArrayEquals(dec, src.getBytes(StandardCharsets.UTF_8)); Assert.assertArrayEquals(dec, src.getBytes(StandardCharsets.UTF_8));
} }
@Test
public void dLengthTest(){
final SM2 sm2 = SmUtil.sm2();
Assert.assertEquals(64, sm2.getDHex().length());
Assert.assertEquals(32, sm2.getD().length);
// 04占位一个字节
Assert.assertEquals(65, sm2.getQ(false).length);
}
} }

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version> <version>5.7.18-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-db</artifactId> <artifactId>hutool-db</artifactId>

View File

@ -1,6 +1,7 @@
package cn.hutool.db; package cn.hutool.db;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.func.Func1;
import cn.hutool.db.dialect.Dialect; import cn.hutool.db.dialect.Dialect;
import cn.hutool.db.handler.BeanListHandler; import cn.hutool.db.handler.BeanListHandler;
import cn.hutool.db.handler.EntityHandler; import cn.hutool.db.handler.EntityHandler;
@ -20,6 +21,7 @@ import cn.hutool.db.sql.Wrapper;
import javax.sql.DataSource; import javax.sql.DataSource;
import java.io.Serializable; import java.io.Serializable;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -194,6 +196,27 @@ public abstract class AbstractDb implements Serializable {
} }
} }
/**
* 执行自定义的{@link PreparedStatement}结果使用{@link RsHandler}处理<br>
* 此方法主要用于自定义场景如游标查询等
*
* @param <T> 结果集需要处理的对象类型
* @param statementFunc 自定义{@link PreparedStatement}创建函数
* @param rsh 结果集处理对象
* @return 结果对象
* @throws SQLException SQL执行异常
* @since 5.7.17
*/
public <T> T query(Func1<Connection, PreparedStatement> statementFunc, RsHandler<T> rsh) throws SQLException {
Connection conn = null;
try {
conn = this.getConnection();
return SqlExecutor.query(conn, statementFunc, rsh);
} finally {
this.closeConnection(conn);
}
}
/** /**
* 执行非查询语句<br> * 执行非查询语句<br>
* 语句包括 插入更新删除 * 语句包括 插入更新删除

View File

@ -1,6 +1,7 @@
package cn.hutool.db.sql; package cn.hutool.db.sql;
import cn.hutool.core.collection.ArrayIter; import cn.hutool.core.collection.ArrayIter;
import cn.hutool.core.lang.func.Func1;
import cn.hutool.db.DbUtil; import cn.hutool.db.DbUtil;
import cn.hutool.db.StatementUtil; import cn.hutool.db.StatementUtil;
import cn.hutool.db.handler.RsHandler; import cn.hutool.db.handler.RsHandler;
@ -239,6 +240,22 @@ public class SqlExecutor {
return query(conn, namedSql.getSql(), rsh, namedSql.getParams()); return query(conn, namedSql.getSql(), rsh, namedSql.getParams());
} }
/**
* 执行查询语句<br>
* 此方法不会关闭Connection
*
* @param <T> 处理结果类型
* @param conn 数据库连接对象
* @param sqlBuilder SQL构建器包含参数
* @param rsh 结果集处理对象
* @return 结果对象
* @throws SQLException SQL执行异常
* @since 5.5.3
*/
public static <T> T query(Connection conn, SqlBuilder sqlBuilder, RsHandler<T> rsh) throws SQLException {
return query(conn, sqlBuilder.build(), rsh, sqlBuilder.getParamValueArray());
}
/** /**
* 执行查询语句<br> * 执行查询语句<br>
* 此方法不会关闭Connection * 此方法不会关闭Connection
@ -262,19 +279,30 @@ public class SqlExecutor {
} }
/** /**
* 执行查询语句<br> * 执行自定义的{@link PreparedStatement}结果使用{@link RsHandler}处理<br>
* 此方法不会关闭Connection * 此方法主要用于自定义场景如游标查询等
* *
* @param <T> 处理结果类型 * @param <T> 处理结果类型
* @param conn 数据库连接对象 * @param conn 数据库连接对象
* @param sqlBuilder SQL构建器包含参 * @param statementFunc 自定义{@link PreparedStatement}创建函
* @param rsh 结果集处理对象 * @param rsh 自定义结果集处理
* @return 结果对象 * @return 结果
* @throws SQLException SQL执行异常 * @throws SQLException SQL执行异常
* @since 5.5.3 * @since 5.7.17
*/ */
public static <T> T query(Connection conn, SqlBuilder sqlBuilder, RsHandler<T> rsh) throws SQLException { public static <T> T query(Connection conn, Func1<Connection, PreparedStatement> statementFunc, RsHandler<T> rsh) throws SQLException {
return query(conn, sqlBuilder.build(), rsh, sqlBuilder.getParamValueArray()); PreparedStatement ps = null;
try {
ps = statementFunc.call(conn);
return executeQuery(ps, rsh);
} catch (Exception e) {
if(e instanceof SQLException){
throw (SQLException) e;
}
throw new RuntimeException(e);
} finally {
DbUtil.close(ps);
}
} }
// -------------------------------------------------------------------------------------- Execute With PreparedStatement // -------------------------------------------------------------------------------------- Execute With PreparedStatement

View File

@ -1,11 +1,14 @@
package cn.hutool.db; package cn.hutool.db;
import cn.hutool.db.handler.EntityListHandler;
import cn.hutool.db.sql.Condition; import cn.hutool.db.sql.Condition;
import cn.hutool.log.StaticLog; import cn.hutool.log.StaticLog;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.List; import java.util.List;
@ -109,4 +112,18 @@ public class DbTest {
db.del("user", "name", "unitTestUser2"); db.del("user", "name", "unitTestUser2");
}); });
} }
@Test
@Ignore
public void queryFetchTest() throws SQLException {
// https://gitee.com/dromara/hutool/issues/I4JXWN
Db.use().query((conn->{
PreparedStatement ps = conn.prepareStatement("select * from table",
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
ps.setFetchSize(Integer.MIN_VALUE);
ps.setFetchDirection(ResultSet.FETCH_FORWARD);
return ps;
}), new EntityListHandler());
}
} }

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version> <version>5.7.18-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-dfa</artifactId> <artifactId>hutool-dfa</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version> <version>5.7.18-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-extra</artifactId> <artifactId>hutool-extra</artifactId>

View File

@ -255,6 +255,15 @@ public class Ftp extends AbstractFtp {
return this; return this;
} }
/**
* 是否执行完操作返回当前目录
* @return 执行完操作是否返回当前目录
* @since 5.7.17
*/
public boolean isBackToPwd(){
return this.backToPwd;
}
/** /**
* 如果连接超时的话重新进行连接 经测试当连接超时时client.isConnected()仍然返回ture无法判断是否连接超时 因此通过发送pwd命令的方式检查连接是否超时 * 如果连接超时的话重新进行连接 经测试当连接超时时client.isConnected()仍然返回ture无法判断是否连接超时 因此通过发送pwd命令的方式检查连接是否超时
* *

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version> <version>5.7.18-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-http</artifactId> <artifactId>hutool-http</artifactId>

View File

@ -12,6 +12,7 @@ import cn.hutool.core.map.MapUtil;
import cn.hutool.core.net.SSLUtil; import cn.hutool.core.net.SSLUtil;
import cn.hutool.core.net.url.UrlBuilder; import cn.hutool.core.net.url.UrlBuilder;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.http.body.BytesBody; import cn.hutool.http.body.BytesBody;
@ -30,6 +31,7 @@ import java.net.HttpURLConnection;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.Proxy; import java.net.Proxy;
import java.net.URLStreamHandler; import java.net.URLStreamHandler;
import java.nio.charset.Charset;
import java.util.Collection; import java.util.Collection;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
@ -43,6 +45,112 @@ import java.util.function.Consumer;
*/ */
public class HttpRequest extends HttpBase<HttpRequest> { public class HttpRequest extends HttpBase<HttpRequest> {
// ---------------------------------------------------------------- static Http Method start
/**
* POST请求
*
* @param url URL
* @return HttpRequest
*/
public static HttpRequest post(String url) {
return of(url).method(Method.POST);
}
/**
* GET请求
*
* @param url URL
* @return HttpRequest
*/
public static HttpRequest get(String url) {
return of(url).method(Method.GET);
}
/**
* HEAD请求
*
* @param url URL
* @return HttpRequest
*/
public static HttpRequest head(String url) {
return of(url).method(Method.HEAD);
}
/**
* OPTIONS请求
*
* @param url URL
* @return HttpRequest
*/
public static HttpRequest options(String url) {
return of(url).method(Method.OPTIONS);
}
/**
* PUT请求
*
* @param url URL
* @return HttpRequest
*/
public static HttpRequest put(String url) {
return of(url).method(Method.PUT);
}
/**
* PATCH请求
*
* @param url URL
* @return HttpRequest
* @since 3.0.9
*/
public static HttpRequest patch(String url) {
return of(url).method(Method.PATCH);
}
/**
* DELETE请求
*
* @param url URL
* @return HttpRequest
*/
public static HttpRequest delete(String url) {
return of(url).method(Method.DELETE);
}
/**
* TRACE请求
*
* @param url URL
* @return HttpRequest
*/
public static HttpRequest trace(String url) {
return of(url).method(Method.TRACE);
}
/**
* 构建一个HTTP请求
*
* @param url URL链接默认自动编码URL中的参数等信息
* @return HttpRequest
* @since 5.7.18
*/
public static HttpRequest of(String url) {
return of(url, CharsetUtil.CHARSET_UTF_8);
}
/**
* 构建一个HTTP请求
*
* @param url URL链接
* @param charset 编码如果为{@code null}不自动解码编码URL
* @return HttpRequest
* @since 5.7.18
*/
public static HttpRequest of(String url, Charset charset) {
return new HttpRequest(UrlBuilder.of(url, charset));
}
/** /**
* 设置全局默认的连接和读取超时时长 * 设置全局默认的连接和读取超时时长
* *
@ -85,6 +193,7 @@ public class HttpRequest extends HttpBase<HttpRequest> {
public static void closeCookie() { public static void closeCookie() {
GlobalCookieManager.setCookieManager(null); GlobalCookieManager.setCookieManager(null);
} }
// ---------------------------------------------------------------- static Http Method end
private UrlBuilder url; private UrlBuilder url;
private URLStreamHandler urlHandler; private URLStreamHandler urlHandler;
@ -168,95 +277,16 @@ public class HttpRequest extends HttpBase<HttpRequest> {
* @param url {@link UrlBuilder} * @param url {@link UrlBuilder}
*/ */
public HttpRequest(UrlBuilder url) { public HttpRequest(UrlBuilder url) {
this.url = url; this.url = Assert.notNull(url, "URL must be not null!");
// 给定默认URL编码
final Charset charset = url.getCharset();
if (null != charset) {
this.charset(charset);
}
// 给定一个默认头信息 // 给定一个默认头信息
this.header(GlobalHeaders.INSTANCE.headers); this.header(GlobalHeaders.INSTANCE.headers);
} }
// ---------------------------------------------------------------- static Http Method start
/**
* POST请求
*
* @param url URL
* @return HttpRequest
*/
public static HttpRequest post(String url) {
return new HttpRequest(url).method(Method.POST);
}
/**
* GET请求
*
* @param url URL
* @return HttpRequest
*/
public static HttpRequest get(String url) {
return new HttpRequest(url).method(Method.GET);
}
/**
* HEAD请求
*
* @param url URL
* @return HttpRequest
*/
public static HttpRequest head(String url) {
return new HttpRequest(url).method(Method.HEAD);
}
/**
* OPTIONS请求
*
* @param url URL
* @return HttpRequest
*/
public static HttpRequest options(String url) {
return new HttpRequest(url).method(Method.OPTIONS);
}
/**
* PUT请求
*
* @param url URL
* @return HttpRequest
*/
public static HttpRequest put(String url) {
return new HttpRequest(url).method(Method.PUT);
}
/**
* PATCH请求
*
* @param url URL
* @return HttpRequest
* @since 3.0.9
*/
public static HttpRequest patch(String url) {
return new HttpRequest(url).method(Method.PATCH);
}
/**
* DELETE请求
*
* @param url URL
* @return HttpRequest
*/
public static HttpRequest delete(String url) {
return new HttpRequest(url).method(Method.DELETE);
}
/**
* TRACE请求
*
* @param url URL
* @return HttpRequest
*/
public static HttpRequest trace(String url) {
return new HttpRequest(url).method(Method.TRACE);
}
// ---------------------------------------------------------------- static Http Method end
/** /**
* 获取请求URL * 获取请求URL
* *

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version> <version>5.7.18-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-json</artifactId> <artifactId>hutool-json</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version> <version>5.7.18-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-jwt</artifactId> <artifactId>hutool-jwt</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version> <version>5.7.18-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-log</artifactId> <artifactId>hutool-log</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version> <version>5.7.18-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-poi</artifactId> <artifactId>hutool-poi</artifactId>

View File

@ -211,7 +211,7 @@ public class StyleUtil {
* @return 数据格式 * @return 数据格式
* @since 5.5.5 * @since 5.5.5
*/ */
public Short getFormat(Workbook workbook, String format) { public static Short getFormat(Workbook workbook, String format) {
final DataFormat dataFormat = workbook.createDataFormat(); final DataFormat dataFormat = workbook.createDataFormat();
return dataFormat.getFormat(format); return dataFormat.getFormat(format);
} }

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version> <version>5.7.18-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-script</artifactId> <artifactId>hutool-script</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version> <version>5.7.18-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-setting</artifactId> <artifactId>hutool-setting</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version> <version>5.7.18-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-socket</artifactId> <artifactId>hutool-socket</artifactId>

View File

@ -9,7 +9,7 @@
<parent> <parent>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version> <version>5.7.18-SNAPSHOT</version>
</parent> </parent>
<artifactId>hutool-system</artifactId> <artifactId>hutool-system</artifactId>

View File

@ -8,7 +8,7 @@
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId> <artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version> <version>5.7.18-SNAPSHOT</version>
<name>hutool</name> <name>hutool</name>
<description>Hutool是一个小而全的Java工具类库通过静态方法封装降低相关API的学习成本提高工作效率使Java拥有函数式语言般的优雅让Java语言也可以“甜甜的”。</description> <description>Hutool是一个小而全的Java工具类库通过静态方法封装降低相关API的学习成本提高工作效率使Java拥有函数式语言般的优雅让Java语言也可以“甜甜的”。</description>
<url>https://github.com/dromara/hutool</url> <url>https://github.com/dromara/hutool</url>