diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ad7a0e9e..41ae1549c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,15 @@ ### 新特性 * 【poi 】 增加单元格位置引用(例如A11等方式获取单元格) +* 【extra】 ServletUtil.fillBean支持数据和集合字段(issue#I19ZMK@Gitee) +* 【core 】 修改ThreadUtil.newSingleExecutor默认队列大小(issue#754@Github) +* 【core 】 修改ExecutorBuilder默认队列大小(issue#753@Github) +* 【core 】 FileTypeUtil增加mp4的magic(issue#756@Github) ### Bug修复 * 【core 】 修复CombinationAnnotationElement数组判断问题(issue#752@Github) +* 【core 】 修复log4j2使用debug行号打印问题(issue#I19NFJ@Github) +* 【poi 】 修复sax读取excel03数组越界问题(issue#750@Github) ------------------------------------------------------------------------------------------------------------- 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 f070c174e..aa6884948 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 @@ -42,7 +42,8 @@ public class FileTypeUtil { fileTypeMap.put("255044462d312e", "pdf"); // Adobe Acrobat (pdf) fileTypeMap.put("2e524d46000000120001", "rmvb"); // rmvb/rm相同 fileTypeMap.put("464c5601050000000900", "flv"); // flv与f4v相同 - fileTypeMap.put("00000020667479706d70", "mp4"); + fileTypeMap.put("00000020667479706", "mp4"); + fileTypeMap.put("00000018667479706D70", "mp4"); fileTypeMap.put("49443303000000002176", "mp3"); fileTypeMap.put("000001ba210001000180", "mpg"); // fileTypeMap.put("3026b2758e66cf11a6d9", "wmv"); // wmv与asf相同 diff --git a/hutool-core/src/main/java/cn/hutool/core/thread/DelegatedExecutorService.java b/hutool-core/src/main/java/cn/hutool/core/thread/DelegatedExecutorService.java new file mode 100644 index 000000000..84fbf66a8 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/thread/DelegatedExecutorService.java @@ -0,0 +1,88 @@ +package cn.hutool.core.thread; + +import java.util.Collection; +import java.util.List; +import java.util.concurrent.AbstractExecutorService; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +/** + * ExecutorService代理 + * + * @author loolly + */ +public class DelegatedExecutorService extends AbstractExecutorService { + private final ExecutorService e; + + DelegatedExecutorService(ExecutorService executor) { + e = executor; + } + + @SuppressWarnings("NullableProblems") + public void execute(Runnable command) { + e.execute(command); + } + + public void shutdown() { + e.shutdown(); + } + + @SuppressWarnings("NullableProblems") + public List shutdownNow() { + return e.shutdownNow(); + } + + public boolean isShutdown() { + return e.isShutdown(); + } + + public boolean isTerminated() { + return e.isTerminated(); + } + + @SuppressWarnings("NullableProblems") + public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { + return e.awaitTermination(timeout, unit); + } + + @SuppressWarnings("NullableProblems") + public Future submit(Runnable task) { + return e.submit(task); + } + + @SuppressWarnings("NullableProblems") + public Future submit(Callable task) { + return e.submit(task); + } + + @SuppressWarnings("NullableProblems") + public Future submit(Runnable task, T result) { + return e.submit(task, result); + } + + @SuppressWarnings("NullableProblems") + public List> invokeAll(Collection> tasks) throws InterruptedException { + return e.invokeAll(tasks); + } + + @SuppressWarnings("NullableProblems") + public List> invokeAll(Collection> tasks, long timeout, TimeUnit unit) + throws InterruptedException { + return e.invokeAll(tasks, timeout, unit); + } + + @SuppressWarnings("NullableProblems") + public T invokeAny(Collection> tasks) + throws InterruptedException, ExecutionException { + return e.invokeAny(tasks); + } + + public T invokeAny(Collection> tasks, long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + return e.invokeAny(tasks, timeout, unit); + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/thread/ExecutorBuilder.java b/hutool-core/src/main/java/cn/hutool/core/thread/ExecutorBuilder.java index 0d944303c..d6f634f9a 100644 --- a/hutool-core/src/main/java/cn/hutool/core/thread/ExecutorBuilder.java +++ b/hutool-core/src/main/java/cn/hutool/core/thread/ExecutorBuilder.java @@ -1,6 +1,8 @@ package cn.hutool.core.thread; +import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RejectedExecutionHandler; @@ -14,31 +16,48 @@ import cn.hutool.core.util.ObjectUtil; /** * {@link ThreadPoolExecutor} 建造者 - * + * * @author looly * @since 4.1.9 */ public class ExecutorBuilder implements Builder { private static final long serialVersionUID = 1L; - /** 初始池大小 */ + /** 默认的等待队列容量 */ + public static final int DEFAULT_QUEUE_CAPACITY = 1024; + + /** + * 初始池大小 + */ private int corePoolSize; - /** 最大池大小(允许同时执行的最大线程数) */ + /** + * 最大池大小(允许同时执行的最大线程数) + */ private int maxPoolSize = Integer.MAX_VALUE; - /** 线程存活时间,即当池中线程多于初始大小时,多出的线程保留的时长 */ + /** + * 线程存活时间,即当池中线程多于初始大小时,多出的线程保留的时长 + */ private long keepAliveTime = TimeUnit.SECONDS.toNanos(60); - /** 队列,用于存在未执行的线程 */ + /** + * 队列,用于存在未执行的线程 + */ private BlockingQueue workQueue; - /** 线程工厂,用于自定义线程创建 */ + /** + * 线程工厂,用于自定义线程创建 + */ private ThreadFactory threadFactory; - /** 当线程阻塞(block)时的异常处理器,所谓线程阻塞即线程池和等待队列已满,无法处理线程时采取的策略 */ + /** + * 当线程阻塞(block)时的异常处理器,所谓线程阻塞即线程池和等待队列已满,无法处理线程时采取的策略 + */ private RejectedExecutionHandler handler; - /** 线程执行超时后是否回收线程 */ + /** + * 线程执行超时后是否回收线程 + */ private Boolean allowCoreThreadTimeOut; /** * 设置初始池大小,默认0 - * + * * @param corePoolSize 初始池大小 * @return this */ @@ -49,7 +68,7 @@ public class ExecutorBuilder implements Builder { /** * 设置最大池大小(允许同时执行的最大线程数) - * + * * @param maxPoolSize 最大池大小(允许同时执行的最大线程数) * @return this */ @@ -60,9 +79,9 @@ public class ExecutorBuilder implements Builder { /** * 设置线程存活时间,即当池中线程多于初始大小时,多出的线程保留的时长 - * + * * @param keepAliveTime 线程存活时间 - * @param unit 单位 + * @param unit 单位 * @return this */ public ExecutorBuilder setKeepAliveTime(long keepAliveTime, TimeUnit unit) { @@ -71,7 +90,7 @@ public class ExecutorBuilder implements Builder { /** * 设置线程存活时间,即当池中线程多于初始大小时,多出的线程保留的时长,单位纳秒 - * + * * @param keepAliveTime 线程存活时间,单位纳秒 * @return this */ @@ -83,13 +102,14 @@ public class ExecutorBuilder implements Builder { /** * 设置队列,用于存在未执行的线程
* 可选队列有: - * + * *
-	 * 1. SynchronousQueue    它将任务直接提交给线程而不保持它们。当运行线程小于maxPoolSize时会创建新线程,否则触发异常策略
-	 * 2. LinkedBlockingQueue 无界队列,当运行线程大于corePoolSize时始终放入此队列,此时maximumPoolSize无效
-	 * 3. ArrayBlockingQueue  有界队列,相对无界队列有利于控制队列大小,队列满时,运行线程小于maxPoolSize时会创建新线程,否则触发异常策略
+	 * 1. {@link SynchronousQueue}    它将任务直接提交给线程而不保持它们。当运行线程小于maxPoolSize时会创建新线程,否则触发异常策略
+	 * 2. {@link LinkedBlockingQueue} 默认无界队列,当运行线程大于corePoolSize时始终放入此队列,此时maximumPoolSize无效。
+	 *                        当构造LinkedBlockingQueue对象时传入参数,变为有界队列,队列满时,运行线程小于maxPoolSize时会创建新线程,否则触发异常策略
+	 * 3. {@link ArrayBlockingQueue}  有界队列,相对无界队列有利于控制队列大小,队列满时,运行线程小于maxPoolSize时会创建新线程,否则触发异常策略
 	 * 
