mirror of
http://git.pig4cloud.com/pig/pigx.git
synced 2026-11-11 05:19:00 +08:00
✨ Introducing new features.添加Excel导入导出功能,基于alibaba的easyexcel
This commit is contained in:
1 parent
5d414fb8e6
commit
45d3718ed6
11 files changed
+824
-2
No files matched your search
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>pigx-common</artifactId>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<version>3.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>pigx-common-excel</artifactId>
|
||||
<description>pigx Excel导入导出工具,基于easyexcel</description>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>easyexcel</artifactId>
|
||||
<version>${easyexcel.version}</version>
|
||||
</dependency>
|
||||
<!--core 工具类-->
|
||||
<dependency>
|
||||
<groupId>com.pig4cloud</groupId>
|
||||
<artifactId>pigx-common-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.pig4cloud.common.excel.annotation;
|
||||
|
||||
import org.apache.poi.ss.usermodel.IndexedColors;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 单元格字体
|
||||
*
|
||||
* @author lishangbu
|
||||
* @date 2019-06-11
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface CellFontFormat {
|
||||
|
||||
String fontName() default "宋体";
|
||||
|
||||
short fontHeightInPoints() default 11;
|
||||
|
||||
IndexedColors fontColor() default IndexedColors.BLACK;
|
||||
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package com.pig4cloud.common.excel.annotation;
|
||||
|
||||
import org.apache.poi.ss.usermodel.BorderStyle;
|
||||
import org.apache.poi.ss.usermodel.HorizontalAlignment;
|
||||
import org.apache.poi.ss.usermodel.IndexedColors;
|
||||
import org.apache.poi.ss.usermodel.VerticalAlignment;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 单元格样式
|
||||
*
|
||||
* @author lishangbu
|
||||
* @date 2019-06-11
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface CellStyleFormat {
|
||||
|
||||
/**
|
||||
* 水平居中方式 默认居中
|
||||
* @see HorizontalAlignment
|
||||
*/
|
||||
HorizontalAlignment horizontalalignment() default HorizontalAlignment.CENTER;
|
||||
|
||||
/**
|
||||
*
|
||||
* 垂直居中方式 默认居中
|
||||
* @see VerticalAlignment
|
||||
*/
|
||||
VerticalAlignment verticalAlignment() default VerticalAlignment.CENTER;
|
||||
|
||||
|
||||
/**
|
||||
* 边框方式 默认无
|
||||
* @see BorderStyle
|
||||
*/
|
||||
BorderStyle borderStyle() default BorderStyle.NONE;
|
||||
|
||||
|
||||
/**
|
||||
* 边框颜色 默认白
|
||||
* @see IndexedColors
|
||||
*/
|
||||
IndexedColors borderColor() default IndexedColors.WHITE;
|
||||
|
||||
|
||||
/**
|
||||
* 字体设置
|
||||
* @see org.apache.poi.xssf.usermodel.XSSFFont
|
||||
* @see org.apache.poi.hssf.usermodel.HSSFFont
|
||||
*/
|
||||
CellFontFormat cellFont() default @CellFontFormat();
|
||||
|
||||
|
||||
/**
|
||||
* 背景颜色
|
||||
* @see IndexedColors
|
||||
*/
|
||||
IndexedColors fillBackgroundColor() default IndexedColors.WHITE;
|
||||
|
||||
|
||||
/**
|
||||
* 单元格是否换行
|
||||
*/
|
||||
boolean warpText() default false;
|
||||
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.pig4cloud.common.excel.exception;
|
||||
|
||||
/**
|
||||
* Excel异常类
|
||||
*
|
||||
* @author lishangbu
|
||||
* @date 2019-06-11
|
||||
*/
|
||||
public class ExcelException extends RuntimeException {
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message. The
|
||||
* cause is not initialized, and may subsequently be initialized by
|
||||
* a call to {@link #initCause}.
|
||||
*
|
||||
* @param message the detail message. The detail message is saved for
|
||||
* later retrieval by the {@link #getMessage()} method.
|
||||
*/
|
||||
public ExcelException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package com.pig4cloud.common.excel.factory;
|
||||
|
||||
import com.alibaba.excel.ExcelWriter;
|
||||
import com.alibaba.excel.metadata.BaseRowModel;
|
||||
import com.alibaba.excel.metadata.Sheet;
|
||||
import com.alibaba.excel.support.ExcelTypeEnum;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* excel工厂
|
||||
*
|
||||
* @author lishangbu
|
||||
* @date 2019-06-11
|
||||
*/
|
||||
public class ExcelWriterFactory extends ExcelWriter {
|
||||
private OutputStream outputStream;
|
||||
private int sheetNo = 1;
|
||||
|
||||
public ExcelWriterFactory(OutputStream outputStream, ExcelTypeEnum typeEnum) {
|
||||
super(outputStream, typeEnum);
|
||||
this.outputStream = outputStream;
|
||||
}
|
||||
|
||||
public ExcelWriterFactory write(List<? extends BaseRowModel> list, String sheetName,
|
||||
BaseRowModel object) {
|
||||
this.sheetNo++;
|
||||
try {
|
||||
Sheet sheet = new Sheet(sheetNo, 0, object.getClass());
|
||||
sheet.setSheetName(sheetName);
|
||||
this.write(list, sheet);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
try {
|
||||
outputStream.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
super.finish();
|
||||
try {
|
||||
outputStream.flush();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
//do something
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
outputStream.close();
|
||||
} catch (IOException e) {
|
||||
//do something
|
||||
}
|
||||
}
|
||||
}
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
package com.pig4cloud.common.excel.handler;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.alibaba.excel.event.WriteHandler;
|
||||
import com.alibaba.excel.metadata.BaseRowModel;
|
||||
import com.pig4cloud.common.excel.annotation.CellStyleFormat;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.xssf.usermodel.XSSFFont;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* excel写入预处理器,支持生成Excel2007版本样式
|
||||
* 参考 https://github.com/alibaba/easyexcel/issues/205
|
||||
*
|
||||
* @author lishangbu
|
||||
* @date 2019-06-12
|
||||
*/
|
||||
public class PreWriterHandler<T extends Class<? extends BaseRowModel>> implements WriteHandler {
|
||||
|
||||
private T rowModel;
|
||||
|
||||
private Map<Integer, CellStyleFormat> colStyleFormat = new HashMap<>();
|
||||
|
||||
private Map<Integer, CellStyle> colStyle = new HashMap<>();
|
||||
|
||||
private Map<String, String> infos = new HashMap<>();
|
||||
|
||||
public static final String TITLE_NUM = "title_num";
|
||||
|
||||
public PreWriterHandler(T rowModel) {
|
||||
this.rowModel = rowModel;
|
||||
init(rowModel);
|
||||
}
|
||||
|
||||
private void init(T rowModel) {
|
||||
Field[] declaredFields = rowModel.getDeclaredFields();
|
||||
//查找有CellStyle注解和ExcelProperty注解的Field加入cellStyle
|
||||
int titleNum = 0;
|
||||
for (Field field : declaredFields) {
|
||||
CellStyleFormat cellStyle = field.getAnnotation(CellStyleFormat.class);
|
||||
ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
|
||||
if (excelProperty != null) {
|
||||
titleNum =Math.max(excelProperty.value().length, titleNum);
|
||||
}
|
||||
if (cellStyle == null || excelProperty == null) {
|
||||
continue;
|
||||
}
|
||||
colStyleFormat.put(excelProperty.index(), cellStyle);
|
||||
|
||||
}
|
||||
infos.put(TITLE_NUM, String.valueOf(titleNum));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sheet(int sheetNo, Sheet sheet) {
|
||||
// 只初始化一次
|
||||
if (sheetNo == 1) {
|
||||
colStyle = colStyleFormat.entrySet().stream()
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, x -> {
|
||||
CellStyle cellStyle = sheet.getWorkbook().createCellStyle();
|
||||
CellStyleFormat value = x.getValue();
|
||||
//居中方式
|
||||
cellStyle.setVerticalAlignment(value.verticalAlignment());
|
||||
cellStyle.setAlignment(value.horizontalalignment());
|
||||
// 设置边框
|
||||
cellStyle.setBorderBottom(value.borderStyle());
|
||||
cellStyle.setBorderLeft(value.borderStyle());
|
||||
cellStyle.setBorderRight(value.borderStyle());
|
||||
cellStyle.setBorderTop(value.borderStyle());
|
||||
cellStyle.setBottomBorderColor(value.borderColor().getIndex());
|
||||
cellStyle.setLeftBorderColor(value.borderColor().getIndex());
|
||||
cellStyle.setRightBorderColor(value.borderColor().getIndex());
|
||||
cellStyle.setTopBorderColor(value.borderColor().getIndex());
|
||||
// 设置字体
|
||||
XSSFFont font = (XSSFFont) sheet.getWorkbook().createFont();
|
||||
font.setFontName(value.cellFont().fontName());
|
||||
font.setColor(value.cellFont().fontColor().getIndex());
|
||||
font.setFontHeightInPoints(value.cellFont().fontHeightInPoints());
|
||||
cellStyle.setFont(font);
|
||||
// 设置单元格是否换行
|
||||
cellStyle.setWrapText(value.warpText());
|
||||
// 背景颜色
|
||||
cellStyle.setFillBackgroundColor(value.fillBackgroundColor().getIndex());
|
||||
return cellStyle;
|
||||
},
|
||||
(u, v) -> v));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void row(int rowNum, Row row) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cell(int cellNum, Cell cell) {
|
||||
CellStyle cellStyle = colStyle.get(cellNum);
|
||||
// 表头不操作 行序号是从0开始的
|
||||
if (cell.getRowIndex() <= Integer.valueOf(infos.get(TITLE_NUM))-1) {
|
||||
return;
|
||||
}
|
||||
// 没有不操作
|
||||
if (cellStyle == null) {
|
||||
return;
|
||||
}
|
||||
//设置居中方式
|
||||
cell.setCellStyle(cellStyle);
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
package com.pig4cloud.common.excel.listener;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.alibaba.excel.context.AnalysisContext;
|
||||
import com.alibaba.excel.event.AnalysisEventListener;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Excel监听器
|
||||
* 可以根据需要,自定义处理获取到的数据
|
||||
*
|
||||
* @author lishangbu
|
||||
* @date 2019-06-11
|
||||
*/
|
||||
public class ExcelListener extends AnalysisEventListener {
|
||||
|
||||
/**
|
||||
* 自定义用于暂时存储data,可以通过实例获取该值
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
private List<Object> dataList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 通过 AnalysisContext 对象还可以获取当前 sheet,当前行等数据
|
||||
*/
|
||||
@Override
|
||||
public void invoke(Object object, AnalysisContext context) {
|
||||
// 数据存储到list,供批量处理,或后续自己业务逻辑处理。
|
||||
if (!checkObjAllFieldsIsNull(object)) {
|
||||
dataList.add(object);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAfterAllAnalysed(AnalysisContext context) {
|
||||
//do something
|
||||
}
|
||||
|
||||
private static final String SERIAL_VERSION_UID = "serialVersionUID";
|
||||
|
||||
/**
|
||||
* 判断对象中属性值是否全为空
|
||||
*
|
||||
* @param object
|
||||
* @return true为空false不为空
|
||||
*/
|
||||
private static boolean checkObjAllFieldsIsNull(Object object) {
|
||||
if (ObjectUtil.isNull(object)) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
for (Field f : object.getClass().getDeclaredFields()) {
|
||||
f.setAccessible(true);
|
||||
//只校验带ExcelProperty注解的属性
|
||||
ExcelProperty property = f.getAnnotation(ExcelProperty.class);
|
||||
if (ObjectUtil.isNull(property) || SERIAL_VERSION_UID.equals(f.getName())) {
|
||||
continue;
|
||||
}
|
||||
if (ObjectUtil.isNotNull(f.get(object)) && StrUtil.isNotBlank(f.get(object).toString())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
//do something
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
package com.pig4cloud.common.excel.util;
|
||||
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import org.springframework.beans.*;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* bean拷贝
|
||||
*
|
||||
* @author lishangbu
|
||||
* @date 2019-06-11
|
||||
*/
|
||||
public class BeanCopyUtils {
|
||||
|
||||
private final class DateToStringConverter implements Converter<LocalDateTime, String> {
|
||||
@Override
|
||||
public String convert(LocalDateTime source) {
|
||||
return source.format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN));
|
||||
}
|
||||
}
|
||||
private static Object convertForProperty(Wrapper wrapper, Object object, Object value, String propertyName)
|
||||
throws TypeMismatchException {
|
||||
Object result;
|
||||
if (wrapper == null) {
|
||||
result = null;
|
||||
} else {
|
||||
wrapper.setWrappedInstance(object);
|
||||
result = wrapper.getBeanWrapper().convertForProperty(value, propertyName);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Object copyProperties(Object source, Object target) throws BeansException {
|
||||
Wrapper wrapper = new BeanCopyUtils().new Wrapper(source);
|
||||
copyProperties(wrapper, source, target);
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the property values of the given source bean into the target bean.
|
||||
* <p>
|
||||
* Note: The source and target classes do not have to match or even be derived from each other, as long as the properties match. Any bean
|
||||
* properties that the source bean exposes but the target bean does not will silently be ignored.
|
||||
* <p>
|
||||
* This is just a convenience method. For more complex transfer needs, consider using a full BeanWrapper.
|
||||
*
|
||||
* @param source
|
||||
* the source bean
|
||||
* @param target
|
||||
* the target bean
|
||||
* @throws BeansException
|
||||
* if the copying failed
|
||||
*/
|
||||
private static void copyProperties(Wrapper wrapper, Object source, Object target) throws BeansException {
|
||||
Assert.notNull(source, "Source must not be null");
|
||||
Assert.notNull(target, "Target must not be null");
|
||||
|
||||
Class<?> actualEditable = target.getClass();
|
||||
PropertyDescriptor[] targetPds = BeanUtils.getPropertyDescriptors(actualEditable);
|
||||
|
||||
for (PropertyDescriptor targetPd : targetPds) {
|
||||
if (targetPd.getWriteMethod() != null) {
|
||||
PropertyDescriptor sourcePd = BeanUtils.getPropertyDescriptor(source.getClass(), targetPd.getName());
|
||||
if ( sourcePd.getReadMethod() != null) {
|
||||
try {
|
||||
Method readMethod = sourcePd.getReadMethod();
|
||||
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
|
||||
readMethod.setAccessible(true);
|
||||
}
|
||||
Object value = readMethod.invoke(source);
|
||||
// 判断是否类型不一致
|
||||
if (value != null && !(targetPd.getPropertyType().isInstance(value))) {
|
||||
// 数据转型
|
||||
value = convertForProperty(wrapper, target, value, targetPd.getName());
|
||||
}
|
||||
Method writeMethod = targetPd.getWriteMethod();
|
||||
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
|
||||
writeMethod.setAccessible(true);
|
||||
}
|
||||
writeMethod.invoke(target, value);
|
||||
} catch (Exception ex) {
|
||||
throw new FatalBeanException("Could not copy properties from source to target", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final class Wrapper {
|
||||
|
||||
private GenericConversionService conversion;
|
||||
private BeanWrapperImpl bean;
|
||||
|
||||
private Wrapper(Object object) {
|
||||
conversion = initDefaultConversionService();
|
||||
bean = initDefaultBeanWrapper(conversion, object);
|
||||
}
|
||||
|
||||
private void setWrappedInstance(Object object) {
|
||||
bean.setWrappedInstance(object);
|
||||
}
|
||||
|
||||
private GenericConversionService initDefaultConversionService() {
|
||||
GenericConversionService conversionService = new DefaultConversionService();
|
||||
conversionService.addConverter(new DateToStringConverter());
|
||||
return conversionService;
|
||||
}
|
||||
|
||||
private BeanWrapperImpl initDefaultBeanWrapper(@SuppressWarnings("hiding") ConversionService conversion,
|
||||
Object object) {
|
||||
BeanWrapperImpl beanWrapper = new BeanWrapperImpl(object);
|
||||
beanWrapper.setConversionService(conversion);
|
||||
return beanWrapper;
|
||||
}
|
||||
|
||||
private BeanWrapperImpl getBeanWrapper() {
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制源对象到目的对象
|
||||
*/
|
||||
private static void convert(Object source, Object target) {
|
||||
copyProperties(source, target);
|
||||
}
|
||||
|
||||
public static <T> List<T> convert(List<?> sources, Class<T> targetClass) {
|
||||
List<?> sourcesObj = sources;
|
||||
if (sourcesObj == null) {
|
||||
sourcesObj = Collections.emptyList();
|
||||
}
|
||||
List<T> targets = new ArrayList<>(sourcesObj.size());
|
||||
BeanCopyUtils.convert(sourcesObj, targets, targetClass);
|
||||
return targets;
|
||||
}
|
||||
|
||||
private static <T> void convert(List<?> sources, List<T> targets, Class<T> targetClass) {
|
||||
if (targets == null) {
|
||||
return;
|
||||
}
|
||||
targets.clear();
|
||||
if (sources == null) {
|
||||
return;
|
||||
}
|
||||
for (Object obj : sources) {
|
||||
try {
|
||||
T target = targetClass.newInstance();
|
||||
targets.add(target);
|
||||
convert(obj, target);
|
||||
} catch (Exception e) {
|
||||
//do something
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
package com.pig4cloud.common.excel.util;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.excel.EasyExcelFactory;
|
||||
import com.alibaba.excel.ExcelReader;
|
||||
import com.alibaba.excel.ExcelWriter;
|
||||
import com.alibaba.excel.metadata.BaseRowModel;
|
||||
import com.alibaba.excel.metadata.Sheet;
|
||||
import com.alibaba.excel.support.ExcelTypeEnum;
|
||||
import com.pig4cloud.common.excel.exception.ExcelException;
|
||||
import com.pig4cloud.common.excel.factory.ExcelWriterFactory;
|
||||
import com.pig4cloud.common.excel.handler.PreWriterHandler;
|
||||
import com.pig4cloud.common.excel.listener.ExcelListener;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Excel工具类
|
||||
*
|
||||
* @author lishangbu
|
||||
* @date 2019-06-11
|
||||
*/
|
||||
@Slf4j
|
||||
@UtilityClass
|
||||
public class ExcelUtils {
|
||||
|
||||
private final String DEFAULT_EXCEL_SHEET_NAME="Sheet1";
|
||||
|
||||
/**
|
||||
* 读取 Excel(多个 sheet)
|
||||
* 将多sheet合并成一个list数据集,通过自定义ExcelReader继承AnalysisEventListener
|
||||
* 重写invoke doAfterAllAnalysed方法
|
||||
* getExtendsBeanList 主要是做Bean的属性拷贝 ,可以通过ExcelReader中添加的数据集直接获取
|
||||
*
|
||||
* @param excel 文件
|
||||
* @param rowModel 实体类映射,继承 BaseRowModel 类
|
||||
* @return Excel 数据 list
|
||||
*/
|
||||
public <T extends BaseRowModel> List<T> readExcel(MultipartFile excel, Class<T> rowModel) {
|
||||
ExcelListener excelListener = new ExcelListener();
|
||||
ExcelReader reader = getReader(excel, excelListener);
|
||||
if (reader == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
for (Sheet sheet : reader.getSheets()) {
|
||||
sheet.setClazz(rowModel);
|
||||
reader.read(sheet);
|
||||
}
|
||||
return getExtendsBeanList(excelListener.getDataList(), rowModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取某个 sheet 的 Excel
|
||||
*
|
||||
* @param excel 文件
|
||||
* @param rowModel 实体类映射,继承 BaseRowModel 类
|
||||
* @param sheetNo sheet 的序号 从1开始
|
||||
* @return Excel 数据 list
|
||||
*/
|
||||
public <T extends BaseRowModel> List<T> readExcel(MultipartFile excel, Class<T> rowModel, int sheetNo) {
|
||||
return readExcel(excel, rowModel, sheetNo, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取某个 sheet 的 Excel
|
||||
*
|
||||
* @param excel 文件
|
||||
* @param rowModel 实体类映射,继承 BaseRowModel 类
|
||||
* @param sheetNo sheet 的序号 从1开始
|
||||
* @param headLineNum 表头行数,默认为1
|
||||
* @return Excel 数据 list
|
||||
*/
|
||||
public <T extends BaseRowModel> List<T> readExcel(MultipartFile excel, Class<T> rowModel, int sheetNo,
|
||||
int headLineNum) {
|
||||
ExcelListener excelListener = new ExcelListener();
|
||||
ExcelReader reader = getReader(excel, excelListener);
|
||||
if (reader == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
reader.read(new Sheet(sheetNo, headLineNum, rowModel));
|
||||
return getExtendsBeanList(excelListener.getDataList(), rowModel);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 导出 2007 Excel :一个 sheet,带表头,默认sheet名称
|
||||
*
|
||||
* @param response HttpServletResponse
|
||||
* @param list 数据 list,每个元素为一个 BaseRowModel
|
||||
* @param fileName 导出的文件名
|
||||
* @param classType 实体类映射,继承 BaseRowModel 类
|
||||
* @param <T>
|
||||
*/
|
||||
public <T extends BaseRowModel> void writeExcel(HttpServletResponse response, List<T> list,
|
||||
String fileName, Class<T> classType){
|
||||
writeExcel(response,list,fileName,null,classType);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 导出 2007 Excel :一个 sheet,带表头
|
||||
*
|
||||
* @param response HttpServletResponse
|
||||
* @param list 数据 list,每个元素为一个 BaseRowModel
|
||||
* @param fileName 导出的文件名
|
||||
* @param sheetName 导入文件的 sheet 名
|
||||
* @param classType 实体类映射,继承 BaseRowModel 类
|
||||
* @param <T>
|
||||
*/
|
||||
public <T extends BaseRowModel> void writeExcel(HttpServletResponse response, List<T> list,
|
||||
String fileName, String sheetName,
|
||||
Class<T> classType){
|
||||
writeExcel(response,list,fileName,sheetName,ExcelTypeEnum.XLSX,classType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出 Excel :一个 sheet,带表头
|
||||
* 自定义WriterHandler 可以定制行列数据进行灵活化操作
|
||||
*
|
||||
* @param response HttpServletResponse
|
||||
* @param list 数据 list,每个元素为一个 BaseRowModel
|
||||
* @param fileName 导出的文件名
|
||||
* @param sheetName 导入文件的 sheet 名
|
||||
* @param excelTypeEnum 导出Excel类型
|
||||
* @param classType 实体类映射,继承 BaseRowModel 类
|
||||
*
|
||||
*/
|
||||
public <T extends BaseRowModel> void writeExcel(HttpServletResponse response, List<T> list,
|
||||
String fileName, String sheetName, ExcelTypeEnum excelTypeEnum,
|
||||
Class<T> classType) {
|
||||
if (StrUtil.isBlank(sheetName)) {
|
||||
sheetName = DEFAULT_EXCEL_SHEET_NAME;
|
||||
}
|
||||
OutputStream outputStream =null;
|
||||
try {
|
||||
response.reset();
|
||||
outputStream = getOutputStream(fileName, response, excelTypeEnum);
|
||||
if (excelTypeEnum == ExcelTypeEnum.XLSX) {
|
||||
ExcelWriter writer = EasyExcelFactory.getWriterWithTempAndHandler(null, outputStream
|
||||
, excelTypeEnum, true, new PreWriterHandler<>(classType));
|
||||
Sheet sheet = new Sheet(1, 0, classType);
|
||||
sheet.setSheetName(sheetName);
|
||||
try {
|
||||
writer.write(list, sheet);
|
||||
} finally {
|
||||
writer.finish();
|
||||
}
|
||||
} else if (excelTypeEnum == ExcelTypeEnum.XLS) {
|
||||
// 其实也可以专门调03版的样式,或者直接套用
|
||||
ExcelWriterFactory writer = new ExcelWriterFactory(outputStream, excelTypeEnum);
|
||||
Sheet sheet = new Sheet(1, 0, classType);
|
||||
sheet.setSheetName(sheetName);
|
||||
try {
|
||||
writer.write(list, sheet);
|
||||
} finally {
|
||||
writer.finish();
|
||||
writer.close();
|
||||
}
|
||||
}
|
||||
outputStream.flush();
|
||||
}catch (IOException e){
|
||||
log.error("导出excel异常:{}",e);
|
||||
}finally {
|
||||
if(outputStream!=null){
|
||||
try {
|
||||
outputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出 Excel :多个 sheet,带表头
|
||||
*
|
||||
* @param response HttpServletResponse
|
||||
* @param list 数据 list,每个元素为一个 BaseRowModel
|
||||
* @param fileName 导出的文件名
|
||||
* @param sheetName 导入文件的 sheet 名
|
||||
* @param object 映射实体类,Excel 模型
|
||||
*/
|
||||
public ExcelWriterFactory writeExcelWithSheets(HttpServletResponse response, List<? extends BaseRowModel> list,
|
||||
String fileName, String sheetName, BaseRowModel object, ExcelTypeEnum excelTypeEnum) {
|
||||
ExcelWriterFactory writer = new ExcelWriterFactory(getOutputStream(fileName, response, excelTypeEnum), excelTypeEnum);
|
||||
Sheet sheet = new Sheet(1, 0, object.getClass());
|
||||
sheet.setSheetName(sheetName);
|
||||
writer.write(list, sheet);
|
||||
return writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出文件时为Writer生成OutputStream
|
||||
*/
|
||||
private OutputStream getOutputStream(String fileName, HttpServletResponse response, ExcelTypeEnum excelTypeEnum) {
|
||||
try {
|
||||
String encodeFilename = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString());
|
||||
response.setContentType(MediaType.MULTIPART_FORM_DATA_VALUE);
|
||||
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
|
||||
response.setHeader("Content-disposition", "attachment;filename="+ encodeFilename+excelTypeEnum.getValue());
|
||||
return response.getOutputStream();
|
||||
} catch (IOException e) {
|
||||
throw new ExcelException("创建文件失败!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回 ExcelReader
|
||||
*
|
||||
* @param excel 需要解析的 Excel 文件
|
||||
* @param excelListener new ExcelListener()
|
||||
*/
|
||||
private ExcelReader getReader(MultipartFile excel,
|
||||
ExcelListener excelListener) {
|
||||
String fileName = excel.getOriginalFilename();
|
||||
if (fileName == null) {
|
||||
throw new ExcelException("文件格式错误!");
|
||||
}
|
||||
if (!fileName.toLowerCase().endsWith(ExcelTypeEnum.XLS.getValue()) && !fileName.toLowerCase().endsWith(ExcelTypeEnum.XLSX.getValue())) {
|
||||
throw new ExcelException("文件格式错误!");
|
||||
}
|
||||
InputStream inputStream;
|
||||
try {
|
||||
inputStream = excel.getInputStream();
|
||||
return new ExcelReader(inputStream, null, excelListener, false);
|
||||
} catch (IOException e) {
|
||||
//do something
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 利用BeanCopy转换list
|
||||
*/
|
||||
private <T extends BaseRowModel> List<T> getExtendsBeanList(List<?> list, Class<T> typeClazz) {
|
||||
return BeanCopyUtils.convert(list, typeClazz);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -36,14 +36,15 @@
|
||||
<module>pigx-common-bom</module>
|
||||
<module>pigx-common-core</module>
|
||||
<module>pigx-common-data</module>
|
||||
<module>pigx-common-datasource</module>
|
||||
<module>pigx-common-excel</module>
|
||||
<module>pigx-common-gateway</module>
|
||||
<module>pigx-common-job</module>
|
||||
<module>pigx-common-log</module>
|
||||
<module>pigx-common-minio</module>
|
||||
<module>pigx-common-security</module>
|
||||
<module>pigx-common-swagger</module>
|
||||
<module>pigx-common-sequence</module>
|
||||
<module>pigx-common-swagger</module>
|
||||
<module>pigx-common-transaction</module>
|
||||
<module>pigx-common-datasource</module>
|
||||
</modules>
|
||||
</project>
|
||||
@@ -49,6 +49,7 @@
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<spring-boot-admin.version>2.1.5</spring-boot-admin.version>
|
||||
<easyexcel.version>1.1.2-beta5</easyexcel.version>
|
||||
<hutool.version>4.5.10</hutool.version>
|
||||
<kaptcha.version>0.0.9</kaptcha.version>
|
||||
<swagger.fox.version>2.9.2</swagger.fox.version>
|
||||
|
||||
Reference in new issue
Block a user