You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
283 lines
9.5 KiB
Java
283 lines
9.5 KiB
Java
package cn.jlw.util.excel;
|
|
|
|
import cn.hutool.core.map.MapUtil;
|
|
import cn.hutool.core.util.ArrayUtil;
|
|
import cn.hutool.core.util.StrUtil;
|
|
import com.alibaba.excel.EasyExcel;
|
|
import com.alibaba.excel.ExcelReader;
|
|
import com.alibaba.excel.annotation.ExcelProperty;
|
|
import com.alibaba.excel.read.listener.ReadListener;
|
|
import com.alibaba.excel.read.metadata.ReadSheet;
|
|
import com.alibaba.excel.support.ExcelTypeEnum;
|
|
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
|
|
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
|
|
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
|
|
import com.ibeetl.admin.core.util.FreezeAndFilter;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import org.apache.poi.ss.usermodel.HorizontalAlignment;
|
|
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.lang.reflect.Field;
|
|
import java.net.URLEncoder;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
@Slf4j
|
|
public class ExcelUtil {
|
|
|
|
/**
|
|
* 默认的sheet名称
|
|
*/
|
|
private static final String DEFAULT_SHEET_NAME = "Sheet1";
|
|
|
|
/**
|
|
* 写Excel数据
|
|
*
|
|
* @param response response
|
|
* @param fileName 文件名称
|
|
* @param data 数据
|
|
* @param clazz 类class
|
|
* @author mlx
|
|
*/
|
|
public static <T> void writeExcel(HttpServletResponse response, String fileName, List<T> data, Class<?> clazz) {
|
|
writeExcel(response, fileName, DEFAULT_SHEET_NAME, data, clazz);
|
|
}
|
|
|
|
/**
|
|
* 写Excel数据
|
|
*
|
|
* @param response response
|
|
* @param fileName 文件名称
|
|
* @param sheetName sheet名称
|
|
* @param data 数据
|
|
* @param clazz 类class
|
|
* @author mlx
|
|
*/
|
|
public static <T> void writeExcel(HttpServletResponse response, String fileName, String sheetName, List<T> data, Class<?> clazz) {
|
|
OutputStream outputStream = null;
|
|
Map<Integer, ExcelSelectorResolve> selectedMap = getSelectedMap(clazz);
|
|
ExcelSelectorDataWriteHandler writeHandler = new ExcelSelectorDataWriteHandler(selectedMap);
|
|
try {
|
|
outputStream = getOutputStream(response, fileName, ExcelTypeEnum.XLSX);
|
|
EasyExcel.write(outputStream, clazz).excelType(ExcelTypeEnum.XLSX).sheet(sheetName)
|
|
.registerWriteHandler(writeHandler)
|
|
.registerWriteHandler(new FreezeAndFilter())
|
|
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 基于 column 长度,自动适配。最大 255 宽度
|
|
.doWrite(data);
|
|
} catch (Exception e) {
|
|
log.error(e.getMessage(), e);
|
|
} finally {
|
|
if (outputStream != null) {
|
|
try {
|
|
outputStream.close();
|
|
} catch (IOException e) {
|
|
log.error(e.getMessage(), e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 读取不包含头信息的Excel
|
|
*
|
|
* @param file 文件
|
|
* @param clazz 类class
|
|
* @author mlx
|
|
*/
|
|
public static <T> List<T> readExcelNotContainHeader(MultipartFile file, Class<T> clazz) throws IOException {
|
|
return readExcel(1, file, clazz);
|
|
}
|
|
|
|
/**
|
|
* 读取包含头信息的Excel
|
|
*
|
|
* @param file 文件
|
|
* @param clazz 类class
|
|
* @author mlx
|
|
*/
|
|
public static <T> List<T> readExcelContainHeader(MultipartFile file, Class<T> clazz) throws IOException {
|
|
return readExcel(0, file, clazz);
|
|
}
|
|
|
|
/**
|
|
* 读取Excel
|
|
*
|
|
* @param rowNum 行数
|
|
* @param file 文件
|
|
* @param clazz 类class
|
|
* @author mlx
|
|
*/
|
|
public static <T> List<T> readExcel(int rowNum, MultipartFile file, Class<T> clazz) throws IOException {
|
|
String fileName = file.getOriginalFilename();
|
|
InputStream inputStream = file.getInputStream();
|
|
return readExcel(rowNum, fileName, inputStream, clazz);
|
|
}
|
|
|
|
/**
|
|
* 读取不包含头信息的Excel
|
|
*
|
|
* @param fileName 文件名称
|
|
* @param inputStream 流
|
|
* @param clazz 类
|
|
* @author mlx
|
|
*/
|
|
public static <T> List<T> readExcelNotContainHeader(String fileName, InputStream inputStream, Class<T> clazz) {
|
|
return readExcel(1, fileName, inputStream, clazz);
|
|
}
|
|
|
|
/**
|
|
* 读取包含头信息的Excel
|
|
*
|
|
* @param fileName 文件名称
|
|
* @param inputStream 流
|
|
* @param clazz 类
|
|
* @param listener 监听
|
|
* @author mlx
|
|
*/
|
|
public static <T> List<T> readExcelContainHeader(String fileName, InputStream inputStream, Class<T> clazz, ExcelCellDataListener<T> listener) {
|
|
return readExcel(0, fileName, inputStream, clazz);
|
|
}
|
|
|
|
/**
|
|
* 读取Excel
|
|
*
|
|
* @param rowNum 行数
|
|
* @param fileName 文件名称
|
|
* @param inputStream 流
|
|
* @param clazz 类
|
|
* @author mlx
|
|
*/
|
|
public static <T> List<T> readExcel(int rowNum, String fileName, InputStream inputStream, Class<T> clazz) {
|
|
ExcelCellDataListener<T> dataListener = new ExcelCellDataListener<>();
|
|
try {
|
|
ExcelReader excelReader = getExcelReader(rowNum, fileName, inputStream, clazz, dataListener);
|
|
if (excelReader == null) {
|
|
return null;
|
|
}
|
|
List<ReadSheet> sheetList = excelReader.excelExecutor().sheetList();
|
|
for (ReadSheet sheet : sheetList) {
|
|
excelReader.read(sheet);
|
|
}
|
|
excelReader.finish();
|
|
} finally {
|
|
try {
|
|
inputStream.close();
|
|
} catch (IOException e) {
|
|
log.error(e.getMessage(), e);
|
|
}
|
|
}
|
|
return dataListener.getData();
|
|
}
|
|
|
|
/**
|
|
* 获取OutputStream
|
|
*
|
|
* @param response response
|
|
* @param fileName 文件名称
|
|
* @return java.io.OutputStream
|
|
* @author mlx
|
|
*/
|
|
private static OutputStream getOutputStream(HttpServletResponse response, String fileName, ExcelTypeEnum typeEnum) throws Exception {
|
|
fileName = URLEncoder.encode(fileName, "UTF-8");
|
|
response.setStatus(200);
|
|
response.setCharacterEncoding("UTF-8");
|
|
if (ExcelTypeEnum.CSV.equals(typeEnum)) {
|
|
response.setContentType("application/csv");
|
|
} else {
|
|
response.setContentType("application/vnd.ms-excel");
|
|
}
|
|
response.setHeader("Content-Disposition", "attachment;filename=" + fileName + typeEnum.getValue());
|
|
return response.getOutputStream();
|
|
}
|
|
|
|
/**
|
|
* 获取ExcelReader
|
|
*
|
|
* @param rowNum 行数
|
|
* @param fileName 文件名称
|
|
* @param inputStream 流
|
|
* @param clazz 类class
|
|
* @param listener 监听
|
|
* @return com.alibaba.excel.ExcelReader
|
|
* @author mlx
|
|
*/
|
|
private static ExcelReader getExcelReader(int rowNum, String fileName, InputStream inputStream, Class<?> clazz, ReadListener listener) {
|
|
if (StrUtil.isBlank(fileName)) {
|
|
return null;
|
|
}
|
|
String fileExtName = getFileExtName(fileName);
|
|
EasyExcelTypeEnum typeEnum = EasyExcelTypeEnum.parseType(fileExtName);
|
|
if (typeEnum == null) {
|
|
log.info("表格类型错误");
|
|
}
|
|
|
|
return EasyExcel.read(inputStream, clazz, listener).headRowNumber(rowNum).build();
|
|
}
|
|
|
|
/**
|
|
* 获取文件后缀名称 .xxx
|
|
*
|
|
* @param fileName 文件名称
|
|
* @return java.lang.String
|
|
* @author mlx
|
|
*/
|
|
private static String getFileExtName(String fileName) {
|
|
if (StrUtil.isBlank(fileName)) {
|
|
return null;
|
|
}
|
|
int lastIndex = fileName.lastIndexOf(StrUtil.DOT);
|
|
if (lastIndex != -1) {
|
|
return fileName.substring(lastIndex);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* 获取样式
|
|
*
|
|
* @return com.alibaba.excel.write.style.HorizontalCellStyleStrategy
|
|
* @author mlx
|
|
*/
|
|
private static HorizontalCellStyleStrategy getStyleStrategy() {
|
|
// 表头样式
|
|
WriteCellStyle headStyle = new WriteCellStyle();
|
|
// 设置表头居中对齐
|
|
headStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
|
|
// 内容样式
|
|
WriteCellStyle contentStyle = new WriteCellStyle();
|
|
// 设置内容靠左对齐
|
|
contentStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
|
|
return new HorizontalCellStyleStrategy(headStyle, contentStyle);
|
|
}
|
|
|
|
/**
|
|
* 获取下拉的map
|
|
*
|
|
* @param clazz 类class
|
|
* @return java.util.Map<java.lang.Integer, cn.com.zxelec.common.resolve.ExcelSelectorResolve>
|
|
* @author mlx
|
|
*/
|
|
private static Map<Integer, ExcelSelectorResolve> getSelectedMap(Class<?> clazz) {
|
|
Map<Integer, ExcelSelectorResolve> selectedMap = MapUtil.newHashMap();
|
|
Field[] fields = clazz.getDeclaredFields();
|
|
for (Field field : fields) {
|
|
if (!field.isAnnotationPresent(ExcelSelector.class) || !field.isAnnotationPresent(ExcelProperty.class)) {
|
|
continue;
|
|
}
|
|
ExcelSelector excelSelector = field.getAnnotation(ExcelSelector.class);
|
|
ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
|
|
ExcelSelectorResolve resolve = new ExcelSelectorResolve();
|
|
String[] data = resolve.resolveExcelSelector(excelSelector);
|
|
if (ArrayUtil.isNotEmpty(data)) {
|
|
resolve.setSelectorData(data);
|
|
selectedMap.put(excelProperty.index(), resolve);
|
|
}
|
|
}
|
|
return selectedMap;
|
|
}
|
|
}
|