diff --git a/CHANGELOG.md b/CHANGELOG.md index 16f2cd0ad..dd46e05c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,42 @@ ------------------------------------------------------------------------------------------------------------- +# 5.4.4 (2020-09-23) + +### 新特性 +* 【core 】 ServiceLoaderUtil改为使用contextClassLoader(pr#183@Gitee) +* 【core 】 NetUtil增加getLocalHostName(pr#1103@Github) +* 【extra 】 FTP增加stat方法(issue#I1W346@Gitee) +* 【core 】 Convert.toNumber支持类似12.2F这种形式字符串转换(issue#I1VYLJ@Gitee) +* 【core 】 使用静态变量替换999等(issue#I1W8IB@Gitee) +* 【core 】 URLUtil自动trim(issue#I1W803@Gitee) +* 【crypto 】 RC4增加ecrypt(pr#1108@Github) +* 【core 】 CharUtil and StrUtil增加@(pr#1106@Github) +* 【extra 】 优化EMOJ查询逻辑(pr#1112@Github) +* 【extra 】 优化CollUtil交并集结果集合设置初始化大小,避免扩容成本(pr#1110@Github) +* 【core 】 优化PageUtil彩虹算法(issue#1110@Github) +* 【core 】 IoUtil增加readUtf8方法 +* 【core 】 优化全局邮箱账户初始化逻辑(pr#1114@Github) +* 【http 】 SoapClient增加addSOAPHeader方法 +* 【http 】 完善StrUtil的注释(pr#186@Gitee) +* 【aop 】 去除调试日志(issue#1116@Github) +* 【core 】 增加'反转义(pr#1121@Github) +* 【poi 】 增加SheetReader和XXXRowHandler(issue#I1WHJP@Gitee) +* 【dfa 】 增加过滤符号(pr#1122@Github) +* 【dfa 】 SensitiveUtil增加setCharFilter方法(pr#1123@Github) +* 【all 】 优化常量大小写规范(pr#188@Gitee) +* 【core 】 优化NumberUtil中针对BigDecimal的一些处理逻辑(pr#1127@Github) +* 【core 】 NumberUtil.factorial注释明确(pr#1126@Github) +* 【core 】 NumberUtil增加isPowerOfTwo方法(pr#1132@Github) + +### Bug修复 +* 【crypto 】 修复SM2验签后无法解密问题(issue#I1W0VP@Gitee) +* 【core 】 修复新建默认TreeSet没有默认比较器导致的问题(issue#1101@Github) +* 【core 】 修复Linux下使用Windows路径分隔符导致的解压错误(issue#I1MW0E@Gitee) +* 【core 】 修复Word07Writer写出map问题(issue#I1W49R@Gitee) + +------------------------------------------------------------------------------------------------------------- + # 5.4.3 (2020-09-16) ### 新特性 diff --git a/README-EN.md b/README-EN.md index 250a758ff..c3ce780e2 100644 --- a/README-EN.md +++ b/README-EN.md @@ -120,19 +120,19 @@ Each module can be introduced individually, or all modules can be introduced by cn.hutool hutool-all - 5.4.3 + 5.4.4 ``` ### Gradle ``` -compile 'cn.hutool:hutool-all:5.4.3' +compile 'cn.hutool:hutool-all:5.4.4' ``` ## Download -- [Maven1](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.4.3/) -- [Maven2](http://repo2.maven.org/maven2/cn/hutool/hutool-all/5.4.3/) +- [Maven1](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.4.4/) +- [Maven2](http://repo2.maven.org/maven2/cn/hutool/hutool-all/5.4.4/) > 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. diff --git a/README.md b/README.md index 6a5801b6c..949c6a321 100644 --- a/README.md +++ b/README.md @@ -119,21 +119,21 @@ Hutool的存在就是为了减少代码搜索成本,避免网络上参差不 cn.hutool hutool-all - 5.4.3 + 5.4.4 ``` ### Gradle ``` -compile 'cn.hutool:hutool-all:5.4.3' +compile 'cn.hutool:hutool-all:5.4.4' ``` ### 非Maven项目 点击以下任一链接,下载`hutool-all-X.X.X.jar`即可: -- [Maven中央库1](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.4.3/) -- [Maven中央库2](http://repo2.maven.org/maven2/cn/hutool/hutool-all/5.4.3/) +- [Maven中央库1](https://repo1.maven.org/maven2/cn/hutool/hutool-all/5.4.4/) +- [Maven中央库2](http://repo2.maven.org/maven2/cn/hutool/hutool-all/5.4.4/) > 注意 > Hutool 5.x支持JDK8+,对Android平台没有测试,不能保证所有工具类或工具方法可用。 diff --git a/bin/version.txt b/bin/version.txt index 6ffbe8ba8..426c1c179 100755 --- a/bin/version.txt +++ b/bin/version.txt @@ -1 +1 @@ -5.4.3 +5.4.4 diff --git a/docs/js/version.js b/docs/js/version.js index 045ef4b03..876d3bc42 100644 --- a/docs/js/version.js +++ b/docs/js/version.js @@ -1 +1 @@ -var version = '5.4.3' \ No newline at end of file +var version = '5.4.4' \ No newline at end of file diff --git a/hutool-all/pom.xml b/hutool-all/pom.xml index 3d4c5d7a7..9a7e395bd 100644 --- a/hutool-all/pom.xml +++ b/hutool-all/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.4.3 + 5.4.4-SNAPSHOT hutool-all diff --git a/hutool-aop/pom.xml b/hutool-aop/pom.xml index cdaab1d84..204c892b4 100644 --- a/hutool-aop/pom.xml +++ b/hutool-aop/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.4.3 + 5.4.4-SNAPSHOT hutool-aop diff --git a/hutool-aop/src/main/java/cn/hutool/aop/interceptor/CglibInterceptor.java b/hutool-aop/src/main/java/cn/hutool/aop/interceptor/CglibInterceptor.java index a4b7ddf02..a157dd9b6 100644 --- a/hutool-aop/src/main/java/cn/hutool/aop/interceptor/CglibInterceptor.java +++ b/hutool-aop/src/main/java/cn/hutool/aop/interceptor/CglibInterceptor.java @@ -1,7 +1,6 @@ package cn.hutool.aop.interceptor; import cn.hutool.aop.aspects.Aspect; -import cn.hutool.core.lang.Console; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; @@ -43,7 +42,6 @@ public class CglibInterceptor implements MethodInterceptor, Serializable { if (aspect.before(target, method, args)) { try { // result = proxy.invokeSuper(obj, args); - Console.log(target); result = proxy.invoke(target, args); } catch (InvocationTargetException e) { // 异常回调(只捕获业务代码导致的异常,而非反射导致的异常) diff --git a/hutool-bloomFilter/pom.xml b/hutool-bloomFilter/pom.xml index bc6275efe..7f219864b 100644 --- a/hutool-bloomFilter/pom.xml +++ b/hutool-bloomFilter/pom.xml @@ -7,7 +7,7 @@ cn.hutool hutool-parent - 5.4.3 + 5.4.4-SNAPSHOT hutool-bloomFilter diff --git a/hutool-bom/pom.xml b/hutool-bom/pom.xml index 3d3c50fd9..47f6c2d47 100644 --- a/hutool-bom/pom.xml +++ b/hutool-bom/pom.xml @@ -7,7 +7,7 @@ cn.hutool hutool-parent - 5.4.3 + 5.4.4-SNAPSHOT hutool-bom diff --git a/hutool-cache/pom.xml b/hutool-cache/pom.xml index 81f36d723..9fbc93e04 100644 --- a/hutool-cache/pom.xml +++ b/hutool-cache/pom.xml @@ -7,7 +7,7 @@ cn.hutool hutool-parent - 5.4.3 + 5.4.4-SNAPSHOT hutool-cache diff --git a/hutool-captcha/pom.xml b/hutool-captcha/pom.xml index 8e21bbe0e..36af6c3e6 100644 --- a/hutool-captcha/pom.xml +++ b/hutool-captcha/pom.xml @@ -7,7 +7,7 @@ cn.hutool hutool-parent - 5.4.3 + 5.4.4-SNAPSHOT hutool-captcha diff --git a/hutool-core/pom.xml b/hutool-core/pom.xml index 51acd8d6e..c4d57ae21 100644 --- a/hutool-core/pom.xml +++ b/hutool-core/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.4.3 + 5.4.4-SNAPSHOT hutool-core diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/BeanPath.java b/hutool-core/src/main/java/cn/hutool/core/bean/BeanPath.java index 96c95594d..750ebde5a 100644 --- a/hutool-core/src/main/java/cn/hutool/core/bean/BeanPath.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/BeanPath.java @@ -41,9 +41,9 @@ public class BeanPath implements Serializable{ private static final long serialVersionUID = 1L; /** 表达式边界符号数组 */ - private static final char[] expChars = { CharUtil.DOT, CharUtil.BRACKET_START, CharUtil.BRACKET_END }; + private static final char[] EXP_CHARS = { CharUtil.DOT, CharUtil.BRACKET_START, CharUtil.BRACKET_END }; - private boolean isStartWith$ = false; + private boolean isStartWith = false; protected List patternParts; /** @@ -154,7 +154,7 @@ public class BeanPath implements Serializable{ subBean = getFieldValue(subBean, patternPart); if (null == subBean) { // 支持表达式的第一个对象为Bean本身(若用户定义表达式$开头,则不做此操作) - if (isFirst && false == this.isStartWith$ && BeanUtil.isMatchName(bean, patternPart, true)) { + if (isFirst && false == this.isStartWith && BeanUtil.isMatchName(bean, patternPart, true)) { subBean = bean; isFirst = false; } else { @@ -229,11 +229,11 @@ public class BeanPath implements Serializable{ c = expression.charAt(i); if (0 == i && '$' == c) { // 忽略开头的$符,表示当前对象 - isStartWith$ = true; + isStartWith = true; continue; } - if (ArrayUtil.contains(expChars, c)) { + if (ArrayUtil.contains(EXP_CHARS, c)) { // 处理边界符号 if (CharUtil.BRACKET_END == c) { // 中括号(数字下标)结束 diff --git a/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanCopier.java b/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanCopier.java index d9c5c1f7a..4708a22e6 100644 --- a/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanCopier.java +++ b/hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanCopier.java @@ -109,6 +109,7 @@ public class BeanCopier implements Copier, Serializable { } } } + return this.dest; } diff --git a/hutool-core/src/main/java/cn/hutool/core/codec/Base32.java b/hutool-core/src/main/java/cn/hutool/core/codec/Base32.java index 09802bab4..245a92207 100644 --- a/hutool-core/src/main/java/cn/hutool/core/codec/Base32.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/Base32.java @@ -17,8 +17,8 @@ public class Base32 { private Base32() {} - private static final String base32Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; - private static final int[] base32Lookup = {// + private static final String BASE32_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + private static final int[] BASE32_LOOKUP = {// 0xFF, 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, // '0', '1', '2', '3', '4', '5', '6', '7' 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // '8', '9', ':', ';', '<', '=', '>', '?' 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, // '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G' @@ -68,7 +68,7 @@ public class Base32 { i++; } } - base32.append(base32Chars.charAt(digit)); + base32.append(BASE32_CHARS.charAt(digit)); } return base32.toString(); @@ -120,11 +120,11 @@ public class Base32 { lookup = base32.charAt(i) - '0'; /* Skip chars outside the lookup table */ - if (lookup < 0 || lookup >= base32Lookup.length) { + if (lookup < 0 || lookup >= BASE32_LOOKUP.length) { continue; } - digit = base32Lookup[lookup]; + digit = BASE32_LOOKUP[lookup]; /* If this digit is not in the table, ignore it */ if (digit == 0xFF) { diff --git a/hutool-core/src/main/java/cn/hutool/core/codec/Base62.java b/hutool-core/src/main/java/cn/hutool/core/codec/Base62.java index 98075bc14..00a935661 100644 --- a/hutool-core/src/main/java/cn/hutool/core/codec/Base62.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/Base62.java @@ -19,7 +19,7 @@ import cn.hutool.core.util.StrUtil; public class Base62 { private static final Charset DEFAULT_CHARSET = CharsetUtil.CHARSET_UTF_8; - private static final Base62Codec codec = Base62Codec.createGmp(); + private static final Base62Codec CODEC = Base62Codec.createGmp(); // -------------------------------------------------------------------- encode /** @@ -50,7 +50,7 @@ public class Base62 { * @return 被加密后的字符串 */ public static String encode(byte[] source) { - return new String(codec.encode(source)); + return new String(CODEC.encode(source)); } /** @@ -144,6 +144,6 @@ public class Base62 { * @return 解码后的bytes */ public static byte[] decode(byte[] base62bytes) { - return codec.decode(base62bytes); + return CODEC.decode(base62bytes); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/codec/Caesar.java b/hutool-core/src/main/java/cn/hutool/core/codec/Caesar.java index 21e589db7..ac01a1a1d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/codec/Caesar.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/Caesar.java @@ -9,7 +9,7 @@ package cn.hutool.core.codec; public class Caesar { // 26个字母表 - public static final String table = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; + public static final String TABLE = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz"; /** * 传入明文,加密得到密文 @@ -63,8 +63,8 @@ public class Caesar { * @return 加密后的字符 */ private static char encodeChar(char c, int offset) { - int position = (table.indexOf(c) + offset) % 52; - return table.charAt(position); + int position = (TABLE.indexOf(c) + offset) % 52; + return TABLE.charAt(position); } @@ -75,11 +75,11 @@ public class Caesar { * @return 解密后的字符 */ private static char decodeChar(char c, int offset) { - int position = (table.indexOf(c) - offset) % 52; + int position = (TABLE.indexOf(c) - offset) % 52; if (position < 0) { position += 52; } - return table.charAt(position); + return TABLE.charAt(position); } // ----------------------------------------------------------------------------------------- Private method end } diff --git a/hutool-core/src/main/java/cn/hutool/core/codec/Morse.java b/hutool-core/src/main/java/cn/hutool/core/codec/Morse.java index 3be48540e..bdbf87017 100644 --- a/hutool-core/src/main/java/cn/hutool/core/codec/Morse.java +++ b/hutool-core/src/main/java/cn/hutool/core/codec/Morse.java @@ -17,8 +17,8 @@ import cn.hutool.core.util.StrUtil; */ public class Morse { - private static final Map alphabets = new HashMap<>(); // code point -> morse - private static final Map dictionaries = new HashMap<>(); // morse -> code point + private static final Map ALPHABETS = new HashMap<>(); // code point -> morse + private static final Map DICTIONARIES = new HashMap<>(); // morse -> code point /** * 注册莫尔斯电码表 @@ -27,8 +27,8 @@ public class Morse { * @param dict 二进制 */ private static void registerMorse(Character abc, String dict) { - alphabets.put(Integer.valueOf(abc), dict); - dictionaries.put(dict, Integer.valueOf(abc)); + ALPHABETS.put(Integer.valueOf(abc), dict); + DICTIONARIES.put(dict, Integer.valueOf(abc)); } static { @@ -129,7 +129,7 @@ public class Morse { final int len = text.codePointCount(0, text.length()); for (int i = 0; i < len; i++) { int codePoint = text.codePointAt(i); - String word = alphabets.get(codePoint); + String word = ALPHABETS.get(codePoint); if (word == null) { word = Integer.toBinaryString(codePoint); } @@ -161,7 +161,7 @@ public class Morse { continue; } word = word.replace(dit, '0').replace(dah, '1'); - codePoint = dictionaries.get(word); + codePoint = DICTIONARIES.get(word); if (codePoint == null) { codePoint = Integer.valueOf(word, 2); } diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java b/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java index a8969ec05..52e1d8151 100644 --- a/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/collection/CollUtil.java @@ -1,6 +1,7 @@ package cn.hutool.core.collection; import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.comparator.CompareUtil; import cn.hutool.core.comparator.PinyinComparator; import cn.hutool.core.comparator.PropertyComparator; import cn.hutool.core.convert.Convert; @@ -103,22 +104,22 @@ public class CollUtil { * @return 并集的集合,返回 {@link ArrayList} */ public static Collection union(Collection coll1, Collection coll2) { - final ArrayList list = new ArrayList<>(); if (isEmpty(coll1)) { - list.addAll(coll2); + return new ArrayList<>(coll2); } else if (isEmpty(coll2)) { - list.addAll(coll1); - } else { - final Map map1 = countMap(coll1); - final Map map2 = countMap(coll2); - final Set elts = newHashSet(coll2); - elts.addAll(coll1); - int m; - for (T t : elts) { - m = Math.max(Convert.toInt(map1.get(t), 0), Convert.toInt(map2.get(t), 0)); - for (int i = 0; i < m; i++) { - list.add(t); - } + return new ArrayList<>(coll1); + } + + final ArrayList list = new ArrayList<>(Math.max(coll1.size(), coll2.size())); + final Map map1 = countMap(coll1); + final Map map2 = countMap(coll2); + final Set elts = newHashSet(coll2); + elts.addAll(coll1); + int m; + for (T t : elts) { + m = Math.max(Convert.toInt(map1.get(t), 0), Convert.toInt(map2.get(t), 0)); + for (int i = 0; i < m; i++) { + list.add(t); } } return list; @@ -225,8 +226,8 @@ public class CollUtil { * @return 交集的集合,返回 {@link ArrayList} */ public static Collection intersection(Collection coll1, Collection coll2) { - final ArrayList list = new ArrayList<>(); if (isNotEmpty(coll1) && isNotEmpty(coll2)) { + final ArrayList list = new ArrayList<>(Math.min(coll1.size(), coll2.size())); final Map map1 = countMap(coll1); final Map map2 = countMap(coll2); final Set elts = newHashSet(coll2); @@ -237,8 +238,10 @@ public class CollUtil { list.add(t); } } + return list; } - return list; + + return new ArrayList<>(); } /** @@ -992,8 +995,13 @@ public class CollUtil { } else if (collectionType.isAssignableFrom(LinkedHashSet.class)) { list = new LinkedHashSet<>(); } else if (collectionType.isAssignableFrom(TreeSet.class)) { - //noinspection SortedCollectionWithNonComparableKeys - list = new TreeSet<>(); + list = new TreeSet<>((o1, o2) -> { + // 优先按照对象本身比较,如果没有实现比较接口,默认按照toString内容比较 + if (o1 instanceof Comparable) { + return ((Comparable) o1).compareTo(o2); + } + return CompareUtil.compare(o1.toString(), o2.toString()); + }); } else if (collectionType.isAssignableFrom(EnumSet.class)) { list = (Collection) EnumSet.noneOf((Class) ClassUtil.getTypeArgument(collectionType)); } @@ -2840,10 +2848,10 @@ public class CollUtil { /** * 使用给定的转换函数,转换源集合为新类型的集合 * - * @param 源元素类型 - * @param 目标元素类型 + * @param 源元素类型 + * @param 目标元素类型 * @param collection 集合 - * @param function 转换函数 + * @param function 转换函数 * @return 新类型的集合 * @since 5.4.3 */ diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/BasicType.java b/hutool-core/src/main/java/cn/hutool/core/convert/BasicType.java index ff9b1837c..44fbbfff9 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/BasicType.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/BasicType.java @@ -12,22 +12,22 @@ public enum BasicType { BYTE, SHORT, INT, INTEGER, LONG, DOUBLE, FLOAT, BOOLEAN, CHAR, CHARACTER, STRING; /** 包装类型为Key,原始类型为Value,例如: Integer.class =》 int.class. */ - public static final Map, Class> wrapperPrimitiveMap = new ConcurrentHashMap<>(8); + public static final Map, Class> WRAPPER_PRIMITIVE_MAP = new ConcurrentHashMap<>(8); /** 原始类型为Key,包装类型为Value,例如: int.class =》 Integer.class. */ - public static final Map, Class> primitiveWrapperMap = new ConcurrentHashMap<>(8); + public static final Map, Class> PRIMITIVE_WRAPPER_MAP = new ConcurrentHashMap<>(8); static { - wrapperPrimitiveMap.put(Boolean.class, boolean.class); - wrapperPrimitiveMap.put(Byte.class, byte.class); - wrapperPrimitiveMap.put(Character.class, char.class); - wrapperPrimitiveMap.put(Double.class, double.class); - wrapperPrimitiveMap.put(Float.class, float.class); - wrapperPrimitiveMap.put(Integer.class, int.class); - wrapperPrimitiveMap.put(Long.class, long.class); - wrapperPrimitiveMap.put(Short.class, short.class); + WRAPPER_PRIMITIVE_MAP.put(Boolean.class, boolean.class); + WRAPPER_PRIMITIVE_MAP.put(Byte.class, byte.class); + WRAPPER_PRIMITIVE_MAP.put(Character.class, char.class); + WRAPPER_PRIMITIVE_MAP.put(Double.class, double.class); + WRAPPER_PRIMITIVE_MAP.put(Float.class, float.class); + WRAPPER_PRIMITIVE_MAP.put(Integer.class, int.class); + WRAPPER_PRIMITIVE_MAP.put(Long.class, long.class); + WRAPPER_PRIMITIVE_MAP.put(Short.class, short.class); - for (Map.Entry, Class> entry : wrapperPrimitiveMap.entrySet()) { - primitiveWrapperMap.put(entry.getValue(), entry.getKey()); + for (Map.Entry, Class> entry : WRAPPER_PRIMITIVE_MAP.entrySet()) { + PRIMITIVE_WRAPPER_MAP.put(entry.getValue(), entry.getKey()); } } @@ -40,7 +40,7 @@ public enum BasicType { if(null == clazz || false == clazz.isPrimitive()){ return clazz; } - Class result = primitiveWrapperMap.get(clazz); + Class result = PRIMITIVE_WRAPPER_MAP.get(clazz); return (null == result) ? clazz : result; } @@ -53,7 +53,7 @@ public enum BasicType { if(null == clazz || clazz.isPrimitive()){ return clazz; } - Class result = wrapperPrimitiveMap.get(clazz); + Class result = WRAPPER_PRIMITIVE_MAP.get(clazz); return (null == result) ? clazz : result; } } diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java b/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java index 9c081999b..3fa034c86 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/ConverterRegistry.java @@ -106,9 +106,9 @@ public class ConverterRegistry implements Serializable { } /** - * 获得单例的 {@link ConverterRegistry} + * 获得单例的 ConverterRegistry * - * @return {@link ConverterRegistry} + * @return ConverterRegistry */ public static ConverterRegistry getInstance() { return SingletonHolder.INSTANCE; @@ -140,7 +140,7 @@ public class ConverterRegistry implements Serializable { * * @param type 转换的目标类型 * @param converterClass 转换器类,必须有默认构造方法 - * @return {@link ConverterRegistry} + * @return ConverterRegistry */ public ConverterRegistry putCustom(Type type, Class> converterClass) { return putCustom(type, ReflectUtil.newInstance(converterClass)); @@ -151,7 +151,7 @@ public class ConverterRegistry implements Serializable { * * @param type 转换的目标类型 * @param converter 转换器 - * @return {@link ConverterRegistry} + * @return ConverterRegistry */ public ConverterRegistry putCustom(Type type, Converter converter) { if (null == customConverterMap) { @@ -257,6 +257,7 @@ public class ConverterRegistry implements Serializable { } } + // 特殊类型转换,包括Collection、Map、强转、Array等 final T result = convertSpecial(type, rowType, value, defaultValue); if (null != result) { @@ -269,7 +270,7 @@ public class ConverterRegistry implements Serializable { } // 无法转换 - throw new ConvertException("No Converter for type [{}]", rowType.getName()); + throw new ConvertException("Can not Converter from [{}] to [{}]", value.getClass().getName(), type.getTypeName()); } /** 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 bfdada466..1b386f77b 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 @@ -18,20 +18,20 @@ public class NumberChineseFormatter { /** * 简体中文形式 **/ - private static final String[] simpleDigits = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九"}; + private static final String[] SIMPLE_DIGITS = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九"}; /** * 繁体中文形式 **/ - private static final String[] traditionalDigits = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"}; + private static final String[] TRADITIONAL_DIGITS = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"}; /** * 简体中文单位 **/ - private static final String[] simpleUnits = {"", "十", "百", "千"}; + private static final String[] SIMPLE_UNITS = {"", "十", "百", "千"}; /** * 繁体中文单位 **/ - private static final String[] traditionalUnits = {"", "拾", "佰", "仟"}; + private static final String[] TRADITIONAL_UNITS = {"", "拾", "佰", "仟"}; /** * 阿拉伯数字转换成中文,小数点后四舍五入保留两位. 使用于整数、小数的转换. @@ -53,7 +53,7 @@ public class NumberChineseFormatter { * @return 中文 */ public static String format(double amount, boolean isUseTraditional, boolean isMoneyMode) { - final String[] numArray = isUseTraditional ? traditionalDigits : simpleDigits; + final String[] numArray = isUseTraditional ? TRADITIONAL_DIGITS : SIMPLE_DIGITS; if (amount > 99999999999999.99 || amount < -99999999999999.99) { throw new IllegalArgumentException("Number support only: (-99999999999999.99 ~ 99999999999999.99)!"); @@ -150,7 +150,7 @@ public class NumberChineseFormatter { * @since 5.3.9 */ public static String numberCharToChinese(char c, boolean isUseTraditional) { - String[] numArray = isUseTraditional ? traditionalDigits : simpleDigits; + String[] numArray = isUseTraditional ? TRADITIONAL_DIGITS : SIMPLE_DIGITS; int index = c - 48; if (index < 0 || index >= numArray.length) { return String.valueOf(c); @@ -170,8 +170,8 @@ public class NumberChineseFormatter { // throw new IllegalArgumentException("Number must 0 < num < 10000!"); // } - String[] numArray = isUseTraditional ? traditionalDigits : simpleDigits; - String[] units = isUseTraditional ? traditionalUnits : simpleUnits; + String[] numArray = isUseTraditional ? TRADITIONAL_DIGITS : SIMPLE_DIGITS; + String[] units = isUseTraditional ? TRADITIONAL_UNITS : SIMPLE_UNITS; int temp = amountPart; diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/CollectionConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/CollectionConverter.java index 6dd82da13..a2633e86d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/CollectionConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/CollectionConverter.java @@ -2,6 +2,7 @@ package cn.hutool.core.convert.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.convert.Converter; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.TypeUtil; import java.lang.reflect.Type; @@ -60,13 +61,8 @@ public class CollectionConverter implements Converter> { @Override public Collection convert(Object value, Collection defaultValue) throws IllegalArgumentException { - Collection result; - try { - result = convertInternal(value); - } catch (RuntimeException e) { - return defaultValue; - } - return ((null == result) ? defaultValue : result); + final Collection result = convertInternal(value); + return ObjectUtil.defaultIfNull(result, defaultValue); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/convert/impl/NumberConverter.java b/hutool-core/src/main/java/cn/hutool/core/convert/impl/NumberConverter.java index 97fca587f..3054e76a8 100644 --- a/hutool-core/src/main/java/cn/hutool/core/convert/impl/NumberConverter.java +++ b/hutool-core/src/main/java/cn/hutool/core/convert/impl/NumberConverter.java @@ -207,7 +207,16 @@ public class NumberConverter extends AbstractConverter { @Override protected String convertToStr(Object value) { - return StrUtil.trim(super.convertToStr(value)); + String result = StrUtil.trim(super.convertToStr(value)); + if(StrUtil.isNotEmpty(result)){ + final char c = Character.toUpperCase(result.charAt(result.length() - 1)); + if(c == 'D' || c == 'L' || c == 'F'){ + // 类型标识形式(例如123.6D) + return StrUtil.subPre(result, -1); + } + } + + return result; } @Override diff --git a/hutool-core/src/main/java/cn/hutool/core/date/ChineseDate.java b/hutool-core/src/main/java/cn/hutool/core/date/ChineseDate.java index 6c9b10687..735f35c2e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/ChineseDate.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/ChineseDate.java @@ -21,7 +21,7 @@ public class ChineseDate { /** * 1900-01-31 */ - private static final long baseDate = -2206425943000L; + private static final long BASE_DATE = -2206425943000L; //农历年 private final int year; //农历月 @@ -46,7 +46,7 @@ public class ChineseDate { */ public ChineseDate(Date date) { // 求出和1900年1月31日相差的天数 - int offset = (int) ((date.getTime() - baseDate) / DateUnit.DAY.getMillis()); + int offset = (int) ((date.getTime() - BASE_DATE) / DateUnit.DAY.getMillis()); // 计算农历年份 // 用offset减去每农历年的天数,计算当天是农历第几天,offset是当年的第几天 int daysOfYear; @@ -299,7 +299,7 @@ public class ChineseDate { if (D >= firstNode) { gzM = GanZhi.cyclicalm((Y - LunarInfo.BASE_YEAR) * 12 + M + 12); } - int dayCyclical = (int) ((DateUtil.parseDate(Y + "-" + M + "-" + "1").getTime() - baseDate + 2592000000L) / DateUnit.DAY.getMillis()) + 10; + int dayCyclical = (int) ((DateUtil.parseDate(Y + "-" + M + "-" + "1").getTime() - BASE_DATE + 2592000000L) / DateUnit.DAY.getMillis()) + 10; String gzD = GanZhi.cyclicalm(dayCyclical + D - 1); return gzyear + "年" + gzM + "月" + gzD + "日"; } diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DateModifier.java b/hutool-core/src/main/java/cn/hutool/core/date/DateModifier.java index 5ae2d1034..d8753b25d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/DateModifier.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/DateModifier.java @@ -20,7 +20,7 @@ import cn.hutool.core.util.ArrayUtil; public class DateModifier { /** 忽略的计算的字段 */ - private static final int[] ignoreFields = new int[] { // + private static final int[] IGNORE_FIELDS = new int[] { // Calendar.HOUR_OF_DAY, // 与HOUR同名 Calendar.AM_PM, // 此字段单独处理,不参与计算起始和结束 Calendar.DAY_OF_WEEK_IN_MONTH, // 不参与计算 @@ -62,7 +62,7 @@ public class DateModifier { // 循环处理各级字段,精确到毫秒字段 for (int i = dateField + 1; i <= Calendar.MILLISECOND; i++) { - if (ArrayUtil.contains(ignoreFields, i)) { + if (ArrayUtil.contains(IGNORE_FIELDS, i)) { // 忽略无关字段(WEEK_OF_MONTH)始终不做修改 continue; } diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java b/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java index ca699fdb1..5b8df51ed 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java @@ -21,13 +21,7 @@ import java.time.Year; import java.time.format.DateTimeFormatter; import java.time.temporal.TemporalAccessor; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Locale; -import java.util.TimeZone; +import java.util.*; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; @@ -220,9 +214,14 @@ public class DateUtil extends CalendarUtil { /** * 获得指定日期是所在年份的第几周
+ * 此方法返回值与一周的第一天有关,比如:
+ * 2016年1月3日为周日,如果一周的第一天为周日,那这天是第二周(返回2)
+ * 如果一周的第一天为周一,那这天是第一周(返回1)
+ * 跨年的那个星期得到的结果总是1 * * @param date 日期 * @return 周 + * @see DateTime#setFirstDayOfWeek(Week) */ public static int weekOfYear(Date date) { return DateTime.of(date).weekOfYear(); diff --git a/hutool-core/src/main/java/cn/hutool/core/date/LocalDateTimeUtil.java b/hutool-core/src/main/java/cn/hutool/core/date/LocalDateTimeUtil.java index c95540f9f..a1745440f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/LocalDateTimeUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/LocalDateTimeUtil.java @@ -428,7 +428,7 @@ public class LocalDateTimeUtil { * @return 一天的开始时间 */ public static LocalDateTime beginOfDay(LocalDateTime time) { - return time.with(LocalTime.of(0, 0, 0, 0)); + return time.with(LocalTime.MIN); } /** @@ -438,7 +438,7 @@ public class LocalDateTimeUtil { * @return 一天的结束时间 */ public static LocalDateTime endOfDay(LocalDateTime time) { - return time.with(LocalTime.of(23, 59, 59, 999_999_999)); + return time.with(LocalTime.MAX); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/date/Zodiac.java b/hutool-core/src/main/java/cn/hutool/core/date/Zodiac.java index 27cdfb30d..9a3f002e6 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/Zodiac.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/Zodiac.java @@ -12,7 +12,7 @@ import java.util.Date; public class Zodiac { /** 星座分隔时间日 */ - private static final int[] dayArr = new int[] { 20, 19, 21, 20, 21, 22, 23, 23, 23, 24, 23, 22 }; + private static final int[] DAY_ARR = new int[] { 20, 19, 21, 20, 21, 22, 23, 23, 23, 24, 23, 22 }; /** 星座 */ private static final String[] ZODIACS = new String[] { "摩羯座", "水瓶座", "双鱼座", "白羊座", "金牛座", "双子座", "巨蟹座", "狮子座", "处女座", "天秤座", "天蝎座", "射手座", "摩羯座" }; private static final String[] CHINESE_ZODIACS = new String[] { "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪" }; @@ -61,7 +61,7 @@ public class Zodiac { */ public static String getZodiac(int month, int day) { // 在分隔日前为前一个星座,否则为后一个星座 - return day < dayArr[month] ? ZODIACS[month] : ZODIACS[month + 1]; + return day < DAY_ARR[month] ? ZODIACS[month] : ZODIACS[month + 1]; } // ----------------------------------------------------------------------------------------------------------- 生肖 diff --git a/hutool-core/src/main/java/cn/hutool/core/date/chinese/LunarFestival.java b/hutool-core/src/main/java/cn/hutool/core/date/chinese/LunarFestival.java index 4dbeca2ee..975302100 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/chinese/LunarFestival.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/chinese/LunarFestival.java @@ -15,71 +15,71 @@ public class LunarFestival { //农历节日 *表示放假日 // 来自:https://baike.baidu.com/item/%E4%B8%AD%E5%9B%BD%E4%BC%A0%E7%BB%9F%E8%8A%82%E6%97%A5/396100 - private static final TableMap, String> lFtv = new TableMap<>(16); + private static final TableMap, String> L_FTV = new TableMap<>(16); static{ - lFtv.put(new Pair<>(1, 1), "春节"); - lFtv.put(new Pair<>(1, 2), "犬日"); - lFtv.put(new Pair<>(1, 3), "猪日"); - lFtv.put(new Pair<>(1, 4), "羊日"); - lFtv.put(new Pair<>(1, 5), "牛日 破五日"); - lFtv.put(new Pair<>(1, 6), "马日 送穷日"); - lFtv.put(new Pair<>(1, 7), "人日 人胜节"); - lFtv.put(new Pair<>(1, 8), "谷日 八仙日"); - lFtv.put(new Pair<>(1, 9), "天日 九皇会"); - lFtv.put(new Pair<>(1, 10), "地日 石头生日"); - lFtv.put(new Pair<>(1, 12), "火日 老鼠娶媳妇日"); - lFtv.put(new Pair<>(1, 13), "上(试)灯日 关公升天日"); - lFtv.put(new Pair<>(1, 15), "元宵节"); - lFtv.put(new Pair<>(1, 18), "落灯日"); + L_FTV.put(new Pair<>(1, 1), "春节"); + L_FTV.put(new Pair<>(1, 2), "犬日"); + L_FTV.put(new Pair<>(1, 3), "猪日"); + L_FTV.put(new Pair<>(1, 4), "羊日"); + L_FTV.put(new Pair<>(1, 5), "牛日 破五日"); + L_FTV.put(new Pair<>(1, 6), "马日 送穷日"); + L_FTV.put(new Pair<>(1, 7), "人日 人胜节"); + L_FTV.put(new Pair<>(1, 8), "谷日 八仙日"); + L_FTV.put(new Pair<>(1, 9), "天日 九皇会"); + L_FTV.put(new Pair<>(1, 10), "地日 石头生日"); + L_FTV.put(new Pair<>(1, 12), "火日 老鼠娶媳妇日"); + L_FTV.put(new Pair<>(1, 13), "上(试)灯日 关公升天日"); + L_FTV.put(new Pair<>(1, 15), "元宵节"); + L_FTV.put(new Pair<>(1, 18), "落灯日"); // 二月 - lFtv.put(new Pair<>(2, 1), "中和节 太阳生日"); - lFtv.put(new Pair<>(2, 2), "龙抬头"); - lFtv.put(new Pair<>(2, 12), "花朝节"); - lFtv.put(new Pair<>(2, 19), "观世音圣诞"); + L_FTV.put(new Pair<>(2, 1), "中和节 太阳生日"); + L_FTV.put(new Pair<>(2, 2), "龙抬头"); + L_FTV.put(new Pair<>(2, 12), "花朝节"); + L_FTV.put(new Pair<>(2, 19), "观世音圣诞"); // 三月 - lFtv.put(new Pair<>(3, 3), "上巳节"); + L_FTV.put(new Pair<>(3, 3), "上巳节"); // 四月 - lFtv.put(new Pair<>(4, 1), "祭雹神"); - lFtv.put(new Pair<>(4, 4), "文殊菩萨诞辰"); - lFtv.put(new Pair<>(4, 8), "佛诞节"); + L_FTV.put(new Pair<>(4, 1), "祭雹神"); + L_FTV.put(new Pair<>(4, 4), "文殊菩萨诞辰"); + L_FTV.put(new Pair<>(4, 8), "佛诞节"); // 五月 - lFtv.put(new Pair<>(5, 5), "端午节"); + L_FTV.put(new Pair<>(5, 5), "端午节"); // 六月 - lFtv.put(new Pair<>(6, 6), "晒衣节 姑姑节"); - lFtv.put(new Pair<>(6, 6), "天贶节"); - lFtv.put(new Pair<>(6, 24), "彝族火把节"); + L_FTV.put(new Pair<>(6, 6), "晒衣节 姑姑节"); + L_FTV.put(new Pair<>(6, 6), "天贶节"); + L_FTV.put(new Pair<>(6, 24), "彝族火把节"); // 七月 - lFtv.put(new Pair<>(7, 7), "七夕"); - lFtv.put(new Pair<>(7, 14), "鬼节(南方)"); - lFtv.put(new Pair<>(7, 15), "中元节"); - lFtv.put(new Pair<>(7, 15), "盂兰盆节"); - lFtv.put(new Pair<>(7, 30), "地藏节"); + L_FTV.put(new Pair<>(7, 7), "七夕"); + L_FTV.put(new Pair<>(7, 14), "鬼节(南方)"); + L_FTV.put(new Pair<>(7, 15), "中元节"); + L_FTV.put(new Pair<>(7, 15), "盂兰盆节"); + L_FTV.put(new Pair<>(7, 30), "地藏节"); // 八月 - lFtv.put(new Pair<>(8, 15), "中秋节"); + L_FTV.put(new Pair<>(8, 15), "中秋节"); // 九月 - lFtv.put(new Pair<>(9, 9), "重阳节"); + L_FTV.put(new Pair<>(9, 9), "重阳节"); // 十月 - lFtv.put(new Pair<>(10, 1), "祭祖节"); - lFtv.put(new Pair<>(10, 15), "下元节"); + L_FTV.put(new Pair<>(10, 1), "祭祖节"); + L_FTV.put(new Pair<>(10, 15), "下元节"); // 十一月 - lFtv.put(new Pair<>(11, 17), "阿弥陀佛圣诞"); + L_FTV.put(new Pair<>(11, 17), "阿弥陀佛圣诞"); // 腊月 - lFtv.put(new Pair<>(12, 8), "腊八节"); - lFtv.put(new Pair<>(12, 16), "尾牙"); - lFtv.put(new Pair<>(12, 23), "小年"); - lFtv.put(new Pair<>(12, 29), "除夕"); - lFtv.put(new Pair<>(12, 30), "除夕"); + L_FTV.put(new Pair<>(12, 8), "腊八节"); + L_FTV.put(new Pair<>(12, 16), "尾牙"); + L_FTV.put(new Pair<>(12, 23), "小年"); + L_FTV.put(new Pair<>(12, 29), "除夕"); + L_FTV.put(new Pair<>(12, 30), "除夕"); } /** @@ -90,6 +90,6 @@ public class LunarFestival { * @return 获得农历节日 */ public static List getFestivals(int month, int day) { - return lFtv.getValues(new Pair<>(month, day)); + return L_FTV.getValues(new Pair<>(month, day)); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/date/chinese/SolarTerms.java b/hutool-core/src/main/java/cn/hutool/core/date/chinese/SolarTerms.java index b4f1cc934..d632ea444 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/chinese/SolarTerms.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/chinese/SolarTerms.java @@ -25,7 +25,7 @@ public class SolarTerms { return -1; } - String _table = sTermInfo[y - 1900]; + String _table = S_TERM_INFO[y - 1900]; Integer[] _info = new Integer[6]; for (int i = 0; i < 6; i++) { _info[i] = NumberUtil.parseInt("0x" + _table.substring(i * 5, 5 * (i + 1))); @@ -44,7 +44,7 @@ public class SolarTerms { * 1900-2100各年的24节气日期速查表 * 此表来自:https://github.com/jjonline/calendar.js/blob/master/calendar.js */ - private static final String[] sTermInfo = new String[]{ + private static final String[] S_TERM_INFO = new String[]{ "9778397bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e", "97bcf97c3598082c95f8c965cc920f", "97bd0b06bdb0722c965ce1cfcc920f", "b027097bd097c36b0b6fc9274c91aa", "97b6b97bd19801ec9210c965cc920e", "97bcf97c359801ec95f8c965cc920f", "97bd0b06bdb0722c965ce1cfcc920f", "b027097bd097c36b0b6fc9274c91aa", diff --git a/hutool-core/src/main/java/cn/hutool/core/date/format/FastDateFormat.java b/hutool-core/src/main/java/cn/hutool/core/date/format/FastDateFormat.java index 4a312249c..7302270a1 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/format/FastDateFormat.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/format/FastDateFormat.java @@ -38,7 +38,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter { /** SHORT locale dependent date or time style. */ public static final int SHORT = DateFormat.SHORT; - private static final FormatCache cache = new FormatCache(){ + private static final FormatCache CACHE = new FormatCache(){ @Override protected FastDateFormat createInstance(final String pattern, final TimeZone timeZone, final Locale locale) { return new FastDateFormat(pattern, timeZone, locale); @@ -55,7 +55,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter { * @return {@link FastDateFormat} */ public static FastDateFormat getInstance() { - return cache.getInstance(); + return CACHE.getInstance(); } /** @@ -67,7 +67,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter { * @throws IllegalArgumentException 日期格式问题 */ public static FastDateFormat getInstance(final String pattern) { - return cache.getInstance(pattern, null, null); + return CACHE.getInstance(pattern, null, null); } /** @@ -80,7 +80,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter { * @throws IllegalArgumentException 日期格式问题 */ public static FastDateFormat getInstance(final String pattern, final TimeZone timeZone) { - return cache.getInstance(pattern, timeZone, null); + return CACHE.getInstance(pattern, timeZone, null); } /** @@ -93,7 +93,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter { * @throws IllegalArgumentException 日期格式问题 */ public static FastDateFormat getInstance(final String pattern, final Locale locale) { - return cache.getInstance(pattern, null, locale); + return CACHE.getInstance(pattern, null, locale); } /** @@ -107,7 +107,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter { * @throws IllegalArgumentException 日期格式问题 */ public static FastDateFormat getInstance(final String pattern, final TimeZone timeZone, final Locale locale) { - return cache.getInstance(pattern, timeZone, locale); + return CACHE.getInstance(pattern, timeZone, locale); } // ----------------------------------------------------------------------- @@ -119,7 +119,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter { * @return 本地化 {@link FastDateFormat} */ public static FastDateFormat getDateInstance(final int style) { - return cache.getDateInstance(style, null, null); + return CACHE.getDateInstance(style, null, null); } /** @@ -131,7 +131,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter { * @return 本地化 {@link FastDateFormat} */ public static FastDateFormat getDateInstance(final int style, final Locale locale) { - return cache.getDateInstance(style, null, locale); + return CACHE.getDateInstance(style, null, locale); } /** @@ -143,7 +143,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter { * @return 本地化 {@link FastDateFormat} */ public static FastDateFormat getDateInstance(final int style, final TimeZone timeZone) { - return cache.getDateInstance(style, timeZone, null); + return CACHE.getDateInstance(style, timeZone, null); } /** @@ -156,7 +156,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter { * @return 本地化 {@link FastDateFormat} */ public static FastDateFormat getDateInstance(final int style, final TimeZone timeZone, final Locale locale) { - return cache.getDateInstance(style, timeZone, locale); + return CACHE.getDateInstance(style, timeZone, locale); } // ----------------------------------------------------------------------- @@ -168,7 +168,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter { * @return 本地化 {@link FastDateFormat} */ public static FastDateFormat getTimeInstance(final int style) { - return cache.getTimeInstance(style, null, null); + return CACHE.getTimeInstance(style, null, null); } /** @@ -180,7 +180,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter { * @return 本地化 {@link FastDateFormat} */ public static FastDateFormat getTimeInstance(final int style, final Locale locale) { - return cache.getTimeInstance(style, null, locale); + return CACHE.getTimeInstance(style, null, locale); } /** @@ -192,7 +192,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter { * @return 本地化 {@link FastDateFormat} */ public static FastDateFormat getTimeInstance(final int style, final TimeZone timeZone) { - return cache.getTimeInstance(style, timeZone, null); + return CACHE.getTimeInstance(style, timeZone, null); } /** @@ -205,7 +205,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter { * @return 本地化 {@link FastDateFormat} */ public static FastDateFormat getTimeInstance(final int style, final TimeZone timeZone, final Locale locale) { - return cache.getTimeInstance(style, timeZone, locale); + return CACHE.getTimeInstance(style, timeZone, locale); } // ----------------------------------------------------------------------- @@ -218,7 +218,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter { * @return 本地化 {@link FastDateFormat} */ public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle) { - return cache.getDateTimeInstance(dateStyle, timeStyle, null, null); + return CACHE.getDateTimeInstance(dateStyle, timeStyle, null, null); } /** @@ -231,7 +231,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter { * @return 本地化 {@link FastDateFormat} */ public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle, final Locale locale) { - return cache.getDateTimeInstance(dateStyle, timeStyle, null, locale); + return CACHE.getDateTimeInstance(dateStyle, timeStyle, null, locale); } /** @@ -258,7 +258,7 @@ public class FastDateFormat extends Format implements DateParser, DatePrinter { * @return 本地化 {@link FastDateFormat} */ public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle, final TimeZone timeZone, final Locale locale) { - return cache.getDateTimeInstance(dateStyle, timeStyle, timeZone, locale); + return CACHE.getDateTimeInstance(dateStyle, timeStyle, timeZone, locale); } // ----------------------------------------------------------------------- Constructor start diff --git a/hutool-core/src/main/java/cn/hutool/core/date/format/FastDateParser.java b/hutool-core/src/main/java/cn/hutool/core/date/format/FastDateParser.java index f5f4b5780..88f6385f5 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/format/FastDateParser.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/format/FastDateParser.java @@ -447,7 +447,7 @@ public class FastDateParser extends AbstractDateBasic implements DateParser { } @SuppressWarnings("unchecked") // OK because we are creating an array with no entries - private static final ConcurrentMap[] caches = new ConcurrentMap[Calendar.FIELD_COUNT]; + private static final ConcurrentMap[] CACHES = new ConcurrentMap[Calendar.FIELD_COUNT]; /** * Get a cache of Strategies for a particular field @@ -456,11 +456,11 @@ public class FastDateParser extends AbstractDateBasic implements DateParser { * @return a cache of Locale to Strategy */ private static ConcurrentMap getCache(final int field) { - synchronized (caches) { - if (caches[field] == null) { - caches[field] = new ConcurrentHashMap<>(3); + synchronized (CACHES) { + if (CACHES[field] == null) { + CACHES[field] = new ConcurrentHashMap<>(3); } - return caches[field]; + return CACHES[field]; } } diff --git a/hutool-core/src/main/java/cn/hutool/core/date/format/FastDatePrinter.java b/hutool-core/src/main/java/cn/hutool/core/date/format/FastDatePrinter.java index 895d9534b..ccb4f009c 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/format/FastDatePrinter.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/format/FastDatePrinter.java @@ -1052,7 +1052,7 @@ public class FastDatePrinter extends AbstractDateBasic implements DatePrinter { // ----------------------------------------------------------------------- - private static final ConcurrentMap cTimeZoneDisplayCache = new ConcurrentHashMap<>(7); + private static final ConcurrentMap C_TIME_ZONE_DISPLAY_CACHE = new ConcurrentHashMap<>(7); /** *

