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
@ -33,6 +39,10 @@
* 【core 】 NumberUtil增加isOdd、isEven方法pr#474@Gitee
* 【http 】 增加HttpGlobalConfig.setBoundary删除MultipartBody.BOUNDARY和getContentTypeissue#I4KSLY@Gitee
* 【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修复
* 【core 】 修复FileResource构造fileName参数无效问题issue#1942@Github
@ -43,10 +53,12 @@
* 【poi 】 修复SoapClient参数未使用问题
* 【core 】 修复HashUtil.cityHash128参数未使用问题
* 【core 】 修复DateUtil.formatChineseDate显示问题issue#I4KK5F@Gitee
* 【poi 】 修复CellUtil.setCellValuestyle空导致值无法写入问题issue#1995@Github
* 【poi 】 修复CellUtil.setCellValueStyle空导致值无法写入问题issue#1995@Github
* 【poi 】 修复CellUtil.setComment参数设置错误问题
* 【core 】 修复QueryBuilder解析路径导致的错误issue#1989@Github
* 【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>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.17</version>
<version>5.7.18</version>
</dependency>
```
### 🍐Gradle
```
implementation 'cn.hutool:hutool-all:5.7.17'
implementation 'cn.hutool:hutool-all:5.7.18'
```
## 📥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:
> 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>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.17</version>
<version>5.7.18</version>
</dependency>
```
### 🍐Gradle
```
implementation 'cn.hutool:hutool-all:5.7.17'
implementation 'cn.hutool:hutool-all:5.7.18'
```
### 📥下载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平台没有测试不能保证所有工具类或工具方法可用。

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>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version>
<version>5.7.18-SNAPSHOT</version>
</parent>
<artifactId>hutool-all</artifactId>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version>
<version>5.7.18-SNAPSHOT</version>
</parent>
<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.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.Function;
import java.util.stream.Collectors;
@ -48,8 +55,7 @@ public class CollStreamUtil {
if (CollUtil.isEmpty(collection)) {
return Collections.emptyMap();
}
return StreamUtil.of(collection, isParallel)
.collect(HashMap::new, (HashMap<K, V> m, V v) -> m.put(Opt.ofNullable(v).map(key).get(), v), HashMap::putAll);
return toMap(collection, (v)-> Opt.ofNullable(v).map(key).get(), Function.identity(), isParallel);
}
/**
@ -82,7 +88,8 @@ public class CollStreamUtil {
if (CollUtil.isEmpty(collection)) {
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 {
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做索引的运算符优先级
/**
@ -26,39 +25,7 @@ public class Calculator {
* @return 计算结果
*/
public static double conversion(String expression) {
final Calculator cal = new Calculator();
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);
}
return (new Calculator()).calculate(expression);
}
/**
@ -68,15 +35,16 @@ public class Calculator {
* @return 计算结果
*/
public double calculate(String expression) {
prepare(transform(expression));
Stack<String> resultStack = new Stack<>();
prepare(expression);
Collections.reverse(postfixStack);// 将后缀式栈反转
String firstValue, secondValue, currentValue;// 参与计算的第一个值第二个值和算术运算符
String firstValue, secondValue, currentOp;// 参与计算的第一个值第二个值和算术运算符
while (false == postfixStack.isEmpty()) {
currentValue = postfixStack.pop();
if (false == isOperator(currentValue.charAt(0))) {// 如果不是运算符则存入操作数栈中
currentValue = currentValue.replace("~", "-");
resultStack.push(currentValue);
currentOp = postfixStack.pop();
if (false == isOperator(currentOp.charAt(0))) {// 如果不是运算符则存入操作数栈中
currentOp = currentOp.replace("~", "-");
resultStack.push(currentOp);
} else {// 如果是运算符则从操作数栈中取两个值和该数值一起参与运算
secondValue = resultStack.pop();
firstValue = resultStack.pop();
@ -85,7 +53,7 @@ public class Calculator {
firstValue = firstValue.replace("~", "-");
secondValue = secondValue.replace("~", "-");
BigDecimal tempResult = calculate(firstValue, secondValue, currentValue.charAt(0));
BigDecimal tempResult = calculate(firstValue, secondValue, currentOp.charAt(0));
resultStack.push(tempResult.toString());
}
}
@ -98,6 +66,7 @@ public class Calculator {
* @param expression 表达式
*/
private void prepare(String expression) {
final Stack<Character> opStack = new Stack<>();
opStack.push(',');// 运算符放入栈底元素逗号此符号优先级最低
char[] arr = expression.toCharArray();
int currentIndex = 0;// 当前字符的位置
@ -152,7 +121,7 @@ public class Calculator {
*
* @param cur 下标
* @param peek peek
* @return 优先级
* @return 优先级如果cur高或相等返回true否则false
*/
private boolean compare(char cur, char peek) {// 如果是peek优先级高于cur返回true默认都是peek优先级要低
final int offset = 40;
@ -199,4 +168,34 @@ public class Calculator {
}
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>
* key1=v1&amp;key2=&amp;key3=v3
* </pre>
* 查询封装分为解析查询字符串和构建查询字符串解析可通过charset为null来自定义是否decode编码后的内容<br>
* 构建则通过charset是否为null是否encode参数键值对
*
* @author looly
* @since 5.3.1

View File

@ -514,20 +514,20 @@ public class XmlUtil {
*
* @param doc XML文档
* @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) {
if (StrUtil.isBlank(charset)) {
charset = doc.getXmlEncoding();
public static void toFile(Document doc, String path, String charsetName) {
if (StrUtil.isBlank(charsetName)) {
charsetName = doc.getXmlEncoding();
}
if (StrUtil.isBlank(charset)) {
charset = CharsetUtil.UTF_8;
if (StrUtil.isBlank(charsetName)) {
charsetName = CharsetUtil.UTF_8;
}
BufferedWriter writer = null;
try {
writer = FileUtil.getWriter(path, charset, false);
write(doc, writer, charset, INDENT_DEFAULT);
writer = FileUtil.getWriter(path, CharsetUtil.charset(charsetName), false);
write(doc, writer, charsetName, INDENT_DEFAULT);
} finally {
IoUtil.close(writer);
}
@ -783,10 +783,10 @@ public class XmlUtil {
*/
public static Element getElement(Element element, String tagName) {
final NodeList nodeList = element.getElementsByTagName(tagName);
if (nodeList == null || nodeList.getLength() < 1) {
final int length = nodeList.getLength();
if (length < 1) {
return null;
}
int length = nodeList.getLength();
for (int i = 0; i < length; i++) {
Element childEle = (Element) nodeList.item(i);
if (childEle == null || childEle.getParentNode() == element) {
@ -1499,22 +1499,20 @@ public class XmlUtil {
*/
private void examineNode(Node node, boolean attributesOnly) {
final NamedNodeMap attributes = node.getAttributes();
if (null != attributes) {
for (int i = 0; i < attributes.getLength(); i++) {
Node attribute = attributes.item(i);
storeAttribute(attribute);
}
final int length = attributes.getLength();
for (int i = 0; i < length; i++) {
Node attribute = attributes.item(i);
storeAttribute(attribute);
}
if (false == attributesOnly) {
final NodeList childNodes = node.getChildNodes();
if (null != childNodes) {
Node item;
for (int i = 0; i < childNodes.getLength(); i++) {
item = childNodes.item(i);
if (item.getNodeType() == Node.ELEMENT_NODE)
examineNode(item, false);
}
Node item;
final int childLength = childNodes.getLength();
for (int i = 0; i < childLength; i++) {
item = childNodes.item(i);
if (item.getNodeType() == Node.ELEMENT_NODE)
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);
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>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version>
<version>5.7.18-SNAPSHOT</version>
</parent>
<artifactId>hutool-cron</artifactId>

View File

@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version>
<version>5.7.18-SNAPSHOT</version>
</parent>
<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.SM2Signer;
import org.bouncycastle.crypto.signers.StandardDSAEncoding;
import org.bouncycastle.util.BigIntegers;
import java.math.BigInteger;
import java.security.PrivateKey;
import java.security.PublicKey;
@ -519,7 +521,27 @@ public class SM2 extends AbstractAsymmetricCrypto<SM2> {
* @since 5.5.9
*/
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);
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>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version>
<version>5.7.18-SNAPSHOT</version>
</parent>
<artifactId>hutool-db</artifactId>

View File

@ -1,6 +1,7 @@
package cn.hutool.db;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.func.Func1;
import cn.hutool.db.dialect.Dialect;
import cn.hutool.db.handler.BeanListHandler;
import cn.hutool.db.handler.EntityHandler;
@ -20,6 +21,7 @@ import cn.hutool.db.sql.Wrapper;
import javax.sql.DataSource;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Collection;
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>
* 语句包括 插入更新删除

View File

@ -1,6 +1,7 @@
package cn.hutool.db.sql;
import cn.hutool.core.collection.ArrayIter;
import cn.hutool.core.lang.func.Func1;
import cn.hutool.db.DbUtil;
import cn.hutool.db.StatementUtil;
import cn.hutool.db.handler.RsHandler;
@ -239,6 +240,22 @@ public class SqlExecutor {
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>
* 此方法不会关闭Connection
@ -262,19 +279,30 @@ public class SqlExecutor {
}
/**
* 执行查询语句<br>
* 此方法不会关闭Connection
* 执行自定义的{@link PreparedStatement}结果使用{@link RsHandler}处理<br>
* 此方法主要用于自定义场景如游标查询等
*
* @param <T> 处理结果类型
* @param conn 数据库连接对象
* @param sqlBuilder SQL构建器包含参
* @param rsh 结果集处理对象
* @return 结果对象
* @param statementFunc 自定义{@link PreparedStatement}创建函
* @param rsh 自定义结果集处理
* @return 结果
* @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 {
return query(conn, sqlBuilder.build(), rsh, sqlBuilder.getParamValueArray());
public static <T> T query(Connection conn, Func1<Connection, PreparedStatement> statementFunc, RsHandler<T> rsh) throws SQLException {
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

View File

@ -1,11 +1,14 @@
package cn.hutool.db;
import cn.hutool.db.handler.EntityListHandler;
import cn.hutool.db.sql.Condition;
import cn.hutool.log.StaticLog;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
@ -109,4 +112,18 @@ public class DbTest {
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>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version>
<version>5.7.18-SNAPSHOT</version>
</parent>
<artifactId>hutool-dfa</artifactId>

View File

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

View File

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

View File

@ -9,7 +9,7 @@
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.7.17-SNAPSHOT</version>
<version>5.7.18-SNAPSHOT</version>
</parent>
<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.url.UrlBuilder;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.body.BytesBody;
@ -30,6 +31,7 @@ import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URLStreamHandler;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
@ -43,6 +45,112 @@ import java.util.function.Consumer;
*/
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() {
GlobalCookieManager.setCookieManager(null);
}
// ---------------------------------------------------------------- static Http Method end
private UrlBuilder url;
private URLStreamHandler urlHandler;
@ -168,95 +277,16 @@ public class HttpRequest extends HttpBase<HttpRequest> {
* @param url {@link UrlBuilder}
*/
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);
}
// ---------------------------------------------------------------- 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
*

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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