mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-05 17:37:59 +08:00
fix bugs
This commit is contained in:
parent
fc8dfc8fb1
commit
0553c5ca0b
@ -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)
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
@ -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相同
|
||||
|
@ -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<Runnable> 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 <T> Future<T> submit(Callable<T> task) {
|
||||
return e.submit(task);
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullableProblems")
|
||||
public <T> Future<T> submit(Runnable task, T result) {
|
||||
return e.submit(task, result);
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullableProblems")
|
||||
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException {
|
||||
return e.invokeAll(tasks);
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullableProblems")
|
||||
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
|
||||
throws InterruptedException {
|
||||
return e.invokeAll(tasks, timeout, unit);
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullableProblems")
|
||||
public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
|
||||
throws InterruptedException, ExecutionException {
|
||||
return e.invokeAny(tasks);
|
||||
}
|
||||
|
||||
public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
|
||||
throws InterruptedException, ExecutionException, TimeoutException {
|
||||
return e.invokeAny(tasks, timeout, unit);
|
||||
}
|
||||
}
|
@ -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<ThreadPoolExecutor> {
|
||||
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<Runnable> 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<ThreadPoolExecutor> {
|
||||
|
||||
/**
|
||||
* 设置最大池大小(允许同时执行的最大线程数)
|
||||
*
|
||||
*
|
||||
* @param maxPoolSize 最大池大小(允许同时执行的最大线程数)
|
||||
* @return this
|
||||
*/
|
||||
@ -60,9 +79,9 @@ public class ExecutorBuilder implements Builder<ThreadPoolExecutor> {
|
||||
|
||||
/**
|
||||
* 设置线程存活时间,即当池中线程多于初始大小时,多出的线程保留的时长
|
||||
*
|
||||
*
|
||||
* @param keepAliveTime 线程存活时间
|
||||
* @param unit 单位
|
||||
* @param unit 单位
|
||||
* @return this
|
||||
*/
|
||||
public ExecutorBuilder setKeepAliveTime(long keepAliveTime, TimeUnit unit) {
|
||||
@ -71,7 +90,7 @@ public class ExecutorBuilder implements Builder<ThreadPoolExecutor> {
|
||||
|
||||
/**
|
||||
* 设置线程存活时间,即当池中线程多于初始大小时,多出的线程保留的时长,单位纳秒
|
||||
*
|
||||
*
|
||||
* @param keepAliveTime 线程存活时间,单位纳秒
|
||||
* @return this
|
||||
*/
|
||||
@ -83,13 +102,14 @@ public class ExecutorBuilder implements Builder<ThreadPoolExecutor> {
|
||||
/**
|
||||
* 设置队列,用于存在未执行的线程<br>
|
||||
* 可选队列有:
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
* 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时会创建新线程,否则触发异常策略
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* @param workQueue 队列
|
||||
* @return this
|
||||
*/
|
||||
@ -98,10 +118,22 @@ public class ExecutorBuilder implements Builder<ThreadPoolExecutor> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用{@link ArrayBlockingQueue} 做为等待队列<br>
|
||||
* 有界队列,相对无界队列有利于控制队列大小,队列满时,运行线程小于maxPoolSize时会创建新线程,否则触发异常策略
|
||||
*
|
||||
* @param capacity 队列容量
|
||||
* @return this
|
||||
* @since 5.1.4
|
||||
*/
|
||||
public ExecutorBuilder useArrayBlockingQueue(int capacity) {
|
||||
return setWorkQueue(new ArrayBlockingQueue<>(capacity));
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用{@link SynchronousQueue} 做为等待队列(非公平策略)<br>
|
||||
* 它将任务直接提交给线程而不保持它们。当运行线程小于maxPoolSize时会创建新线程,否则触发异常策略
|
||||
*
|
||||
*
|
||||
* @return this
|
||||
* @since 4.1.11
|
||||
*/
|
||||
@ -112,7 +144,7 @@ public class ExecutorBuilder implements Builder<ThreadPoolExecutor> {
|
||||
/**
|
||||
* 使用{@link SynchronousQueue} 做为等待队列<br>
|
||||
* 它将任务直接提交给线程而不保持它们。当运行线程小于maxPoolSize时会创建新线程,否则触发异常策略
|
||||
*
|
||||
*
|
||||
* @param fair 是否使用公平访问策略
|
||||
* @return this
|
||||
* @since 4.5.0
|
||||
@ -123,7 +155,7 @@ public class ExecutorBuilder implements Builder<ThreadPoolExecutor> {
|
||||
|
||||
/**
|
||||
* 设置线程工厂,用于自定义线程创建
|
||||
*
|
||||
*
|
||||
* @param threadFactory 线程工厂
|
||||
* @return this
|
||||
* @see ThreadFactoryBuilder
|
||||
@ -137,7 +169,7 @@ public class ExecutorBuilder implements Builder<ThreadPoolExecutor> {
|
||||
* 设置当线程阻塞(block)时的异常处理器,所谓线程阻塞即线程池和等待队列已满,无法处理线程时采取的策略
|
||||
* <p>
|
||||
* 此处可以使用JDK预定义的几种策略,见{@link RejectPolicy}枚举
|
||||
*
|
||||
*
|
||||
* @param handler {@link RejectedExecutionHandler}
|
||||
* @return this
|
||||
* @see RejectPolicy
|
||||
@ -149,7 +181,7 @@ public class ExecutorBuilder implements Builder<ThreadPoolExecutor> {
|
||||
|
||||
/**
|
||||
* 设置线程执行超时后是否回收线程
|
||||
*
|
||||
*
|
||||
* @param allowCoreThreadTimeOut 线程执行超时后是否回收线程
|
||||
* @return this
|
||||
*/
|
||||
@ -160,7 +192,7 @@ public class ExecutorBuilder implements Builder<ThreadPoolExecutor> {
|
||||
|
||||
/**
|
||||
* 创建ExecutorBuilder,开始构建
|
||||
*
|
||||
*
|
||||
* @return {@link ExecutorBuilder}
|
||||
*/
|
||||
public static ExecutorBuilder create() {
|
||||
@ -175,9 +207,19 @@ public class ExecutorBuilder implements Builder<ThreadPoolExecutor> {
|
||||
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<ThreadPoolExecutor> {
|
||||
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());
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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<String>() {
|
||||
@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<String, Cookie> 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());
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.lang.Console;
|
||||
|
||||
public class FtpTest {
|
||||
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void cdTest() {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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读取<br>
|
||||
@ -194,7 +194,7 @@ public class Excel03SaxReader extends AbstractExcelSaxReader<Excel03SaxReader> 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<Excel03SaxReader> 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<Excel03SaxReader> 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<Excel03SaxReader> 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<Excel03SaxReader> 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<Excel03SaxReader> 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<Excel03SaxReader> i
|
||||
}
|
||||
}
|
||||
// 向容器加入列值
|
||||
rowCellList.add(numrec.getColumn(), value);
|
||||
addToRowCellList(numrec.getColumn(), value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user