@@ -1067,11 +1067,11 @@ public class FastDatePrinter extends AbstractDateBasic implements DatePrinter { */ static String getTimeZoneDisplay(final TimeZone tz, final boolean daylight, final int style, final Locale locale) { final TimeZoneDisplayKey key = new TimeZoneDisplayKey(tz, daylight, style, locale); - String value = cTimeZoneDisplayCache.get(key); + String value = C_TIME_ZONE_DISPLAY_CACHE.get(key); if (value == null) { // This is a very slow call, so cache the results. value = tz.getDisplayName(daylight, style, locale); - final String prior = cTimeZoneDisplayCache.putIfAbsent(key, value); + final String prior = C_TIME_ZONE_DISPLAY_CACHE.putIfAbsent(key, value); if (prior != null) { value = prior; } diff --git a/hutool-core/src/main/java/cn/hutool/core/date/format/FormatCache.java b/hutool-core/src/main/java/cn/hutool/core/date/format/FormatCache.java index 456a4c170..a3491393d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/format/FormatCache.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/format/FormatCache.java @@ -26,7 +26,7 @@ abstract class FormatCache { private final ConcurrentMap cInstanceCache = new ConcurrentHashMap<>(7); - private static final ConcurrentMap cDateTimeInstanceCache = new ConcurrentHashMap<>(7); + private static final ConcurrentMap C_DATE_TIME_INSTANCE_CACHE = new ConcurrentHashMap<>(7); /** * 使用默认的pattern、timezone和locale获得缓存中的实例 @@ -163,7 +163,7 @@ abstract class FormatCache { static String getPatternForStyle(final Integer dateStyle, final Integer timeStyle, final Locale locale) { final Tuple key = new Tuple(dateStyle, timeStyle, locale); - String pattern = cDateTimeInstanceCache.get(key); + String pattern = C_DATE_TIME_INSTANCE_CACHE.get(key); if (pattern == null) { try { DateFormat formatter; @@ -175,7 +175,7 @@ abstract class FormatCache { formatter = DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale); } pattern = ((SimpleDateFormat) formatter).toPattern(); - final String previous = cDateTimeInstanceCache.putIfAbsent(key, pattern); + final String previous = C_DATE_TIME_INSTANCE_CACHE.putIfAbsent(key, pattern); if (previous != null) { // even though it doesn't matter if another thread put the pattern // it's still good practice to return the String instance that is diff --git a/hutool-core/src/main/java/cn/hutool/core/img/gif/GifDecoder.java b/hutool-core/src/main/java/cn/hutool/core/img/gif/GifDecoder.java index 97353f787..0c1dd00b5 100644 --- a/hutool-core/src/main/java/cn/hutool/core/img/gif/GifDecoder.java +++ b/hutool-core/src/main/java/cn/hutool/core/img/gif/GifDecoder.java @@ -95,7 +95,7 @@ public class GifDecoder { protected int delay = 0; // delay in milliseconds protected int transIndex; // transparent color index - protected static final int MaxStackSize = 4096; + protected static final int MAX_STACK_SIZE = 4096; // max decoder pixel stack size // LZW decoder working arrays @@ -378,9 +378,9 @@ public class GifDecoder { if ((pixels == null) || (pixels.length < npix)) { pixels = new byte[npix]; // allocate new pixel array } - if (prefix == null) prefix = new short[MaxStackSize]; - if (suffix == null) suffix = new byte[MaxStackSize]; - if (pixelStack == null) pixelStack = new byte[MaxStackSize + 1]; + if (prefix == null) prefix = new short[MAX_STACK_SIZE]; + if (suffix == null) suffix = new byte[MAX_STACK_SIZE]; + if (pixelStack == null) pixelStack = new byte[MAX_STACK_SIZE + 1]; // Initialize GIF data stream decoder. @@ -455,7 +455,7 @@ public class GifDecoder { // Add a new string to the string table, - if (available >= MaxStackSize) { + if (available >= MAX_STACK_SIZE) { pixelStack[top++] = (byte) first; continue; } @@ -464,7 +464,7 @@ public class GifDecoder { suffix[available] = (byte) first; available++; if (((available & code_mask) == 0) - && (available < MaxStackSize)) { + && (available < MAX_STACK_SIZE)) { code_size++; code_mask += available; } @@ -606,10 +606,11 @@ public class GifDecoder { for (int i = 0; i < 11; i++) { app.append((char) block[i]); } - if (app.toString().equals("NETSCAPE2.0")) { + if ("NETSCAPE2.0".equals(app.toString())) { readNetscapeExt(); - } else + } else { skip(); // don't care + } break; default: // uninteresting extension diff --git a/hutool-core/src/main/java/cn/hutool/core/img/gif/NeuQuant.java b/hutool-core/src/main/java/cn/hutool/core/img/gif/NeuQuant.java index f80f9cbd9..fb152c7c5 100644 --- a/hutool-core/src/main/java/cn/hutool/core/img/gif/NeuQuant.java +++ b/hutool-core/src/main/java/cn/hutool/core/img/gif/NeuQuant.java @@ -29,16 +29,16 @@ package cn.hutool.core.img.gif; */ public class NeuQuant { - protected static final int netsize = 256; /* number of colours used */ + protected static final int NETSIZE = 256; /* number of colours used */ /* four primes near 500 - assume no image has a length so large */ /* that it is divisible by all four primes */ - protected static final int prime1 = 499; - protected static final int prime2 = 491; - protected static final int prime3 = 487; - protected static final int prime4 = 503; + protected static final int PRIME1 = 499; + protected static final int PRIME2 = 491; + protected static final int PRIME3 = 487; + protected static final int PRIME4 = 503; - protected static final int minpicturebytes = (3 * prime4); + protected static final int MINPICTUREBYTES = (3 * PRIME4); /* minimum size for input image */ /* Program Skeleton @@ -56,38 +56,38 @@ public class NeuQuant { /* Network Definitions ------------------- */ - protected static final int maxnetpos = (netsize - 1); - protected static final int netbiasshift = 4; /* bias for colour values */ - protected static final int ncycles = 100; /* no. of learning cycles */ + protected static final int MAXNETPOS = (NETSIZE - 1); + protected static final int NETBIASSHIFT = 4; /* bias for colour values */ + protected static final int NCYCLES = 100; /* no. of learning cycles */ /* defs for freq and bias */ - protected static final int intbiasshift = 16; /* bias for fractions */ - protected static final int intbias = (1 << intbiasshift); - protected static final int gammashift = 10; /* gamma = 1024 */ - protected static final int gamma = (1 << gammashift); - protected static final int betashift = 10; - protected static final int beta = (intbias >> betashift); /* beta = 1/1024 */ - protected static final int betagamma = - (intbias << (gammashift - betashift)); + protected static final int INTBIASSHIFT = 16; /* bias for fractions */ + protected static final int INTBIAS = (1 << INTBIASSHIFT); + protected static final int GAMMASHIFT = 10; /* gamma = 1024 */ + protected static final int GAMMA = (1 << GAMMASHIFT); + protected static final int BETASHIFT = 10; + protected static final int BETA = (INTBIAS >> BETASHIFT); /* beta = 1/1024 */ + protected static final int BETAGAMMA = + (INTBIAS << (GAMMASHIFT - BETASHIFT)); /* defs for decreasing radius factor */ - protected static final int initrad = (netsize >> 3); /* for 256 cols, radius starts */ - protected static final int radiusbiasshift = 6; /* at 32.0 biased by 6 bits */ - protected static final int radiusbias = (1 << radiusbiasshift); - protected static final int initradius = (initrad * radiusbias); /* and decreases by a */ - protected static final int radiusdec = 30; /* factor of 1/30 each cycle */ + protected static final int INITRAD = (NETSIZE >> 3); /* for 256 cols, radius starts */ + protected static final int RADIUSBIASSHIFT = 6; /* at 32.0 biased by 6 bits */ + protected static final int RADIUSBIAS = (1 << RADIUSBIASSHIFT); + protected static final int INITRADIUS = (INITRAD * RADIUSBIAS); /* and decreases by a */ + protected static final int RADIUSDEC = 30; /* factor of 1/30 each cycle */ /* defs for decreasing alpha factor */ - protected static final int alphabiasshift = 10; /* alpha starts at 1.0 */ - protected static final int initalpha = (1 << alphabiasshift); + protected static final int ALPHABIASSHIFT = 10; /* alpha starts at 1.0 */ + protected static final int INITALPHA = (1 << ALPHABIASSHIFT); protected int alphadec; /* biased by 10 bits */ /* radbias and alpharadbias used for radpower calculation */ - protected static final int radbiasshift = 8; - protected static final int radbias = (1 << radbiasshift); - protected static final int alpharadbshift = (alphabiasshift + radbiasshift); - protected static final int alpharadbias = (1 << alpharadbshift); + protected static final int RADBIASSHIFT = 8; + protected static final int RADBIAS = (1 << RADBIASSHIFT); + protected static final int ALPHARADBSHIFT = (ALPHABIASSHIFT + RADBIASSHIFT); + protected static final int ALPHARADBIAS = (1 << ALPHARADBSHIFT); /* Types and Global Variables -------------------------- */ @@ -103,10 +103,10 @@ public class NeuQuant { protected int[] netindex = new int[256]; /* for network lookup - really 256 */ - protected int[] bias = new int[netsize]; + protected int[] bias = new int[NETSIZE]; /* bias and freq arrays for learning */ - protected int[] freq = new int[netsize]; - protected int[] radpower = new int[initrad]; + protected int[] freq = new int[NETSIZE]; + protected int[] radpower = new int[INITRAD]; /* radpower for precomputation */ /* Initialise network in range (0,0,0) to (255,255,255) and set parameters @@ -120,23 +120,23 @@ public class NeuQuant { lengthcount = len; samplefac = sample; - network = new int[netsize][]; - for (i = 0; i < netsize; i++) { + network = new int[NETSIZE][]; + for (i = 0; i < NETSIZE; i++) { network[i] = new int[4]; p = network[i]; - p[0] = p[1] = p[2] = (i << (netbiasshift + 8)) / netsize; - freq[i] = intbias / netsize; /* 1/netsize */ + p[0] = p[1] = p[2] = (i << (NETBIASSHIFT + 8)) / NETSIZE; + freq[i] = INTBIAS / NETSIZE; /* 1/netsize */ bias[i] = 0; } } public byte[] colorMap() { - byte[] map = new byte[3 * netsize]; - int[] index = new int[netsize]; - for (int i = 0; i < netsize; i++) + byte[] map = new byte[3 * NETSIZE]; + int[] index = new int[NETSIZE]; + for (int i = 0; i < NETSIZE; i++) index[network[i][3]] = i; int k = 0; - for (int i = 0; i < netsize; i++) { + for (int i = 0; i < NETSIZE; i++) { int j = index[i]; map[k++] = (byte) (network[j][0]); map[k++] = (byte) (network[j][1]); @@ -156,12 +156,12 @@ public class NeuQuant { previouscol = 0; startpos = 0; - for (i = 0; i < netsize; i++) { + for (i = 0; i < NETSIZE; i++) { p = network[i]; smallpos = i; smallval = p[1]; /* index on g */ /* find smallest in i..netsize-1 */ - for (j = i + 1; j < netsize; j++) { + for (j = i + 1; j < NETSIZE; j++) { q = network[j]; if (q[1] < smallval) { /* index on g */ smallpos = j; @@ -193,9 +193,9 @@ public class NeuQuant { startpos = i; } } - netindex[previouscol] = (startpos + maxnetpos) >> 1; + netindex[previouscol] = (startpos + MAXNETPOS) >> 1; for (j = previouscol + 1; j < 256; j++) - netindex[j] = maxnetpos; /* really 256 */ + netindex[j] = MAXNETPOS; /* really 256 */ } /* Main Learning Loop @@ -207,44 +207,44 @@ public class NeuQuant { byte[] p; int pix, lim; - if (lengthcount < minpicturebytes) + if (lengthcount < MINPICTUREBYTES) samplefac = 1; alphadec = 30 + ((samplefac - 1) / 3); p = thepicture; pix = 0; lim = lengthcount; samplepixels = lengthcount / (3 * samplefac); - delta = samplepixels / ncycles; - alpha = initalpha; - radius = initradius; + delta = samplepixels / NCYCLES; + alpha = INITALPHA; + radius = INITRADIUS; - rad = radius >> radiusbiasshift; + rad = radius >> RADIUSBIASSHIFT; for (i = 0; i < rad; i++) radpower[i] = - alpha * (((rad * rad - i * i) * radbias) / (rad * rad)); + alpha * (((rad * rad - i * i) * RADBIAS) / (rad * rad)); //fprintf(stderr,"beginning 1D learning: initial radius=%d\n", rad); - if (lengthcount < minpicturebytes) + if (lengthcount < MINPICTUREBYTES) step = 3; - else if ((lengthcount % prime1) != 0) - step = 3 * prime1; + else if ((lengthcount % PRIME1) != 0) + step = 3 * PRIME1; else { - if ((lengthcount % prime2) != 0) - step = 3 * prime2; + if ((lengthcount % PRIME2) != 0) + step = 3 * PRIME2; else { - if ((lengthcount % prime3) != 0) - step = 3 * prime3; + if ((lengthcount % PRIME3) != 0) + step = 3 * PRIME3; else - step = 3 * prime4; + step = 3 * PRIME4; } } i = 0; while (i < samplepixels) { - b = (p[pix] & 0xff) << netbiasshift; - g = (p[pix + 1] & 0xff) << netbiasshift; - r = (p[pix + 2] & 0xff) << netbiasshift; + b = (p[pix] & 0xff) << NETBIASSHIFT; + g = (p[pix + 1] & 0xff) << NETBIASSHIFT; + r = (p[pix + 2] & 0xff) << NETBIASSHIFT; j = contest(b, g, r); altersingle(alpha, j, b, g, r); @@ -260,13 +260,13 @@ public class NeuQuant { delta = 1; if (i % delta == 0) { alpha -= alpha / alphadec; - radius -= radius / radiusdec; - rad = radius >> radiusbiasshift; + radius -= radius / RADIUSDEC; + rad = radius >> RADIUSBIASSHIFT; if (rad <= 1) rad = 0; for (j = 0; j < rad; j++) radpower[j] = - alpha * (((rad * rad - j * j) * radbias) / (rad * rad)); + alpha * (((rad * rad - j * j) * RADBIAS) / (rad * rad)); } } //fprintf(stderr,"finished 1D learning: final alpha=%f !\n",((float)alpha)/initalpha); @@ -285,12 +285,12 @@ public class NeuQuant { i = netindex[g]; /* index on g */ j = i - 1; /* start at netindex[g] and work outwards */ - while ((i < netsize) || (j >= 0)) { - if (i < netsize) { + while ((i < NETSIZE) || (j >= 0)) { + if (i < NETSIZE) { p = network[i]; dist = p[1] - g; /* inx key */ if (dist >= bestd) - i = netsize; /* stop iter */ + i = NETSIZE; /* stop iter */ else { i++; if (dist < 0) @@ -353,10 +353,10 @@ public class NeuQuant { int i, j; - for (i = 0; i < netsize; i++) { - network[i][0] >>= netbiasshift; - network[i][1] >>= netbiasshift; - network[i][2] >>= netbiasshift; + for (i = 0; i < NETSIZE; i++) { + network[i][0] >>= NETBIASSHIFT; + network[i][1] >>= NETBIASSHIFT; + network[i][2] >>= NETBIASSHIFT; network[i][3] = i; /* record colour no */ } } @@ -372,8 +372,8 @@ public class NeuQuant { if (lo < -1) lo = -1; hi = i + rad; - if (hi > netsize) - hi = netsize; + if (hi > NETSIZE) + hi = NETSIZE; j = i + 1; k = i - 1; @@ -383,18 +383,18 @@ public class NeuQuant { if (j < hi) { p = network[j++]; try { - p[0] -= (a * (p[0] - b)) / alpharadbias; - p[1] -= (a * (p[1] - g)) / alpharadbias; - p[2] -= (a * (p[2] - r)) / alpharadbias; + p[0] -= (a * (p[0] - b)) / ALPHARADBIAS; + p[1] -= (a * (p[1] - g)) / ALPHARADBIAS; + p[2] -= (a * (p[2] - r)) / ALPHARADBIAS; } catch (Exception ignored) { } // prevents 1.3 miscompilation } if (k > lo) { p = network[k--]; try { - p[0] -= (a * (p[0] - b)) / alpharadbias; - p[1] -= (a * (p[1] - g)) / alpharadbias; - p[2] -= (a * (p[2] - r)) / alpharadbias; + p[0] -= (a * (p[0] - b)) / ALPHARADBIAS; + p[1] -= (a * (p[1] - g)) / ALPHARADBIAS; + p[2] -= (a * (p[2] - r)) / ALPHARADBIAS; } catch (Exception ignored) { } } @@ -407,9 +407,9 @@ public class NeuQuant { /* alter hit neuron */ int[] n = network[i]; - n[0] -= (alpha * (n[0] - b)) / initalpha; - n[1] -= (alpha * (n[1] - g)) / initalpha; - n[2] -= (alpha * (n[2] - r)) / initalpha; + n[0] -= (alpha * (n[0] - b)) / INITALPHA; + n[1] -= (alpha * (n[1] - g)) / INITALPHA; + n[2] -= (alpha * (n[2] - r)) / INITALPHA; } /* Search for biased BGR values @@ -430,7 +430,7 @@ public class NeuQuant { bestpos = -1; bestbiaspos = bestpos; - for (i = 0; i < netsize; i++) { + for (i = 0; i < NETSIZE; i++) { n = network[i]; dist = n[0] - b; if (dist < 0) @@ -447,17 +447,17 @@ public class NeuQuant { bestd = dist; bestpos = i; } - biasdist = dist - ((bias[i]) >> (intbiasshift - netbiasshift)); + biasdist = dist - ((bias[i]) >> (INTBIASSHIFT - NETBIASSHIFT)); if (biasdist < bestbiasd) { bestbiasd = biasdist; bestbiaspos = i; } - betafreq = (freq[i] >> betashift); + betafreq = (freq[i] >> BETASHIFT); freq[i] -= betafreq; - bias[i] += (betafreq << gammashift); + bias[i] += (betafreq << GAMMASHIFT); } - freq[bestpos] += beta; - bias[bestpos] -= betagamma; + freq[bestpos] += BETA; + bias[bestpos] -= BETAGAMMA; return (bestbiaspos); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/io/FileTypeUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/FileTypeUtil.java index aa6884948..5b34d4a25 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/FileTypeUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/FileTypeUtil.java @@ -20,60 +20,60 @@ import cn.hutool.core.util.StrUtil; */ public class FileTypeUtil { - private static final Map fileTypeMap; + private static final Map FILE_TYPE_MAP; static { - fileTypeMap = new ConcurrentHashMap<>(); + FILE_TYPE_MAP = new ConcurrentHashMap<>(); - fileTypeMap.put("ffd8ff", "jpg"); // JPEG (jpg) - fileTypeMap.put("89504e47", "png"); // PNG (png) - fileTypeMap.put("4749463837", "gif"); // GIF (gif) - fileTypeMap.put("4749463839", "gif"); // GIF (gif) - fileTypeMap.put("49492a00227105008037", "tif"); // TIFF (tif) - fileTypeMap.put("424d228c010000000000", "bmp"); // 16色位图(bmp) - fileTypeMap.put("424d8240090000000000", "bmp"); // 24位位图(bmp) - fileTypeMap.put("424d8e1b030000000000", "bmp"); // 256色位图(bmp) - fileTypeMap.put("41433130313500000000", "dwg"); // CAD (dwg) - fileTypeMap.put("7b5c727466315c616e73", "rtf"); // Rich Text Format (rtf) - fileTypeMap.put("38425053000100000000", "psd"); // Photoshop (psd) - fileTypeMap.put("46726f6d3a203d3f6762", "eml"); // Email [Outlook Express 6] (eml) - fileTypeMap.put("5374616E64617264204A", "mdb"); // MS Access (mdb) - fileTypeMap.put("252150532D41646F6265", "ps"); - fileTypeMap.put("255044462d312e", "pdf"); // Adobe Acrobat (pdf) - fileTypeMap.put("2e524d46000000120001", "rmvb"); // rmvb/rm相同 - fileTypeMap.put("464c5601050000000900", "flv"); // flv与f4v相同 - fileTypeMap.put("00000020667479706", "mp4"); - fileTypeMap.put("00000018667479706D70", "mp4"); - fileTypeMap.put("49443303000000002176", "mp3"); - fileTypeMap.put("000001ba210001000180", "mpg"); // - fileTypeMap.put("3026b2758e66cf11a6d9", "wmv"); // wmv与asf相同 - fileTypeMap.put("52494646e27807005741", "wav"); // Wave (wav) - fileTypeMap.put("52494646d07d60074156", "avi"); - fileTypeMap.put("4d546864000000060001", "mid"); // MIDI (mid) - fileTypeMap.put("526172211a0700cf9073", "rar");// WinRAR - fileTypeMap.put("235468697320636f6e66", "ini"); - fileTypeMap.put("504B03040a0000000000", "jar"); - fileTypeMap.put("504B0304140008000800", "jar"); + FILE_TYPE_MAP.put("ffd8ff", "jpg"); // JPEG (jpg) + FILE_TYPE_MAP.put("89504e47", "png"); // PNG (png) + FILE_TYPE_MAP.put("4749463837", "gif"); // GIF (gif) + FILE_TYPE_MAP.put("4749463839", "gif"); // GIF (gif) + FILE_TYPE_MAP.put("49492a00227105008037", "tif"); // TIFF (tif) + FILE_TYPE_MAP.put("424d228c010000000000", "bmp"); // 16色位图(bmp) + FILE_TYPE_MAP.put("424d8240090000000000", "bmp"); // 24位位图(bmp) + FILE_TYPE_MAP.put("424d8e1b030000000000", "bmp"); // 256色位图(bmp) + FILE_TYPE_MAP.put("41433130313500000000", "dwg"); // CAD (dwg) + FILE_TYPE_MAP.put("7b5c727466315c616e73", "rtf"); // Rich Text Format (rtf) + FILE_TYPE_MAP.put("38425053000100000000", "psd"); // Photoshop (psd) + FILE_TYPE_MAP.put("46726f6d3a203d3f6762", "eml"); // Email [Outlook Express 6] (eml) + FILE_TYPE_MAP.put("5374616E64617264204A", "mdb"); // MS Access (mdb) + FILE_TYPE_MAP.put("252150532D41646F6265", "ps"); + FILE_TYPE_MAP.put("255044462d312e", "pdf"); // Adobe Acrobat (pdf) + FILE_TYPE_MAP.put("2e524d46000000120001", "rmvb"); // rmvb/rm相同 + FILE_TYPE_MAP.put("464c5601050000000900", "flv"); // flv与f4v相同 + FILE_TYPE_MAP.put("00000020667479706", "mp4"); + FILE_TYPE_MAP.put("00000018667479706D70", "mp4"); + FILE_TYPE_MAP.put("49443303000000002176", "mp3"); + FILE_TYPE_MAP.put("000001ba210001000180", "mpg"); // + FILE_TYPE_MAP.put("3026b2758e66cf11a6d9", "wmv"); // wmv与asf相同 + FILE_TYPE_MAP.put("52494646e27807005741", "wav"); // Wave (wav) + FILE_TYPE_MAP.put("52494646d07d60074156", "avi"); + FILE_TYPE_MAP.put("4d546864000000060001", "mid"); // MIDI (mid) + FILE_TYPE_MAP.put("526172211a0700cf9073", "rar");// WinRAR + FILE_TYPE_MAP.put("235468697320636f6e66", "ini"); + FILE_TYPE_MAP.put("504B03040a0000000000", "jar"); + FILE_TYPE_MAP.put("504B0304140008000800", "jar"); // MS Excel 注意:word、msi 和 excel的文件头一样 - fileTypeMap.put("d0cf11e0a1b11ae10", "xls"); - fileTypeMap.put("504B0304", "zip"); - fileTypeMap.put("4d5a9000030000000400", "exe");// 可执行文件 - fileTypeMap.put("3c25402070616765206c", "jsp");// jsp文件 - fileTypeMap.put("4d616e69666573742d56", "mf");// MF文件 - fileTypeMap.put("7061636b616765207765", "java");// java文件 - fileTypeMap.put("406563686f206f66660d", "bat");// bat文件 - fileTypeMap.put("1f8b0800000000000000", "gz");// gz文件 - fileTypeMap.put("cafebabe0000002e0041", "class");// bat文件 - fileTypeMap.put("49545346030000006000", "chm");// bat文件 - fileTypeMap.put("04000000010000001300", "mxp");// bat文件 - fileTypeMap.put("6431303a637265617465", "torrent"); - fileTypeMap.put("6D6F6F76", "mov"); // Quicktime (mov) - fileTypeMap.put("FF575043", "wpd"); // WordPerfect (wpd) - fileTypeMap.put("CFAD12FEC5FD746F", "dbx"); // Outlook Express (dbx) - fileTypeMap.put("2142444E", "pst"); // Outlook (pst) - fileTypeMap.put("AC9EBD8F", "qdf"); // Quicken (qdf) - fileTypeMap.put("E3828596", "pwl"); // Windows Password (pwl) - fileTypeMap.put("2E7261FD", "ram"); // Real Audio (ram) + FILE_TYPE_MAP.put("d0cf11e0a1b11ae10", "xls"); + FILE_TYPE_MAP.put("504B0304", "zip"); + FILE_TYPE_MAP.put("4d5a9000030000000400", "exe");// 可执行文件 + FILE_TYPE_MAP.put("3c25402070616765206c", "jsp");// jsp文件 + FILE_TYPE_MAP.put("4d616e69666573742d56", "mf");// MF文件 + FILE_TYPE_MAP.put("7061636b616765207765", "java");// java文件 + FILE_TYPE_MAP.put("406563686f206f66660d", "bat");// bat文件 + FILE_TYPE_MAP.put("1f8b0800000000000000", "gz");// gz文件 + FILE_TYPE_MAP.put("cafebabe0000002e0041", "class");// bat文件 + FILE_TYPE_MAP.put("49545346030000006000", "chm");// bat文件 + FILE_TYPE_MAP.put("04000000010000001300", "mxp");// bat文件 + FILE_TYPE_MAP.put("6431303a637265617465", "torrent"); + FILE_TYPE_MAP.put("6D6F6F76", "mov"); // Quicktime (mov) + FILE_TYPE_MAP.put("FF575043", "wpd"); // WordPerfect (wpd) + FILE_TYPE_MAP.put("CFAD12FEC5FD746F", "dbx"); // Outlook Express (dbx) + FILE_TYPE_MAP.put("2142444E", "pst"); // Outlook (pst) + FILE_TYPE_MAP.put("AC9EBD8F", "qdf"); // Quicken (qdf) + FILE_TYPE_MAP.put("E3828596", "pwl"); // Windows Password (pwl) + FILE_TYPE_MAP.put("2E7261FD", "ram"); // Real Audio (ram) } /** @@ -85,7 +85,7 @@ public class FileTypeUtil { * @return 之前已经存在的文件扩展名 */ public static String putFileType(String fileStreamHexHead, String extName) { - return fileTypeMap.put(fileStreamHexHead.toLowerCase(), extName); + return FILE_TYPE_MAP.put(fileStreamHexHead.toLowerCase(), extName); } /** @@ -95,7 +95,7 @@ public class FileTypeUtil { * @return 移除的文件扩展名 */ public static String removeFileType(String fileStreamHexHead) { - return fileTypeMap.remove(fileStreamHexHead.toLowerCase()); + return FILE_TYPE_MAP.remove(fileStreamHexHead.toLowerCase()); } /** @@ -105,7 +105,7 @@ public class FileTypeUtil { * @return 文件类型,未找到为null */ public static String getType(String fileStreamHexHead) { - for (Entry fileTypeEntry : fileTypeMap.entrySet()) { + for (Entry fileTypeEntry : FILE_TYPE_MAP.entrySet()) { if (StrUtil.startWithIgnoreCase(fileStreamHexHead, fileTypeEntry.getKey())) { return fileTypeEntry.getValue(); } diff --git a/hutool-core/src/main/java/cn/hutool/core/io/IoUtil.java b/hutool-core/src/main/java/cn/hutool/core/io/IoUtil.java index 6700bb29b..134f377fa 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/IoUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/IoUtil.java @@ -421,6 +421,18 @@ public class IoUtil { // -------------------------------------------------------------------------------------- read start + /** + * 从流中读取UTF8编码的内容 + * + * @param in 输入流 + * @return 内容 + * @throws IORuntimeException IO异常 + * @since 5.4.4 + */ + public static String readUtf8(InputStream in) throws IORuntimeException { + return read(in, CharsetUtil.CHARSET_UTF_8); + } + /** * 从流中读取内容 * @@ -1251,7 +1263,7 @@ public class IoUtil { * @throws IORuntimeException IO异常 * @since 5.4.0 */ - public static long checksumValue(InputStream in, Checksum checksum){ + public static long checksumValue(InputStream in, Checksum checksum) { return checksum(in, checksum).getValue(); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16Ansi.java b/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16Ansi.java index 662a8759d..44830d137 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16Ansi.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16Ansi.java @@ -8,7 +8,7 @@ package cn.hutool.core.io.checksum.crc16; */ public class CRC16Ansi extends CRC16Checksum{ - private static final int wCPoly = 0xa001; + private static final int WC_POLY = 0xa001; @Override public void reset() { @@ -25,7 +25,7 @@ public class CRC16Ansi extends CRC16Checksum{ int flag = wCRCin & 0x0001; wCRCin = wCRCin >> 1; if (flag == 1) { - wCRCin ^= wCPoly; + wCRCin ^= WC_POLY; } } } diff --git a/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16CCITT.java b/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16CCITT.java index 7811855e3..2279fdc37 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16CCITT.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16CCITT.java @@ -9,7 +9,7 @@ package cn.hutool.core.io.checksum.crc16; */ public class CRC16CCITT extends CRC16Checksum{ - private static final int wCPoly = 0x8408; + private static final int WC_POLY = 0x8408; @Override public void update(int b) { @@ -17,7 +17,7 @@ public class CRC16CCITT extends CRC16Checksum{ for (int j = 0; j < 8; j++) { if ((wCRCin & 0x0001) != 0) { wCRCin >>= 1; - wCRCin ^= wCPoly; + wCRCin ^= WC_POLY; } else { wCRCin >>= 1; } diff --git a/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16CCITTFalse.java b/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16CCITTFalse.java index 2e8c56b62..bdfd203ff 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16CCITTFalse.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16CCITTFalse.java @@ -8,7 +8,7 @@ package cn.hutool.core.io.checksum.crc16; */ public class CRC16CCITTFalse extends CRC16Checksum{ - private static final int wCPoly = 0x1021; + private static final int WC_POLY = 0x1021; @Override public void reset() { @@ -28,7 +28,7 @@ public class CRC16CCITTFalse extends CRC16Checksum{ boolean c15 = ((wCRCin >> 15 & 1) == 1); wCRCin <<= 1; if (c15 ^ bit) - wCRCin ^= wCPoly; + wCRCin ^= WC_POLY; } } } diff --git a/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16DNP.java b/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16DNP.java index fe89a00f0..c03649791 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16DNP.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16DNP.java @@ -9,7 +9,7 @@ package cn.hutool.core.io.checksum.crc16; */ public class CRC16DNP extends CRC16Checksum{ - private static final int wCPoly = 0xA6BC; + private static final int WC_POLY = 0xA6BC; @Override public void update(byte[] b, int off, int len) { @@ -23,7 +23,7 @@ public class CRC16DNP extends CRC16Checksum{ for (int j = 0; j < 8; j++) { if ((wCRCin & 0x0001) != 0) { wCRCin >>= 1; - wCRCin ^= wCPoly; + wCRCin ^= WC_POLY; } else { wCRCin >>= 1; } diff --git a/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16IBM.java b/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16IBM.java index 1c340d29f..fdc793bca 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16IBM.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16IBM.java @@ -9,7 +9,7 @@ package cn.hutool.core.io.checksum.crc16; */ public class CRC16IBM extends CRC16Checksum{ - private static final int wCPoly = 0xa001; + private static final int WC_POLY = 0xa001; @Override public void update(int b) { @@ -17,7 +17,7 @@ public class CRC16IBM extends CRC16Checksum{ for (int j = 0; j < 8; j++) { if ((wCRCin & 0x0001) != 0) { wCRCin >>= 1; - wCRCin ^= wCPoly; + wCRCin ^= WC_POLY; } else { wCRCin >>= 1; } diff --git a/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16Maxim.java b/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16Maxim.java index 195bd55bf..38f916cd8 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16Maxim.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16Maxim.java @@ -9,7 +9,7 @@ package cn.hutool.core.io.checksum.crc16; */ public class CRC16Maxim extends CRC16Checksum{ - private static final int wCPoly = 0xa001; + private static final int WC_POLY = 0xa001; @Override public void update(byte[] b, int off, int len) { @@ -23,7 +23,7 @@ public class CRC16Maxim extends CRC16Checksum{ for (int j = 0; j < 8; j++) { if ((wCRCin & 0x0001) != 0) { wCRCin >>= 1; - wCRCin ^= wCPoly; + wCRCin ^= WC_POLY; } else { wCRCin >>= 1; } diff --git a/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16Modbus.java b/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16Modbus.java index 857f3bf16..4d4ee64a5 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16Modbus.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16Modbus.java @@ -10,7 +10,7 @@ package cn.hutool.core.io.checksum.crc16; */ public class CRC16Modbus extends CRC16Checksum{ - private static final int wCPoly = 0xa001; + private static final int WC_POLY = 0xa001; @Override public void reset(){ @@ -23,7 +23,7 @@ public class CRC16Modbus extends CRC16Checksum{ for (int j = 0; j < 8; j++) { if ((wCRCin & 0x0001) != 0) { wCRCin >>= 1; - wCRCin ^= wCPoly; + wCRCin ^= WC_POLY; } else { wCRCin >>= 1; } diff --git a/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16USB.java b/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16USB.java index b9f9503c5..143e7aba0 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16USB.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16USB.java @@ -9,7 +9,7 @@ package cn.hutool.core.io.checksum.crc16; */ public class CRC16USB extends CRC16Checksum{ - private static final int wCPoly = 0xa001; + private static final int WC_POLY = 0xa001; @Override public void reset(){ @@ -28,7 +28,7 @@ public class CRC16USB extends CRC16Checksum{ for (int j = 0; j < 8; j++) { if ((wCRCin & 0x0001) != 0) { wCRCin >>= 1; - wCRCin ^= wCPoly; + wCRCin ^= WC_POLY; } else { wCRCin >>= 1; } diff --git a/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16X25.java b/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16X25.java index 5c938852d..140e6ab15 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16X25.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16X25.java @@ -9,7 +9,7 @@ package cn.hutool.core.io.checksum.crc16; */ public class CRC16X25 extends CRC16Checksum{ - private static final int wCPoly = 0x8408; + private static final int WC_POLY = 0x8408; @Override public void reset(){ @@ -28,7 +28,7 @@ public class CRC16X25 extends CRC16Checksum{ for (int j = 0; j < 8; j++) { if ((wCRCin & 0x0001) != 0) { wCRCin >>= 1; - wCRCin ^= wCPoly; + wCRCin ^= WC_POLY; } else { wCRCin >>= 1; } diff --git a/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16XModem.java b/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16XModem.java index 86689e6c9..27d8c5235 100644 --- a/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16XModem.java +++ b/hutool-core/src/main/java/cn/hutool/core/io/checksum/crc16/CRC16XModem.java @@ -10,7 +10,7 @@ package cn.hutool.core.io.checksum.crc16; public class CRC16XModem extends CRC16Checksum{ // 0001 0000 0010 0001 (0, 5, 12) - private static final int wCPoly = 0x1021; + private static final int WC_POLY = 0x1021; @Override public void update(byte[] b, int off, int len) { @@ -25,7 +25,7 @@ public class CRC16XModem extends CRC16Checksum{ boolean c15 = ((wCRCin >> 15 & 1) == 1); wCRCin <<= 1; if (c15 ^ bit) - wCRCin ^= wCPoly; + wCRCin ^= WC_POLY; } } } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/ConsoleTableUtil.java b/hutool-core/src/main/java/cn/hutool/core/lang/ConsoleTableUtil.java new file mode 100644 index 000000000..f894dbf50 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/lang/ConsoleTableUtil.java @@ -0,0 +1,177 @@ +package cn.hutool.core.lang; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.StrUtil; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * 控制台打印表格工具 + * + * @author 孙宇 + */ +public class ConsoleTableUtil { + /** + * 表格头信息 + */ + private final List> HEADER_LIST = new ArrayList<>(); + /** + * 表格体信息 + */ + private final List> BODY_LIST = new ArrayList<>(); + /** + * 每列最大字符个数 + */ + private List columnCharNumber; + + /** + * 测试 + * + * @param args + */ + public static void main(String[] args) { + ConsoleTableUtil t = new ConsoleTableUtil(); + t.addHeader("姓名", "年龄"); + t.addBody("张三", "15"); + t.addBody("李四", "29"); + t.addBody("王二麻子", "37"); + t.print(); + + t = new ConsoleTableUtil(); + t.addHeader("体温", "占比"); + t.addHeader("℃", "%"); + t.addBody("36.8", "10"); + t.addBody("37", "5"); + t.print(); + + t = new ConsoleTableUtil(); + t.addHeader("标题1", "标题2"); + t.addBody("12345", "混合321654asdfcSDF"); + t.addBody("sd e3ee ff22", "ff值"); + t.print(); + } + + /** + * 添加头信息 + * + * @param titles 列名 + * @return 自身对象 + */ + public ConsoleTableUtil addHeader(String... titles) { + if (columnCharNumber == null) { + columnCharNumber = new ArrayList<>(Collections.nCopies(titles.length, 0)); + } + List l = new ArrayList<>(); + HEADER_LIST.add(l); + fillColumns(l, titles); + return this; + } + + /** + * 添加体信息 + * + * @param values 列值 + * @return 自身对象 + */ + public ConsoleTableUtil addBody(String... values) { + List l = new ArrayList<>(); + BODY_LIST.add(l); + fillColumns(l, values); + return this; + } + + /** + * 填充表格头或者体 + * + * @param l + * @param columns + */ + private void fillColumns(List l, String[] columns) { + for (int i = 0; i < columns.length; i++) { + String column = columns[i]; + String col = Convert.toSBC(column); + l.add(col); + int width = col.length(); + if (width > columnCharNumber.get(i)) { + columnCharNumber.set(i, width); + } + } + } + + /** + * 获取表格字符串 + * + * @return 表格字符串 + */ + public String toString() { + StringBuilder sb = new StringBuilder(); + fillBorder(sb); + for (List headers : HEADER_LIST) { + for (int i = 0; i < headers.size(); i++) { + if (i == 0) { + sb.append('|'); + } + String header = headers.get(i); + sb.append(Convert.toSBC(" ")); + sb.append(header); + sb.append(Convert.toSBC(" ")); + int l = header.length(); + int lw = columnCharNumber.get(i); + if (lw > l) { + for (int j = 0; j < (lw - l); j++) { + sb.append(Convert.toSBC(" ")); + } + } + sb.append('|'); + } + sb.append('\n'); + } + fillBorder(sb); + for (List bodys : BODY_LIST) { + for (int i = 0; i < bodys.size(); i++) { + if (i == 0) { + sb.append('|'); + } + String body = bodys.get(i); + sb.append(Convert.toSBC(" ")); + sb.append(body); + sb.append(Convert.toSBC(" ")); + int l = body.length(); + int lw = columnCharNumber.get(i); + if (lw > l) { + for (int j = 0; j < (lw - l); j++) { + sb.append(Convert.toSBC(" ")); + } + } + sb.append('|'); + } + sb.append('\n'); + } + fillBorder(sb); + return sb.toString(); + } + + /** + * 拼装边框 + * + * @param sb + */ + private void fillBorder(StringBuilder sb) { + sb.append('*'); + for (Integer width : columnCharNumber) { + sb.append(Convert.toSBC(StrUtil.fillAfter("", '-', width + 2))); + sb.append('*'); + } + sb.append('\n'); + } + + /** + * 打印到控制台 + */ + public void print() { + Console.print(toString()); + } + +} \ No newline at end of file diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/ObjectId.java b/hutool-core/src/main/java/cn/hutool/core/lang/ObjectId.java index bc6acdbd4..eda64d776 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/ObjectId.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/ObjectId.java @@ -31,9 +31,9 @@ import cn.hutool.core.util.StrUtil; public class ObjectId { /** 线程安全的下一个随机数,每次生成自增+1 */ - private static final AtomicInteger nextInc = new AtomicInteger(RandomUtil.randomInt()); + private static final AtomicInteger NEXT_INC = new AtomicInteger(RandomUtil.randomInt()); /** 机器信息 */ - private static final int machine = getMachinePiece() | getProcessPiece(); + private static final int MACHINE = getMachinePiece() | getProcessPiece(); /** * 给定的字符串是否为有效的ObjectId @@ -77,8 +77,8 @@ public class ObjectId { public static byte[] nextBytes() { final ByteBuffer bb = ByteBuffer.wrap(new byte[12]); bb.putInt((int) DateUtil.currentSeconds());// 4位 - bb.putInt(machine);// 4位 - bb.putInt(nextInc.getAndIncrement());// 4位 + bb.putInt(MACHINE);// 4位 + bb.putInt(NEXT_INC.getAndIncrement());// 4位 return bb.array(); } diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/UUID.java b/hutool-core/src/main/java/cn/hutool/core/lang/UUID.java index 0735769ab..9acdd342b 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/UUID.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/UUID.java @@ -49,7 +49,7 @@ public class UUID implements java.io.Serializable, Comparable { * @author looly */ private static class Holder { - static final SecureRandom numberGenerator = RandomUtil.getSecureRandom(); + static final SecureRandom NUMBER_GENERATOR = RandomUtil.getSecureRandom(); } /** @@ -117,7 +117,7 @@ public class UUID implements java.io.Serializable, Comparable { * @return 随机生成的 {@code UUID} */ public static UUID randomUUID(boolean isSecure) { - final Random ng = isSecure ? Holder.numberGenerator : RandomUtil.getRandom(); + final Random ng = isSecure ? Holder.NUMBER_GENERATOR : RandomUtil.getRandom(); final byte[] randomBytes = new byte[16]; ng.nextBytes(randomBytes); diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/reflect/ActualTypeMapperPool.java b/hutool-core/src/main/java/cn/hutool/core/lang/reflect/ActualTypeMapperPool.java index 1bf09c11a..5df621904 100644 --- a/hutool-core/src/main/java/cn/hutool/core/lang/reflect/ActualTypeMapperPool.java +++ b/hutool-core/src/main/java/cn/hutool/core/lang/reflect/ActualTypeMapperPool.java @@ -17,7 +17,7 @@ import java.util.Map; */ public class ActualTypeMapperPool { - private static final SimpleCache> cache = new SimpleCache<>(); + private static final SimpleCache> CACHE = new SimpleCache<>(); /** * 获取泛型变量和泛型实际类型的对应关系Map @@ -26,7 +26,7 @@ public class ActualTypeMapperPool { * @return 泛型对应关系Map */ public static Map get(Type type) { - return cache.get(type, () -> createTypeMap(type)); + return CACHE.get(type, () -> createTypeMap(type)); } /** diff --git a/hutool-core/src/main/java/cn/hutool/core/math/Money.java b/hutool-core/src/main/java/cn/hutool/core/math/Money.java index 7845181c9..59d4288f4 100644 --- a/hutool-core/src/main/java/cn/hutool/core/math/Money.java +++ b/hutool-core/src/main/java/cn/hutool/core/math/Money.java @@ -67,7 +67,7 @@ public class Money implements Serializable, Comparable { * 此处,“分”是指货币的最小单位,“元”是货币的最常用单位, * 不同的币种有不同的元/分换算比例,如人民币是100,而日元为1。 */ - private static final int[] centFactors = new int[]{1, 10, 100, 1000}; + private static final int[] CENT_FACTORS = new int[]{1, 10, 100, 1000}; /** * 金额,以分为单位。 @@ -318,7 +318,7 @@ public class Money implements Serializable, Comparable { * @return 本货币币种的元/分换算比率。 */ public int getCentFactor() { - return centFactors[currency.getDefaultFractionDigits()]; + return CENT_FACTORS[currency.getDefaultFractionDigits()]; } // 基本对象方法 =================================================== diff --git a/hutool-core/src/main/java/cn/hutool/core/net/MaskBit.java b/hutool-core/src/main/java/cn/hutool/core/net/MaskBit.java index 108ee1635..49647d977 100644 --- a/hutool-core/src/main/java/cn/hutool/core/net/MaskBit.java +++ b/hutool-core/src/main/java/cn/hutool/core/net/MaskBit.java @@ -11,41 +11,41 @@ import java.util.Map; */ public class MaskBit { - private static final Map maskBitMap; + private static final Map MASK_BIT_MAP; static { - maskBitMap = new HashMap<>(32); - maskBitMap.put(1, "128.0.0.0"); - maskBitMap.put(2, "192.0.0.0"); - maskBitMap.put(3, "224.0.0.0"); - maskBitMap.put(4, "240.0.0.0"); - maskBitMap.put(5, "248.0.0.0"); - maskBitMap.put(6, "252.0.0.0"); - maskBitMap.put(7, "254.0.0.0"); - maskBitMap.put(8, "255.0.0.0"); - maskBitMap.put(9, "255.128.0.0"); - maskBitMap.put(10, "255.192.0.0"); - maskBitMap.put(11, "255.224.0.0"); - maskBitMap.put(12, "255.240.0.0"); - maskBitMap.put(13, "255.248.0.0"); - maskBitMap.put(14, "255.252.0.0"); - maskBitMap.put(15, "255.254.0.0"); - maskBitMap.put(16, "255.255.0.0"); - maskBitMap.put(17, "255.255.128.0"); - maskBitMap.put(18, "255.255.192.0"); - maskBitMap.put(19, "255.255.224.0"); - maskBitMap.put(20, "255.255.240.0"); - maskBitMap.put(21, "255.255.248.0"); - maskBitMap.put(22, "255.255.252.0"); - maskBitMap.put(23, "255.255.254.0"); - maskBitMap.put(24, "255.255.255.0"); - maskBitMap.put(25, "255.255.255.128"); - maskBitMap.put(26, "255.255.255.192"); - maskBitMap.put(27, "255.255.255.224"); - maskBitMap.put(28, "255.255.255.240"); - maskBitMap.put(29, "255.255.255.248"); - maskBitMap.put(30, "255.255.255.252"); - maskBitMap.put(31, "255.255.255.254"); - maskBitMap.put(32, "255.255.255.255"); + MASK_BIT_MAP = new HashMap<>(32); + MASK_BIT_MAP.put(1, "128.0.0.0"); + MASK_BIT_MAP.put(2, "192.0.0.0"); + MASK_BIT_MAP.put(3, "224.0.0.0"); + MASK_BIT_MAP.put(4, "240.0.0.0"); + MASK_BIT_MAP.put(5, "248.0.0.0"); + MASK_BIT_MAP.put(6, "252.0.0.0"); + MASK_BIT_MAP.put(7, "254.0.0.0"); + MASK_BIT_MAP.put(8, "255.0.0.0"); + MASK_BIT_MAP.put(9, "255.128.0.0"); + MASK_BIT_MAP.put(10, "255.192.0.0"); + MASK_BIT_MAP.put(11, "255.224.0.0"); + MASK_BIT_MAP.put(12, "255.240.0.0"); + MASK_BIT_MAP.put(13, "255.248.0.0"); + MASK_BIT_MAP.put(14, "255.252.0.0"); + MASK_BIT_MAP.put(15, "255.254.0.0"); + MASK_BIT_MAP.put(16, "255.255.0.0"); + MASK_BIT_MAP.put(17, "255.255.128.0"); + MASK_BIT_MAP.put(18, "255.255.192.0"); + MASK_BIT_MAP.put(19, "255.255.224.0"); + MASK_BIT_MAP.put(20, "255.255.240.0"); + MASK_BIT_MAP.put(21, "255.255.248.0"); + MASK_BIT_MAP.put(22, "255.255.252.0"); + MASK_BIT_MAP.put(23, "255.255.254.0"); + MASK_BIT_MAP.put(24, "255.255.255.0"); + MASK_BIT_MAP.put(25, "255.255.255.128"); + MASK_BIT_MAP.put(26, "255.255.255.192"); + MASK_BIT_MAP.put(27, "255.255.255.224"); + MASK_BIT_MAP.put(28, "255.255.255.240"); + MASK_BIT_MAP.put(29, "255.255.255.248"); + MASK_BIT_MAP.put(30, "255.255.255.252"); + MASK_BIT_MAP.put(31, "255.255.255.254"); + MASK_BIT_MAP.put(32, "255.255.255.255"); } /** @@ -55,6 +55,6 @@ public class MaskBit { * @return 掩码 */ public static String get(int maskBit) { - return maskBitMap.get(maskBit); + return MASK_BIT_MAP.get(maskBit); } } 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 7aa04aaca..a27af3716 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 @@ -43,6 +43,8 @@ public class NetUtil { public final static String LOCAL_IP = "127.0.0.1"; + public static String localhostName; + /** * 默认最小端口,1024 */ @@ -533,6 +535,29 @@ public class NetUtil { return null; } + /** + * 获取主机名称,一次获取会缓存名称 + * + * @return 主机名称 + * @since 5.4.4 + */ + public static String getLocalHostName() { + if (StrUtil.isNotBlank(localhostName)) { + return localhostName; + } + + final InetAddress localhost = getLocalhost(); + if(null != localhost){ + String name = localhost.getHostName(); + if(StrUtil.isEmpty(name)){ + name = localhost.getHostAddress(); + } + localhostName = name; + } + + return localhostName; + } + /** * 创建 {@link InetSocketAddress} * diff --git a/hutool-core/src/main/java/cn/hutool/core/swing/RobotUtil.java b/hutool-core/src/main/java/cn/hutool/core/swing/RobotUtil.java index 64abd532b..c25d7138c 100644 --- a/hutool-core/src/main/java/cn/hutool/core/swing/RobotUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/swing/RobotUtil.java @@ -20,12 +20,12 @@ import cn.hutool.core.swing.clipboard.ClipboardUtil; */ public class RobotUtil { - private static final Robot robot; + private static final Robot ROBOT; private static int delay; static { try { - robot = new Robot(); + ROBOT = new Robot(); } catch (AWTException e) { throw new UtilException(e); } @@ -50,7 +50,7 @@ public class RobotUtil { * @since 4.5.7 */ public static void mouseMove(int x, int y) { - robot.mouseMove(x, y); + ROBOT.mouseMove(x, y); } /** @@ -60,8 +60,8 @@ public class RobotUtil { * @since 4.5.7 */ public static void click() { - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.mouseRelease(InputEvent.BUTTON1_MASK); + ROBOT.mousePress(InputEvent.BUTTON1_MASK); + ROBOT.mouseRelease(InputEvent.BUTTON1_MASK); delay(); } @@ -72,8 +72,8 @@ public class RobotUtil { * @since 4.5.7 */ public static void rightClick() { - robot.mousePress(InputEvent.BUTTON1_MASK); - robot.mouseRelease(InputEvent.BUTTON1_MASK); + ROBOT.mousePress(InputEvent.BUTTON1_MASK); + ROBOT.mouseRelease(InputEvent.BUTTON1_MASK); delay(); } @@ -84,7 +84,7 @@ public class RobotUtil { * @since 4.5.7 */ public static void mouseWheel(int wheelAmt) { - robot.mouseWheel(wheelAmt); + ROBOT.mouseWheel(wheelAmt); delay(); } @@ -97,8 +97,8 @@ public class RobotUtil { */ public static void keyClick(int... keyCodes) { for (int keyCode : keyCodes) { - robot.keyPress(keyCode); - robot.keyRelease(keyCode); + ROBOT.keyPress(keyCode); + ROBOT.keyRelease(keyCode); } delay(); } @@ -120,10 +120,10 @@ public class RobotUtil { * @param key 按键 */ public static void keyPressWithShift(int key) { - robot.keyPress(KeyEvent.VK_SHIFT); - robot.keyPress(key); - robot.keyRelease(key); - robot.keyRelease(KeyEvent.VK_SHIFT); + ROBOT.keyPress(KeyEvent.VK_SHIFT); + ROBOT.keyPress(key); + ROBOT.keyRelease(key); + ROBOT.keyRelease(KeyEvent.VK_SHIFT); delay(); } @@ -133,10 +133,10 @@ public class RobotUtil { * @param key 按键 */ public static void keyPressWithCtrl(int key) { - robot.keyPress(KeyEvent.VK_CONTROL); - robot.keyPress(key); - robot.keyRelease(key); - robot.keyRelease(KeyEvent.VK_CONTROL); + ROBOT.keyPress(KeyEvent.VK_CONTROL); + ROBOT.keyPress(key); + ROBOT.keyRelease(key); + ROBOT.keyRelease(KeyEvent.VK_CONTROL); delay(); } @@ -146,10 +146,10 @@ public class RobotUtil { * @param key 按键 */ public static void keyPressWithAlt(int key) { - robot.keyPress(KeyEvent.VK_ALT); - robot.keyPress(key); - robot.keyRelease(key); - robot.keyRelease(KeyEvent.VK_ALT); + ROBOT.keyPress(KeyEvent.VK_ALT); + ROBOT.keyPress(key); + ROBOT.keyRelease(key); + ROBOT.keyRelease(KeyEvent.VK_ALT); delay(); } @@ -180,7 +180,7 @@ public class RobotUtil { * @return 截屏的图片 */ public static BufferedImage captureScreen(Rectangle screenRect) { - return robot.createScreenCapture(screenRect); + return ROBOT.createScreenCapture(screenRect); } /** @@ -200,7 +200,7 @@ public class RobotUtil { */ private static void delay() { if (delay > 0) { - robot.delay(delay); + ROBOT.delay(delay); } } } diff --git a/hutool-core/src/main/java/cn/hutool/core/text/escape/Html4Escape.java b/hutool-core/src/main/java/cn/hutool/core/text/escape/Html4Escape.java index e44b818b0..6b141626f 100644 --- a/hutool-core/src/main/java/cn/hutool/core/text/escape/Html4Escape.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/escape/Html4Escape.java @@ -5,6 +5,8 @@ import cn.hutool.core.text.replacer.ReplacerChain; /** * HTML4的ESCAPE + * 参考:Commons Lang3 + * * @author looly * */ diff --git a/hutool-core/src/main/java/cn/hutool/core/text/escape/Html4Unescape.java b/hutool-core/src/main/java/cn/hutool/core/text/escape/Html4Unescape.java index b6d4de9ef..163860349 100644 --- a/hutool-core/src/main/java/cn/hutool/core/text/escape/Html4Unescape.java +++ b/hutool-core/src/main/java/cn/hutool/core/text/escape/Html4Unescape.java @@ -15,11 +15,14 @@ public class Html4Unescape extends ReplacerChain { protected static final String[][] BASIC_UNESCAPE = InternalEscapeUtil.invert(Html4Escape.BASIC_ESCAPE); protected static final String[][] ISO8859_1_UNESCAPE = InternalEscapeUtil.invert(Html4Escape.ISO8859_1_ESCAPE); protected static final String[][] HTML40_EXTENDED_UNESCAPE = InternalEscapeUtil.invert(Html4Escape.HTML40_EXTENDED_ESCAPE); + // issue#1118 + protected static final String[][] OTHER_UNESCAPE = new String[][]{new String[]{"'", "'"}}; public Html4Unescape() { addChain(new LookupReplacer(BASIC_UNESCAPE)); addChain(new LookupReplacer(ISO8859_1_UNESCAPE)); addChain(new LookupReplacer(HTML40_EXTENDED_UNESCAPE)); + addChain(new LookupReplacer(OTHER_UNESCAPE)); addChain(new NumericEntityUnescaper()); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/CharUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/CharUtil.java index e88a02322..e39bb286e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/CharUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/CharUtil.java @@ -11,24 +11,44 @@ import cn.hutool.core.text.ASCIIStrCache; */ public class CharUtil { + /** 字符常量:空格符 ' ' */ public static final char SPACE = ' '; + /** 字符常量:制表符 \t */ public static final char TAB = ' '; + /** 字符常量:点 . */ public static final char DOT = '.'; + /** 字符常量:斜杠 / */ public static final char SLASH = '/'; + /** 字符常量:反斜杠 \ */ public static final char BACKSLASH = '\\'; + /** 字符常量:回车符 \r */ public static final char CR = '\r'; + /** 字符常量:换行符 \n */ public static final char LF = '\n'; - public static final char UNDERLINE = '_'; + /** 字符常量:连接符 - */ public static final char DASHED = '-'; + /** 字符常量:下划线 _ */ + public static final char UNDERLINE = '_'; + /** 字符常量:逗号 , */ public static final char COMMA = ','; + /** 字符常量:花括号(左) { */ public static final char DELIM_START = '{'; + /** 字符常量:花括号(右) } */ public static final char DELIM_END = '}'; + /** 字符常量:中括号(左) [ */ public static final char BRACKET_START = '['; + /** 字符常量:中括号(右) ] */ public static final char BRACKET_END = ']'; - public static final char COLON = ':'; + /** 字符常量:双引号 : */ public static final char DOUBLE_QUOTES = '"'; + /** 字符常量:单引号 ' */ public static final char SINGLE_QUOTE = '\''; + /** 字符常量:与 & */ public static final char AMP = '&'; + /** 字符常量:冒号 : */ + public static final char COLON = ':'; + /** 字符常量:艾特 @ */ + public static final char AT = '@'; /** * 是否为ASCII字符,ASCII字符位于0~127之间 diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ClassLoaderUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ClassLoaderUtil.java index a7fcfd72d..dd821f44e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/ClassLoaderUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/ClassLoaderUtil.java @@ -33,13 +33,13 @@ public class ClassLoaderUtil { private static final char INNER_CLASS_SEPARATOR = '$'; /** 原始类型名和其class对应表,例如:int =》 int.class */ - private static final Map> primitiveTypeNameMap = new ConcurrentHashMap<>(32); - private static final SimpleCache> classCache = new SimpleCache<>(); + private static final Map> PRIMITIVE_TYPE_NAME_MAP = new ConcurrentHashMap<>(32); + private static final SimpleCache> CLASS_CACHE = new SimpleCache<>(); static { List> primitiveTypes = new ArrayList<>(32); // 加入原始类型 - primitiveTypes.addAll(BasicType.primitiveWrapperMap.keySet()); + primitiveTypes.addAll(BasicType.PRIMITIVE_WRAPPER_MAP.keySet()); // 加入原始类型数组类型 primitiveTypes.add(boolean[].class); primitiveTypes.add(byte[].class); @@ -51,7 +51,7 @@ public class ClassLoaderUtil { primitiveTypes.add(short[].class); primitiveTypes.add(void.class); for (Class primitiveType : primitiveTypes) { - primitiveTypeNameMap.put(primitiveType.getName(), primitiveType); + PRIMITIVE_TYPE_NAME_MAP.put(primitiveType.getName(), primitiveType); } } @@ -150,7 +150,7 @@ public class ClassLoaderUtil { // 加载原始类型和缓存中的类 Class clazz = loadPrimitiveClass(name); if (clazz == null) { - clazz = classCache.get(name); + clazz = CLASS_CACHE.get(name); } if (clazz != null) { return clazz; @@ -188,7 +188,7 @@ public class ClassLoaderUtil { } // 加入缓存并返回 - return classCache.put(name, clazz); + return CLASS_CACHE.put(name, clazz); } /** @@ -202,7 +202,7 @@ public class ClassLoaderUtil { if (StrUtil.isNotBlank(name)) { name = name.trim(); if (name.length() <= 8) { - result = primitiveTypeNameMap.get(name); + result = PRIMITIVE_TYPE_NAME_MAP.get(name); } } return result; diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ClassUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ClassUtil.java index 5793cc71a..7ef8108f3 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/ClassUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/ClassUtil.java @@ -713,7 +713,7 @@ public class ClassUtil { if (null == clazz) { return false; } - return BasicType.wrapperPrimitiveMap.containsKey(clazz); + return BasicType.WRAPPER_PRIMITIVE_MAP.containsKey(clazz); } /** @@ -798,11 +798,11 @@ public class ClassUtil { // 基本类型 if (targetType.isPrimitive()) { // 原始类型 - Class resolvedPrimitive = BasicType.wrapperPrimitiveMap.get(sourceType); + Class resolvedPrimitive = BasicType.WRAPPER_PRIMITIVE_MAP.get(sourceType); return targetType.equals(resolvedPrimitive); } else { // 包装类型 - Class resolvedWrapper = BasicType.primitiveWrapperMap.get(sourceType); + Class resolvedWrapper = BasicType.PRIMITIVE_WRAPPER_MAP.get(sourceType); return resolvedWrapper != null && targetType.isAssignableFrom(resolvedWrapper); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/IdcardUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/IdcardUtil.java index 0dc707e64..7fdfb75e5 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/IdcardUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/IdcardUtil.java @@ -38,7 +38,7 @@ public class IdcardUtil { /** * 每位加权因子 */ - private static final int[] power = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}; + private static final int[] POWER = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}; /** * 省市代码表 */ @@ -602,9 +602,9 @@ public class IdcardUtil { */ private static int getPowerSum(char[] iArr) { int iSum = 0; - if (power.length == iArr.length) { + if (POWER.length == iArr.length) { for (int i = 0; i < iArr.length; i++) { - iSum += Integer.parseInt(String.valueOf(iArr[i])) * power[i]; + iSum += Integer.parseInt(String.valueOf(iArr[i])) * POWER[i]; } } return iSum; diff --git a/hutool-core/src/main/java/cn/hutool/core/util/NumberUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/NumberUtil.java index 190762502..2f0f95a5e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/NumberUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/NumberUtil.java @@ -134,7 +134,7 @@ public class NumberUtil { } Number value = values[0]; - BigDecimal result = new BigDecimal(null == value ? "0" : value.toString()); + BigDecimal result = null == value ? BigDecimal.ZERO : new BigDecimal(value.toString()); for (int i = 1; i < values.length; i++) { value = values[i]; if (null != value) { @@ -158,7 +158,7 @@ public class NumberUtil { } String value = values[0]; - BigDecimal result = new BigDecimal(null == value ? "0" : value); + BigDecimal result = null == value ? BigDecimal.ZERO : new BigDecimal(value); for (int i = 1; i < values.length; i++) { value = values[i]; if (null != value) { @@ -274,7 +274,7 @@ public class NumberUtil { } Number value = values[0]; - BigDecimal result = new BigDecimal(null == value ? "0" : value.toString()); + BigDecimal result = null == value ? BigDecimal.ZERO : new BigDecimal(value.toString()); for (int i = 1; i < values.length; i++) { value = values[i]; if (null != value) { @@ -298,7 +298,7 @@ public class NumberUtil { } String value = values[0]; - BigDecimal result = new BigDecimal(null == value ? "0" : value); + BigDecimal result = null == value ? BigDecimal.ZERO : new BigDecimal(value); for (int i = 1; i < values.length; i++) { value = values[i]; if (null != value) { @@ -410,15 +410,15 @@ public class NumberUtil { * @since 4.0.0 */ public static BigDecimal mul(Number... values) { - if (ArrayUtil.isEmpty(values)) { + if (ArrayUtil.isEmpty(values) || ArrayUtil.hasNull(values)) { return BigDecimal.ZERO; } Number value = values[0]; - BigDecimal result = new BigDecimal(null == value ? "0" : value.toString()); + BigDecimal result = new BigDecimal(value.toString()); for (int i = 1; i < values.length; i++) { value = values[i]; - result = result.multiply(new BigDecimal(null == value ? "0" : value.toString())); + result = result.multiply(new BigDecimal(value.toString())); } return result; } @@ -444,18 +444,15 @@ public class NumberUtil { * @since 4.0.0 */ public static BigDecimal mul(String... values) { - if (ArrayUtil.isEmpty(values)) { + if (ArrayUtil.isEmpty(values) || ArrayUtil.hasNull(values)) { return BigDecimal.ZERO; } - String value = values[0]; - BigDecimal result = new BigDecimal(null == value ? "0" : value); + BigDecimal result =new BigDecimal(values[0]); for (int i = 1; i < values.length; i++) { - value = values[i]; - if (null != value) { - result = result.multiply(new BigDecimal(value)); - } + result = result.multiply(new BigDecimal(values[i])); } + return result; } @@ -468,17 +465,13 @@ public class NumberUtil { * @since 4.0.0 */ public static BigDecimal mul(BigDecimal... values) { - if (ArrayUtil.isEmpty(values)) { + if (ArrayUtil.isEmpty(values) || ArrayUtil.hasNull(values)) { return BigDecimal.ZERO; } - BigDecimal value = values[0]; - BigDecimal result = null == value ? BigDecimal.ZERO : value; + BigDecimal result = values[0]; for (int i = 1; i < values.length; i++) { - value = values[i]; - if (null != value) { - result = result.multiply(value); - } + result = result.multiply(values[i]); } return result; } @@ -1427,13 +1420,13 @@ public class NumberUtil { // ------------------------------------------------------------------------------------------- others /** - * 计算阶乘 + * 计算范围阶乘 *

- * n! = n * (n-1) * ... * end + * factorial(start, end) = start * (start - 1) * ... * (end - 1) *

* - * @param start 阶乘起始 - * @param end 阶乘结束,必须小于起始 + * @param start 阶乘起始(包含) + * @param end 阶乘结束,必须小于起始(不包括) * @return 结果 * @since 4.1.0 */ @@ -1744,6 +1737,7 @@ public class NumberUtil { public static boolean equals(BigDecimal bigNum1, BigDecimal bigNum2) { //noinspection NumberEquality if (bigNum1 == bigNum2){ + // 如果用户传入同一对象,省略compareTo以提高性能。 return true; } if (bigNum1==null || bigNum2==null){ @@ -2192,6 +2186,17 @@ public class NumberUtil { public static BigDecimal pow(BigDecimal number, int n) { return number.pow(n); } + + + /** + * 判断一个整数是否是2的幂 + * + * @param n 待验证的整数 + * @return 如果n是2的幂返回true, 反之返回false + */ + public static boolean isPowerOfTwo(long n) { + return (n > 0) && ((n & (n - 1)) == 0); + } /** * 解析转换数字字符串为int型数字,规则如下: diff --git a/hutool-core/src/main/java/cn/hutool/core/util/PageUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/PageUtil.java index b1e7081fc..59670070d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/PageUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/PageUtil.java @@ -160,9 +160,10 @@ public class PageUtil { * @return 分页条 */ public static int[] rainbow(int pageNo, int totalPage, int displayCount) { - boolean isEven = displayCount % 2 == 0; - int left = displayCount / 2; - int right = displayCount / 2; + // displayCount % 2 + boolean isEven = (displayCount & 1) == 0; + int left = displayCount >> 1; + int right = displayCount >> 1; int length = displayCount; if (isEven) { diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ServiceLoaderUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ServiceLoaderUtil.java index 113703285..ae7b76d93 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/ServiceLoaderUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/ServiceLoaderUtil.java @@ -34,7 +34,7 @@ public class ServiceLoaderUtil { while (iterator.hasNext()) { try { return iterator.next(); - } catch (ServiceConfigurationError e) { + } catch (ServiceConfigurationError ignore) { // ignore } } @@ -76,7 +76,7 @@ public class ServiceLoaderUtil { * @return 服务接口实现列表 */ public static ServiceLoader load(Class clazz, ClassLoader loader) { - return ServiceLoader.load(clazz, loader); + return ServiceLoader.load(clazz, ObjectUtil.defaultIfNull(loader, ClassLoaderUtil.getClassLoader())); } /** @@ -101,6 +101,6 @@ public class ServiceLoaderUtil { * @since 5.4.2 */ public static List loadList(Class clazz, ClassLoader loader) { - return ListUtil.list(false, load(clazz)); + return ListUtil.list(false, load(clazz, loader)); } } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java index 662ac844f..c4f1e686e 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java @@ -34,60 +34,125 @@ public class StrUtil { public static final int INDEX_NOT_FOUND = -1; + /** 字符常量:空格符 ' ' */ public static final char C_SPACE = CharUtil.SPACE; + /** 字符常量:制表符 \t */ public static final char C_TAB = CharUtil.TAB; + /** 字符常量:点 . */ public static final char C_DOT = CharUtil.DOT; + /** 字符常量:斜杠 / */ public static final char C_SLASH = CharUtil.SLASH; + /** 字符常量:反斜杠 \ */ public static final char C_BACKSLASH = CharUtil.BACKSLASH; + /** 字符常量:回车符 \r */ public static final char C_CR = CharUtil.CR; + /** 字符常量:换行符 \n */ public static final char C_LF = CharUtil.LF; + /** 字符常量:下划线 _ */ public static final char C_UNDERLINE = CharUtil.UNDERLINE; + /** 字符常量:逗号 , */ public static final char C_COMMA = CharUtil.COMMA; + /** 字符常量:花括号(左) { */ public static final char C_DELIM_START = CharUtil.DELIM_START; + /** 字符常量:花括号(右) } */ public static final char C_DELIM_END = CharUtil.DELIM_END; + /** 字符常量:中括号(左) [ */ public static final char C_BRACKET_START = CharUtil.BRACKET_START; + /** 字符常量:中括号(右) ] */ public static final char C_BRACKET_END = CharUtil.BRACKET_END; + /** 字符常量:冒号 : */ public static final char C_COLON = CharUtil.COLON; + /** 字符常量:艾特 @ */ + public static final char C_AT = CharUtil.AT; + /** 字符串常量:空格符 ' ' */ public static final String SPACE = " "; + /** 字符串常量:制表符 \t */ public static final String TAB = " "; + /** 字符串常量:点 . */ public static final String DOT = "."; + /** + * 字符串常量:双点 .. + * 用途:作为指向上级文件夹的路径 "../path" + */ public static final String DOUBLE_DOT = ".."; + /** 字符串常量:斜杠 / */ public static final String SLASH = "/"; + /** 字符串常量:反斜杠 \ */ public static final String BACKSLASH = "\\"; + /** 字符串常量:空字符串 "" */ public static final String EMPTY = ""; + /** + * 字符串常量:"null" + * 注意:"null" != null + */ public static final String NULL = "null"; + /** + * 字符串常量:回车符 \r + * 解释:该字符常用于表示 Linux 系统和 MacOS 系统下的文本换行 + */ public static final String CR = "\r"; + /** 字符串常量:换行符 \n */ public static final String LF = "\n"; + /** + * 字符串常量:Windows 换行 \r\n + * 解释:该字符串常用于表示 Windows 系统下的文本换行 + */ public static final String CRLF = "\r\n"; + /** 字符串常量:下划线 _ */ public static final String UNDERLINE = "_"; + /** 字符串常量:减号(中划线) - */ public static final String DASHED = "-"; + /** 字符串常量:逗号 , */ public static final String COMMA = ","; + /** 字符串常量:花括号(左) { */ public static final String DELIM_START = "{"; + /** 字符串常量:花括号(右) } */ public static final String DELIM_END = "}"; + /** 字符串常量:中括号(左) [ */ public static final String BRACKET_START = "["; + /** 字符串常量:中括号(右) ] */ public static final String BRACKET_END = "]"; + /** 字符串常量:冒号 : */ public static final String COLON = ":"; + /** 字符串常量:艾特 @ */ + public static final String AT = "@"; + /** 字符串常量:HTML 空格转义 */ public static final String HTML_NBSP = " "; + /** 字符串常量:HTML And 符转义 & */ public static final String HTML_AMP = "&"; + /** 字符串常量:HTML 双引号转义 " */ public static final String HTML_QUOTE = """; + /** 字符串常量:HTML 单引号转义 ' */ public static final String HTML_APOS = "'"; + /** 字符串常量:HTML 小于号转义 < */ public static final String HTML_LT = "<"; + /** 字符串常量:HTML 大于号转义 > */ public static final String HTML_GT = ">"; - + /** 字符串常量:空 JSON "{}" */ public static final String EMPTY_JSON = "{}"; // ------------------------------------------------------------------------ Blank /** - * 字符串是否为空白 空白的定义如下:
- * 1、为null
- * 2、为不可见字符(如空格)
- * 3、""
+ *

字符串是否为空白,空白的定义如下:

+ *
    + *
  1. {@code null}
  2. + *
  3. 空字符串:{@code ""}
  4. + *
  5. 空格、全角空格、制表符、换行符,等不可见字符
  6. + *
+ * + *

例:

+ *
    + *
  • {@code StrUtil.isBlank(null) // true}
  • + *
  • {@code StrUtil.isBlank("") // true}
  • + *
  • {@code StrUtil.isBlank(" \t\n") // true}
  • + *
  • {@code StrUtil.isBlank("abc") // false}
  • + *
* * @param str 被检测的字符串 - * @return 是否为空 + * @return 若为空白,则返回 true */ public static boolean isBlank(CharSequence str) { int length; @@ -107,13 +172,25 @@ public class StrUtil { } /** - * 如果对象是字符串是否为空白,空白的定义如下:
- * 1、为null
- * 2、为不可见字符(如空格)
- * 3、""
+ *

如果对象是字符串是否为空白,空白的定义如下:

+ *
    + *
  1. {@code null}
  2. + *
  3. 空字符串:{@code ""}
  4. + *
  5. 空格、全角空格、制表符、换行符,等不可见字符
  6. + *
+ * + *

例:

+ *
    + *
  • {@code StrUtil.isBlankIfStr(null) // true}
  • + *
  • {@code StrUtil.isBlankIfStr("") // true}
  • + *
  • {@code StrUtil.isBlankIfStr(" \t\n") // true}
  • + *
  • {@code StrUtil.isBlankIfStr("abc") // false}
  • + *
* * @param obj 对象 * @return 如果为字符串是否为空串 + * + * @see StrUtil#isBlank(CharSequence) * @since 3.3.0 */ public static boolean isBlankIfStr(Object obj) { @@ -4150,7 +4227,7 @@ public class StrUtil { } /** - * 计算连个字符串的相似度百分比 + * 计算两个字符串的相似度百分比 * * @param str1 字符串1 * @param str2 字符串2 diff --git a/hutool-core/src/main/java/cn/hutool/core/util/URLUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/URLUtil.java index 78e7a8d94..8f61aeb5d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/URLUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/URLUtil.java @@ -483,13 +483,7 @@ public class URLUtil { * @throws UtilException 包装URISyntaxException */ public static String getPath(String uriStr) { - URI uri; - try { - uri = new URI(uriStr); - } catch (URISyntaxException e) { - throw new UtilException(e); - } - return uri.getPath(); + return toURI(uriStr).getPath(); } /** @@ -509,7 +503,7 @@ public class URLUtil { String path = null; try { // URL对象的getPath方法对于包含中文或空格的问题 - path = URLUtil.toURI(url).getPath(); + path = toURI(url).getPath(); } catch (UtilException e) { // ignore } @@ -569,7 +563,7 @@ public class URLUtil { location = encode(location); } try { - return new URI(location); + return new URI(StrUtil.trim(location)); } catch (URISyntaxException e) { throw new UtilException(e); } diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ZipUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ZipUtil.java index 582a5a539..a78212d1c 100644 --- a/hutool-core/src/main/java/cn/hutool/core/util/ZipUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/util/ZipUtil.java @@ -1116,6 +1116,8 @@ public class ZipUtil { * @since 5.0.5 */ private static File buildFile(File outFile, String fileName) { + // 替换Windows路径分隔符为Linux路径分隔符,便于统一处理 + fileName = fileName.replace('\\', '/'); if (false == FileUtil.isWindows() // 检查文件名中是否包含"/",不考虑以"/"结尾的情况 && fileName.lastIndexOf(CharUtil.SLASH, fileName.length() - 2) > 0) { diff --git a/hutool-core/src/test/java/cn/hutool/core/convert/ConvertToNumberTest.java b/hutool-core/src/test/java/cn/hutool/core/convert/ConvertToNumberTest.java index f8b30cf26..a1600c664 100644 --- a/hutool-core/src/test/java/cn/hutool/core/convert/ConvertToNumberTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/convert/ConvertToNumberTest.java @@ -5,6 +5,7 @@ import cn.hutool.core.date.DateUtil; import org.junit.Assert; import org.junit.Test; +import java.math.BigDecimal; import java.util.concurrent.atomic.AtomicLong; public class ConvertToNumberTest { @@ -31,4 +32,13 @@ public class ConvertToNumberTest { assert date != null; Assert.assertEquals(date.getTime(), dateLong.longValue()); } + + @Test + public void toBigDecimalTest(){ + BigDecimal bigDecimal = Convert.toBigDecimal("1.1f"); + Assert.assertEquals(1.1f, bigDecimal.floatValue(), 1); + + bigDecimal = Convert.toBigDecimal("1L"); + Assert.assertEquals(1L, bigDecimal.longValue()); + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java index 2ded43d89..8d8d00213 100644 --- a/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java @@ -3,7 +3,6 @@ package cn.hutool.core.date; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.BetweenFormater.Level; import cn.hutool.core.date.format.FastDateFormat; -import cn.hutool.core.lang.Console; import org.junit.Assert; import org.junit.Test; 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 475bd1a01..f12f4482f 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 @@ -74,4 +74,9 @@ public class NetUtilTest { Assert.assertEquals("/", httpCookie.getPath()); Assert.assertEquals("cookiedomain.com", httpCookie.getDomain()); } + + @Test + public void getLocalHostNameTest() { + Assert.assertNotNull(NetUtil.getLocalHostName()); + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/util/EscapeUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/EscapeUtilTest.java index 238667630..76cb16472 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/EscapeUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/EscapeUtilTest.java @@ -37,4 +37,11 @@ public class EscapeUtilTest { String unescape = EscapeUtil.unescape(escape); Assert.assertEquals(str, unescape); } + + @Test + public void escapeSinleQuotesTest(){ + String str = "'some text with single quotes'"; + final String s = EscapeUtil.escapeHtml4(str); + Assert.assertEquals(str, s); + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java index e68df8941..dd1710807 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java @@ -1,261 +1,272 @@ -package cn.hutool.core.util; - -import org.junit.Assert; -import org.junit.Test; - -import java.math.BigDecimal; -import java.math.RoundingMode; - -/** - * {@link NumberUtil} 单元测试类 - * - * @author Looly - * - */ -public class NumberUtilTest { - - @Test - public void addTest() { - Float a = 3.15f; - Double b = 4.22; - double result = NumberUtil.add(a, b).doubleValue(); - Assert.assertEquals(7.37, result, 2); - } - - @Test - public void addTest2() { - double a = 3.15f; - double b = 4.22; - double result = NumberUtil.add(a, b); - Assert.assertEquals(7.37, result, 2); - } - - @Test - public void addTest3() { - float a = 3.15f; - double b = 4.22; - double result = NumberUtil.add(a, b, a, b).doubleValue(); - Assert.assertEquals(14.74, result, 2); - } - - @Test - public void addTest4() { - BigDecimal result = NumberUtil.add(new BigDecimal("133"), new BigDecimal("331")); - Assert.assertEquals(new BigDecimal("464"), result); - } - - @Test - public void isIntegerTest() { - Assert.assertTrue(NumberUtil.isInteger("-12")); - Assert.assertTrue(NumberUtil.isInteger("256")); - Assert.assertTrue(NumberUtil.isInteger("0256")); - Assert.assertTrue(NumberUtil.isInteger("0")); - Assert.assertFalse(NumberUtil.isInteger("23.4")); - } - - @Test - public void isLongTest() { - Assert.assertTrue(NumberUtil.isLong("-12")); - Assert.assertTrue(NumberUtil.isLong("256")); - Assert.assertTrue(NumberUtil.isLong("0256")); - Assert.assertTrue(NumberUtil.isLong("0")); - Assert.assertFalse(NumberUtil.isLong("23.4")); - } - - @Test - public void isNumberTest() { - Assert.assertTrue(NumberUtil.isNumber("28.55")); - Assert.assertTrue(NumberUtil.isNumber("0")); - Assert.assertTrue(NumberUtil.isNumber("+100.10")); - Assert.assertTrue(NumberUtil.isNumber("-22.022")); - Assert.assertTrue(NumberUtil.isNumber("0X22")); - } - - @Test - public void divTest() { - double result = NumberUtil.div(0, 1); - Assert.assertEquals(0.0, result, 0); - } - - @Test - public void roundTest() { - - // 四舍 - String round1 = NumberUtil.roundStr(2.674, 2); - String round2 = NumberUtil.roundStr("2.674", 2); - Assert.assertEquals("2.67", round1); - Assert.assertEquals("2.67", round2); - - // 五入 - String round3 = NumberUtil.roundStr(2.675, 2); - String round4 = NumberUtil.roundStr("2.675", 2); - Assert.assertEquals("2.68", round3); - Assert.assertEquals("2.68", round4); - - // 四舍六入五成双 - String round31 = NumberUtil.roundStr(4.245, 2, RoundingMode.HALF_EVEN); - String round41 = NumberUtil.roundStr("4.2451", 2, RoundingMode.HALF_EVEN); - Assert.assertEquals("4.24", round31); - Assert.assertEquals("4.25", round41); - - // 补0 - String round5 = NumberUtil.roundStr(2.6005, 2); - String round6 = NumberUtil.roundStr("2.6005", 2); - Assert.assertEquals("2.60", round5); - Assert.assertEquals("2.60", round6); - - // 补0 - String round7 = NumberUtil.roundStr(2.600, 2); - String round8 = NumberUtil.roundStr("2.600", 2); - Assert.assertEquals("2.60", round7); - Assert.assertEquals("2.60", round8); - } - - @Test - public void roundStrTest() { - String roundStr = NumberUtil.roundStr(2.647, 2); - Assert.assertEquals(roundStr, "2.65"); - } - - @Test - public void roundHalfEvenTest() { - String roundStr = NumberUtil.roundHalfEven(4.245, 2).toString(); - Assert.assertEquals(roundStr, "4.24"); - roundStr = NumberUtil.roundHalfEven(4.2450, 2).toString(); - Assert.assertEquals(roundStr, "4.24"); - roundStr = NumberUtil.roundHalfEven(4.2451, 2).toString(); - Assert.assertEquals(roundStr, "4.25"); - roundStr = NumberUtil.roundHalfEven(4.2250, 2).toString(); - Assert.assertEquals(roundStr, "4.22"); - - roundStr = NumberUtil.roundHalfEven(1.2050, 2).toString(); - Assert.assertEquals(roundStr, "1.20"); - roundStr = NumberUtil.roundHalfEven(1.2150, 2).toString(); - Assert.assertEquals(roundStr, "1.22"); - roundStr = NumberUtil.roundHalfEven(1.2250, 2).toString(); - Assert.assertEquals(roundStr, "1.22"); - roundStr = NumberUtil.roundHalfEven(1.2350, 2).toString(); - Assert.assertEquals(roundStr, "1.24"); - roundStr = NumberUtil.roundHalfEven(1.2450, 2).toString(); - Assert.assertEquals(roundStr, "1.24"); - roundStr = NumberUtil.roundHalfEven(1.2550, 2).toString(); - Assert.assertEquals(roundStr, "1.26"); - roundStr = NumberUtil.roundHalfEven(1.2650, 2).toString(); - Assert.assertEquals(roundStr, "1.26"); - roundStr = NumberUtil.roundHalfEven(1.2750, 2).toString(); - Assert.assertEquals(roundStr, "1.28"); - roundStr = NumberUtil.roundHalfEven(1.2850, 2).toString(); - Assert.assertEquals(roundStr, "1.28"); - roundStr = NumberUtil.roundHalfEven(1.2950, 2).toString(); - Assert.assertEquals(roundStr, "1.30"); - } - - @Test - public void decimalFormatTest() { - long c = 299792458;// 光速 - - String format = NumberUtil.decimalFormat(",###", c); - Assert.assertEquals("299,792,458", format); - } - - @Test - public void decimalFormatMoneyTest() { - double c = 299792400.543534534; - - String format = NumberUtil.decimalFormatMoney(c); - Assert.assertEquals("299,792,400.54", format); - - double value = 0.5; - String money = NumberUtil.decimalFormatMoney(value); - Assert.assertEquals("0.50", money); - } - - @Test - public void equalsTest() { - Assert.assertTrue(NumberUtil.equals(new BigDecimal("0.00"), BigDecimal.ZERO)); - } - - @Test - public void formatPercentTest() { - String str = NumberUtil.formatPercent(0.33543545, 2); - Assert.assertEquals("33.54%", str); - } - - @Test - public void toBigDecimalTest() { - double a = 3.14; - - BigDecimal bigDecimal = NumberUtil.toBigDecimal(a); - Assert.assertEquals("3.14", bigDecimal.toString()); - } - - @Test - public void maxTest() { - int max = NumberUtil.max(5,4,3,6,1); - Assert.assertEquals(6, max); - } - - @Test - public void minTest() { - int min = NumberUtil.min(5,4,3,6,1); - Assert.assertEquals(1, min); - } - - @Test - public void parseIntTest() { - int v1 = NumberUtil.parseInt("0xFF"); - Assert.assertEquals(255, v1); - int v2 = NumberUtil.parseInt("010"); - Assert.assertEquals(10, v2); - int v3 = NumberUtil.parseInt("10"); - Assert.assertEquals(10, v3); - int v4 = NumberUtil.parseInt(" "); - Assert.assertEquals(0, v4); - int v5 = NumberUtil.parseInt("10F"); - Assert.assertEquals(10, v5); - int v6 = NumberUtil.parseInt("22.4D"); - Assert.assertEquals(22, v6); - - int v7 = NumberUtil.parseInt("0"); - Assert.assertEquals(0, v7); - } - - @Test - public void parseLongTest() { - long v1 = NumberUtil.parseLong("0xFF"); - Assert.assertEquals(255L, v1); - long v2 = NumberUtil.parseLong("010"); - Assert.assertEquals(10L, v2); - long v3 = NumberUtil.parseLong("10"); - Assert.assertEquals(10L, v3); - long v4 = NumberUtil.parseLong(" "); - Assert.assertEquals(0L, v4); - long v5 = NumberUtil.parseLong("10F"); - Assert.assertEquals(10L, v5); - long v6 = NumberUtil.parseLong("22.4D"); - Assert.assertEquals(22L, v6); - } - - @Test - public void factorialTest(){ - long factorial = NumberUtil.factorial(0); - Assert.assertEquals(1, factorial); - - Assert.assertEquals(1L, NumberUtil.factorial(1)); - Assert.assertEquals(1307674368000L, NumberUtil.factorial(15)); - Assert.assertEquals(2432902008176640000L, NumberUtil.factorial(20)); - - factorial = NumberUtil.factorial(5, 0); - Assert.assertEquals(120, factorial); - factorial = NumberUtil.factorial(5, 1); - Assert.assertEquals(120, factorial); - Assert.assertEquals(5, NumberUtil.factorial(5, 4)); - Assert.assertEquals(2432902008176640000L, NumberUtil.factorial(20, 0)); - } - - @Test - public void mulTest(){ - final BigDecimal mul = NumberUtil.mul(new BigDecimal("10"), null); - Assert.assertEquals(BigDecimal.ZERO, mul); - } -} +package cn.hutool.core.util; + +import org.junit.Assert; +import org.junit.Test; + +import java.math.BigDecimal; +import java.math.RoundingMode; + +/** + * {@link NumberUtil} 单元测试类 + * + * @author Looly + * + */ +public class NumberUtilTest { + + @Test + public void addTest() { + Float a = 3.15f; + Double b = 4.22; + double result = NumberUtil.add(a, b).doubleValue(); + Assert.assertEquals(7.37, result, 2); + } + + @Test + public void addTest2() { + double a = 3.15f; + double b = 4.22; + double result = NumberUtil.add(a, b); + Assert.assertEquals(7.37, result, 2); + } + + @Test + public void addTest3() { + float a = 3.15f; + double b = 4.22; + double result = NumberUtil.add(a, b, a, b).doubleValue(); + Assert.assertEquals(14.74, result, 2); + } + + @Test + public void addTest4() { + BigDecimal result = NumberUtil.add(new BigDecimal("133"), new BigDecimal("331")); + Assert.assertEquals(new BigDecimal("464"), result); + } + + @Test + public void isIntegerTest() { + Assert.assertTrue(NumberUtil.isInteger("-12")); + Assert.assertTrue(NumberUtil.isInteger("256")); + Assert.assertTrue(NumberUtil.isInteger("0256")); + Assert.assertTrue(NumberUtil.isInteger("0")); + Assert.assertFalse(NumberUtil.isInteger("23.4")); + } + + @Test + public void isLongTest() { + Assert.assertTrue(NumberUtil.isLong("-12")); + Assert.assertTrue(NumberUtil.isLong("256")); + Assert.assertTrue(NumberUtil.isLong("0256")); + Assert.assertTrue(NumberUtil.isLong("0")); + Assert.assertFalse(NumberUtil.isLong("23.4")); + } + + @Test + public void isNumberTest() { + Assert.assertTrue(NumberUtil.isNumber("28.55")); + Assert.assertTrue(NumberUtil.isNumber("0")); + Assert.assertTrue(NumberUtil.isNumber("+100.10")); + Assert.assertTrue(NumberUtil.isNumber("-22.022")); + Assert.assertTrue(NumberUtil.isNumber("0X22")); + } + + @Test + public void divTest() { + double result = NumberUtil.div(0, 1); + Assert.assertEquals(0.0, result, 0); + } + + @Test + public void roundTest() { + + // 四舍 + String round1 = NumberUtil.roundStr(2.674, 2); + String round2 = NumberUtil.roundStr("2.674", 2); + Assert.assertEquals("2.67", round1); + Assert.assertEquals("2.67", round2); + + // 五入 + String round3 = NumberUtil.roundStr(2.675, 2); + String round4 = NumberUtil.roundStr("2.675", 2); + Assert.assertEquals("2.68", round3); + Assert.assertEquals("2.68", round4); + + // 四舍六入五成双 + String round31 = NumberUtil.roundStr(4.245, 2, RoundingMode.HALF_EVEN); + String round41 = NumberUtil.roundStr("4.2451", 2, RoundingMode.HALF_EVEN); + Assert.assertEquals("4.24", round31); + Assert.assertEquals("4.25", round41); + + // 补0 + String round5 = NumberUtil.roundStr(2.6005, 2); + String round6 = NumberUtil.roundStr("2.6005", 2); + Assert.assertEquals("2.60", round5); + Assert.assertEquals("2.60", round6); + + // 补0 + String round7 = NumberUtil.roundStr(2.600, 2); + String round8 = NumberUtil.roundStr("2.600", 2); + Assert.assertEquals("2.60", round7); + Assert.assertEquals("2.60", round8); + } + + @Test + public void roundStrTest() { + String roundStr = NumberUtil.roundStr(2.647, 2); + Assert.assertEquals(roundStr, "2.65"); + } + + @Test + public void roundHalfEvenTest() { + String roundStr = NumberUtil.roundHalfEven(4.245, 2).toString(); + Assert.assertEquals(roundStr, "4.24"); + roundStr = NumberUtil.roundHalfEven(4.2450, 2).toString(); + Assert.assertEquals(roundStr, "4.24"); + roundStr = NumberUtil.roundHalfEven(4.2451, 2).toString(); + Assert.assertEquals(roundStr, "4.25"); + roundStr = NumberUtil.roundHalfEven(4.2250, 2).toString(); + Assert.assertEquals(roundStr, "4.22"); + + roundStr = NumberUtil.roundHalfEven(1.2050, 2).toString(); + Assert.assertEquals(roundStr, "1.20"); + roundStr = NumberUtil.roundHalfEven(1.2150, 2).toString(); + Assert.assertEquals(roundStr, "1.22"); + roundStr = NumberUtil.roundHalfEven(1.2250, 2).toString(); + Assert.assertEquals(roundStr, "1.22"); + roundStr = NumberUtil.roundHalfEven(1.2350, 2).toString(); + Assert.assertEquals(roundStr, "1.24"); + roundStr = NumberUtil.roundHalfEven(1.2450, 2).toString(); + Assert.assertEquals(roundStr, "1.24"); + roundStr = NumberUtil.roundHalfEven(1.2550, 2).toString(); + Assert.assertEquals(roundStr, "1.26"); + roundStr = NumberUtil.roundHalfEven(1.2650, 2).toString(); + Assert.assertEquals(roundStr, "1.26"); + roundStr = NumberUtil.roundHalfEven(1.2750, 2).toString(); + Assert.assertEquals(roundStr, "1.28"); + roundStr = NumberUtil.roundHalfEven(1.2850, 2).toString(); + Assert.assertEquals(roundStr, "1.28"); + roundStr = NumberUtil.roundHalfEven(1.2950, 2).toString(); + Assert.assertEquals(roundStr, "1.30"); + } + + @Test + public void decimalFormatTest() { + long c = 299792458;// 光速 + + String format = NumberUtil.decimalFormat(",###", c); + Assert.assertEquals("299,792,458", format); + } + + @Test + public void decimalFormatMoneyTest() { + double c = 299792400.543534534; + + String format = NumberUtil.decimalFormatMoney(c); + Assert.assertEquals("299,792,400.54", format); + + double value = 0.5; + String money = NumberUtil.decimalFormatMoney(value); + Assert.assertEquals("0.50", money); + } + + @Test + public void equalsTest() { + Assert.assertTrue(NumberUtil.equals(new BigDecimal("0.00"), BigDecimal.ZERO)); + } + + @Test + public void formatPercentTest() { + String str = NumberUtil.formatPercent(0.33543545, 2); + Assert.assertEquals("33.54%", str); + } + + @Test + public void toBigDecimalTest() { + double a = 3.14; + + BigDecimal bigDecimal = NumberUtil.toBigDecimal(a); + Assert.assertEquals("3.14", bigDecimal.toString()); + } + + @Test + public void maxTest() { + int max = NumberUtil.max(5,4,3,6,1); + Assert.assertEquals(6, max); + } + + @Test + public void minTest() { + int min = NumberUtil.min(5,4,3,6,1); + Assert.assertEquals(1, min); + } + + @Test + public void parseIntTest() { + int v1 = NumberUtil.parseInt("0xFF"); + Assert.assertEquals(255, v1); + int v2 = NumberUtil.parseInt("010"); + Assert.assertEquals(10, v2); + int v3 = NumberUtil.parseInt("10"); + Assert.assertEquals(10, v3); + int v4 = NumberUtil.parseInt(" "); + Assert.assertEquals(0, v4); + int v5 = NumberUtil.parseInt("10F"); + Assert.assertEquals(10, v5); + int v6 = NumberUtil.parseInt("22.4D"); + Assert.assertEquals(22, v6); + + int v7 = NumberUtil.parseInt("0"); + Assert.assertEquals(0, v7); + } + + @Test + public void parseLongTest() { + long v1 = NumberUtil.parseLong("0xFF"); + Assert.assertEquals(255L, v1); + long v2 = NumberUtil.parseLong("010"); + Assert.assertEquals(10L, v2); + long v3 = NumberUtil.parseLong("10"); + Assert.assertEquals(10L, v3); + long v4 = NumberUtil.parseLong(" "); + Assert.assertEquals(0L, v4); + long v5 = NumberUtil.parseLong("10F"); + Assert.assertEquals(10L, v5); + long v6 = NumberUtil.parseLong("22.4D"); + Assert.assertEquals(22L, v6); + } + + @Test + public void factorialTest(){ + long factorial = NumberUtil.factorial(0); + Assert.assertEquals(1, factorial); + + Assert.assertEquals(1L, NumberUtil.factorial(1)); + Assert.assertEquals(1307674368000L, NumberUtil.factorial(15)); + Assert.assertEquals(2432902008176640000L, NumberUtil.factorial(20)); + + factorial = NumberUtil.factorial(5, 0); + Assert.assertEquals(120, factorial); + factorial = NumberUtil.factorial(5, 1); + Assert.assertEquals(120, factorial); + + Assert.assertEquals(5, NumberUtil.factorial(5, 4)); + Assert.assertEquals(2432902008176640000L, NumberUtil.factorial(20, 0)); + } + + @Test + public void mulTest(){ + final BigDecimal mul = NumberUtil.mul(new BigDecimal("10"), null); + Assert.assertEquals(BigDecimal.ZERO, mul); + } + + + @Test + public void isPowerOfTwoTest() { + Assert.assertEquals(false, NumberUtil.isPowerOfTwo(-1)); + Assert.assertEquals(true, NumberUtil.isPowerOfTwo(16)); + Assert.assertEquals(true, NumberUtil.isPowerOfTwo(65536)); + Assert.assertEquals(true, NumberUtil.isPowerOfTwo(1)); + Assert.assertEquals(false, NumberUtil.isPowerOfTwo(17)); + } +} diff --git a/hutool-core/src/test/java/cn/hutool/core/util/URLUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/util/URLUtilTest.java index 2e925c164..1381a7fe8 100644 --- a/hutool-core/src/test/java/cn/hutool/core/util/URLUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/util/URLUtilTest.java @@ -84,4 +84,11 @@ public class URLUtilTest { String encode2 = URLUtil.encodeQuery(body); Assert.assertEquals("366466+-+%E5%89%AF%E6%9C%AC.jpg", encode2); } + + @Test + public void getPathTest(){ + String url = " http://www.aaa.bbb/search?scope=ccc&q=ddd"; + String path = URLUtil.getPath(url); + Assert.assertEquals("/search", path); + } } diff --git a/hutool-cron/pom.xml b/hutool-cron/pom.xml index 2c62bc5a0..e1fb492f9 100644 --- a/hutool-cron/pom.xml +++ b/hutool-cron/pom.xml @@ -7,7 +7,7 @@ cn.hutool hutool-parent - 5.4.3 + 5.4.4-SNAPSHOT hutool-cron diff --git a/hutool-cron/src/main/java/cn/hutool/cron/listener/TaskListenerManager.java b/hutool-cron/src/main/java/cn/hutool/cron/listener/TaskListenerManager.java index 4556a55dc..ff2f5502c 100644 --- a/hutool-cron/src/main/java/cn/hutool/cron/listener/TaskListenerManager.java +++ b/hutool-cron/src/main/java/cn/hutool/cron/listener/TaskListenerManager.java @@ -1,12 +1,12 @@ package cn.hutool.cron.listener; +import cn.hutool.cron.TaskExecutor; +import cn.hutool.log.StaticLog; + import java.io.Serializable; import java.util.ArrayList; import java.util.List; -import cn.hutool.cron.TaskExecutor; -import cn.hutool.log.StaticLog; - /** * 监听调度器,统一管理监听 * @author Looly @@ -49,9 +49,9 @@ public class TaskListenerManager implements Serializable { synchronized (listeners) { int size = listeners.size(); TaskListener listener; - for (int i = 0; i < size; i++) { - listener = listeners.get(i); - if(null != listener){ + for (TaskListener taskListener : listeners) { + listener = taskListener; + if (null != listener) { listener.onStart(executor); } } @@ -65,8 +65,7 @@ public class TaskListenerManager implements Serializable { public void notifyTaskSucceeded(TaskExecutor executor) { synchronized (listeners) { int size = listeners.size(); - for (int i = 0; i < size; i++) { - TaskListener listenerl = listeners.get(i); + for (TaskListener listenerl : listeners) { listenerl.onSucceeded(executor); } } @@ -82,8 +81,7 @@ public class TaskListenerManager implements Serializable { synchronized (listeners) { int size = listeners.size(); if(size > 0){ - for (int i = 0; i < size; i++) { - TaskListener listenerl = listeners.get(i); + for (TaskListener listenerl : listeners) { listenerl.onFailed(executor, exception); } }else{ diff --git a/hutool-cron/src/test/java/cn/hutool/cron/demo/CronTest.java b/hutool-cron/src/test/java/cn/hutool/cron/demo/CronTest.java index 2f166c2c9..569e54cd4 100644 --- a/hutool-cron/src/test/java/cn/hutool/cron/demo/CronTest.java +++ b/hutool-cron/src/test/java/cn/hutool/cron/demo/CronTest.java @@ -1,12 +1,13 @@ package cn.hutool.cron.demo; -import org.junit.Ignore; -import org.junit.Test; - import cn.hutool.core.lang.Console; import cn.hutool.core.thread.ThreadUtil; import cn.hutool.cron.CronUtil; +import cn.hutool.cron.TaskExecutor; +import cn.hutool.cron.listener.TaskListener; import cn.hutool.cron.task.Task; +import org.junit.Ignore; +import org.junit.Test; /** * 定时任务样例 @@ -38,6 +39,23 @@ public class CronTest { @Test @Ignore public void cronTest2() { + CronUtil.getScheduler().addListener(new TaskListener() { + @Override + public void onStart(TaskExecutor executor) { + Console.log("Listen task start!"); + } + + @Override + public void onSucceeded(TaskExecutor executor) { + + } + + @Override + public void onFailed(TaskExecutor executor, Throwable exception) { + + } + }); + // 支持秒级别定时任务 CronUtil.setMatchSecond(true); CronUtil.start(); diff --git a/hutool-crypto/pom.xml b/hutool-crypto/pom.xml index 1a7b014a9..e84f71c45 100644 --- a/hutool-crypto/pom.xml +++ b/hutool-crypto/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.4.3 + 5.4.4-SNAPSHOT hutool-crypto diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/SM2.java b/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/SM2.java index b33f49614..d0315bd61 100644 --- a/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/SM2.java +++ b/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/SM2.java @@ -499,8 +499,10 @@ public class SM2 extends AbstractAsymmetricCrypto { */ private SM2Engine getEngine() { if (null == this.engine) { + Assert.notNull(this.digest, "digest must be not null !"); this.engine = new SM2Engine(this.digest, this.mode); } + this.digest.reset(); return this.engine; } @@ -511,8 +513,10 @@ public class SM2 extends AbstractAsymmetricCrypto { */ private SM2Signer getSigner() { if (null == this.signer) { + Assert.notNull(this.digest, "digest must be not null !"); this.signer = new SM2Signer(this.encoding, this.digest); } + this.digest.reset(); return this.signer; } // ------------------------------------------------------------------------------------------------------------------------- Private method end diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/symmetric/RC4.java b/hutool-crypto/src/main/java/cn/hutool/crypto/symmetric/RC4.java index 2cf2e477e..13fb145f1 100644 --- a/hutool-crypto/src/main/java/cn/hutool/crypto/symmetric/RC4.java +++ b/hutool-crypto/src/main/java/cn/hutool/crypto/symmetric/RC4.java @@ -1,16 +1,17 @@ package cn.hutool.crypto.symmetric; -import java.io.Serializable; -import java.nio.charset.Charset; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; -import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; - import cn.hutool.core.codec.Base64; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.HexUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.CryptoException; +import cn.hutool.crypto.SecureUtil; + +import java.io.Serializable; +import java.nio.charset.Charset; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; +import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; /** * RC4加密解密算法实现
@@ -97,6 +98,17 @@ public class RC4 implements Serializable { return HexUtil.encodeHexStr(encrypt(data, charset)); } + /** + * 加密,使用UTF-8编码 + * + * @param data 被加密的字符串 + * @return 加密后的Hex + * @since 5.4.4 + */ + public String encryptHex(String data) { + return HexUtil.encodeHexStr(encrypt(data)); + } + /** * 加密 * @@ -109,6 +121,18 @@ public class RC4 implements Serializable { return Base64.encode(encrypt(data, charset)); } + + /** + * 加密,使用UTF-8编码 + * + * @param data 被加密的字符串 + * @return 加密后的Base64 + * @since 5.4.4 + */ + public String encryptBase64(String data) { + return Base64.encode(encrypt(data)); + } + /** * 解密 * @@ -132,6 +156,30 @@ public class RC4 implements Serializable { return decrypt(message, CharsetUtil.CHARSET_UTF_8); } + /** + * 解密Hex(16进制)或Base64表示的字符串,使用默认编码UTF-8 + * + * @param message 消息 + * @return 明文 + * @since 5.4.4 + */ + public String decrypt(String message) { + return decrypt(SecureUtil.decode(message)); + } + + /** + * 解密Hex(16进制)或Base64表示的字符串 + * + * @param message 明文 + * @param charset 解密后的charset + * @return 明文 + * @since 5.4.4 + */ + public String decrypt(String message, Charset charset) { + return StrUtil.str(decrypt(message), charset); + } + + /** * 加密或解密指定值,调用此方法前需初始化密钥 * @@ -216,4 +264,4 @@ public class RC4 implements Serializable { sbox[j] = temp; } //----------------------------------------------------------------------------------------------------------------------- Private method end -} \ No newline at end of file +} diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/asymmetric/SM2Test.java b/hutool-crypto/src/test/java/cn/hutool/crypto/test/asymmetric/SM2Test.java index 40d5f12f5..42e2bcb97 100644 --- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/asymmetric/SM2Test.java +++ b/hutool-crypto/src/test/java/cn/hutool/crypto/test/asymmetric/SM2Test.java @@ -229,4 +229,18 @@ public class SM2Test { Assert.assertEquals(data, decryptStr); } + @Test + public void encryptAndSignTest(){ + SM2 sm2 = SmUtil.sm2(); + + String src = "Sm2Test"; + byte[] data = sm2.encrypt(src, KeyType.PublicKey); + byte[] sign = sm2.sign(src.getBytes()); + + Assert.assertTrue(sm2.verify( src.getBytes(), sign)); + + byte[] dec = sm2.decrypt(data, KeyType.PrivateKey); + Assert.assertArrayEquals(dec, src.getBytes()); + } + } diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/RC4Test.java b/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/RC4Test.java index 7869edc6a..bb9980bd5 100644 --- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/RC4Test.java +++ b/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/RC4Test.java @@ -1,5 +1,6 @@ package cn.hutool.crypto.test.symmetric; +import cn.hutool.core.util.CharsetUtil; import org.junit.Assert; import org.junit.Test; @@ -36,4 +37,35 @@ public class RC4Test { String msg2 = rc4.decrypt(crypt2); Assert.assertEquals(message2, msg2); } + + @Test + public void testDecryptWithHexMessage() { + String message = "这是第一个用来测试密文为十六进制字符串的消息!"; + String key = "生成一个密钥"; + RC4 rc4 = new RC4(key); + String encryptHex = rc4.encryptHex(message, CharsetUtil.CHARSET_UTF_8); + String msg = rc4.decrypt(encryptHex); + Assert.assertEquals(message, msg); + + String message2 = "这是第二个用来测试密文为十六进制字符串的消息!"; + String encryptHex2 = rc4.encryptHex(message2); + String msg2 = rc4.decrypt(encryptHex2); + Assert.assertEquals(message2, msg2); + } + + + @Test + public void testDecryptWithBase64Message() { + String message = "这是第一个用来测试密文为Base64编码的消息!"; + String key = "生成一个密钥"; + RC4 rc4 = new RC4(key); + String encryptHex = rc4.encryptBase64(message, CharsetUtil.CHARSET_UTF_8); + String msg = rc4.decrypt(encryptHex); + Assert.assertEquals(message, msg); + + String message2 = "这是第一个用来测试密文为Base64编码的消息!"; + String encryptHex2 = rc4.encryptBase64(message2); + String msg2 = rc4.decrypt(encryptHex2); + Assert.assertEquals(message2, msg2); + } } diff --git a/hutool-db/pom.xml b/hutool-db/pom.xml index afd15bb8a..991444907 100644 --- a/hutool-db/pom.xml +++ b/hutool-db/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.4.3 + 5.4.4-SNAPSHOT hutool-db diff --git a/hutool-dfa/pom.xml b/hutool-dfa/pom.xml index 27bf6f64d..07dc1656d 100644 --- a/hutool-dfa/pom.xml +++ b/hutool-dfa/pom.xml @@ -7,7 +7,7 @@ cn.hutool hutool-parent - 5.4.3 + 5.4.4-SNAPSHOT hutool-dfa diff --git a/hutool-dfa/src/main/java/cn/hutool/dfa/SensitiveUtil.java b/hutool-dfa/src/main/java/cn/hutool/dfa/SensitiveUtil.java index c61f71b61..d64100494 100644 --- a/hutool-dfa/src/main/java/cn/hutool/dfa/SensitiveUtil.java +++ b/hutool-dfa/src/main/java/cn/hutool/dfa/SensitiveUtil.java @@ -1,5 +1,6 @@ package cn.hutool.dfa; +import cn.hutool.core.lang.Filter; import cn.hutool.core.thread.ThreadUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; @@ -13,8 +14,7 @@ import java.util.List; * */ public final class SensitiveUtil { -// private static final Log log = LogFactory.get(); - + public static final char DEFAULT_SEPARATOR = StrUtil.C_COMMA; private static final WordTree sensitiveTree = new WordTree(); @@ -72,6 +72,19 @@ public final class SensitiveUtil { init(sensitiveWords, DEFAULT_SEPARATOR, isAsync); } + /** + * 设置字符过滤规则,通过定义字符串过滤规则,过滤不需要的字符
+ * 当accept为false时,此字符不参与匹配 + * + * @param charFilter 过滤函数 + * @since 5.4.4 + */ + public static void setCharFilter(Filter charFilter) { + if(charFilter != null) { + sensitiveTree.setCharFilter(charFilter); + } + } + /** * 是否包含敏感词 * @param text 文本 diff --git a/hutool-dfa/src/main/java/cn/hutool/dfa/StopChar.java b/hutool-dfa/src/main/java/cn/hutool/dfa/StopChar.java index c576b4e7a..9aaa7b6a9 100644 --- a/hutool-dfa/src/main/java/cn/hutool/dfa/StopChar.java +++ b/hutool-dfa/src/main/java/cn/hutool/dfa/StopChar.java @@ -11,7 +11,7 @@ import cn.hutool.core.collection.CollUtil; */ public class StopChar { /** 不需要处理的词,如标点符号、空格等 */ - public static final Set STOP_WORD = CollUtil.newHashSet(new Character[] { ' ', '\'', '、', '。', // + public static final Set STOP_WORD = CollUtil.newHashSet(' ', '\'', '、', '。', // '·', 'ˉ', 'ˇ', '々', '—', '~', '‖', '…', '‘', '’', '“', '”', '〔', '〕', '〈', '〉', '《', '》', '「', '」', '『', // '』', '〖', '〗', '【', '】', '±', '+', '-', '×', '÷', '∧', '∨', '∑', '∏', '∪', '∩', '∈', '√', '⊥', '⊙', '∫', // '∮', '≡', '≌', '≈', '∽', '∝', '≠', '≮', '≯', '≤', '≥', '∞', '∶', '∵', '∴', '∷', '♂', '♀', '°', '′', '〃', // @@ -26,7 +26,8 @@ public class StopChar { 'Υ', 'Φ', 'Χ', 'Ψ', 'Ω', 'α', 'β', 'γ', 'δ', 'ε', 'ζ', 'η', 'θ', 'ι', 'κ', 'λ', 'μ', 'ν', 'ξ', 'ο', 'π', // 'ρ', 'σ', 'τ', 'υ', 'φ', 'χ', 'ψ', 'ω', '(', ')', '〔', '〕', '^', '﹊', '﹍', '╭', '╮', '╰', '╯', '', '_', // '', '^', '(', '^', ':', '!', '/', '\\', '\"', '<', '>', '`', '·', '。', '{', '}', '~', '~', '(', ')', '-', // - '√', '$', '@', '*', '&', '#', '卐', '㎎', '㎏', '㎜', '㎝', '㎞', '㎡', '㏄', '㏎', '㏑', '㏒', '㏕' }); + '√', '$', '@', '*', '&', '#', '卐', '㎎', '㎏', '㎜', '㎝', '㎞', '㎡', '㏄', '㏎', '㏑', '㏒', '㏕', '+', '=', '?', + ':', '.', '!', ';', ']','|','%'); /** * 判断指定的词是否是不处理的词。 如果参数为空,则返回true,因为空也属于不处理的字符。 diff --git a/hutool-extra/pom.xml b/hutool-extra/pom.xml index e4e9f3ffa..454c0df47 100644 --- a/hutool-extra/pom.xml +++ b/hutool-extra/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.4.3 + 5.4.4-SNAPSHOT hutool-extra diff --git a/hutool-extra/src/main/java/cn/hutool/extra/emoji/EmojiUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/emoji/EmojiUtil.java index b1b0612dc..1a55be8a5 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/emoji/EmojiUtil.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/emoji/EmojiUtil.java @@ -1,15 +1,13 @@ package cn.hutool.extra.emoji; -import java.util.Arrays; -import java.util.List; -import java.util.Set; - import com.vdurmont.emoji.Emoji; import com.vdurmont.emoji.EmojiManager; import com.vdurmont.emoji.EmojiParser; -import com.vdurmont.emoji.EmojiTrie; import com.vdurmont.emoji.EmojiParser.FitzpatrickAction; +import java.util.List; +import java.util.Set; + /** * 基于https://github.com/vdurmont/emoji-java的Emoji表情工具类 *

@@ -38,22 +36,7 @@ public class EmojiUtil { * @since 4.5.11 */ public static boolean containsEmoji(String str) { - if (str == null) { - return false; - } - final char[] chars = str.toCharArray(); - EmojiTrie.Matches status; - for (int i = 0; i < chars.length; i++) { - for (int j = i + 1; j <= chars.length; j++) { - status = EmojiManager.isEmoji(Arrays.copyOfRange(chars, i, j)); - if (status.impossibleMatch()) { - break; - } else if (status.exactMatch()) { - return true; - } - } - } - return false; + return EmojiManager.containsEmoji(str); } /** diff --git a/hutool-extra/src/main/java/cn/hutool/extra/ftp/Ftp.java b/hutool-extra/src/main/java/cn/hutool/extra/ftp/Ftp.java index 8d4539793..2ae68c917 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/ftp/Ftp.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/ftp/Ftp.java @@ -342,6 +342,20 @@ public class Ftp extends AbstractFtp { } } + /** + * 获取服务端目录状态。 + * @param path 路径 + * @return 状态int,服务端不同,返回不同 + * @since 5.4.3 + */ + public int stat(String path) { + try { + return this.client.stat(path); + } catch (IOException e) { + throw new FtpException(e); + } + } + /** * 判断ftp服务器文件是否存在 * diff --git a/hutool-extra/src/main/java/cn/hutool/extra/mail/GlobalMailAccount.java b/hutool-extra/src/main/java/cn/hutool/extra/mail/GlobalMailAccount.java index f881aeb29..ca9ab1796 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/mail/GlobalMailAccount.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/mail/GlobalMailAccount.java @@ -3,7 +3,7 @@ package cn.hutool.extra.mail; import cn.hutool.core.io.IORuntimeException; /** - * 全局邮件帐户,依赖于邮件配置文件{@link MailAccount#MAIL_SETTING_PATH}或{@link MailAccount#MAIL_SETTING_PATH2} + * 全局邮件帐户,依赖于邮件配置文件{@link MailAccount#MAIL_SETTING_PATHS} * * @author looly * @@ -35,31 +35,13 @@ public enum GlobalMailAccount { * @return MailAccount */ private MailAccount createDefaultAccount() { - MailAccount mailAccount = null; - try { - mailAccount = new MailAccount(MailAccount.MAIL_SETTING_PATH); - } catch (IORuntimeException e) { - //ignore - } - - // 寻找config/mailAccount.setting - if(null == mailAccount) { + for (String mailSettingPath : MailAccount.MAIL_SETTING_PATHS) { try { - mailAccount = new MailAccount(MailAccount.MAIL_SETTING_PATH2); - } catch (IORuntimeException e) { + return new MailAccount(mailSettingPath); + } catch (IORuntimeException ignore) { //ignore } } - - // 寻找mail.setting - if(null == mailAccount) { - try { - mailAccount = new MailAccount(MailAccount.MAIL_SETTING_PATH3); - } catch (IORuntimeException e) { - //ignore - } - } - - return mailAccount; + return null; } } diff --git a/hutool-extra/src/main/java/cn/hutool/extra/mail/MailAccount.java b/hutool-extra/src/main/java/cn/hutool/extra/mail/MailAccount.java index 8641c990d..199c79368 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/mail/MailAccount.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/mail/MailAccount.java @@ -32,9 +32,7 @@ public class MailAccount implements Serializable { private static final String MAIL_DEBUG = "mail.debug"; private static final String SPLIT_LONG_PARAMS = "mail.mime.splitlongparameters"; - public static final String MAIL_SETTING_PATH = "config/mail.setting"; - public static final String MAIL_SETTING_PATH2 = "config/mailAccount.setting"; - public static final String MAIL_SETTING_PATH3 = "mail.setting"; + public static final String[] MAIL_SETTING_PATHS = new String[]{"config/mail.setting", "config/mailAccount.setting", "mail.setting"}; /** * SMTP服务器域名 diff --git a/hutool-extra/src/test/java/cn/hutool/extra/emoji/EmojiUtilTest.java b/hutool-extra/src/test/java/cn/hutool/extra/emoji/EmojiUtilTest.java index fe1620c58..f307e4fe3 100644 --- a/hutool-extra/src/test/java/cn/hutool/extra/emoji/EmojiUtilTest.java +++ b/hutool-extra/src/test/java/cn/hutool/extra/emoji/EmojiUtilTest.java @@ -16,4 +16,13 @@ public class EmojiUtilTest { String alias = EmojiUtil.toAlias("😄"); Assert.assertEquals(":smile:", alias); } + + @Test + public void containsEmojiTest() { + boolean containsEmoji = EmojiUtil.containsEmoji("测试一下是否包含EMOJ:😄"); + Assert.assertEquals(containsEmoji, true); + boolean notContainsEmoji = EmojiUtil.containsEmoji("不包含EMOJ:^_^"); + Assert.assertEquals(notContainsEmoji, false); + + } } diff --git a/hutool-http/pom.xml b/hutool-http/pom.xml index 1f6f3ead8..f5ca543b9 100644 --- a/hutool-http/pom.xml +++ b/hutool-http/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.4.3 + 5.4.4-SNAPSHOT hutool-http diff --git a/hutool-http/src/main/java/cn/hutool/http/webservice/SoapClient.java b/hutool-http/src/main/java/cn/hutool/http/webservice/SoapClient.java index d2dfc74b6..f8358e400 100644 --- a/hutool-http/src/main/java/cn/hutool/http/webservice/SoapClient.java +++ b/hutool-http/src/main/java/cn/hutool/http/webservice/SoapClient.java @@ -19,7 +19,6 @@ import javax.xml.soap.Name; import javax.xml.soap.SOAPBodyElement; import javax.xml.soap.SOAPElement; import javax.xml.soap.SOAPException; -import javax.xml.soap.SOAPHeader; import javax.xml.soap.SOAPHeaderElement; import javax.xml.soap.SOAPMessage; import java.io.IOException; @@ -93,7 +92,7 @@ public class SoapClient extends HttpBase { * 创建SOAP客户端,默认使用soap1.1版本协议 * * @param url WS的URL地址 - * @return {@link SoapClient} + * @return this */ public static SoapClient create(String url) { return new SoapClient(url); @@ -104,7 +103,7 @@ public class SoapClient extends HttpBase { * * @param url WS的URL地址 * @param protocol 协议,见{@link SoapProtocol} - * @return {@link SoapClient} + * @return this */ public static SoapClient create(String url, SoapProtocol protocol) { return new SoapClient(url, protocol); @@ -116,7 +115,7 @@ public class SoapClient extends HttpBase { * @param url WS的URL地址 * @param protocol 协议,见{@link SoapProtocol} * @param namespaceURI 方法上的命名空间URI - * @return {@link SoapClient} + * @return this * @since 4.5.6 */ public static SoapClient create(String url, SoapProtocol protocol, String namespaceURI) { @@ -235,7 +234,7 @@ public class SoapClient extends HttpBase { * * @param name 头信息标签名 * @return this - * @deprecated 为了和Http Hrader区分,请使用{@link #setSOAPHeader(QName)} + * @deprecated 为了和Http Hrader区分,请使用{@link #addSOAPHeader(QName)} */ @Deprecated public SoapClient setHeader(QName name) { @@ -247,9 +246,12 @@ public class SoapClient extends HttpBase { * * @param name 头信息标签名 * @return this + * @deprecated 为了便于设置子节点或者value值,请使用{@link #addSOAPHeader(QName)} */ + @Deprecated public SoapClient setSOAPHeader(QName name) { - return setSOAPHeader(name, null, null, null, null); + addSOAPHeader(name); + return this; } /** @@ -261,7 +263,7 @@ public class SoapClient extends HttpBase { * @param mustUnderstand 标题项对于要对其进行处理的接收者来说是强制的还是可选的 * @param relay relay属性 * @return this - * @deprecated 为了和Http Hrader区分,请使用{@link #setSOAPHeader(QName, String, String, Boolean, Boolean)} + * @deprecated 为了和Http Header区分,请使用{@link #addSOAPHeader(QName, String, String, Boolean, Boolean)} */ @Deprecated public SoapClient setHeader(QName name, String actorURI, String roleUri, Boolean mustUnderstand, Boolean relay) { @@ -277,13 +279,29 @@ public class SoapClient extends HttpBase { * @param mustUnderstand 标题项对于要对其进行处理的接收者来说是强制的还是可选的 * @param relay relay属性 * @return this + * @deprecated 为了便于设置子节点或者value值,请使用{@link #addSOAPHeader(QName, String, String, Boolean, Boolean)} */ + @Deprecated public SoapClient setSOAPHeader(QName name, String actorURI, String roleUri, Boolean mustUnderstand, Boolean relay) { - SOAPHeader header; - SOAPHeaderElement ele; + addSOAPHeader(name, actorURI, roleUri, mustUnderstand, relay); + + return this; + } + + /** + * 增加SOAP头信息,方法返回{@link SOAPHeaderElement}可以设置具体属性和子节点 + * + * @param name 头信息标签名 + * @param actorURI 中间的消息接收者 + * @param roleUri Role的URI + * @param mustUnderstand 标题项对于要对其进行处理的接收者来说是强制的还是可选的 + * @param relay relay属性 + * @return {@link SOAPHeaderElement} + * @since 5.4.4 + */ + public SOAPHeaderElement addSOAPHeader(QName name, String actorURI, String roleUri, Boolean mustUnderstand, Boolean relay) { + final SOAPHeaderElement ele = addSOAPHeader(name); try { - header = this.message.getSOAPHeader(); - ele = header.addHeaderElement(name); if (StrUtil.isNotBlank(roleUri)) { ele.setRole(roleUri); } @@ -301,7 +319,24 @@ public class SoapClient extends HttpBase { ele.setMustUnderstand(mustUnderstand); } - return this; + return ele; + } + + /** + * 增加SOAP头信息,方法返回{@link SOAPHeaderElement}可以设置具体属性和子节点 + * + * @param name 头节点名称 + * @return {@link SOAPHeaderElement} + * @since 5.4.4 + */ + public SOAPHeaderElement addSOAPHeader(QName name){ + SOAPHeaderElement ele; + try { + ele = this.message.getSOAPHeader().addHeaderElement(name); + } catch (SOAPException e) { + throw new SoapRuntimeException(e); + } + return ele; } /** diff --git a/hutool-http/src/test/java/cn/hutool/http/test/HtmlUtilTest.java b/hutool-http/src/test/java/cn/hutool/http/test/HtmlUtilTest.java index 9e390f267..66eb9421e 100644 --- a/hutool-http/src/test/java/cn/hutool/http/test/HtmlUtilTest.java +++ b/hutool-http/src/test/java/cn/hutool/http/test/HtmlUtilTest.java @@ -119,6 +119,7 @@ public class HtmlUtilTest { Assert.assertEquals("<html><body>123'123'</body></html>", escape); String restoreEscaped = HtmlUtil.unescape(escape); Assert.assertEquals(html, restoreEscaped); + Assert.assertEquals("'", HtmlUtil.unescape("'")); } @Test diff --git a/hutool-json/pom.xml b/hutool-json/pom.xml index 2da738c75..617a9ca00 100644 --- a/hutool-json/pom.xml +++ b/hutool-json/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.4.3 + 5.4.4-SNAPSHOT hutool-json diff --git a/hutool-json/src/test/java/cn/hutool/json/Issue1101Test.java b/hutool-json/src/test/java/cn/hutool/json/Issue1101Test.java new file mode 100644 index 000000000..cdb17b458 --- /dev/null +++ b/hutool-json/src/test/java/cn/hutool/json/Issue1101Test.java @@ -0,0 +1,96 @@ +package cn.hutool.json; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.TypeReference; +import lombok.Data; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Comparator; +import java.util.TreeSet; + +/** + * 测试转换为TreeSet是否成功。 TreeSet必须有默认的比较器 + */ +public class Issue1101Test { + + @Test + public void treeMapConvertTest(){ + String json = "[{\"nodeName\":\"admin\",\"treeNodeId\":\"00010001_52c95b83-2083-4138-99fb-e6e21f0c1277\",\"sort\":0,\"type\":10,\"parentId\":\"00010001\",\"children\":[],\"id\":\"52c95b83-2083-4138-99fb-e6e21f0c1277\",\"status\":true},{\"nodeName\":\"test\",\"treeNodeId\":\"00010001_97054a82-f8ff-46a1-b76c-cbacf6d18045\",\"sort\":0,\"type\":10,\"parentId\":\"00010001\",\"children\":[],\"id\":\"97054a82-f8ff-46a1-b76c-cbacf6d18045\",\"status\":true}]"; + final JSONArray objects = JSONUtil.parseArray(json); + final TreeSet convert = Convert.convert(new TypeReference>() { + }, objects); + Assert.assertEquals(2, convert.size()); + } + + @Test + public void test(){ + String json = "{\n" + + "\t\"children\": [{\n" + + "\t\t\"children\": [],\n" + + "\t\t\"id\": \"52c95b83-2083-4138-99fb-e6e21f0c1277\",\n" + + "\t\t\"nodeName\": \"admin\",\n" + + "\t\t\"parentId\": \"00010001\",\n" + + "\t\t\"sort\": 0,\n" + + "\t\t\"status\": true,\n" + + "\t\t\"treeNodeId\": \"00010001_52c95b83-2083-4138-99fb-e6e21f0c1277\",\n" + + "\t\t\"type\": 10\n" + + "\t}, {\n" + + "\t\t\"children\": [],\n" + + "\t\t\"id\": \"97054a82-f8ff-46a1-b76c-cbacf6d18045\",\n" + + "\t\t\"nodeName\": \"test\",\n" + + "\t\t\"parentId\": \"00010001\",\n" + + "\t\t\"sort\": 0,\n" + + "\t\t\"status\": true,\n" + + "\t\t\"treeNodeId\": \"00010001_97054a82-f8ff-46a1-b76c-cbacf6d18045\",\n" + + "\t\t\"type\": 10\n" + + "\t}],\n" + + "\t\"id\": \"00010001\",\n" + + "\t\"nodeName\": \"测试\",\n" + + "\t\"parentId\": \"0001\",\n" + + "\t\"sort\": 0,\n" + + "\t\"status\": true,\n" + + "\t\"treeNodeId\": \"00010001\",\n" + + "\t\"type\": 0\n" + + "}"; + + final JSONObject jsonObject = JSONUtil.parseObj(json); + + final TreeNode treeNode = JSONUtil.toBean(jsonObject, TreeNode.class); + Assert.assertEquals(2, treeNode.getChildren().size()); + + TreeNodeDto dto = new TreeNodeDto(); + BeanUtil.copyProperties(treeNode, dto, true); + Assert.assertEquals(2, dto.getChildren().size()); + } + + @Data + public static class TreeNodeDto { + private String id; + private String parentId; + private int sort; + private String nodeName; + private int type; + private Boolean status; + private String treeNodeId; + private TreeSet children = new TreeSet<>(Comparator.comparing(o -> o.id)); + } + + @Data + public static class TreeNode implements Comparable { + private String id; + private String parentId; + private int sort; + private String nodeName; + private int type; + private Boolean status; + private String treeNodeId; + private TreeSet children = new TreeSet<>(); + + @Override + public int compareTo(TreeNode o) { + return id.compareTo(o.getId()); + } + } +} diff --git a/hutool-log/pom.xml b/hutool-log/pom.xml index cb2a0d056..19429e26e 100644 --- a/hutool-log/pom.xml +++ b/hutool-log/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.4.3 + 5.4.4-SNAPSHOT hutool-log diff --git a/hutool-log/src/test/resources/log4j2.xml b/hutool-log/src/test/resources/log4j2.xml index 62fd07ae1..0293b6473 100644 --- a/hutool-log/src/test/resources/log4j2.xml +++ b/hutool-log/src/test/resources/log4j2.xml @@ -10,7 +10,7 @@ - + diff --git a/hutool-poi/pom.xml b/hutool-poi/pom.xml index 4effed78f..6d74e4a4b 100644 --- a/hutool-poi/pom.xml +++ b/hutool-poi/pom.xml @@ -8,7 +8,7 @@ cn.hutool hutool-parent - 5.4.3 + 5.4.4-SNAPSHOT hutool-poi diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelExtractorUtil.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelExtractorUtil.java new file mode 100644 index 000000000..1b5214469 --- /dev/null +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelExtractorUtil.java @@ -0,0 +1,46 @@ +package cn.hutool.poi.excel; + +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.extractor.ExcelExtractor; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.extractor.XSSFExcelExtractor; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + +/** + * {@link ExcelExtractor}工具封装 + * + * @author looly + * @since 5.4.4 + */ +public class ExcelExtractorUtil { + /** + * 获取 {@link ExcelExtractor} 对象 + * + * @param wb {@link Workbook} + * @return {@link ExcelExtractor} + */ + public static ExcelExtractor getExtractor(Workbook wb) { + ExcelExtractor extractor; + if (wb instanceof HSSFWorkbook) { + extractor = new org.apache.poi.hssf.extractor.ExcelExtractor((HSSFWorkbook) wb); + } else { + extractor = new XSSFExcelExtractor((XSSFWorkbook) wb); + } + return extractor; + } + + /** + * 读取为文本格式
+ * 使用{@link ExcelExtractor} 提取Excel内容 + * + * @param wb {@link Workbook} + * @param withSheetName 是否附带sheet名 + * @return Excel文本 + * @since 4.1.0 + */ + public static String readAsText(Workbook wb, boolean withSheetName) { + final ExcelExtractor extractor = getExtractor(wb); + extractor.setIncludeSheetNames(withSheetName); + return extractor.getText(); + } +} diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelReader.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelReader.java index 308de73b7..a8dd2c4e6 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelReader.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/ExcelReader.java @@ -1,28 +1,22 @@ package cn.hutool.poi.excel; -import cn.hutool.core.bean.BeanUtil; -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.collection.IterUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.lang.Assert; -import cn.hutool.core.map.MapUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; import cn.hutool.poi.excel.cell.CellEditor; import cn.hutool.poi.excel.cell.CellHandler; import cn.hutool.poi.excel.cell.CellUtil; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import cn.hutool.poi.excel.reader.BeanSheetReader; +import cn.hutool.poi.excel.reader.ListSheetReader; +import cn.hutool.poi.excel.reader.MapSheetReader; +import cn.hutool.poi.excel.reader.SheetReader; import org.apache.poi.ss.extractor.ExcelExtractor; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; -import org.apache.poi.xssf.extractor.XSSFExcelExtractor; -import org.apache.poi.xssf.usermodel.XSSFWorkbook; import java.io.File; import java.io.InputStream; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -256,37 +250,31 @@ public class ExcelReader extends ExcelBase { } /** - * 读取工作簿中指定的Sheet + * 读取工作簿中指定的Sheet,此方法会把第一行作为标题行,替换标题别名 * * @param startRowIndex 起始行(包含,从0开始计数) * @param endRowIndex 结束行(包含,从0开始计数) * @return 行的集合,一行使用List表示 */ - @SuppressWarnings({"rawtypes", "unchecked"}) public List> read(int startRowIndex, int endRowIndex) { - checkNotClosed(); - List> resultList = new ArrayList<>(); + return read(startRowIndex, endRowIndex, true); + } - startRowIndex = Math.max(startRowIndex, this.sheet.getFirstRowNum());// 读取起始行(包含) - endRowIndex = Math.min(endRowIndex, this.sheet.getLastRowNum());// 读取结束行(包含) - boolean isFirstLine = true; - List rowList; - for (int i = startRowIndex; i <= endRowIndex; i++) { - rowList = readRow(i); - if (CollUtil.isNotEmpty(rowList) || false == ignoreEmptyRow) { - if (null == rowList) { - rowList = new ArrayList<>(0); - } - if (isFirstLine) { - isFirstLine = false; - if (MapUtil.isNotEmpty(this.headerAlias)) { - rowList = aliasHeader(rowList); - } - } - resultList.add(rowList); - } - } - return resultList; + /** + * 读取工作簿中指定的Sheet + * + * @param startRowIndex 起始行(包含,从0开始计数) + * @param endRowIndex 结束行(包含,从0开始计数) + * @param aliasFirstLine 是否首行作为标题行转换别名 + * @return 行的集合,一行使用List表示 + * @since 5.4.4 + */ + public List> read(int startRowIndex, int endRowIndex, boolean aliasFirstLine) { + final ListSheetReader reader = new ListSheetReader(startRowIndex, endRowIndex, aliasFirstLine); + reader.setCellEditor(this.cellEditor); + reader.setIgnoreEmptyRow(this.ignoreEmptyRow); + reader.setHeaderAlias(headerAlias); + return read(reader); } /** @@ -348,33 +336,11 @@ public class ExcelReader extends ExcelBase { * @return Map的列表 */ public List> read(int headerRowIndex, int startRowIndex, int endRowIndex) { - checkNotClosed(); - // 边界判断 - final int firstRowNum = sheet.getFirstRowNum(); - final int lastRowNum = sheet.getLastRowNum(); - if (headerRowIndex < firstRowNum) { - throw new IndexOutOfBoundsException(StrUtil.format("Header row index {} is lower than first row index {}.", headerRowIndex, firstRowNum)); - } else if (headerRowIndex > lastRowNum) { - throw new IndexOutOfBoundsException(StrUtil.format("Header row index {} is greater than last row index {}.", headerRowIndex, firstRowNum)); - } - startRowIndex = Math.max(startRowIndex, firstRowNum);// 读取起始行(包含) - endRowIndex = Math.min(endRowIndex, lastRowNum);// 读取结束行(包含) - - // 读取header - List headerList = readRow(sheet.getRow(headerRowIndex)); - - final List> result = new ArrayList<>(endRowIndex - startRowIndex + 1); - List rowList; - for (int i = startRowIndex; i <= endRowIndex; i++) { - if (i != headerRowIndex) { - // 跳过标题行 - rowList = readRow(sheet.getRow(i)); - if (CollUtil.isNotEmpty(rowList) || false == ignoreEmptyRow) { - result.add(IterUtil.toMap(aliasHeader(headerList), rowList, true)); - } - } - } - return result; + final MapSheetReader reader = new MapSheetReader(headerRowIndex, startRowIndex, endRowIndex); + reader.setCellEditor(this.cellEditor); + reader.setIgnoreEmptyRow(this.ignoreEmptyRow); + reader.setHeaderAlias(headerAlias); + return read(reader); } /** @@ -412,19 +378,25 @@ public class ExcelReader extends ExcelBase { * @param beanType 每行对应Bean的类型 * @return Map的列表 */ - @SuppressWarnings("unchecked") public List read(int headerRowIndex, int startRowIndex, int endRowIndex, Class beanType) { - checkNotClosed(); - final List> mapList = read(headerRowIndex, startRowIndex, endRowIndex); - if (Map.class.isAssignableFrom(beanType)) { - return (List) mapList; - } + final BeanSheetReader reader = new BeanSheetReader<>(headerRowIndex, startRowIndex, endRowIndex, beanType); + reader.setCellEditor(this.cellEditor); + reader.setIgnoreEmptyRow(this.ignoreEmptyRow); + reader.setHeaderAlias(headerAlias); + return read(reader); + } - final List beanList = new ArrayList<>(mapList.size()); - for (Map map : mapList) { - beanList.add(BeanUtil.toBean(map, beanType)); - } - return beanList; + /** + * 读取数据为指定类型 + * + * @param 读取数据类型 + * @param sheetReader {@link SheetReader}实现 + * @return 数据读取结果 + * @since 5.4.4 + */ + public T read(SheetReader sheetReader){ + checkNotClosed(); + return Assert.notNull(sheetReader).read(this.sheet); } /** @@ -436,9 +408,7 @@ public class ExcelReader extends ExcelBase { * @since 4.1.0 */ public String readAsText(boolean withSheetName) { - final ExcelExtractor extractor = getExtractor(); - extractor.setIncludeSheetNames(withSheetName); - return extractor.getText(); + return ExcelExtractorUtil.readAsText(this.workbook, withSheetName); } /** @@ -448,14 +418,7 @@ public class ExcelReader extends ExcelBase { * @since 4.1.0 */ public ExcelExtractor getExtractor() { - ExcelExtractor extractor; - Workbook wb = this.workbook; - if (wb instanceof HSSFWorkbook) { - extractor = new org.apache.poi.hssf.extractor.ExcelExtractor((HSSFWorkbook) wb); - } else { - extractor = new XSSFExcelExtractor((XSSFWorkbook) wb); - } - return extractor; + return ExcelExtractorUtil.getExtractor(this.workbook); } /** @@ -504,42 +467,6 @@ public class ExcelReader extends ExcelBase { return RowUtil.readRow(row, this.cellEditor); } - /** - * 转换标题别名,如果没有别名则使用原标题,当标题为空时,列号对应的字母便是header - * - * @param headerList 原标题列表 - * @return 转换别名列表 - */ - private List aliasHeader(List headerList) { - if(CollUtil.isEmpty(headerList)){ - return new ArrayList<>(0); - } - - final int size = headerList.size(); - final ArrayList result = new ArrayList<>(size); - for (int i = 0; i < size; i++) { - result.add(aliasHeader(headerList.get(i), i)); - } - return result; - } - - /** - * 转换标题别名,如果没有别名则使用原标题,当标题为空时,列号对应的字母便是header - * - * @param headerObj 原标题 - * @param index 标题所在列号,当标题为空时,列号对应的字母便是header - * @return 转换别名列表 - * @since 4.3.2 - */ - private String aliasHeader(Object headerObj, int index) { - if (null == headerObj) { - return ExcelUtil.indexToColName(index); - } - - final String header = headerObj.toString(); - return ObjectUtil.defaultIfNull(this.headerAlias.get(header), header); - } - /** * 检查是否未关闭状态 */ diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/reader/AbstractSheetReader.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/reader/AbstractSheetReader.java new file mode 100644 index 000000000..aa15e80cf --- /dev/null +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/reader/AbstractSheetReader.java @@ -0,0 +1,140 @@ +package cn.hutool.poi.excel.reader; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.poi.excel.ExcelUtil; +import cn.hutool.poi.excel.RowUtil; +import cn.hutool.poi.excel.cell.CellEditor; +import org.apache.poi.ss.usermodel.Sheet; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 抽象{@link Sheet}数据读取实现 + * + * @param 读取类型 + * @author looly + * @since 5.4.4 + */ +public abstract class AbstractSheetReader implements SheetReader { + + /** + * 读取起始行(包含,从0开始计数) + */ + protected final int startRowIndex; + /** + * 读取结束行(包含,从0开始计数) + */ + protected final int endRowIndex; + /** + * 是否忽略空行 + */ + protected boolean ignoreEmptyRow = true; + /** + * 单元格值处理接口 + */ + protected CellEditor cellEditor; + /** + * 标题别名 + */ + private Map headerAlias = new HashMap<>(); + + /** + * 构造 + * + * @param startRowIndex 起始行(包含,从0开始计数) + * @param endRowIndex 结束行(包含,从0开始计数) + */ + public AbstractSheetReader(int startRowIndex, int endRowIndex) { + this.startRowIndex = startRowIndex; + this.endRowIndex = endRowIndex; + } + + /** + * 设置单元格值处理逻辑
+ * 当Excel中的值并不能满足我们的读取要求时,通过传入一个编辑接口,可以对单元格值自定义,例如对数字和日期类型值转换为字符串等 + * + * @param cellEditor 单元格值处理接口 + */ + public void setCellEditor(CellEditor cellEditor) { + this.cellEditor = cellEditor; + } + + /** + * 设置是否忽略空行 + * + * @param ignoreEmptyRow 是否忽略空行 + */ + public void setIgnoreEmptyRow(boolean ignoreEmptyRow) { + this.ignoreEmptyRow = ignoreEmptyRow; + } + + /** + * 设置标题行的别名Map + * + * @param headerAlias 别名Map + */ + public void setHeaderAlias(Map headerAlias) { + this.headerAlias = headerAlias; + } + + /** + * 增加标题别名 + * + * @param header 标题 + * @param alias 别名 + */ + public void addHeaderAlias(String header, String alias) { + this.headerAlias.put(header, alias); + } + + /** + * 转换标题别名,如果没有别名则使用原标题,当标题为空时,列号对应的字母便是header + * + * @param headerList 原标题列表 + * @return 转换别名列表 + */ + protected List aliasHeader(List headerList) { + if (CollUtil.isEmpty(headerList)) { + return new ArrayList<>(0); + } + + final int size = headerList.size(); + final ArrayList result = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + result.add(aliasHeader(headerList.get(i), i)); + } + return result; + } + + /** + * 转换标题别名,如果没有别名则使用原标题,当标题为空时,列号对应的字母便是header + * + * @param headerObj 原标题 + * @param index 标题所在列号,当标题为空时,列号对应的字母便是header + * @return 转换别名列表 + * @since 4.3.2 + */ + protected String aliasHeader(Object headerObj, int index) { + if (null == headerObj) { + return ExcelUtil.indexToColName(index); + } + + final String header = headerObj.toString(); + return ObjectUtil.defaultIfNull(this.headerAlias.get(header), header); + } + + /** + * 读取某一行数据 + * + * @param sheet {@link Sheet} + * @param rowIndex 行号,从0开始 + * @return 一行数据 + */ + protected List readRow(Sheet sheet, int rowIndex) { + return RowUtil.readRow(sheet.getRow(rowIndex), this.cellEditor); + } +} diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/reader/BeanSheetReader.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/reader/BeanSheetReader.java new file mode 100644 index 000000000..94327ace4 --- /dev/null +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/reader/BeanSheetReader.java @@ -0,0 +1,87 @@ +package cn.hutool.poi.excel.reader; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.poi.excel.cell.CellEditor; +import org.apache.poi.ss.usermodel.Sheet; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 读取{@link Sheet}为bean的List列表形式 + * + * @author looly + * @since 5.4.4 + */ +public class BeanSheetReader implements SheetReader> { + + private final Class beanClass; + private final MapSheetReader mapSheetReader; + + /** + * 构造 + * + * @param headerRowIndex 标题所在行,如果标题行在读取的内容行中间,这行做为数据将忽略 + * @param startRowIndex 起始行(包含,从0开始计数) + * @param endRowIndex 结束行(包含,从0开始计数) + * @param beanClass 每行对应Bean的类型 + */ + public BeanSheetReader(int headerRowIndex, int startRowIndex, int endRowIndex, Class beanClass) { + mapSheetReader = new MapSheetReader(headerRowIndex, startRowIndex, endRowIndex); + this.beanClass = beanClass; + } + + @Override + @SuppressWarnings("unchecked") + public List read(Sheet sheet) { + final List> mapList = mapSheetReader.read(sheet); + if (Map.class.isAssignableFrom(this.beanClass)) { + return (List) mapList; + } + + final List beanList = new ArrayList<>(mapList.size()); + for (Map map : mapList) { + beanList.add(BeanUtil.toBean(map, this.beanClass)); + } + return beanList; + } + + /** + * 设置单元格值处理逻辑
+ * 当Excel中的值并不能满足我们的读取要求时,通过传入一个编辑接口,可以对单元格值自定义,例如对数字和日期类型值转换为字符串等 + * + * @param cellEditor 单元格值处理接口 + */ + public void setCellEditor(CellEditor cellEditor) { + this.mapSheetReader.setCellEditor(cellEditor); + } + + /** + * 设置是否忽略空行 + * + * @param ignoreEmptyRow 是否忽略空行 + */ + public void setIgnoreEmptyRow(boolean ignoreEmptyRow) { + this.mapSheetReader.setIgnoreEmptyRow(ignoreEmptyRow); + } + + /** + * 设置标题行的别名Map + * + * @param headerAlias 别名Map + */ + public void setHeaderAlias(Map headerAlias) { + this.mapSheetReader.setHeaderAlias(headerAlias); + } + + /** + * 增加标题别名 + * + * @param header 标题 + * @param alias 别名 + */ + public void addHeaderAlias(String header, String alias) { + this.mapSheetReader.addHeaderAlias(header, alias); + } +} diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/reader/ListSheetReader.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/reader/ListSheetReader.java new file mode 100644 index 000000000..098398639 --- /dev/null +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/reader/ListSheetReader.java @@ -0,0 +1,52 @@ +package cn.hutool.poi.excel.reader; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.convert.Convert; +import org.apache.poi.ss.usermodel.Sheet; + +import java.util.ArrayList; +import java.util.List; + +/** + * 读取{@link Sheet}为List列表形式 + * + * @author looly + * @since 5.4.4 + */ +public class ListSheetReader extends AbstractSheetReader>> { + + /** 是否首行作为标题行转换别名 */ + private final boolean aliasFirstLine; + + /** + * 构造 + * + * @param startRowIndex 起始行(包含,从0开始计数) + * @param endRowIndex 结束行(包含,从0开始计数) + * @param aliasFirstLine 是否首行作为标题行转换别名 + */ + public ListSheetReader(int startRowIndex, int endRowIndex, boolean aliasFirstLine) { + super(startRowIndex, endRowIndex); + this.aliasFirstLine = aliasFirstLine; + } + + @Override + public List> read(Sheet sheet) { + final List> resultList = new ArrayList<>(); + + int startRowIndex = Math.max(this.startRowIndex, sheet.getFirstRowNum());// 读取起始行(包含) + int endRowIndex = Math.min(this.endRowIndex, sheet.getLastRowNum());// 读取结束行(包含) + List rowList; + for (int i = startRowIndex; i <= endRowIndex; i++) { + rowList = readRow(sheet, i); + if (CollUtil.isNotEmpty(rowList) || false == ignoreEmptyRow) { + if (aliasFirstLine && i == startRowIndex) { + // 第一行作为标题行,替换别名 + rowList = Convert.toList(Object.class, aliasHeader(rowList)); + } + resultList.add(rowList); + } + } + return resultList; + } +} diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/reader/MapSheetReader.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/reader/MapSheetReader.java new file mode 100644 index 000000000..91f915bc5 --- /dev/null +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/reader/MapSheetReader.java @@ -0,0 +1,63 @@ +package cn.hutool.poi.excel.reader; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.IterUtil; +import cn.hutool.core.util.StrUtil; +import org.apache.poi.ss.usermodel.Sheet; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 读取{@link Sheet}为Map的List列表形式 + * + * @author looly + * @since 5.4.4 + */ +public class MapSheetReader extends AbstractSheetReader>> { + + private final int headerRowIndex; + + /** + * 构造 + * + * @param headerRowIndex 标题所在行,如果标题行在读取的内容行中间,这行做为数据将忽略 + * @param startRowIndex 起始行(包含,从0开始计数) + * @param endRowIndex 结束行(包含,从0开始计数) + */ + public MapSheetReader(int headerRowIndex, int startRowIndex, int endRowIndex) { + super(startRowIndex, endRowIndex); + this.headerRowIndex = headerRowIndex; + } + + @Override + public List> read(Sheet sheet) { + // 边界判断 + final int firstRowNum = sheet.getFirstRowNum(); + final int lastRowNum = sheet.getLastRowNum(); + if (headerRowIndex < firstRowNum) { + throw new IndexOutOfBoundsException(StrUtil.format("Header row index {} is lower than first row index {}.", headerRowIndex, firstRowNum)); + } else if (headerRowIndex > lastRowNum) { + throw new IndexOutOfBoundsException(StrUtil.format("Header row index {} is greater than last row index {}.", headerRowIndex, firstRowNum)); + } + final int startRowIndex = Math.max(this.startRowIndex, firstRowNum);// 读取起始行(包含) + final int endRowIndex = Math.min(this.endRowIndex, lastRowNum);// 读取结束行(包含) + + // 读取header + List headerList = aliasHeader(readRow(sheet, headerRowIndex)); + + final List> result = new ArrayList<>(endRowIndex - startRowIndex + 1); + List rowList; + for (int i = startRowIndex; i <= endRowIndex; i++) { + // 跳过标题行 + if (i != headerRowIndex) { + rowList = readRow(sheet, i); + if (CollUtil.isNotEmpty(rowList) || false == ignoreEmptyRow) { + result.add(IterUtil.toMap(headerList, rowList, true)); + } + } + } + return result; + } +} diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/reader/SheetReader.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/reader/SheetReader.java new file mode 100644 index 000000000..2e20dff1d --- /dev/null +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/reader/SheetReader.java @@ -0,0 +1,20 @@ +package cn.hutool.poi.excel.reader; + +import org.apache.poi.ss.usermodel.Sheet; + +/** + * Excel {@link Sheet}读取接口,通过实现此接口,将{@link Sheet}中的数据读取为不同类型。 + * + * @param 读取的数据类型 + */ +@FunctionalInterface +public interface SheetReader { + + /** + * 读取数据 + * + * @param sheet {@link Sheet} + * @return 读取结果 + */ + T read(Sheet sheet); +} diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/reader/package-info.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/reader/package-info.java new file mode 100644 index 000000000..8d343fd12 --- /dev/null +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/reader/package-info.java @@ -0,0 +1,7 @@ +/** + * 数据读取接口及实现,此包中定义了SheetReader,通过实现此接口,实现sheet中的数据读取为不同类型。 + * + * @author looly + * + */ +package cn.hutool.poi.excel.reader; \ No newline at end of file diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/handler/AbstractRowHandler.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/handler/AbstractRowHandler.java new file mode 100644 index 000000000..540bb84f4 --- /dev/null +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/handler/AbstractRowHandler.java @@ -0,0 +1,59 @@ +package cn.hutool.poi.excel.sax.handler; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.lang.func.Func1; + +import java.util.List; + +/** + * 抽象行数据处理器,通过实现{@link #handle(int, long, List)} 处理原始数据
+ * 并调用{@link #handleData(int, long, Object)}处理经过转换后的数据。 + * + * @param 转换后的数据类型 + * @author looly + * @since 5.4.4 + */ +public abstract class AbstractRowHandler implements RowHandler { + + /** + * 读取起始行(包含,从0开始计数) + */ + protected final int startRowIndex; + /** + * 读取结束行(包含,从0开始计数) + */ + protected final int endRowIndex; + /** + * 行数据转换函数 + */ + protected Func1, T> convertFunc; + + /** + * 构造 + * + * @param startRowIndex 读取起始行(包含,从0开始计数) + * @param endRowIndex 读取结束行(包含,从0开始计数) + */ + public AbstractRowHandler(int startRowIndex, int endRowIndex) { + this.startRowIndex = startRowIndex; + this.endRowIndex = endRowIndex; + } + + @Override + public void handle(int sheetIndex, long rowIndex, List rowList) { + Assert.notNull(convertFunc); + if (rowIndex < this.startRowIndex || rowIndex > this.endRowIndex) { + return; + } + handleData(sheetIndex, rowIndex, convertFunc.callWithRuntimeException(rowList)); + } + + /** + * 处理转换后的数据 + * + * @param sheetIndex 当前Sheet序号 + * @param rowIndex 当前行号,从0开始计数 + * @param data 行数据 + */ + public abstract void handleData(int sheetIndex, long rowIndex, T data); +} diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/handler/BeanRowHandler.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/handler/BeanRowHandler.java new file mode 100644 index 000000000..bcfdcb91e --- /dev/null +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/handler/BeanRowHandler.java @@ -0,0 +1,52 @@ +package cn.hutool.poi.excel.sax.handler; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.IterUtil; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Assert; + +import java.util.List; + +/** + * Bean形式的行处理器
+ * 将一行数据转换为Map,key为指定行,value为当前行对应位置的值 + * + * @author looly + * @since 5.4.4 + */ +public abstract class BeanRowHandler extends AbstractRowHandler { + + /** + * 标题所在行(从0开始计数) + */ + private final int headerRowIndex; + /** + * 标题行 + */ + List headerList; + + /** + * 构造 + * + * @param headerRowIndex 标题所在行(从0开始计数) + * @param startRowIndex 读取起始行(包含,从0开始计数) + * @param endRowIndex 读取结束行(包含,从0开始计数) + * @param clazz Bean类型 + */ + public BeanRowHandler(int headerRowIndex, int startRowIndex, int endRowIndex, Class clazz) { + super(startRowIndex, endRowIndex); + Assert.isTrue(headerRowIndex <= startRowIndex, "Header row must before the start row!"); + this.headerRowIndex = headerRowIndex; + this.convertFunc = (rowList) -> BeanUtil.toBean(IterUtil.toMap(headerList, rowList), clazz); + } + + @Override + public void handle(int sheetIndex, long rowIndex, List rowList) { + if (rowIndex == this.headerRowIndex) { + this.headerList = ListUtil.unmodifiable(Convert.toList(String.class, rowList)); + return; + } + super.handle(sheetIndex, rowIndex, rowList); + } +} diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/handler/MapRowHandler.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/handler/MapRowHandler.java new file mode 100644 index 000000000..1771da41f --- /dev/null +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/handler/MapRowHandler.java @@ -0,0 +1,49 @@ +package cn.hutool.poi.excel.sax.handler; + +import cn.hutool.core.collection.IterUtil; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.convert.Convert; + +import java.util.List; +import java.util.Map; + +/** + * Map形式的行处理器
+ * 将一行数据转换为Map,key为指定行,value为当前行对应位置的值 + * + * @author looly + * @since 5.4.4 + */ +public abstract class MapRowHandler extends AbstractRowHandler> { + + /** + * 标题所在行(从0开始计数) + */ + private final int headerRowIndex; + /** + * 标题行 + */ + List headerList; + + /** + * 构造 + * + * @param headerRowIndex 标题所在行(从0开始计数) + * @param startRowIndex 读取起始行(包含,从0开始计数) + * @param endRowIndex 读取结束行(包含,从0开始计数) + */ + public MapRowHandler(int headerRowIndex, int startRowIndex, int endRowIndex){ + super(startRowIndex, endRowIndex); + this.headerRowIndex = headerRowIndex; + this.convertFunc = (rowList)-> IterUtil.toMap(headerList, rowList); + } + + @Override + public void handle(int sheetIndex, long rowIndex, List rowList) { + if (rowIndex == this.headerRowIndex) { + this.headerList = ListUtil.unmodifiable(Convert.toList(String.class, rowList)); + return; + } + super.handle(sheetIndex, rowIndex, rowList); + } +} diff --git a/hutool-poi/src/main/java/cn/hutool/poi/word/TableUtil.java b/hutool-poi/src/main/java/cn/hutool/poi/word/TableUtil.java index a3eb3c991..4a700a086 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/word/TableUtil.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/word/TableUtil.java @@ -71,7 +71,7 @@ public class TableUtil { return; } - Map rowMap = null; + Map rowMap; if(rowBean instanceof Map) { rowMap = (Map) rowBean; } else if (BeanUtil.isBean(rowBean.getClass())) { @@ -79,6 +79,7 @@ public class TableUtil { } else { // 其它转为字符串默认输出 writeRow(row, CollUtil.newArrayList(rowBean), isWriteKeyAsHead); + return; } writeRow(row, rowMap, isWriteKeyAsHead); @@ -98,6 +99,7 @@ public class TableUtil { if (isWriteKeyAsHead) { writeRow(row, rowMap.keySet()); + row = row.getTable().createRow(); } writeRow(row, rowMap.values()); } diff --git a/hutool-poi/src/test/java/cn/hutool/poi/word/test/WordWriterTest.java b/hutool-poi/src/test/java/cn/hutool/poi/word/test/WordWriterTest.java index 11df0311b..b05131edd 100644 --- a/hutool-poi/src/test/java/cn/hutool/poi/word/test/WordWriterTest.java +++ b/hutool-poi/src/test/java/cn/hutool/poi/word/test/WordWriterTest.java @@ -1,5 +1,6 @@ package cn.hutool.poi.word.test; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.lang.Console; import cn.hutool.poi.word.Word07Writer; @@ -8,6 +9,8 @@ import org.junit.Test; import java.awt.Font; import java.io.File; +import java.util.LinkedHashMap; +import java.util.Map; public class WordWriterTest { @@ -32,4 +35,18 @@ public class WordWriterTest { // 关闭 writer.close(); } + + @Test + @Ignore + public void writeTableTest(){ + final Word07Writer writer = new Word07Writer(); + Map map = new LinkedHashMap<>(); + map.put("姓名", "张三"); + map.put("年龄", "23"); + map.put("成绩", 88.32); + map.put("是否合格", true); + + writer.addTable(CollUtil.newArrayList(map)); + writer.flush(FileUtil.file("d:/test/test.docx")); + } } diff --git a/hutool-script/pom.xml b/hutool-script/pom.xml index b1b5ef988..0bc5d4c63 100644 --- a/hutool-script/pom.xml +++ b/hutool-script/pom.xml @@ -8,7 +8,7 @@ cn.hutool hutool-parent - 5.4.3 + 5.4.4-SNAPSHOT hutool-script diff --git a/hutool-setting/pom.xml b/hutool-setting/pom.xml index 42941f24e..7ab60de80 100644 --- a/hutool-setting/pom.xml +++ b/hutool-setting/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.4.3 + 5.4.4-SNAPSHOT hutool-setting diff --git a/hutool-setting/src/main/java/cn/hutool/setting/Setting.java b/hutool-setting/src/main/java/cn/hutool/setting/Setting.java index f6004fa7b..44eaff7ce 100644 --- a/hutool-setting/src/main/java/cn/hutool/setting/Setting.java +++ b/hutool-setting/src/main/java/cn/hutool/setting/Setting.java @@ -164,6 +164,18 @@ public class Setting extends AbsSetting implements Map { Assert.notNull(url, "Null setting url define!"); this.init(new UrlResource(url), charset, isUseVariable); } + + /** + * 构造 + * + * @param resource Setting的Resource + * @param charset 字符集 + * @param isUseVariable 是否使用变量 + * @since 5.4.4 + */ + public Setting(Resource resource, Charset charset, boolean isUseVariable) { + this.init(resource, charset, isUseVariable); + } // ------------------------------------------------------------------------------------- Constructor end /** @@ -176,7 +188,7 @@ public class Setting extends AbsSetting implements Map { */ public boolean init(Resource resource, Charset charset, boolean isUseVariable) { if (resource == null) { - throw new NullPointerException("Null setting url define!"); + throw new NullPointerException("Null setting resource define!"); } this.settingUrl = resource.getUrl(); this.charset = charset; @@ -319,10 +331,10 @@ public class Setting extends AbsSetting implements Map { } /** - * 获取group分组下所有配置键值对,组成新的{@link Setting} + * 获取group分组下所有配置键值对,组成新的Setting * * @param group 分组 - * @return {@link Setting} + * @return Setting */ public Setting getSetting(String group) { final Setting setting = new Setting(); diff --git a/hutool-socket/pom.xml b/hutool-socket/pom.xml index b8473cb5c..19509870c 100644 --- a/hutool-socket/pom.xml +++ b/hutool-socket/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.4.3 + 5.4.4-SNAPSHOT hutool-socket diff --git a/hutool-system/pom.xml b/hutool-system/pom.xml index f03d3b658..93fb286bb 100644 --- a/hutool-system/pom.xml +++ b/hutool-system/pom.xml @@ -9,7 +9,7 @@ cn.hutool hutool-parent - 5.4.3 + 5.4.4-SNAPSHOT hutool-system diff --git a/pom.xml b/pom.xml index f34f2d137..534a944a2 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ cn.hutool hutool-parent - 5.4.3 + 5.4.4-SNAPSHOT hutool Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。 https://github.com/looly/hutool