mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-24 18:04:54 +08:00
Merge branch 'v6-dev' of gitee.com:dromara/hutool into v6-dev
This commit is contained in:
commit
296f3c794d
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
-------------------------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
# 6.0.0.M1 (2023-04-23)
|
# 6.0.0.M4 (2023-05-09)
|
||||||
|
|
||||||
### 计划实现
|
### 计划实现
|
||||||
* 【poi 】 Markdown相关(如HTML转换等),基于commonmark-java
|
* 【poi 】 Markdown相关(如HTML转换等),基于commonmark-java
|
||||||
@ -14,5 +14,6 @@
|
|||||||
### ❌不兼容特性
|
### ❌不兼容特性
|
||||||
|
|
||||||
### 🐣新特性
|
### 🐣新特性
|
||||||
|
* 【db 】 优化count查询兼容informix(issue#I713XQ@Gitee)
|
||||||
|
|
||||||
### 🐞Bug修复
|
### 🐞Bug修复
|
@ -144,8 +144,8 @@ public abstract class ReentrantCache<K, V> extends AbstractCache<K, V> {
|
|||||||
* @param withMissCount 是否计数丢失数
|
* @param withMissCount 是否计数丢失数
|
||||||
*/
|
*/
|
||||||
private void remove(final K key, final boolean withMissCount) {
|
private void remove(final K key, final boolean withMissCount) {
|
||||||
lock.lock();
|
|
||||||
CacheObj<K, V> co;
|
CacheObj<K, V> co;
|
||||||
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
co = removeWithoutLock(key, withMissCount);
|
co = removeWithoutLock(key, withMissCount);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -43,7 +43,7 @@ public interface HierarchyIterator<H, R> {
|
|||||||
*
|
*
|
||||||
* @param result 结果
|
* @param result 结果
|
||||||
* @param hierarchy 当前层级
|
* @param hierarchy 当前层级
|
||||||
* @return 向容器中添加元素的方法
|
* @return 下一需要遍历的层级
|
||||||
*/
|
*/
|
||||||
Collection<H> nextHierarchies(R result, H hierarchy);
|
Collection<H> nextHierarchies(R result, H hierarchy);
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ public class HierarchyIteratorImpl<H, R> implements HierarchyIterator<H, R> {
|
|||||||
*
|
*
|
||||||
* @param result 结果
|
* @param result 结果
|
||||||
* @param hierarchy 当前层级
|
* @param hierarchy 当前层级
|
||||||
* @return 向容器中添加元素的方法
|
* @return 下一需要遍历的层级
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Collection<H> nextHierarchies(final R result, final H hierarchy) {
|
public Collection<H> nextHierarchies(final R result, final H hierarchy) {
|
||||||
|
@ -35,11 +35,11 @@ import java.util.function.Predicate;
|
|||||||
* Node root = Tree.build();
|
* Node root = Tree.build();
|
||||||
* // 从树结构中通过深度优先查找某个节点
|
* // 从树结构中通过深度优先查找某个节点
|
||||||
* Node target = HierarchyUtil.traverseByDepthFirst(
|
* Node target = HierarchyUtil.traverseByDepthFirst(
|
||||||
* root, HierarchyUtil.finder(Node::getChildren, node -> Objects.equals(node.getId(), "target") ? node : null)
|
* root, HierarchyIteratorUtil.find(Node::getChildren, node -> Objects.equals(node.getId(), "target") ? node : null)
|
||||||
* );
|
* );
|
||||||
* // 从树结构中通过广度优先获取其所有的子节点
|
* // 从树结构中通过广度优先获取其所有的子节点
|
||||||
* List<Node> nodes = HierarchyUtil.traverseByBreadthFirst(
|
* List<Node> nodes = HierarchyUtil.traverseByBreadthFirst(
|
||||||
* root, HierarchyUtil.collector(Node::getChildren)
|
* root, HierarchyIteratorUtil.collect(Node::getChildren)
|
||||||
* );
|
* );
|
||||||
* }</pre>
|
* }</pre>
|
||||||
*
|
*
|
||||||
@ -123,17 +123,15 @@ public class HierarchyUtil {
|
|||||||
Objects.requireNonNull(hierarchyIterator);
|
Objects.requireNonNull(hierarchyIterator);
|
||||||
|
|
||||||
// 遍历层级结构
|
// 遍历层级结构
|
||||||
final Predicate<? super H> hierarchyFilter = filter.negate();
|
|
||||||
final LinkedList<H> queue = new LinkedList<>();
|
final LinkedList<H> queue = new LinkedList<>();
|
||||||
final Set<H> accessed = new HashSet<>();
|
final Set<H> accessed = new HashSet<>();
|
||||||
queue.add(hierarchy);
|
queue.add(hierarchy);
|
||||||
while (!queue.isEmpty()) {
|
while (!queue.isEmpty()) {
|
||||||
// 跳过已经访问过或者被过滤的层级结构
|
// 跳过已经访问过或者被过滤的层级结构
|
||||||
final H curr = queue.removeFirst();
|
final H curr = queue.removeFirst();
|
||||||
if (accessed.contains(curr) || hierarchyFilter.test(curr)) {
|
if (!accessed.add(curr) || !filter.test(curr)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
accessed.add(curr);
|
|
||||||
|
|
||||||
// 若迭代器返回true,则结束遍历
|
// 若迭代器返回true,则结束遍历
|
||||||
if (hierarchyIterator.isBreak(curr)) {
|
if (hierarchyIterator.isBreak(curr)) {
|
||||||
|
@ -12,13 +12,12 @@
|
|||||||
|
|
||||||
package org.dromara.hutool.core.tree.hierarchy;
|
package org.dromara.hutool.core.tree.hierarchy;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* test for {@link HierarchyUtil}
|
* test for {@link HierarchyUtil}
|
||||||
@ -27,63 +26,72 @@ import java.util.stream.Collectors;
|
|||||||
*/
|
*/
|
||||||
class HierarchyUtilTest {
|
class HierarchyUtilTest {
|
||||||
|
|
||||||
private Map<String, String> tree;
|
@Data
|
||||||
|
static class Node {
|
||||||
|
private String parent;
|
||||||
|
private String value;
|
||||||
|
private List<Node> children;
|
||||||
|
|
||||||
|
public Node(final String parent, final String value) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Node root;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void init() {
|
void init() {
|
||||||
tree = new LinkedHashMap<>();
|
|
||||||
|
|
||||||
// 根节点
|
// 根节点
|
||||||
tree.put("0", null);
|
root = new Node(null, "0");
|
||||||
|
|
||||||
// 第一层
|
// 第二层
|
||||||
tree.put("0-1", "0");
|
final Node first1 = new Node(root.value, "0-1");
|
||||||
tree.put("0-2", "0");
|
final Node first2 = new Node(root.value, "0-2");
|
||||||
tree.put("0-3", "0");
|
final Node first3 = new Node(root.value, "0-3");
|
||||||
|
root.setChildren(Arrays.asList(first1, first2, first3));
|
||||||
|
|
||||||
// 第三层
|
// 第三层
|
||||||
tree.put("0-1-1", "0-1");
|
final Node second11 = new Node(first1.value, "0-1-1");
|
||||||
tree.put("0-1-2", "0-1");
|
final Node second12 = new Node(first1.value, "0-1-2");
|
||||||
tree.put("0-1-3", "0-1");
|
final Node second13 = new Node(first1.value, "0-1-3");
|
||||||
|
first1.setChildren(Arrays.asList(second11, second12, second13));
|
||||||
|
|
||||||
tree.put("0-2-1", "0-2");
|
final Node second21 = new Node(first2.value, "0-2-1");
|
||||||
tree.put("0-2-2", "0-2");
|
final Node second22 = new Node(first2.value, "0-2-2");
|
||||||
tree.put("0-2-3", "0-2");
|
final Node second23 = new Node(first2.value, "0-2-3");
|
||||||
|
first2.setChildren(Arrays.asList(second21, second22, second23));
|
||||||
|
|
||||||
tree.put("0-3-1", "0-3");
|
final Node second31 = new Node(first3.value, "0-3-1");
|
||||||
tree.put("0-3-2", "0-3");
|
final Node second32 = new Node(first3.value, "0-3-2");
|
||||||
tree.put("0-3-3", "0-3");
|
final Node second33 = new Node(first3.value, "0-3-3");
|
||||||
|
first3.setChildren(Arrays.asList(second31, second32, second33));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testTraverseByBreadthFirst() {
|
void testTraverseByBreadthFirst() {
|
||||||
// 按广度优先遍历所有节点
|
// // 按广度优先遍历所有节点
|
||||||
final Set<String> nodes = new LinkedHashSet<>();
|
final List<String> nodes = new ArrayList<>();
|
||||||
HierarchyUtil.traverseByBreadthFirst("0", HierarchyIteratorUtil.scan(t -> {
|
HierarchyUtil.traverseByBreadthFirst(root, HierarchyIteratorUtil.scan(t -> {
|
||||||
nodes.add(t);
|
nodes.add(t.getValue());
|
||||||
return tree.entrySet().stream()
|
return t.getChildren();
|
||||||
.filter(e -> Objects.equals(t, e.getValue()))
|
|
||||||
.map(Map.Entry::getKey)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}));
|
}));
|
||||||
Assertions.assertEquals(13, nodes.size());
|
Assertions.assertEquals(13, nodes.size());
|
||||||
Assertions.assertEquals(
|
Assertions.assertEquals(
|
||||||
new LinkedHashSet<>(Arrays.asList("0", "0-1", "0-2", "0-3", "0-1-1", "0-1-2", "0-1-3", "0-2-1", "0-2-2", "0-2-3", "0-3-1", "0-3-2", "0-3-3")),
|
Arrays.asList("0", "0-1", "0-2", "0-3", "0-1-1", "0-1-2", "0-1-3", "0-2-1", "0-2-2", "0-2-3", "0-3-1", "0-3-2", "0-3-3"),
|
||||||
nodes
|
nodes
|
||||||
);
|
);
|
||||||
|
|
||||||
// 按广度优先寻找 0-2-3
|
// 按广度优先寻找 0-2-3
|
||||||
final String target = HierarchyUtil.traverseByBreadthFirst("0", HierarchyIteratorUtil.find(parentFinder(),
|
final String target = HierarchyUtil.traverseByBreadthFirst(root, HierarchyIteratorUtil.find(Node::getChildren,
|
||||||
t -> Objects.equals(t, "0-2-3") ? t : null
|
t -> Objects.equals(t.getValue(), "0-2-3") ? t.getValue() : null
|
||||||
));
|
));
|
||||||
Assertions.assertEquals("0-2-3", target);
|
Assertions.assertEquals("0-2-3", target);
|
||||||
|
|
||||||
// 按广度优先获取 0-2 的所有子节点
|
// 按广度优先获取 0-2 的所有子节点
|
||||||
final List<String> children = HierarchyUtil.traverseByBreadthFirst(
|
final List<String> children = HierarchyUtil.traverseByBreadthFirst(root, HierarchyIteratorUtil.collect(Node::getChildren,
|
||||||
"0", HierarchyIteratorUtil.collect(parentFinder(),
|
t -> Objects.equals(t.getParent(), "0-2") ? t.getValue() : null
|
||||||
t -> Objects.equals(tree.get(t), "0-2") ? t : null
|
));
|
||||||
)
|
|
||||||
);
|
|
||||||
Assertions.assertEquals(3, children.size());
|
Assertions.assertEquals(3, children.size());
|
||||||
Assertions.assertEquals(new ArrayList<>(Arrays.asList("0-2-1", "0-2-2", "0-2-3")), children);
|
Assertions.assertEquals(new ArrayList<>(Arrays.asList("0-2-1", "0-2-2", "0-2-3")), children);
|
||||||
}
|
}
|
||||||
@ -92,40 +100,28 @@ class HierarchyUtilTest {
|
|||||||
void testTraverseByDepthFirst() {
|
void testTraverseByDepthFirst() {
|
||||||
// 按深度优先遍历所有节点
|
// 按深度优先遍历所有节点
|
||||||
final Set<String> nodes = new LinkedHashSet<>();
|
final Set<String> nodes = new LinkedHashSet<>();
|
||||||
HierarchyUtil.traverseByDepthFirst("0", HierarchyIteratorUtil.scan(t -> {
|
HierarchyUtil.traverseByDepthFirst(root, HierarchyIteratorUtil.scan(t -> {
|
||||||
nodes.add(t);
|
nodes.add(t.getValue());
|
||||||
return tree.entrySet().stream()
|
return t.getChildren();
|
||||||
.filter(e -> Objects.equals(t, e.getValue()))
|
|
||||||
.map(Map.Entry::getKey)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}));
|
}));
|
||||||
Assertions.assertEquals(13, nodes.size());
|
Assertions.assertEquals(13, nodes.size());
|
||||||
Assertions.assertEquals(
|
Assertions.assertEquals(
|
||||||
new LinkedHashSet<>(Arrays.asList("0", "0-1", "0-1-1", "0-1-2", "0-1-3", "0-2", "0-2-1", "0-2-2", "0-2-3", "0-3", "0-3-1", "0-3-2", "0-3-3")),
|
new LinkedHashSet<>(Arrays.asList("0", "0-1", "0-1-1", "0-1-2", "0-1-3", "0-2", "0-2-1", "0-2-2", "0-2-3", "0-3", "0-3-1", "0-3-2", "0-3-3")),
|
||||||
nodes
|
nodes
|
||||||
);
|
);
|
||||||
|
|
||||||
// 按深度优先寻找 0-2-3
|
// 按深度优先寻找 0-2-3
|
||||||
final String target = HierarchyUtil.traverseByDepthFirst("0", HierarchyIteratorUtil.find(parentFinder(),
|
final String target = HierarchyUtil.traverseByDepthFirst(root, HierarchyIteratorUtil.find(Node::getChildren,
|
||||||
t -> Objects.equals(t, "0-2-3") ? t : null
|
t -> Objects.equals(t.getValue(), "0-2-3") ? t.getValue() : null
|
||||||
));
|
));
|
||||||
Assertions.assertEquals("0-2-3", target);
|
Assertions.assertEquals("0-2-3", target);
|
||||||
|
|
||||||
// 按深度优先获取 0-2 的所有子节点
|
// 按深度优先获取 0-2 的所有子节点
|
||||||
final List<String> children = HierarchyUtil.traverseByDepthFirst(
|
final List<String> children = HierarchyUtil.traverseByDepthFirst(root, HierarchyIteratorUtil.collect(Node::getChildren,
|
||||||
"0", HierarchyIteratorUtil.collect(parentFinder(),
|
t -> Objects.equals(t.getParent(), "0-2") ? t.getValue() : null
|
||||||
t -> Objects.equals(tree.get(t), "0-2") ? t : null
|
));
|
||||||
)
|
|
||||||
);
|
|
||||||
Assertions.assertEquals(3, children.size());
|
Assertions.assertEquals(3, children.size());
|
||||||
Assertions.assertEquals(new ArrayList<>(Arrays.asList("0-2-1", "0-2-2", "0-2-3")), children);
|
Assertions.assertEquals(new ArrayList<>(Arrays.asList("0-2-1", "0-2-2", "0-2-3")), children);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Function<String, Collection<String>> parentFinder() {
|
|
||||||
return t -> tree.entrySet()
|
|
||||||
.stream()
|
|
||||||
.filter(e -> Objects.equals(t, e.getValue()))
|
|
||||||
.map(Map.Entry::getKey)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -302,9 +302,8 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
|
|||||||
* @since 6.0.0
|
* @since 6.0.0
|
||||||
*/
|
*/
|
||||||
public byte[] encrypt(final byte[] data, final byte[] salt) {
|
public byte[] encrypt(final byte[] data, final byte[] salt) {
|
||||||
lock.lock();
|
|
||||||
|
|
||||||
byte[] result;
|
byte[] result;
|
||||||
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
final Cipher cipher = initMode(Cipher.ENCRYPT_MODE, salt);
|
final Cipher cipher = initMode(Cipher.ENCRYPT_MODE, salt);
|
||||||
result = cipher.doFinal(paddingDataWithZero(data, cipher.getBlockSize()));
|
result = cipher.doFinal(paddingDataWithZero(data, cipher.getBlockSize()));
|
||||||
@ -318,9 +317,8 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void encrypt(final InputStream data, final OutputStream out, final boolean isClose) throws IORuntimeException {
|
public void encrypt(final InputStream data, final OutputStream out, final boolean isClose) throws IORuntimeException {
|
||||||
lock.lock();
|
|
||||||
|
|
||||||
CipherOutputStream cipherOutputStream = null;
|
CipherOutputStream cipherOutputStream = null;
|
||||||
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
final Cipher cipher = initMode(Cipher.ENCRYPT_MODE, null);
|
final Cipher cipher = initMode(Cipher.ENCRYPT_MODE, null);
|
||||||
cipherOutputStream = new CipherOutputStream(out, cipher);
|
cipherOutputStream = new CipherOutputStream(out, cipher);
|
||||||
@ -358,10 +356,9 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
|
|||||||
public byte[] decrypt(final byte[] bytes) {
|
public byte[] decrypt(final byte[] bytes) {
|
||||||
final int blockSize;
|
final int blockSize;
|
||||||
final byte[] decryptData;
|
final byte[] decryptData;
|
||||||
|
|
||||||
lock.lock();
|
lock.lock();
|
||||||
final byte[] salt = SaltMagic.getSalt(bytes);
|
|
||||||
try {
|
try {
|
||||||
|
final byte[] salt = SaltMagic.getSalt(bytes);
|
||||||
final Cipher cipher = initMode(Cipher.DECRYPT_MODE, salt);
|
final Cipher cipher = initMode(Cipher.DECRYPT_MODE, salt);
|
||||||
blockSize = cipher.getBlockSize();
|
blockSize = cipher.getBlockSize();
|
||||||
decryptData = cipher.doFinal(SaltMagic.getData(bytes));
|
decryptData = cipher.doFinal(SaltMagic.getData(bytes));
|
||||||
@ -376,8 +373,8 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void decrypt(final InputStream data, final OutputStream out, final boolean isClose) throws IORuntimeException {
|
public void decrypt(final InputStream data, final OutputStream out, final boolean isClose) throws IORuntimeException {
|
||||||
lock.lock();
|
|
||||||
CipherInputStream cipherInputStream = null;
|
CipherInputStream cipherInputStream = null;
|
||||||
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
final Cipher cipher = initMode(Cipher.DECRYPT_MODE, null);
|
final Cipher cipher = initMode(Cipher.DECRYPT_MODE, null);
|
||||||
cipherInputStream = new CipherInputStream(data, cipher);
|
cipherInputStream = new CipherInputStream(data, cipher);
|
||||||
|
@ -160,8 +160,10 @@ public interface Dialect extends Serializable {
|
|||||||
* @since 5.7.2
|
* @since 5.7.2
|
||||||
*/
|
*/
|
||||||
default PreparedStatement psForCount(final Connection conn, SqlBuilder sqlBuilder) throws SQLException {
|
default PreparedStatement psForCount(final Connection conn, SqlBuilder sqlBuilder) throws SQLException {
|
||||||
|
// https://gitee.com/dromara/hutool/issues/I713XQ
|
||||||
|
// 为了兼容informix等数据库,此处使用count(*)而非count(1)
|
||||||
sqlBuilder = sqlBuilder
|
sqlBuilder = sqlBuilder
|
||||||
.insertPreFragment("SELECT count(1) from(")
|
.insertPreFragment("SELECT count(*) from(")
|
||||||
// issue#I3IJ8X@Gitee,在子查询时需设置单独别名,此处为了防止和用户的表名冲突,使用自定义的较长别名
|
// issue#I3IJ8X@Gitee,在子查询时需设置单独别名,此处为了防止和用户的表名冲突,使用自定义的较长别名
|
||||||
.append(") hutool_alias_count_");
|
.append(") hutool_alias_count_");
|
||||||
return psForPage(conn, sqlBuilder, null);
|
return psForPage(conn, sqlBuilder, null);
|
||||||
|
Loading…
Reference in New Issue
Block a user