- * + * * @param workQueue 队列 * @return this */ @@ -98,10 +118,22 @@ public class ExecutorBuilder implements Builder { return this; } + /** + * 使用{@link ArrayBlockingQueue} 做为等待队列
+ * 有界队列,相对无界队列有利于控制队列大小,队列满时,运行线程小于maxPoolSize时会创建新线程,否则触发异常策略 + * + * @param capacity 队列容量 + * @return this + * @since 5.1.4 + */ + public ExecutorBuilder useArrayBlockingQueue(int capacity) { + return setWorkQueue(new ArrayBlockingQueue<>(capacity)); + } + /** * 使用{@link SynchronousQueue} 做为等待队列(非公平策略)
* 它将任务直接提交给线程而不保持它们。当运行线程小于maxPoolSize时会创建新线程,否则触发异常策略 - * + * * @return this * @since 4.1.11 */ @@ -112,7 +144,7 @@ public class ExecutorBuilder implements Builder { /** * 使用{@link SynchronousQueue} 做为等待队列
* 它将任务直接提交给线程而不保持它们。当运行线程小于maxPoolSize时会创建新线程,否则触发异常策略 - * + * * @param fair 是否使用公平访问策略 * @return this * @since 4.5.0 @@ -123,7 +155,7 @@ public class ExecutorBuilder implements Builder { /** * 设置线程工厂,用于自定义线程创建 - * + * * @param threadFactory 线程工厂 * @return this * @see ThreadFactoryBuilder @@ -137,7 +169,7 @@ public class ExecutorBuilder implements Builder { * 设置当线程阻塞(block)时的异常处理器,所谓线程阻塞即线程池和等待队列已满,无法处理线程时采取的策略 *

* 此处可以使用JDK预定义的几种策略,见{@link RejectPolicy}枚举 - * + * * @param handler {@link RejectedExecutionHandler} * @return this * @see RejectPolicy @@ -149,7 +181,7 @@ public class ExecutorBuilder implements Builder { /** * 设置线程执行超时后是否回收线程 - * + * * @param allowCoreThreadTimeOut 线程执行超时后是否回收线程 * @return this */ @@ -160,7 +192,7 @@ public class ExecutorBuilder implements Builder { /** * 创建ExecutorBuilder,开始构建 - * + * * @return {@link ExecutorBuilder} */ public static ExecutorBuilder create() { @@ -175,9 +207,19 @@ public class ExecutorBuilder implements Builder { return build(this); } + /** + * 创建有回收关闭功能的ExecutorService + * + * @return 创建有回收关闭功能的ExecutorService + * @since 5.1.4 + */ + public ExecutorService buildFinalizable() { + return new FinalizableDelegatedExecutorService(build()); + } + /** * 构建ThreadPoolExecutor - * + * * @param builder {@link ExecutorBuilder} * @return {@link ThreadPoolExecutor} */ @@ -190,7 +232,7 @@ public class ExecutorBuilder implements Builder { workQueue = builder.workQueue; } else { // corePoolSize为0则要使用SynchronousQueue避免无限阻塞 - workQueue = (corePoolSize <= 0) ? new SynchronousQueue<>() : new LinkedBlockingQueue<>(); + workQueue = (corePoolSize <= 0) ? new SynchronousQueue<>() : new LinkedBlockingQueue<>(DEFAULT_QUEUE_CAPACITY); } final ThreadFactory threadFactory = (null != builder.threadFactory) ? builder.threadFactory : Executors.defaultThreadFactory(); RejectedExecutionHandler handler = ObjectUtil.defaultIfNull(builder.handler, new ThreadPoolExecutor.AbortPolicy()); diff --git a/hutool-core/src/main/java/cn/hutool/core/thread/FinalizableDelegatedExecutorService.java b/hutool-core/src/main/java/cn/hutool/core/thread/FinalizableDelegatedExecutorService.java new file mode 100644 index 000000000..29749783d --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/thread/FinalizableDelegatedExecutorService.java @@ -0,0 +1,19 @@ +package cn.hutool.core.thread; + +import java.util.concurrent.ExecutorService; + +/** + * 保证ExecutorService在对象回收时正常结束 + * + * @author loolly + */ +public class FinalizableDelegatedExecutorService extends DelegatedExecutorService { + FinalizableDelegatedExecutorService(ExecutorService executor) { + super(executor); + } + + @Override + protected void finalize() { + super.shutdown(); + } +} \ No newline at end of file diff --git a/hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java b/hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java index 4a35c563b..379e4ff8d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/thread/ThreadUtil.java @@ -6,7 +6,6 @@ import java.util.concurrent.CompletionService; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; @@ -48,7 +47,11 @@ public class ThreadUtil { * @return ExecutorService */ public static ExecutorService newSingleExecutor() { - return Executors.newSingleThreadExecutor(); + return ExecutorBuilder.create()// + .setCorePoolSize(1)// + .setMaxPoolSize(1)// + .setKeepAliveTime(0)// + .buildFinalizable(); } /** diff --git a/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java index 41e911471..774901cce 100644 --- a/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java +++ b/hutool-extra/src/main/java/cn/hutool/extra/servlet/ServletUtil.java @@ -1,25 +1,5 @@ package cn.hutool.extra.servlet; -import java.io.BufferedInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintWriter; -import java.io.Writer; -import java.lang.reflect.Type; -import java.nio.charset.Charset; -import java.util.Collections; -import java.util.Date; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Map; - -import javax.servlet.ServletOutputStream; -import javax.servlet.ServletRequest; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.bean.copier.CopyOptions; import cn.hutool.core.bean.copier.ValueProvider; @@ -37,6 +17,25 @@ import cn.hutool.core.util.URLUtil; import cn.hutool.extra.servlet.multipart.MultipartFormData; import cn.hutool.extra.servlet.multipart.UploadSetting; +import javax.servlet.ServletOutputStream; +import javax.servlet.ServletRequest; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.io.Writer; +import java.lang.reflect.Type; +import java.nio.charset.Charset; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + /** * Servlet相关工具类封装 * @@ -128,16 +127,21 @@ public class ServletUtil { return BeanUtil.fillBean(bean, new ValueProvider() { @Override public Object value(String key, Type valueType) { - String value = request.getParameter(key); - if (StrUtil.isEmpty(value)) { - // 使用类名前缀尝试查找值 - value = request.getParameter(beanName + StrUtil.DOT + key); - if (StrUtil.isEmpty(value)) { - // 此处取得的值为空时跳过,包括null和"" - value = null; + String[] values = request.getParameterValues(key); + if(ArrayUtil.isEmpty(values)){ + values = request.getParameterValues(beanName + StrUtil.DOT + key); + if(ArrayUtil.isEmpty(values)){ + return null; } } - return value; + + if(1 == values.length){ + // 单值表单直接返回这个值 + return values[0]; + }else{ + // 多值表单返回数组 + return values; + } } @Override @@ -346,6 +350,7 @@ public class ServletUtil { public static boolean isIE(HttpServletRequest request) { String userAgent = getHeaderIgnoreCase(request, "User-Agent"); if (StrUtil.isNotBlank(userAgent)) { + //noinspection ConstantConditions userAgent = userAgent.toUpperCase(); return userAgent.contains("MSIE") || userAgent.contains("TRIDENT"); } @@ -400,8 +405,7 @@ public class ServletUtil { * @return Cookie对象 */ public static Cookie getCookie(HttpServletRequest httpServletRequest, String name) { - final Map cookieMap = readCookieMap(httpServletRequest); - return cookieMap == null ? null : cookieMap.get(name); + return readCookieMap(httpServletRequest).get(name); } /** @@ -604,7 +608,7 @@ public class ServletUtil { } else if (Date.class.isAssignableFrom(value.getClass())) { response.setDateHeader(name, ((Date) value).getTime()); } else if (value instanceof Integer || "int".equals(value.getClass().getSimpleName().toLowerCase())) { - response.setIntHeader(name, (Integer) value); + response.setIntHeader(name, (int) value); } else { response.setHeader(name, value.toString()); } diff --git a/hutool-extra/src/test/java/cn/hutool/extra/ftp/FtpTest.java b/hutool-extra/src/test/java/cn/hutool/extra/ftp/FtpTest.java index a8213a04d..ede110773 100644 --- a/hutool-extra/src/test/java/cn/hutool/extra/ftp/FtpTest.java +++ b/hutool-extra/src/test/java/cn/hutool/extra/ftp/FtpTest.java @@ -10,7 +10,7 @@ import cn.hutool.core.io.IoUtil; import cn.hutool.core.lang.Console; public class FtpTest { - + @Test @Ignore public void cdTest() { diff --git a/hutool-log/src/main/java/cn/hutool/log/dialect/log4j2/Log4j2Log.java b/hutool-log/src/main/java/cn/hutool/log/dialect/log4j2/Log4j2Log.java index 61fac64d7..04e46e3b2 100644 --- a/hutool-log/src/main/java/cn/hutool/log/dialect/log4j2/Log4j2Log.java +++ b/hutool-log/src/main/java/cn/hutool/log/dialect/log4j2/Log4j2Log.java @@ -54,11 +54,6 @@ public class Log4j2Log extends AbstractLog { return logger.isDebugEnabled(); } - @Override - public void debug(String format, Object... arguments) { - debug(null, format, arguments); - } - @Override public void debug(String fqcn, Throwable t, String format, Object... arguments) { logIfEnabled(fqcn, Level.DEBUG, t, format, arguments); diff --git a/hutool-log/src/test/java/cn/hutool/log/test/CustomLogTest.java b/hutool-log/src/test/java/cn/hutool/log/test/CustomLogTest.java index 4eb5089cf..e08ff6e45 100644 --- a/hutool-log/src/test/java/cn/hutool/log/test/CustomLogTest.java +++ b/hutool-log/src/test/java/cn/hutool/log/test/CustomLogTest.java @@ -57,7 +57,9 @@ public class CustomLogTest { LogFactory factory = new Log4j2LogFactory(); LogFactory.setCurrentLogFactory(factory); Log log = LogFactory.get(); - + + log.debug(null); + log.debug("This is custom '{}' log\n{}", factory.getName(), LINE); log.info(null); log.info("This is custom '{}' log\n{}", factory.getName(), LINE); } diff --git a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel03SaxReader.java b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel03SaxReader.java index 5b9541f89..5f3cda733 100644 --- a/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel03SaxReader.java +++ b/hutool-poi/src/main/java/cn/hutool/poi/excel/sax/Excel03SaxReader.java @@ -1,12 +1,11 @@ package cn.hutool.poi.excel.sax; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; - +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.lang.Console; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.poi.excel.sax.handler.RowHandler; +import cn.hutool.poi.exceptions.POIException; import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder.SheetRecordCollectingListener; import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; import org.apache.poi.hssf.eventusermodel.HSSFEventFactory; @@ -30,10 +29,11 @@ import org.apache.poi.hssf.record.StringRecord; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.poifs.filesystem.POIFSFileSystem; -import cn.hutool.core.io.IoUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.poi.excel.sax.handler.RowHandler; -import cn.hutool.poi.exceptions.POIException; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; /** * Excel2003格式的事件-用户模型方式读取器,在Hutool中,统一将此归类为Sax读取
@@ -194,7 +194,7 @@ public class Excel03SaxReader extends AbstractExcelSaxReader i if (record instanceof MissingCellDummyRecord) { // 空值的操作 MissingCellDummyRecord mc = (MissingCellDummyRecord) record; - rowCellList.add(mc.getColumn(), StrUtil.EMPTY); + addToRowCellList(mc.getColumn(), StrUtil.EMPTY); } else if (record instanceof LastCellOfRowDummyRecord) { // 行结束 processLastCell((LastCellOfRowDummyRecord) record); @@ -208,6 +208,20 @@ public class Excel03SaxReader extends AbstractExcelSaxReader i // ---------------------------------------------------------------------------------------------- Private method start + /** + * 将单元格数据加入到行列表中 + * @param index 加入位置 + * @param value 值 + */ + private void addToRowCellList(int index, Object value){ + while(index > this.rowCellList.size()){ + // 对于中间无数据的单元格补齐空白 + this.rowCellList.add(StrUtil.EMPTY); + } + + this.rowCellList.add(index, value); + } + /** * 处理单元格值 * @@ -219,12 +233,12 @@ public class Excel03SaxReader extends AbstractExcelSaxReader i switch (record.getSid()) { case BlankRecord.sid: // 空白记录 - rowCellList.add(((BlankRecord) record).getColumn(), StrUtil.EMPTY); + addToRowCellList(((BlankRecord) record).getColumn(), StrUtil.EMPTY); break; case BoolErrRecord.sid: // 布尔类型 final BoolErrRecord berec = (BoolErrRecord) record; - rowCellList.add(berec.getColumn(), berec.getBooleanValue()); + addToRowCellList(berec.getColumn(), berec.getBooleanValue()); break; case FormulaRecord.sid: // 公式类型 @@ -240,7 +254,7 @@ public class Excel03SaxReader extends AbstractExcelSaxReader i } else { value = StrUtil.wrap(HSSFFormulaParser.toFormulaString(stubWorkbook, formulaRec.getParsedExpression()), "\""); } - rowCellList.add(formulaRec.getColumn(), value); + addToRowCellList(formulaRec.getColumn(), value); break; case StringRecord.sid: // 单元格中公式的字符串 @@ -253,7 +267,7 @@ public class Excel03SaxReader extends AbstractExcelSaxReader i case LabelRecord.sid: final LabelRecord lrec = (LabelRecord) record; value = lrec.getValue(); - this.rowCellList.add(lrec.getColumn(), value); + addToRowCellList(lrec.getColumn(), value); break; case LabelSSTRecord.sid: // 字符串类型 @@ -261,7 +275,7 @@ public class Excel03SaxReader extends AbstractExcelSaxReader i if (null != sstRecord) { value = sstRecord.getString(lsrec.getSSTIndex()).toString(); } - rowCellList.add(lsrec.getColumn(), ObjectUtil.defaultIfNull(value, StrUtil.EMPTY)); + addToRowCellList(lsrec.getColumn(), ObjectUtil.defaultIfNull(value, StrUtil.EMPTY)); break; case NumberRecord.sid: // 数字类型 final NumberRecord numrec = (NumberRecord) record; @@ -283,7 +297,7 @@ public class Excel03SaxReader extends AbstractExcelSaxReader i } } // 向容器加入列值 - rowCellList.add(numrec.getColumn(), value); + addToRowCellList(numrec.getColumn(), value); break; default: break; diff --git a/hutool-poi/src/test/java/cn/hutool/poi/excel/test/ExcelSaxReadTest.java b/hutool-poi/src/test/java/cn/hutool/poi/excel/test/ExcelSaxReadTest.java index e0c2b5c7b..2a293a62b 100644 --- a/hutool-poi/src/test/java/cn/hutool/poi/excel/test/ExcelSaxReadTest.java +++ b/hutool-poi/src/test/java/cn/hutool/poi/excel/test/ExcelSaxReadTest.java @@ -19,6 +19,20 @@ import org.junit.Test; */ public class ExcelSaxReadTest { + @Test + public void excel07Test() { + // 工具化快速读取 + ExcelUtil.read07BySax("aaa.xlsx", 0, createRowHandler()); + } + + @Test + public void excel03Test() { + Excel03SaxReader reader = new Excel03SaxReader(createRowHandler()); + reader.read("aaa.xls", 1); + // Console.log("Sheet index: [{}], Sheet name: [{}]", reader.getSheetIndex(), reader.getSheetName()); + ExcelUtil.read03BySax("aaa.xls", 1, createRowHandler()); + } + @Test @Ignore public void readBlankLineTest() { @@ -47,26 +61,12 @@ public class ExcelSaxReadTest { ExcelUtil.readBySax("e:/excel/writeMapTest.xlsx", 0, (sheetIndex, rowIndex, rowList) -> Console.log(rowList)); } - @Test - public void excel07Test() { - // 工具化快速读取 - ExcelUtil.read07BySax("aaa.xlsx", 0, createRowHandler()); - } - - @Test - public void excel03Test() { - Excel03SaxReader reader = new Excel03SaxReader(createRowHandler()); - reader.read("aaa.xls", 1); - // Console.log("Sheet index: [{}], Sheet name: [{}]", reader.getSheetIndex(), reader.getSheetName()); - ExcelUtil.read03BySax("aaa.xls", 1, createRowHandler()); - } - @Test @Ignore public void readBySaxTest4() { ExcelUtil.readBySax("e:/excel/single_line.xlsx", 2, createRowHandler()); } - + @Test @Ignore public void readBySaxTest5() { @@ -79,6 +79,11 @@ public class ExcelSaxReadTest { ExcelUtil.readBySax("f:\\test\\sax_test.xlsx", 0, createRowHandler()); } + @Test + public void readBySaxTest7() { + ExcelUtil.readBySax("d:/test/行政许可信息.xls", 0, (sheetIndex, rowIndex, rowList) -> Console.log(rowList)); + } + private RowHandler createRowHandler() { return (sheetIndex, rowIndex, rowlist) -> { // Console.log("[{}] [{}] {}", sheetIndex, rowIndex, rowlist);