no message
parent
62efd8ff9a
commit
140cfa1b5b
|
|
@ -0,0 +1,115 @@
|
||||||
|
package com.youchain.utils;
|
||||||
|
|
||||||
|
import cn.idev.excel.context.AnalysisContext;
|
||||||
|
import cn.idev.excel.read.listener.ReadListener;
|
||||||
|
import com.youchain.exception.BadRequestException;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public class FastExcelCellListener implements ReadListener<Map<Integer, String>> {
|
||||||
|
private final Map<CellPosition, String> cellValues = new ConcurrentHashMap<>();
|
||||||
|
private final Set<CellPosition> targetCells = new HashSet<>();
|
||||||
|
private volatile boolean allCellsRead = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加目标单元格
|
||||||
|
*
|
||||||
|
* @param row 行索引(从1开始,Excel格式)
|
||||||
|
* @param col 列索引(从1开始,Excel格式)
|
||||||
|
* @return 当前监听器实例,支持链式调用
|
||||||
|
*/
|
||||||
|
public FastExcelCellListener addTargetCell(int row, int col) {
|
||||||
|
if (row < 1 || col < 1) {
|
||||||
|
throw new BadRequestException("行列索引必须从1开始");
|
||||||
|
}
|
||||||
|
targetCells.add(new CellPosition(row, col));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invoke(Map<Integer, String> rowData, AnalysisContext context) {
|
||||||
|
// 如果所有目标单元格已读取完毕,直接返回
|
||||||
|
if (allCellsRead) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// EasyExcel 的行索引从0开始,转换为Excel格式(从1开始)
|
||||||
|
int currentRowIndex = context.readRowHolder().getRowIndex() + 1;
|
||||||
|
|
||||||
|
// 检查当前行是否包含目标单元格
|
||||||
|
for (CellPosition targetCell : targetCells) {
|
||||||
|
if (currentRowIndex == targetCell.row) {
|
||||||
|
// 列索引需要减1转换为0-based
|
||||||
|
String cellValue = rowData.get(targetCell.col - 1);
|
||||||
|
if (cellValue != null) {
|
||||||
|
cellValues.put(targetCell, cellValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否所有目标单元格都已读取
|
||||||
|
if (cellValues.size() == targetCells.size()) {
|
||||||
|
allCellsRead = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
|
||||||
|
// 可根据需要添加逻辑
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定单元格的值
|
||||||
|
*
|
||||||
|
* @param row 行索引(从1开始,Excel格式)
|
||||||
|
* @param col 列索引(从1开始,Excel格式)
|
||||||
|
* @return 单元格值,如果不存在返回null
|
||||||
|
*/
|
||||||
|
public String getCellValue(int row, int col) {
|
||||||
|
return cellValues.get(new CellPosition(row, col));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有单元格值(字符串格式的key)
|
||||||
|
*
|
||||||
|
* @return 所有单元格值的Map,key为"row-col"格式
|
||||||
|
*/
|
||||||
|
public Map<String, String> getAllCellValues() {
|
||||||
|
Map<String, String> result = new HashMap<>();
|
||||||
|
cellValues.forEach((pos, value) ->
|
||||||
|
result.put(pos.row + "-" + pos.col, value));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单元格位置封装类
|
||||||
|
*/
|
||||||
|
public static class CellPosition {
|
||||||
|
private final int row;
|
||||||
|
private final int col;
|
||||||
|
|
||||||
|
public CellPosition(int row, int col) {
|
||||||
|
this.row = row;
|
||||||
|
this.col = col;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
CellPosition that = (CellPosition) o;
|
||||||
|
return row == that.row && col == that.col;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(row, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "(" + row + "," + col + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,167 @@
|
||||||
|
package com.youchain.utils;
|
||||||
|
|
||||||
|
import cn.idev.excel.FastExcel;
|
||||||
|
import cn.idev.excel.write.metadata.style.WriteCellStyle;
|
||||||
|
import cn.idev.excel.write.metadata.style.WriteFont;
|
||||||
|
import cn.idev.excel.write.style.HorizontalCellStyleStrategy;
|
||||||
|
import com.youchain.exception.BadRequestException;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.poi.ss.usermodel.IndexedColors;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.MediaTypeFactory;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static cn.hutool.core.util.CharsetUtil.UTF_8;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class FastExcelUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置下载文件消息头
|
||||||
|
*
|
||||||
|
* @param response 响应
|
||||||
|
* @param fileName 文件名
|
||||||
|
* @param fileSize 文件大小
|
||||||
|
*/
|
||||||
|
public static void setDownloadFileHeader(HttpServletResponse response, String fileName, Long fileSize) {
|
||||||
|
response.setCharacterEncoding(UTF_8);
|
||||||
|
if (fileSize != null) {
|
||||||
|
response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(fileSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringUtils.isNotEmpty(fileName)) {
|
||||||
|
response.setHeader(HttpHeaders.CONTENT_TYPE, MediaTypeFactory.getMediaType(fileName).orElse(MediaType.APPLICATION_OCTET_STREAM) + ";charset=utf-8");
|
||||||
|
try {
|
||||||
|
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode(fileName, UTF_8).replaceAll("\\+", "%20"));
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
response.setHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, HttpHeaders.CONTENT_DISPOSITION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取样式
|
||||||
|
*
|
||||||
|
* @return horizontalCellStyleStrategy
|
||||||
|
*/
|
||||||
|
public static HorizontalCellStyleStrategy getHorizontalCellStyleStrategy() {
|
||||||
|
|
||||||
|
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
|
||||||
|
headWriteCellStyle.setFillForegroundColor(IndexedColors.SKY_BLUE.getIndex());
|
||||||
|
|
||||||
|
WriteFont headWriteFont = new WriteFont();
|
||||||
|
headWriteFont.setFontName("宋体");
|
||||||
|
headWriteFont.setColor(IndexedColors.WHITE.getIndex());
|
||||||
|
headWriteCellStyle.setWriteFont(headWriteFont);
|
||||||
|
|
||||||
|
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
|
||||||
|
contentWriteCellStyle.setFillForegroundColor(IndexedColors.BLACK.getIndex());
|
||||||
|
|
||||||
|
return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用单sheet导出
|
||||||
|
*/
|
||||||
|
public static void exportExcel(HttpServletResponse response, String fileName, String sheetName, Class head, Collection<?> data) throws IOException {
|
||||||
|
// 设置下载消息头
|
||||||
|
setDownloadFileHeader(response, fileName, null);
|
||||||
|
//样式
|
||||||
|
HorizontalCellStyleStrategy horizontalCellStyleStrategy = getHorizontalCellStyleStrategy();
|
||||||
|
// 下载
|
||||||
|
FastExcel.write(response.getOutputStream(), head)
|
||||||
|
.autoCloseStream(Boolean.FALSE)
|
||||||
|
.sheet(sheetName)
|
||||||
|
.registerWriteHandler(horizontalCellStyleStrategy)
|
||||||
|
.doWrite(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从 Excel 文件中读取指定类型的数据
|
||||||
|
*
|
||||||
|
* @param file 上传的 Excel 文件
|
||||||
|
* @param clazz 数据映射的类(如 Template1.class)
|
||||||
|
* @param <T> 数据类型
|
||||||
|
* @return 解析后的数据列表
|
||||||
|
*/
|
||||||
|
public static <T> List<T> readExcelData(MultipartFile file, Class<T> clazz, int sheetNo, int headRowNumber) {
|
||||||
|
List<T> dataList;
|
||||||
|
try {
|
||||||
|
dataList = FastExcel.read(file.getInputStream()).head(clazz)
|
||||||
|
.sheet(sheetNo)
|
||||||
|
.headRowNumber(headRowNumber)
|
||||||
|
.doReadSync();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new BadRequestException("数据格式存在问题,无法读取");
|
||||||
|
}
|
||||||
|
if (CollectionUtils.isEmpty(dataList)) {
|
||||||
|
throw new BadRequestException("数据为空");
|
||||||
|
}
|
||||||
|
return dataList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取Excel文件中指定位置的单元格值
|
||||||
|
*
|
||||||
|
* @param file Excel文件
|
||||||
|
* @param reader 指定行和列
|
||||||
|
*/
|
||||||
|
public static Map<String, String> readExcelCellValues(MultipartFile file, FastExcelCellListener reader) {
|
||||||
|
try {
|
||||||
|
FastExcel.read(file.getInputStream(), reader)
|
||||||
|
.sheet()
|
||||||
|
.doReadSync();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new BadRequestException("Excel文件读取失败,请检查文件格式是否正确");
|
||||||
|
}
|
||||||
|
return reader.getAllCellValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取 Excel 文件头部的所有内容(第一行)
|
||||||
|
*
|
||||||
|
* @param file Excel 文件
|
||||||
|
* @return 回返指定目录指定行返回的内容
|
||||||
|
*/
|
||||||
|
public static List<String> readHeadContent(MultipartFile file, int sheetNo, int headRowNumber) {
|
||||||
|
List<Object> data;
|
||||||
|
try {
|
||||||
|
data = FastExcel.read(file.getInputStream())
|
||||||
|
.sheet(sheetNo)
|
||||||
|
.headRowNumber(headRowNumber)
|
||||||
|
.doReadSync();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new BadRequestException("数据格式存在问题,无法读取");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否有数据
|
||||||
|
if (CollectionUtils.isEmpty(data)) {
|
||||||
|
throw new BadRequestException("数据为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
Object firstRow = data.get(0);
|
||||||
|
// 将头部内容转换为字符串列表
|
||||||
|
if (firstRow instanceof Map) {
|
||||||
|
Map<?, ?> rowMap = (Map<?, ?>) firstRow;
|
||||||
|
return rowMap.values().stream()
|
||||||
|
.map(value -> value == null ? "" : value.toString())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
} else {
|
||||||
|
throw new BadRequestException("读取Excel头部内容格式异常");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue