diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f859e2cb..c95884674 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ * 【core 】 PhoneUtil中新增获取固话号码中区号,以及固话号码中号码的方法(pr#387@Gitee) * 【json 】 JSONGetter增加getLocalDateTime方法(pr#387@Gitee) * 【core 】 增加JNDIUtil(issue#1727@Github) +* 【core 】 NetUtil增加getDnsInfo方法(issue#1727@Github) * 【core 】 SpringUtil增加unregisterBean方法(pr#388@Gitee) * 【core 】 优化TextSimilarity公共子串算法(issue#I42A6V@Gitee) * 【core 】 优化DateUtil.parse对UTC附带时区字符串解析(issue#I437AP@Gitee) @@ -20,6 +21,9 @@ * 【core 】 修复SpringUtil无法处理autowired问题(pr#388@Gitee) * 【core 】 修复AbsCollValueMap中常量拼写错误(pr#1736@Github) * 【core 】 修复FileUtil.del在文件只读情况下无法删除的问题(pr#389@Gitee) +* 【core 】 修复FileUtil.move在不同分区下失败的问题(pr#390@Gitee) +* 【core 】 修复FileUtil.copy强制覆盖参数无效问题 +* 【core 】 修复NumberChineseFormatter转换金额多零问题(issue#1739@Github) ------------------------------------------------------------------------------------------------------------- diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/NumberChineseFormatter.java b/hutool-core/src/main/java/cn/hutool/core/convert/NumberChineseFormatter.java index 729682d1d..6fc3daa87 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/NumberChineseFormatter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/NumberChineseFormatter.java @@ -97,7 +97,7 @@ public class NumberChineseFormatter { // TODO 此处逻辑过于复杂,等待整理重构 if (i != 0) { if (i % 2 == 0) { - if (parts[i - 1] < 1000) { + if (parts[i - 1] < 1000 && parts[i - 1] > 0) { // 如果"亿"的部分不为 0, 而"亿"以下的部分小于 1000,则亿后面应该跟“零”,如一亿零三十五万 chineseStr.insert(0, "零"); } diff --git a/hutool-core/src/main/java/cn/hutool/core/io/file/PathUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/file/PathUtil.java index 6dfa7e174..4b5edf039 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/file/PathUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/file/PathUtil.java @@ -4,6 +4,7 @@ import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; import cn.hutool.core.io.file.visitor.CopyVisitor; import cn.hutool.core.io.file.visitor.DelVisitor; +import cn.hutool.core.io.file.visitor.MoveVisitor; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.CharsetUtil; @@ -16,7 +17,17 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.Charset; -import java.nio.file.*; +import java.nio.file.AccessDeniedException; +import java.nio.file.CopyOption; +import java.nio.file.DirectoryStream; +import java.nio.file.FileVisitOption; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardCopyOption; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.EnumSet; @@ -221,7 +232,7 @@ public class PathUtil { */ public static Path copyContent(Path src, Path target, CopyOption... options) throws IORuntimeException { try { - Files.walkFileTree(src, new CopyVisitor(src, target)); + Files.walkFileTree(src, new CopyVisitor(src, target, options)); } catch (IOException e) { throw new IORuntimeException(e); } @@ -440,7 +451,8 @@ public class PathUtil { /** * 移动文件或目录
- * 当目标是目录时,会将源文件或文件夹整体移动至目标目录下 + * 当目标是目录时,会将源文件或文件夹整体移动至目标目录下
+ * 例如:move("/usr/aaa", "/usr/bbb")结果为:"/usr/bbb/aaa" * * @param src 源文件或目录路径 * @param target 目标路径,如果为目录,则移动到此目录下 @@ -460,7 +472,15 @@ public class PathUtil { try { return Files.move(src, target, options); } catch (IOException e) { - throw new IORuntimeException(e); + // 移动失败,可能是跨分区移动导致的,采用递归移动方式 + try { + Files.walkFileTree(src, new MoveVisitor(src, target, options)); + // 移动后空目录没有删除, + del(src); + } catch (IOException e2) { + throw new IORuntimeException(e2); + } + return target; } } diff --git a/hutool-core/src/main/java/cn/hutool/core/io/file/visitor/CopyVisitor.java b/hutool-core/src/main/java/cn/hutool/core/io/file/visitor/CopyVisitor.java index 8a684eb69..842dbff1e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/file/visitor/CopyVisitor.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/file/visitor/CopyVisitor.java @@ -3,6 +3,7 @@ package cn.hutool.core.io.file.visitor; import cn.hutool.core.io.file.PathUtil; import java.io.IOException; +import java.nio.file.CopyOption; import java.nio.file.FileAlreadyExistsException; import java.nio.file.FileVisitResult; import java.nio.file.Files; @@ -22,19 +23,22 @@ public class CopyVisitor extends SimpleFileVisitor { private final Path source; private final Path target; private boolean isTargetCreated; + private final CopyOption[] copyOptions; /** * 构造 * * @param source 源Path * @param target 目标Path + * @param copyOptions 拷贝选项,如跳过已存在等 */ - public CopyVisitor(Path source, Path target) { + public CopyVisitor(Path source, Path target, CopyOption... copyOptions) { if(PathUtil.exists(target, false) && false == PathUtil.isDirectory(target)){ throw new IllegalArgumentException("Target must be a directory"); } this.source = source; this.target = target; + this.copyOptions = copyOptions; } @Override @@ -44,7 +48,7 @@ public class CopyVisitor extends SimpleFileVisitor { // 将当前目录相对于源路径转换为相对于目标路径 final Path targetDir = target.resolve(source.relativize(dir)); try { - Files.copy(dir, targetDir); + Files.copy(dir, targetDir, copyOptions); } catch (FileAlreadyExistsException e) { if (false == Files.isDirectory(targetDir)) throw e; @@ -56,7 +60,7 @@ public class CopyVisitor extends SimpleFileVisitor { public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { initTarget(); - Files.copy(file, target.resolve(source.relativize(file))); + Files.copy(file, target.resolve(source.relativize(file)), copyOptions); return FileVisitResult.CONTINUE; } diff --git a/hutool-core/src/main/java/cn/hutool/core/io/file/visitor/MoveVisitor.java b/hutool-core/src/main/java/cn/hutool/core/io/file/visitor/MoveVisitor.java new file mode 100755 index 000000000..15f2efb88 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/io/file/visitor/MoveVisitor.java @@ -0,0 +1,74 @@ +package cn.hutool.core.io.file.visitor; + +import cn.hutool.core.io.file.PathUtil; + +import java.io.IOException; +import java.nio.file.CopyOption; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; + +/** + * 文件移动操作的FileVisitor实现,用于递归遍历移动目录和文件,此类非线程安全
+ * 此类在遍历源目录并移动过程中会自动创建目标目录中不存在的上级目录。 + * + * @author looly + * @since 5.7.7 + */ +public class MoveVisitor extends SimpleFileVisitor { + + private final Path source; + private final Path target; + private boolean isTargetCreated; + private final CopyOption[] copyOptions; + + /** + * 构造 + * + * @param source 源Path + * @param target 目标Path + */ + public MoveVisitor(Path source, Path target, CopyOption... copyOptions) { + if(PathUtil.exists(target, false) && false == PathUtil.isDirectory(target)){ + throw new IllegalArgumentException("Target must be a directory"); + } + this.source = source; + this.target = target; + this.copyOptions = copyOptions; + } + + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) + throws IOException { + initTarget(); + // 将当前目录相对于源路径转换为相对于目标路径 + final Path targetDir = target.resolve(source.relativize(dir)); + if(false == Files.exists(targetDir)){ + Files.createDirectories(targetDir); + } else if(false == Files.isDirectory(targetDir)){ + throw new FileAlreadyExistsException(targetDir.toString()); + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException { + initTarget(); + Files.move(file, target.resolve(source.relativize(file)), copyOptions); + return FileVisitResult.CONTINUE; + } + + /** + * 初始化目标文件或目录 + */ + private void initTarget(){ + if(false == this.isTargetCreated){ + PathUtil.mkdir(this.target); + this.isTargetCreated = true; + } + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/net/NetUtil.java b/hutool-core/src/main/java/cn/hutool/core/net/NetUtil.java index f66361926..ecebe74b6 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/NetUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/NetUtil.java @@ -1,13 +1,18 @@ package cn.hutool.core.net; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.EnumerationIter; import cn.hutool.core.exceptions.UtilException; import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.IoUtil; import cn.hutool.core.lang.Filter; +import cn.hutool.core.util.JNDIUtil; import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.StrUtil; +import javax.naming.NamingException; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; import java.io.IOException; import java.io.OutputStream; import java.math.BigInteger; @@ -823,6 +828,34 @@ public class NetUtil { public static void setGlobalAuthenticator(Authenticator authenticator) { Authenticator.setDefault(authenticator); } + + /** + * 获取DNS信息,如TXT信息: + * + *
+	 *     NetUtil.attrNames("hutool.cn", "TXT")
+	 * 
+ * + * @param hostName 主机域名 + * @param attrNames 属性 + * @since 5.7.7 + * @return DNS信息 + */ + public static List getDnsInfo(String hostName, String... attrNames){ + final String uri = StrUtil.addPrefixIfNot(hostName, "dns:"); + final Attributes attributes = JNDIUtil.getAttributes(uri, attrNames); + + final List infos = new ArrayList<>(); + for (Attribute attribute: new EnumerationIter<>(attributes.getAll())){ + try { + infos.add((String) attribute.get()); + } catch (NamingException ignore) { + //ignore + } + } + return infos; + } + // ----------------------------------------------------------------------------------------- Private method start /** diff --git a/hutool-core/src/test/java/cn/hutool/core/convert/ConvertOtherTest.java b/hutool-core/src/test/java/cn/hutool/core/convert/ConvertOtherTest.java index 214e0485f..9f2ea4bd3 100644 --- a/hutool-core/src/test/java/cn/hutool/core/convert/ConvertOtherTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/convert/ConvertOtherTest.java @@ -1,11 +1,10 @@ package cn.hutool.core.convert; -import java.util.concurrent.TimeUnit; - +import cn.hutool.core.util.CharsetUtil; import org.junit.Assert; import org.junit.Test; -import cn.hutool.core.util.CharsetUtil; +import java.util.concurrent.TimeUnit; /** * 其它转换 @@ -58,21 +57,6 @@ public class ConvertOtherTest { Assert.assertEquals(75, minutes); } - @Test - public void digitToChineseTest() { - double a = 67556.32; - String digitUppercase = Convert.digitToChinese(a); - Assert.assertEquals("陆万柒仟伍佰伍拾陆元叁角贰分", digitUppercase); - - a = 1024.00; - digitUppercase = Convert.digitToChinese(a); - Assert.assertEquals("壹仟零贰拾肆元整", digitUppercase); - - a = 1024; - digitUppercase = Convert.digitToChinese(a); - Assert.assertEquals("壹仟零贰拾肆元整", digitUppercase); - } - @Test public void wrapUnwrapTest() { // 去包装 diff --git a/hutool-core/src/test/java/cn/hutool/core/convert/NumberChineseFormatterTest.java b/hutool-core/src/test/java/cn/hutool/core/convert/NumberChineseFormatterTest.java index 83c0abfc8..d091c3bcd 100644 --- a/hutool-core/src/test/java/cn/hutool/core/convert/NumberChineseFormatterTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/convert/NumberChineseFormatterTest.java @@ -83,6 +83,31 @@ public class NumberChineseFormatterTest { Assert.assertEquals("贰仟肆佰贰拾壹元零贰分", digitToChinese3); } + @Test + public void digitToChineseTest2() { + double a = 67556.32; + String digitUppercase = Convert.digitToChinese(a); + Assert.assertEquals("陆万柒仟伍佰伍拾陆元叁角贰分", digitUppercase); + + a = 1024.00; + digitUppercase = Convert.digitToChinese(a); + Assert.assertEquals("壹仟零贰拾肆元整", digitUppercase); + + a = 1024; + digitUppercase = Convert.digitToChinese(a); + Assert.assertEquals("壹仟零贰拾肆元整", digitUppercase); + } + + @Test + public void digitToChineseTest3() { + String digitToChinese = Convert.digitToChinese(2_0000_0000.00); + Assert.assertEquals("贰亿元整", digitToChinese); + digitToChinese = Convert.digitToChinese(2_0000.00); + Assert.assertEquals("贰万元整", digitToChinese); + digitToChinese = Convert.digitToChinese(2_0000_0000_0000.00); + Assert.assertEquals("贰万亿元整", digitToChinese); + } + @Test public void numberCharToChineseTest(){ String s = NumberChineseFormatter.numberCharToChinese('1', false); diff --git a/hutool-core/src/test/java/cn/hutool/core/io/file/PathUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/io/file/PathUtilTest.java index 1db254742..5e9e79ba7 100644 --- a/hutool-core/src/test/java/cn/hutool/core/io/file/PathUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/io/file/PathUtilTest.java @@ -44,6 +44,18 @@ public class PathUtilTest { PathUtil.move(Paths.get("d:/lombok.jar"), Paths.get("d:/test/"), false); } + @Test + @Ignore + public void moveDirTest(){ + PathUtil.move(Paths.get("c:\\aaa"), Paths.get("d:/test/looly"), false); + } + + @Test + @Ignore + public void delDirTest(){ + PathUtil.del(Paths.get("d:/test/looly")); + } + @Test @Ignore public void getMimeTypeTest(){ diff --git a/hutool-core/src/test/java/cn/hutool/core/net/NetUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/net/NetUtilTest.java index 4624032eb..ff467456a 100644 --- a/hutool-core/src/test/java/cn/hutool/core/net/NetUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/net/NetUtilTest.java @@ -1,5 +1,6 @@ package cn.hutool.core.net; +import cn.hutool.core.lang.Console; import cn.hutool.core.lang.PatternPool; import cn.hutool.core.util.ReUtil; import org.junit.Assert; @@ -13,7 +14,7 @@ import java.util.List; /** * NetUtil单元测试 - * + * * @author Looly * */ @@ -93,4 +94,11 @@ public class NetUtilTest { Assert.assertTrue(NetUtil.isOpen(address, 200)); } + @Test + @Ignore + public void getDnsInfoTest(){ + final List txt = NetUtil.getDnsInfo("hutool.cn", "TXT"); + Console.log(txt); + } + } diff --git a/hutool-core/src/test/java/cn/hutool/core/util/JNDIUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/JNDIUtilTest.java index 040f75d6d..232492f10 100755 --- a/hutool-core/src/test/java/cn/hutool/core/util/JNDIUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/JNDIUtilTest.java @@ -5,6 +5,7 @@ import cn.hutool.core.lang.Console; import org.junit.Ignore; import org.junit.Test; +import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; @@ -12,10 +13,10 @@ public class JNDIUtilTest { @Test @Ignore - public void getDnsTest(){ - final Attributes attributes = JNDIUtil.getAttributes("dns:hutool.cn", "TXT"); + public void getDnsTest() throws NamingException { + final Attributes attributes = JNDIUtil.getAttributes("dns:paypal.com", "TXT"); for (Attribute attribute: new EnumerationIter<>(attributes.getAll())){ - Console.log(attribute); + Console.log(attribute.get()); } } } diff --git a/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java b/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java index 33c398723..2bcfcf289 100644 --- a/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java +++ b/hutool-http/src/main/java/cn/hutool/http/HttpRequest.java @@ -31,7 +31,6 @@ import java.net.Proxy; import java.net.URLStreamHandler; import java.util.Collection; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; /** diff --git a/hutool-http/src/test/java/cn/hutool/http/RestTest.java b/hutool-http/src/test/java/cn/hutool/http/RestTest.java index 15d022b1e..18e13ac4f 100644 --- a/hutool-http/src/test/java/cn/hutool/http/RestTest.java +++ b/hutool-http/src/test/java/cn/hutool/http/RestTest.java @@ -8,7 +8,7 @@ import org.junit.Test; /** * Rest类型请求单元测试 - * + * * @author looly * */ @@ -52,4 +52,16 @@ public class RestTest { .set("键2", "值2").toString()); Console.log(request.execute().body()); } + + @Test + @Ignore + public void getWithBodyTest2() { + HttpRequest request = HttpRequest.get("https://ad.oceanengine.com/open_api/2/advertiser/info/")// + .setHttpProxy("localhost", 8888) + .header("Access-Token","b91e44f37ff2544079ceabcfafaf02bd3db9b769") + .body(JSONUtil.createObj() + .set("advertiser_ids", new Long[] {1690657248243790L}) + .set("fields", new String[] {"id", "name", "status"}).toString()); + Console.log(request.execute().body()); + } } diff --git a/hutool-http/src/test/java/cn/hutool/http/server/SimpleServerTest.java b/hutool-http/src/test/java/cn/hutool/http/server/SimpleServerTest.java index 1b71d0941..55a1ea51b 100644 --- a/hutool-http/src/test/java/cn/hutool/http/server/SimpleServerTest.java +++ b/hutool-http/src/test/java/cn/hutool/http/server/SimpleServerTest.java @@ -26,6 +26,7 @@ public class SimpleServerTest { String res = JSONUtil.createObj() .set("id", 1) .set("method", request.getMethod()) + .set("request", request.getBody()) .toStringPretty(); response.write(res, ContentType.JSON.toString()); })