This commit is contained in:
Looly 2022-07-29 23:05:20 +08:00
parent a36a970341
commit 7769822e11
17 changed files with 237 additions and 27 deletions

View File

@ -60,7 +60,7 @@ public class CopyOptions implements Serializable {
*/ */
protected boolean transientSupport = true; protected boolean transientSupport = true;
/** /**
* 是否覆盖目标值如果不覆盖会先读取目标对象的值{@code null}则写否则忽略如果覆盖则不判断直接写 * 是否覆盖目标值如果不覆盖会先读取目标对象的值{@code null}则写否则忽略如果覆盖则不判断直接写
*/ */
protected boolean override = true; protected boolean override = true;
@ -282,7 +282,7 @@ public class CopyOptions implements Serializable {
} }
/** /**
* 设置是否覆盖目标值如果不覆盖会先读取目标对象的值{@code null}则写否则忽略如果覆盖则不判断直接写 * 设置是否覆盖目标值如果不覆盖会先读取目标对象的值{@code null}则写否则忽略如果覆盖则不判断直接写
* *
* @param override 是否覆盖目标值 * @param override 是否覆盖目标值
* @return this * @return this

View File

@ -263,6 +263,10 @@ public class Base64 {
* @since 5.7.5 * @since 5.7.5
*/ */
public static boolean isBase64(final byte[] base64Bytes) { public static boolean isBase64(final byte[] base64Bytes) {
if (base64Bytes == null || base64Bytes.length < 3) {
return false;
}
boolean hasPadding = false; boolean hasPadding = false;
for (final byte base64Byte : base64Bytes) { for (final byte base64Byte : base64Bytes) {
if (hasPadding) { if (hasPadding) {

View File

@ -29,6 +29,7 @@ import java.nio.file.FileSystem;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
@ -260,6 +261,7 @@ public class ZipUtil {
*/ */
public static File zip(final File zipFile, final Charset charset, final boolean withSrcDir, final FileFilter filter, final File... srcFiles) throws IORuntimeException { public static File zip(final File zipFile, final Charset charset, final boolean withSrcDir, final FileFilter filter, final File... srcFiles) throws IORuntimeException {
validateFiles(zipFile, srcFiles); validateFiles(zipFile, srcFiles);
//noinspection resource
ZipWriter.of(zipFile, charset).add(withSrcDir, filter, srcFiles).close(); ZipWriter.of(zipFile, charset).add(withSrcDir, filter, srcFiles).close();
return zipFile; return zipFile;
} }
@ -412,6 +414,7 @@ public class ZipUtil {
* @since 5.5.2 * @since 5.5.2
*/ */
public static File zip(final File zipFile, final Charset charset, final Resource... resources) throws UtilException { public static File zip(final File zipFile, final Charset charset, final Resource... resources) throws UtilException {
//noinspection resource
ZipWriter.of(zipFile, charset).add(resources).close(); ZipWriter.of(zipFile, charset).add(resources).close();
return zipFile; return zipFile;
} }
@ -528,11 +531,38 @@ public class ZipUtil {
* @since 4.5.8 * @since 4.5.8
*/ */
public static File unzip(final ZipFile zipFile, final File outFile) throws IORuntimeException { public static File unzip(final ZipFile zipFile, final File outFile) throws IORuntimeException {
return unzip(zipFile, outFile, -1);
}
/**
* 限制解压后文件大小
*
* @param zipFile zip文件附带编码信息使用完毕自动关闭
* @param outFile 解压到的目录
* @param limit 限制解压文件大小(单位B)
* @return 解压的目录
* @throws IORuntimeException IO异常
* @since 5.8.5
*/
public static File unzip(ZipFile zipFile, File outFile, long limit) throws IORuntimeException {
if (outFile.exists() && outFile.isFile()) { if (outFile.exists() && outFile.isFile()) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
StrUtil.format("Target path [{}] exist!", outFile.getAbsolutePath())); StrUtil.format("Target path [{}] exist!", outFile.getAbsolutePath()));
} }
// pr#726@Gitee
if (limit > 0) {
final Enumeration<? extends ZipEntry> zipEntries = zipFile.entries();
long zipFileSize = 0L;
while (zipEntries.hasMoreElements()) {
ZipEntry zipEntry = zipEntries.nextElement();
zipFileSize += zipEntry.getSize();
if (zipFileSize > limit) {
throw new IllegalArgumentException("The file size exceeds the limit");
}
}
}
try (final ZipReader reader = new ZipReader(zipFile)) { try (final ZipReader reader = new ZipReader(zipFile)) {
reader.readTo(outFile); reader.readTo(outFile);
} }

View File

@ -605,7 +605,7 @@ public class Convert {
} }
/** /**
* 转换为Map * 转换为Map若value原本就是Map则转为原始类型若不是则默认转为HashMap
* *
* @param <K> 键类型 * @param <K> 键类型
* @param <V> 值类型 * @param <V> 值类型
@ -615,9 +615,28 @@ public class Convert {
* @return {@link Map} * @return {@link Map}
* @since 4.6.8 * @since 4.6.8
*/ */
@SuppressWarnings("unchecked") public static <K, V> Map<K, V> toMap(Class<K> keyType, Class<V> valueType, Object value) {
public static <K, V> Map<K, V> toMap(final Class<K> keyType, final Class<V> valueType, final Object value) { if (value instanceof Map) {
return (Map<K, V>) new MapConverter().convert(HashMap.class, keyType, valueType, value); return toMap(value.getClass(), keyType, valueType, value);
} else {
return toMap(HashMap.class, keyType, valueType, value);
}
}
/**
* 转换为Map
*
* @param mapType 转后的具体Map类型
* @param <K> 键类型
* @param <V> 值类型
* @param keyType 键类型
* @param valueType 值类型
* @param value 被转换的值
* @return {@link Map}
*/
@SuppressWarnings({"unchecked"})
public static <K, V> Map<K, V> toMap(Class<?> mapType, Class<K> keyType, Class<V> valueType, Object value) {
return (Map<K, V>) MapConverter.INSTANCE.convert(mapType, keyType, valueType, value);
} }
/** /**

View File

@ -86,13 +86,13 @@ public class NetUtil {
/** /**
* 将IPv6地址字符串转为大整数 * 将IPv6地址字符串转为大整数
* *
* @param IPv6Str 字符串 * @param ipv6Str 字符串
* @return 大整数, 如发生异常返回 null * @return 大整数, 如发生异常返回 null
* @since 5.5.7 * @since 5.5.7
*/ */
public static BigInteger ipv6ToBitInteger(final String IPv6Str) { public static BigInteger ipv6ToBigInteger(final String ipv6Str) {
try { try {
final InetAddress address = InetAddress.getByName(IPv6Str); final InetAddress address = InetAddress.getByName(ipv6Str);
if (address instanceof Inet6Address) { if (address instanceof Inet6Address) {
return new BigInteger(1, address.getAddress()); return new BigInteger(1, address.getAddress());
} }

View File

@ -133,7 +133,7 @@ public class PatternPool {
/** /**
* 时间正则 * 时间正则
*/ */
public static final Pattern TIME = Pattern.compile("\\d{1,2}:\\d{1,2}(:\\d{1,2})?"); public static final Pattern TIME = Pattern.compile(RegexPool.TIME);
/** /**
* 中国车牌号码兼容新能源车牌 * 中国车牌号码兼容新能源车牌
*/ */

View File

@ -64,4 +64,25 @@ public class BeanCopierTest {
private static class B { private static class B {
private String value; private String value;
} }
/**
* {@code null}则写否则忽略如果覆盖则不判断直接写
*/
@Test
public void issues2484Test() {
final A a = new A();
a.setValue("abc");
final B b = new B();
b.setValue("123");
BeanCopier<B> copier = BeanCopier.of(a, b, CopyOptions.of().setOverride(false));
copier.copy();
Assert.assertEquals("123", b.getValue());
b.setValue(null);
copier = BeanCopier.of(a, b, CopyOptions.of().setOverride(false));
copier.copy();
Assert.assertEquals("abc", b.getValue());
}
} }

View File

@ -1,6 +1,7 @@
package cn.hutool.core.convert; package cn.hutool.core.convert;
import cn.hutool.core.bean.BeanUtilTest.SubPerson; import cn.hutool.core.bean.BeanUtilTest.SubPerson;
import cn.hutool.core.map.CaseInsensitiveMap;
import cn.hutool.core.reflect.TypeReference; import cn.hutool.core.reflect.TypeReference;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@ -91,4 +92,30 @@ public class ConvertToBeanTest {
final SubPerson subPerson = Convert.convertQuietly(SubPerson.class, nullStr); final SubPerson subPerson = Convert.convertQuietly(SubPerson.class, nullStr);
Assert.assertNull(subPerson); Assert.assertNull(subPerson);
} }
@Test
public void mapToMapWithSelfTypeTest() {
final CaseInsensitiveMap<String, Integer> caseInsensitiveMap = new CaseInsensitiveMap<>();
caseInsensitiveMap.put("jerry", 1);
caseInsensitiveMap.put("Jerry", 2);
caseInsensitiveMap.put("tom", 3);
Map<String, String> map = Convert.toMap(String.class, String.class, caseInsensitiveMap);
Assert.assertEquals("2", map.get("jerry"));
Assert.assertEquals("2", map.get("Jerry"));
Assert.assertEquals("3", map.get("tom"));
}
@Test
public void beanToSpecifyMapTest() {
final SubPerson person = new SubPerson();
person.setAge(14);
person.setOpenid("11213232");
person.setName("测试A11");
person.setSubName("sub名字");
Map<String, String> map = Convert.toMap(LinkedHashMap.class, String.class, String.class, person);
Assert.assertEquals("测试A11", map.get("name"));
Assert.assertEquals("14", map.get("age"));
Assert.assertEquals("11213232", map.get("openid"));
}
} }

View File

@ -18,6 +18,7 @@ import java.io.OutputStream;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.zip.ZipFile;
/** /**
* {@link ZipUtil}单元测试 * {@link ZipUtil}单元测试
@ -197,4 +198,19 @@ public class ZipUtilTest {
ZipUtil.zip(FileUtil.file("d:\\test\\qr.zip"),false,dd); ZipUtil.zip(FileUtil.file("d:\\test\\qr.zip"),false,dd);
} }
@Test
@Ignore
public void sizeUnzip() throws IOException {
String zipPath = "F:\\BaiduNetdiskDownload\\demo.zip";
String outPath = "F:\\BaiduNetdiskDownload\\test";
ZipFile zipFile = new ZipFile(zipPath, Charset.forName("GBK"));
File file = new File(outPath);
// 限制解压文件大小为637KB
long size = 637*1024L;
// 限制解压文件大小为636KB
// long size = 636*1024L;
ZipUtil.unzip(zipFile, file, size);
}
} }

View File

@ -1,10 +1,13 @@
package cn.hutool.db; package cn.hutool.db;
import cn.hutool.core.map.CaseInsensitiveMap;
import cn.hutool.core.map.MapUtil;
import org.junit.Assert; import org.junit.Assert;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* H2数据库单元测试 * H2数据库单元测试
@ -46,4 +49,15 @@ public class H2Test {
final Entity a1=db.get("test","a",1); final Entity a1=db.get("test","a",1);
Assert.assertEquals(Long.valueOf(111),a1.getLong("b")); Assert.assertEquals(Long.valueOf(111),a1.getLong("b"));
} }
@Test
public void pageTest() {
String sql = "select * from test where a = @a and b = :b";
Map<String, Object> paramMap = MapUtil.builder(new CaseInsensitiveMap<String, Object>())
.put("A", 3)
.put("b", 31)
.build();
final List<Entity> query = Db.of(DS_GROUP_NAME).page(sql, Page.of(0, 3), paramMap);
Assert.assertEquals(1, query.size());
}
} }

View File

@ -11,6 +11,7 @@ import org.apache.commons.compress.archivers.ArchiveOutputStream;
import org.apache.commons.compress.archivers.ArchiveStreamFactory; import org.apache.commons.compress.archivers.ArchiveStreamFactory;
import org.apache.commons.compress.archivers.ar.ArArchiveOutputStream; import org.apache.commons.compress.archivers.ar.ArArchiveOutputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -78,6 +79,16 @@ public class StreamArchiver implements Archiver {
* @param targetStream 归档输出的流 * @param targetStream 归档输出的流
*/ */
public StreamArchiver(final Charset charset, final String archiverName, final OutputStream targetStream) { public StreamArchiver(final Charset charset, final String archiverName, final OutputStream targetStream) {
if("tgz".equalsIgnoreCase(archiverName) || "tar.gz".equalsIgnoreCase(archiverName)){
//issue#I5J33E支持tgz格式解压
try {
this.out = new TarArchiveOutputStream(new GzipCompressorOutputStream(targetStream));
} catch (IOException e) {
throw new IORuntimeException(e);
}
return;
}
final ArchiveStreamFactory factory = new ArchiveStreamFactory(charset.name()); final ArchiveStreamFactory factory = new ArchiveStreamFactory(charset.name());
try { try {
this.out = factory.createArchiveOutputStream(archiverName, targetStream); this.out = factory.createArchiveOutputStream(archiverName, targetStream);

View File

@ -10,6 +10,8 @@ import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveException; import org.apache.commons.compress.archivers.ArchiveException;
import org.apache.commons.compress.archivers.ArchiveInputStream; import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.ArchiveStreamFactory; import org.apache.commons.compress.archivers.ArchiveStreamFactory;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -71,6 +73,13 @@ public class StreamExtractor implements Extractor {
in = IoUtil.toBuffered(in); in = IoUtil.toBuffered(in);
if (StrUtil.isBlank(archiverName)) { if (StrUtil.isBlank(archiverName)) {
this.in = factory.createArchiveInputStream(in); this.in = factory.createArchiveInputStream(in);
} else if("tgz".equalsIgnoreCase(archiverName) || "tar.gz".equalsIgnoreCase(archiverName)){
//issue#I5J33E支持tgz格式解压
try {
this.in = new TarArchiveInputStream(new GzipCompressorInputStream(in));
} catch (IOException e) {
throw new IORuntimeException(e);
}
} else { } else {
this.in = factory.createArchiveInputStream(archiverName, in); this.in = factory.createArchiveInputStream(archiverName, in);
} }

View File

@ -10,6 +10,7 @@ import org.junit.Test;
import java.io.File; import java.io.File;
@SuppressWarnings("resource")
public class ArchiverTest { public class ArchiverTest {
@Test @Test
@ -53,7 +54,19 @@ public class ArchiverTest {
public void sevenZTest() { public void sevenZTest() {
final File file = FileUtil.file("d:/test/compress/test.7z"); final File file = FileUtil.file("d:/test/compress/test.7z");
CompressUtil.createArchiver(CharsetUtil.UTF_8, ArchiveStreamFactory.SEVEN_Z, file) CompressUtil.createArchiver(CharsetUtil.UTF_8, ArchiveStreamFactory.SEVEN_Z, file)
.add(FileUtil.file("d:/Java/apache-maven-3.6.3"), (f)->{ .add(FileUtil.file("d:/Java/apache-maven-3.8.1"), (f) -> {
Console.log("Add: {}", f.getPath());
return true;
})
.finish().close();
}
@Test
@Ignore
public void tgzTest() {
final File file = FileUtil.file("d:/test/compress/test.tgz");
CompressUtil.createArchiver(CharsetUtil.UTF_8, "tgz", file)
.add(FileUtil.file("d:/Java/apache-maven-3.8.1"), (f) -> {
Console.log("Add: {}", f.getPath()); Console.log("Add: {}", f.getPath());
return true; return true;
}) })

View File

@ -27,4 +27,15 @@ public class ExtractorTest {
extractor.extract(FileUtil.file("d:/test/compress/test2/")); extractor.extract(FileUtil.file("d:/test/compress/test2/"));
} }
@Test
@Ignore
public void tgzTest(){
Extractor extractor = CompressUtil.createExtractor(
CharsetUtil.defaultCharset(),
"tgz",
FileUtil.file("d:/test/test.tgz"));
extractor.extract(FileUtil.file("d:/test/tgz/"));
}
} }

View File

@ -299,7 +299,7 @@ public class BackgroundRemoval {
} }
} }
final Map<String, Integer> map = new HashMap<>(list.size()); final Map<String, Integer> map = new HashMap<>(list.size(), 1);
for (final String string : list) { for (final String string : list) {
Integer integer = map.get(string); Integer integer = map.get(string);
if (integer == null) { if (integer == null) {
@ -309,7 +309,7 @@ public class BackgroundRemoval {
} }
map.put(string, integer); map.put(string, integer);
} }
String max = ""; String max = StrUtil.EMPTY;
long num = 0; long num = 0;
for (final Map.Entry<String, Integer> entry : map.entrySet()) { for (final Map.Entry<String, Integer> entry : map.entrySet()) {
final String key = entry.getKey(); final String key = entry.getKey();
@ -326,7 +326,7 @@ public class BackgroundRemoval {
return ImgUtil.toHex(Integer.parseInt(strings[0]), Integer.parseInt(strings[1]), return ImgUtil.toHex(Integer.parseInt(strings[0]), Integer.parseInt(strings[1]),
Integer.parseInt(strings[2])); Integer.parseInt(strings[2]));
} }
return ""; return StrUtil.EMPTY;
} }
// -------------------------------------------------------------------------- private // -------------------------------------------------------------------------- private

View File

@ -1356,6 +1356,19 @@ public class ImgUtil {
return out.toByteArray(); return out.toByteArray();
} }
/**
* 根据文字创建透明背景的PNG图片
*
* @param str 文字
* @param font 字体{@link Font}
* @param fontColor 字体颜色默认黑色
* @param out 图片输出地
* @throws IORuntimeException IO异常
*/
public static void createTransparentImage(String str, Font font, Color fontColor, ImageOutputStream out) throws IORuntimeException {
writePng(createImage(str, font, null, fontColor, BufferedImage.TYPE_INT_ARGB), out);
}
/** /**
* 根据文字创建PNG图片 * 根据文字创建PNG图片
* *

View File

@ -1,7 +1,7 @@
package cn.hutool.swing.img; package cn.hutool.swing.img;
import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.FileUtil;
import cn.hutool.swing.img.ImgUtil; import cn.hutool.core.io.IORuntimeException;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
@ -147,4 +147,26 @@ public class ImgUtilTest {
System.out.println(mainColor); System.out.println(mainColor);
} }
@Test
@Ignore
public void createImageTest() throws IORuntimeException, IOException {
ImgUtil.createImage(
"版权所有",
new Font("黑体", Font.BOLD, 50),
Color.WHITE,
Color.BLACK,
ImageIO.createImageOutputStream(new File("d:/test/createImageTest.png"))
);
}
@Test
@Ignore
public void createTransparentImageTest() throws IORuntimeException, IOException {
ImgUtil.createTransparentImage(
"版权所有",
new Font("黑体", Font.BOLD, 50),
Color.BLACK,
ImageIO.createImageOutputStream(new File("d:/test/createTransparentImageTest.png"))
);
}
} }