mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-05 17:37:59 +08:00
Merge branch 'v5-dev' of gitee.com:dromara/hutool into v5-dev
This commit is contained in:
commit
60a8fd48f5
@ -3,7 +3,7 @@
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
# 5.7.17 (2021-11-16)
|
||||
# 5.7.17 (2021-11-19)
|
||||
|
||||
### 🐣新特性
|
||||
* 【core 】 增加AsyncUtil(pr#457@Gitee)
|
||||
@ -17,9 +17,13 @@
|
||||
* 【core 】 改进TextFinder,支持限制结束位置及反向查找模式
|
||||
* 【core 】 Opt增加部分方法(pr#459@Gitee)
|
||||
* 【core 】 增加DefaultCloneable(pr#459@Gitee)
|
||||
* 【core 】 CollStreamUtil增加是否并行的重载(pr#467@Gitee)
|
||||
* 【core 】 ResourceClassLoader增加缓存(pr#1959@Github)
|
||||
* 【crypto 】 增加CipherWrapper,增加setRandom(issue#1958@Github)
|
||||
*
|
||||
### 🐞Bug修复
|
||||
* 【core 】 修复FileResource构造fileName参数无效问题(issue#1942@Github)
|
||||
* 【cache 】 修复WeakCache键值强关联导致的无法回收问题(issue#1953@Github)
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
@ -17,11 +17,11 @@ public class CacheObj<K, V> implements Serializable{
|
||||
protected final V obj;
|
||||
|
||||
/** 上次访问时间 */
|
||||
private volatile long lastAccess;
|
||||
protected volatile long lastAccess;
|
||||
/** 访问次数 */
|
||||
protected AtomicLong accessCount = new AtomicLong();
|
||||
/** 对象存活时长,0表示永久存活*/
|
||||
private final long ttl;
|
||||
protected final long ttl;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
|
@ -1,5 +1,10 @@
|
||||
package cn.hutool.cache.impl;
|
||||
|
||||
import cn.hutool.cache.Cache;
|
||||
import cn.hutool.core.lang.func.Func0;
|
||||
import cn.hutool.core.lang.mutable.MutableObj;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
@ -7,18 +12,112 @@ import java.util.WeakHashMap;
|
||||
* 对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。<br>
|
||||
* 丢弃某个键时,其条目从映射中有效地移除。<br>
|
||||
*
|
||||
* @param <K> 键类型
|
||||
* @param <V> 值类型
|
||||
* @author Looly
|
||||
*
|
||||
* @param <K> 键
|
||||
* @param <V> 值
|
||||
* @author looly
|
||||
* @since 3.0.7
|
||||
*/
|
||||
public class WeakCache<K, V> extends TimedCache<K, V>{
|
||||
public class WeakCache<K, V> implements Cache<K, V> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
TimedCache<MutableObj<K>, V> timedCache;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param timeout 超时
|
||||
*/
|
||||
public WeakCache(long timeout) {
|
||||
super(timeout, new WeakHashMap<>());
|
||||
this.timedCache = new TimedCache<>(timeout, new WeakHashMap<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int capacity() {
|
||||
return timedCache.capacity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long timeout() {
|
||||
return timedCache.timeout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, V object) {
|
||||
timedCache.put(new MutableObj<>(key), object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(K key, V object, long timeout) {
|
||||
timedCache.put(new MutableObj<>(key), object, timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(K key, boolean isUpdateLastAccess, Func0<V> supplier) {
|
||||
return timedCache.get(new MutableObj<>(key), isUpdateLastAccess, supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(K key, boolean isUpdateLastAccess) {
|
||||
return timedCache.get(new MutableObj<>(key), isUpdateLastAccess);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<CacheObj<K, V>> cacheObjIterator() {
|
||||
final Iterator<CacheObj<MutableObj<K>, V>> timedIter = timedCache.cacheObjIterator();
|
||||
return new Iterator<CacheObj<K, V>>() {
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return timedIter.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CacheObj<K, V> next() {
|
||||
final CacheObj<MutableObj<K>, V> next = timedIter.next();
|
||||
final CacheObj<K, V> nextNew = new CacheObj<>(next.key.get(), next.obj, next.ttl);
|
||||
nextNew.lastAccess = next.lastAccess;
|
||||
nextNew.accessCount = next.accessCount;
|
||||
return nextNew;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int prune() {
|
||||
return timedCache.prune();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFull() {
|
||||
return timedCache.isFull();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(K key) {
|
||||
timedCache.remove(new MutableObj<>(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
timedCache.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return timedCache.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return timedCache.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(K key) {
|
||||
return timedCache.containsKey(new MutableObj<>(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<V> iterator() {
|
||||
return timedCache.iterator();
|
||||
}
|
||||
}
|
||||
|
21
hutool-cache/src/test/java/cn/hutool/cache/WeakCacheTest.java
vendored
Normal file
21
hutool-cache/src/test/java/cn/hutool/cache/WeakCacheTest.java
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
package cn.hutool.cache;
|
||||
|
||||
import cn.hutool.cache.impl.WeakCache;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class WeakCacheTest {
|
||||
|
||||
@Test
|
||||
public void removeTest(){
|
||||
final WeakCache<String, String> cache = new WeakCache<>(-1);
|
||||
cache.put("abc", "123");
|
||||
cache.put("def", "456");
|
||||
|
||||
Assert.assertEquals(2, cache.size());
|
||||
|
||||
cache.remove("abc");
|
||||
|
||||
Assert.assertEquals(1, cache.size());
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package cn.hutool.core.collection;
|
||||
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.stream.StreamUtil;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiFunction;
|
||||
@ -27,10 +28,27 @@ public class CollStreamUtil {
|
||||
* @return 转化后的map
|
||||
*/
|
||||
public static <V, K> Map<K, V> toIdentityMap(Collection<V> collection, Function<V, K> key) {
|
||||
return toIdentityMap(collection, key, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将collection转化为类型不变的map<br>
|
||||
* <B>{@code Collection<V> ----> Map<K,V>}</B>
|
||||
*
|
||||
* @param collection 需要转化的集合
|
||||
* @param key V类型转化为K类型的lambda方法
|
||||
* @param isParallel 是否并行流
|
||||
* @param <V> collection中的泛型
|
||||
* @param <K> map中的key类型
|
||||
* @return 转化后的map
|
||||
*/
|
||||
public static <V, K> Map<K, V> toIdentityMap(Collection<V> collection, Function<V, K> key, boolean isParallel) {
|
||||
if (CollUtil.isEmpty(collection)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return collection.stream().collect(Collectors.toMap(key, Function.identity(), (l, r) -> l));
|
||||
return StreamUtil.of(collection, isParallel)
|
||||
.collect(Collectors.toMap(key, Function.identity(), (l, r) -> l));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -46,12 +64,27 @@ public class CollStreamUtil {
|
||||
* @return 转化后的map
|
||||
*/
|
||||
public static <E, K, V> Map<K, V> toMap(Collection<E> collection, Function<E, K> key, Function<E, V> value) {
|
||||
return toMap(collection, key, value, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param collection 需要转化的集合
|
||||
* @param key E类型转化为K类型的lambda方法
|
||||
* @param value E类型转化为V类型的lambda方法
|
||||
* @param isParallel 是否并行流
|
||||
* @param <E> collection中的泛型
|
||||
* @param <K> map中的key类型
|
||||
* @param <V> map中的value类型
|
||||
* @return 转化后的map
|
||||
*/
|
||||
public static <E, K, V> Map<K, V> toMap(Collection<E> collection, Function<E, K> key, Function<E, V> value, boolean isParallel) {
|
||||
if (CollUtil.isEmpty(collection)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return collection.stream().collect(Collectors.toMap(key, value, (l, r) -> l));
|
||||
return StreamUtil.of(collection, isParallel).collect(Collectors.toMap(key, value, (l, r) -> l));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将collection按照规则(比如有相同的班级id)分类成map<br>
|
||||
* <B>{@code Collection<E> -------> Map<K,List<E>> } </B>
|
||||
@ -63,12 +96,25 @@ public class CollStreamUtil {
|
||||
* @return 分类后的map
|
||||
*/
|
||||
public static <E, K> Map<K, List<E>> groupByKey(Collection<E> collection, Function<E, K> key) {
|
||||
return groupByKey(collection, key, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将collection按照规则(比如有相同的班级id)分类成map<br>
|
||||
* <B>{@code Collection<E> -------> Map<K,List<E>> } </B>
|
||||
*
|
||||
* @param collection 需要分类的集合
|
||||
* @param key 分类的规则
|
||||
* @param isParallel 是否并行流
|
||||
* @param <E> collection中的泛型
|
||||
* @param <K> map中的key类型
|
||||
* @return 分类后的map
|
||||
*/
|
||||
public static <E, K> Map<K, List<E>> groupByKey(Collection<E> collection, Function<E, K> key, boolean isParallel) {
|
||||
if (CollUtil.isEmpty(collection)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return collection
|
||||
.stream()
|
||||
.collect(Collectors.groupingBy(key, Collectors.toList()));
|
||||
return StreamUtil.of(collection, isParallel).collect(Collectors.groupingBy(key, Collectors.toList()));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -84,11 +130,29 @@ public class CollStreamUtil {
|
||||
* @return 分类后的map
|
||||
*/
|
||||
public static <E, K, U> Map<K, Map<U, List<E>>> groupBy2Key(Collection<E> collection, Function<E, K> key1, Function<E, U> key2) {
|
||||
return groupBy2Key(collection, key1, key2, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map<br>
|
||||
* <B>{@code Collection<E> ---> Map<T,Map<U,List<E>>> } </B>
|
||||
*
|
||||
* @param collection 需要分类的集合
|
||||
* @param key1 第一个分类的规则
|
||||
* @param key2 第二个分类的规则
|
||||
* @param isParallel 是否并行流
|
||||
* @param <E> 集合元素类型
|
||||
* @param <K> 第一个map中的key类型
|
||||
* @param <U> 第二个map中的key类型
|
||||
* @return 分类后的map
|
||||
*/
|
||||
public static <E, K, U> Map<K, Map<U, List<E>>> groupBy2Key(Collection<E> collection, Function<E, K> key1,
|
||||
Function<E, U> key2, boolean isParallel) {
|
||||
if (CollUtil.isEmpty(collection)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return collection
|
||||
.stream()
|
||||
return StreamUtil.of(collection, isParallel)
|
||||
.collect(Collectors.groupingBy(key1, Collectors.groupingBy(key2, Collectors.toList())));
|
||||
}
|
||||
|
||||
@ -105,11 +169,28 @@ public class CollStreamUtil {
|
||||
* @return 分类后的map
|
||||
*/
|
||||
public static <E, T, U> Map<T, Map<U, E>> group2Map(Collection<E> collection, Function<E, T> key1, Function<E, U> key2) {
|
||||
return group2Map(collection, key1, key2, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map<br>
|
||||
* <B>{@code Collection<E> ---> Map<T,Map<U,E>> } </B>
|
||||
*
|
||||
* @param collection 需要分类的集合
|
||||
* @param key1 第一个分类的规则
|
||||
* @param key2 第二个分类的规则
|
||||
* @param isParallel 是否并行流
|
||||
* @param <T> 第一个map中的key类型
|
||||
* @param <U> 第二个map中的key类型
|
||||
* @param <E> collection中的泛型
|
||||
* @return 分类后的map
|
||||
*/
|
||||
public static <E, T, U> Map<T, Map<U, E>> group2Map(Collection<E> collection,
|
||||
Function<E, T> key1, Function<E, U> key2, boolean isParallel) {
|
||||
if (CollUtil.isEmpty(collection) || key1 == null || key2 == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return collection
|
||||
.stream()
|
||||
return StreamUtil.of(collection, isParallel)
|
||||
.collect(Collectors.groupingBy(key1, Collectors.toMap(key2, Function.identity(), (l, r) -> l)));
|
||||
}
|
||||
|
||||
@ -124,11 +205,25 @@ public class CollStreamUtil {
|
||||
* @return 转化后的list
|
||||
*/
|
||||
public static <E, T> List<T> toList(Collection<E> collection, Function<E, T> function) {
|
||||
return toList(collection, function, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将collection转化为List集合,但是两者的泛型不同<br>
|
||||
* <B>{@code Collection<E> ------> List<T> } </B>
|
||||
*
|
||||
* @param collection 需要转化的集合
|
||||
* @param function collection中的泛型转化为list泛型的lambda表达式
|
||||
* @param isParallel 是否并行流
|
||||
* @param <E> collection中的泛型
|
||||
* @param <T> List中的泛型
|
||||
* @return 转化后的list
|
||||
*/
|
||||
public static <E, T> List<T> toList(Collection<E> collection, Function<E, T> function, boolean isParallel) {
|
||||
if (CollUtil.isEmpty(collection)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return collection
|
||||
.stream()
|
||||
return StreamUtil.of(collection, isParallel)
|
||||
.map(function)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
@ -145,11 +240,25 @@ public class CollStreamUtil {
|
||||
* @return 转化后的Set
|
||||
*/
|
||||
public static <E, T> Set<T> toSet(Collection<E> collection, Function<E, T> function) {
|
||||
if (CollUtil.isEmpty(collection) || function == null) {
|
||||
return toSet(collection, function, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将collection转化为Set集合,但是两者的泛型不同<br>
|
||||
* <B>{@code Collection<E> ------> Set<T> } </B>
|
||||
*
|
||||
* @param collection 需要转化的集合
|
||||
* @param function collection中的泛型转化为set泛型的lambda表达式
|
||||
* @param isParallel 是否并行流
|
||||
* @param <E> collection中的泛型
|
||||
* @param <T> Set中的泛型
|
||||
* @return 转化后的Set
|
||||
*/
|
||||
public static <E, T> Set<T> toSet(Collection<E> collection, Function<E, T> function, boolean isParallel) {
|
||||
if (CollUtil.isEmpty(collection)) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
return collection
|
||||
.stream()
|
||||
return StreamUtil.of(collection, isParallel)
|
||||
.map(function)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
|
@ -12,12 +12,16 @@ import java.util.Map;
|
||||
* 资源类加载器,可以加载任意类型的资源类
|
||||
*
|
||||
* @param <T> {@link Resource}接口实现类
|
||||
* @author looly
|
||||
* @author looly, lzpeng
|
||||
* @since 5.5.2
|
||||
*/
|
||||
public class ResourceClassLoader<T extends Resource> extends SecureClassLoader {
|
||||
|
||||
private final Map<String, T> resourceMap;
|
||||
/**
|
||||
* 缓存已经加载的类
|
||||
*/
|
||||
private final Map<String, Class<?>> cacheClassMap;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
@ -28,25 +32,42 @@ public class ResourceClassLoader<T extends Resource> extends SecureClassLoader {
|
||||
public ResourceClassLoader(ClassLoader parentClassLoader, Map<String, T> resourceMap) {
|
||||
super(ObjectUtil.defaultIfNull(parentClassLoader, ClassLoaderUtil.getClassLoader()));
|
||||
this.resourceMap = ObjectUtil.defaultIfNull(resourceMap, new HashMap<>());
|
||||
this.cacheClassMap = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加需要加载的类资源
|
||||
*
|
||||
* @param resource 资源,可以是文件、流或者字符串
|
||||
* @return this
|
||||
*/
|
||||
public ResourceClassLoader<T> addResource(T resource){
|
||||
public ResourceClassLoader<T> addResource(T resource) {
|
||||
this.resourceMap.put(resource.getName(), resource);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(String name) throws ClassNotFoundException {
|
||||
final Class<?> clazz = cacheClassMap.computeIfAbsent(name, this::defineByName);
|
||||
if (clazz == null) {
|
||||
return super.findClass(name);
|
||||
}
|
||||
return clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从给定资源中读取class的二进制流,然后生成类<br>
|
||||
* 如果这个类资源不存在,返回{@code null}
|
||||
*
|
||||
* @param name 类名
|
||||
* @return 定义的类
|
||||
*/
|
||||
private Class<?> defineByName(String name) {
|
||||
final Resource resource = resourceMap.get(name);
|
||||
if (null != resource) {
|
||||
final byte[] bytes = resource.readBytes();
|
||||
return defineClass(name, bytes, 0, bytes.length);
|
||||
}
|
||||
return super.findClass(name);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
121
hutool-crypto/src/main/java/cn/hutool/crypto/CipherWrapper.java
Normal file
121
hutool-crypto/src/main/java/cn/hutool/crypto/CipherWrapper.java
Normal file
@ -0,0 +1,121 @@
|
||||
package cn.hutool.crypto;
|
||||
|
||||
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}包装类,提供初始化模式等额外方法<br>
|
||||
* 包装之后可提供自定义或默认的:
|
||||
* <ul>
|
||||
* <li>{@link AlgorithmParameterSpec}</li>
|
||||
* <li>{@link SecureRandom}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.7.17
|
||||
*/
|
||||
public class CipherWrapper {
|
||||
|
||||
private final Cipher cipher;
|
||||
/**
|
||||
* 算法参数
|
||||
*/
|
||||
private AlgorithmParameterSpec params;
|
||||
/**
|
||||
* 随机数生成器,可自定义随机数种子
|
||||
*/
|
||||
private SecureRandom random;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param algorithm 算法名称
|
||||
*/
|
||||
public CipherWrapper(String algorithm) {
|
||||
this(SecureUtil.createCipher(algorithm));
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param cipher {@link Cipher}
|
||||
*/
|
||||
public CipherWrapper(Cipher cipher) {
|
||||
this.cipher = cipher;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取{@link AlgorithmParameterSpec}<br>
|
||||
* 在某些算法中,需要特别的参数,例如在ECIES中,此处为IESParameterSpec
|
||||
*
|
||||
* @return {@link AlgorithmParameterSpec}
|
||||
*/
|
||||
public AlgorithmParameterSpec getParams() {
|
||||
return this.params;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 {@link AlgorithmParameterSpec},通常用于加盐或偏移向量
|
||||
*
|
||||
* @param params {@link AlgorithmParameterSpec}
|
||||
* @return this
|
||||
*/
|
||||
public CipherWrapper setParams(AlgorithmParameterSpec params) {
|
||||
this.params = params;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置随机数生成器,可自定义随机数种子
|
||||
*
|
||||
* @param random 随机数生成器,可自定义随机数种子
|
||||
* @return this
|
||||
*/
|
||||
public CipherWrapper setRandom(SecureRandom random) {
|
||||
this.random = random;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取被包装的{@link Cipher}
|
||||
*
|
||||
* @return {@link Cipher}
|
||||
*/
|
||||
public Cipher getCipher() {
|
||||
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(int mode, 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;
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package cn.hutool.crypto.asymmetric;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.io.FastByteArrayOutputStream;
|
||||
import cn.hutool.crypto.CipherWrapper;
|
||||
import cn.hutool.crypto.CryptoException;
|
||||
import cn.hutool.crypto.KeyUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
@ -16,6 +17,7 @@ import java.security.InvalidKeyException;
|
||||
import java.security.Key;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
|
||||
/**
|
||||
@ -37,7 +39,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
|
||||
/**
|
||||
* Cipher负责完成加密或解密工作
|
||||
*/
|
||||
protected Cipher cipher;
|
||||
protected CipherWrapper cipherWrapper;
|
||||
|
||||
/**
|
||||
* 加密的块大小
|
||||
@ -47,12 +49,6 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
|
||||
* 解密的块大小
|
||||
*/
|
||||
protected int decryptBlockSize = -1;
|
||||
|
||||
/**
|
||||
* 算法参数
|
||||
*/
|
||||
private AlgorithmParameterSpec algorithmParameterSpec;
|
||||
|
||||
// ------------------------------------------------------------------ Constructor start
|
||||
|
||||
/**
|
||||
@ -201,7 +197,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
|
||||
* @since 5.4.3
|
||||
*/
|
||||
public AlgorithmParameterSpec getAlgorithmParameterSpec() {
|
||||
return algorithmParameterSpec;
|
||||
return this.cipherWrapper.getParams();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -212,7 +208,19 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
|
||||
* @since 5.4.3
|
||||
*/
|
||||
public void setAlgorithmParameterSpec(AlgorithmParameterSpec algorithmParameterSpec) {
|
||||
this.algorithmParameterSpec = algorithmParameterSpec;
|
||||
this.cipherWrapper.setParams(algorithmParameterSpec);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置随机数生成器,可自定义随机数种子
|
||||
*
|
||||
* @param random 随机数生成器,可自定义随机数种子
|
||||
* @return this
|
||||
* @since 5.7.17
|
||||
*/
|
||||
public AsymmetricCrypto setRandom(SecureRandom random) {
|
||||
this.cipherWrapper.setRandom(random);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -229,11 +237,11 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
|
||||
final Key key = getKeyByType(keyType);
|
||||
lock.lock();
|
||||
try {
|
||||
initMode(Cipher.ENCRYPT_MODE, key);
|
||||
final Cipher cipher = initMode(Cipher.ENCRYPT_MODE, key);
|
||||
|
||||
if (this.encryptBlockSize < 0) {
|
||||
// 在引入BC库情况下,自动获取块大小
|
||||
final int blockSize = this.cipher.getBlockSize();
|
||||
final int blockSize = cipher.getBlockSize();
|
||||
if (blockSize > 0) {
|
||||
this.encryptBlockSize = blockSize;
|
||||
}
|
||||
@ -254,11 +262,11 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
|
||||
final Key key = getKeyByType(keyType);
|
||||
lock.lock();
|
||||
try {
|
||||
initMode(Cipher.DECRYPT_MODE, key);
|
||||
final Cipher cipher = initMode(Cipher.DECRYPT_MODE, key);
|
||||
|
||||
if (this.decryptBlockSize < 0) {
|
||||
// 在引入BC库情况下,自动获取块大小
|
||||
final int blockSize = this.cipher.getBlockSize();
|
||||
final int blockSize = cipher.getBlockSize();
|
||||
if (blockSize > 0) {
|
||||
this.decryptBlockSize = blockSize;
|
||||
}
|
||||
@ -281,7 +289,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
|
||||
* @since 5.4.3
|
||||
*/
|
||||
public Cipher getCipher() {
|
||||
return cipher;
|
||||
return this.cipherWrapper.getCipher();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -290,7 +298,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
|
||||
* @since 4.5.2
|
||||
*/
|
||||
protected void initCipher() {
|
||||
this.cipher = SecureUtil.createCipher(algorithm);
|
||||
this.cipherWrapper = new CipherWrapper(this.algorithm);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -309,7 +317,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
|
||||
|
||||
// 不足分段
|
||||
if (dataLength <= maxBlockSize) {
|
||||
return this.cipher.doFinal(data, 0, dataLength);
|
||||
return getCipher().doFinal(data, 0, dataLength);
|
||||
}
|
||||
|
||||
// 分段解密
|
||||
@ -337,7 +345,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
|
||||
// 对数据分段处理
|
||||
while (remainLength > 0) {
|
||||
blockSize = Math.min(remainLength, maxBlockSize);
|
||||
out.write(cipher.doFinal(data, offSet, blockSize));
|
||||
out.write(getCipher().doFinal(data, offSet, blockSize));
|
||||
|
||||
offSet += blockSize;
|
||||
remainLength = dataLength - offSet;
|
||||
@ -351,14 +359,11 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
|
||||
*
|
||||
* @param mode 模式,可选{@link Cipher#ENCRYPT_MODE}或者{@link Cipher#DECRYPT_MODE}
|
||||
* @param key 密钥
|
||||
* @return {@link Cipher}
|
||||
* @throws InvalidAlgorithmParameterException 异常算法错误
|
||||
* @throws InvalidKeyException 异常KEY错误
|
||||
*/
|
||||
private void initMode(int mode, Key key) throws InvalidAlgorithmParameterException, InvalidKeyException {
|
||||
if (null != this.algorithmParameterSpec) {
|
||||
cipher.init(mode, key, this.algorithmParameterSpec);
|
||||
} else {
|
||||
cipher.init(mode, key);
|
||||
}
|
||||
private Cipher initMode(int mode, Key key) throws InvalidAlgorithmParameterException, InvalidKeyException {
|
||||
return this.cipherWrapper.initMode(mode, key).getCipher();
|
||||
}
|
||||
}
|
||||
|
@ -3,15 +3,16 @@ package cn.hutool.crypto.symmetric;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.lang.Opt;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.HexUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.CipherMode;
|
||||
import cn.hutool.crypto.CipherWrapper;
|
||||
import cn.hutool.crypto.CryptoException;
|
||||
import cn.hutool.crypto.KeyUtil;
|
||||
import cn.hutool.crypto.Padding;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.CipherInputStream;
|
||||
@ -25,6 +26,7 @@ import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
@ -40,18 +42,11 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor, Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private CipherWrapper cipherWrapper;
|
||||
/**
|
||||
* SecretKey 负责保存对称密钥
|
||||
*/
|
||||
private SecretKey secretKey;
|
||||
/**
|
||||
* Cipher负责完成加密或解密工作
|
||||
*/
|
||||
private Cipher cipher;
|
||||
/**
|
||||
* 加密解密参数
|
||||
*/
|
||||
private AlgorithmParameterSpec params;
|
||||
/**
|
||||
* 是否0填充
|
||||
*/
|
||||
@ -152,7 +147,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
|
||||
this.isZeroPadding = true;
|
||||
}
|
||||
|
||||
this.cipher = SecureUtil.createCipher(algorithm);
|
||||
this.cipherWrapper = new CipherWrapper(algorithm);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -171,7 +166,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
|
||||
* @return 加密或解密
|
||||
*/
|
||||
public Cipher getCipher() {
|
||||
return cipher;
|
||||
return cipherWrapper.getCipher();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -181,7 +176,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
|
||||
* @return 自身
|
||||
*/
|
||||
public SymmetricCrypto setParams(AlgorithmParameterSpec params) {
|
||||
this.params = params;
|
||||
this.cipherWrapper.setParams(params);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -192,8 +187,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
|
||||
* @return 自身
|
||||
*/
|
||||
public SymmetricCrypto setIv(IvParameterSpec iv) {
|
||||
setParams(iv);
|
||||
return this;
|
||||
return setParams(iv);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -203,7 +197,18 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
|
||||
* @return 自身
|
||||
*/
|
||||
public SymmetricCrypto setIv(byte[] iv) {
|
||||
setIv(new IvParameterSpec(iv));
|
||||
return setIv(new IvParameterSpec(iv));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置随机数生成器,可自定义随机数种子
|
||||
*
|
||||
* @param random 随机数生成器,可自定义随机数种子
|
||||
* @return this
|
||||
* @since 5.7.17
|
||||
*/
|
||||
public SymmetricCrypto setRandom(SecureRandom random){
|
||||
this.cipherWrapper.setRandom(random);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -237,6 +242,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
|
||||
* @since 5.6.8
|
||||
*/
|
||||
public byte[] update(byte[] data) {
|
||||
final Cipher cipher = cipherWrapper.getCipher();
|
||||
lock.lock();
|
||||
try {
|
||||
return cipher.update(paddingDataWithZero(data, cipher.getBlockSize()));
|
||||
@ -376,11 +382,8 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
|
||||
*/
|
||||
private SymmetricCrypto initParams(String algorithm, AlgorithmParameterSpec paramsSpec) {
|
||||
if (null == paramsSpec) {
|
||||
byte[] iv = null;
|
||||
final Cipher cipher = this.cipher;
|
||||
if (null != cipher) {
|
||||
iv = cipher.getIV();
|
||||
}
|
||||
byte[] iv = Opt.ofNullable(cipherWrapper)
|
||||
.map(CipherWrapper::getCipher).map(Cipher::getIV).get();
|
||||
|
||||
// 随机IV
|
||||
if (StrUtil.startWithIgnoreCase(algorithm, "PBE")) {
|
||||
@ -409,13 +412,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
|
||||
* @throws InvalidAlgorithmParameterException 无效算法
|
||||
*/
|
||||
private Cipher initMode(int mode) throws InvalidKeyException, InvalidAlgorithmParameterException {
|
||||
final Cipher cipher = this.cipher;
|
||||
if (null == this.params) {
|
||||
cipher.init(mode, secretKey);
|
||||
} else {
|
||||
cipher.init(mode, secretKey, params);
|
||||
}
|
||||
return cipher;
|
||||
return this.cipherWrapper.initMode(mode, this.secretKey).getCipher();
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user