本文仅针对文字相关的合并做了处理 ,图片合并及保存需要另做处理!!
目标:Excel合并行内容的导入

结果:

1. ExcelUtil.java 类,新增方法:判断是否是合并行
/**
* 新增 合并行相关代码:判断是否是合并行
*
* @param sheet
* @param row
* @param column
* @return
*/
private boolean isMergedRow(Sheet sheet, int row, int column) {
int sheetMergeCount = sheet.getNumMergedRegions();//当前表格(sheet)中,所有合单元格总数
//遍历所有合并单元格
for (int i = 0; i < sheetMergeCount; i++) {
CellRangeAddress cellAddresses = sheet.getMergedRegion(i);//当前合并单元格对象
int firstColumn = cellAddresses.getFirstColumn();//当前合并单元格的首列
int lastColumn = cellAddresses.getLastColumn();//当前合并单元格的末列
int firstRow = cellAddresses.getFirstRow();//当前合并单元格的首行
int lastRow = cellAddresses.getLastRow();//当前合并单元格的末行
//指定的行 包含在合并单元格中
if (row >= firstRow && row <= lastRow) {
//指定的列 包含在合并单元格中
if (column >= firstColumn && column <= lastColumn) {
return true;
}
}
}
return false;
}
2. ExcelUtil.java 类,新增方法:获取合并行单元格数据
思路:
POI对于Excel的处理:合并行中 只有首列能获取到值 非首列的其他列数据默认是空。由于是合并行,则可以认为 合并行内所有列的数据 都与合并行的首列数据相同。
所以,以下代码中,判断该列如果包含在合并行内,则该列值默认赋值为 所在合并行的首列值。
图1 Excel中的2/3/4行内的合并行内容相同:

POI对Excel处理时,默认获取到的值大概如图2:下面代码则在图2逻辑上 对3/4行的空内容做赋值操作

/**
* 新增 合并行相关代码:获取合并行的数据
*
* @param sheet
* @param row
* @param column
* @return
*/
private String getMergedRegionValue(Sheet sheet, int row, int column) {
// 获得该sheet所有合并单元格数量
int sheetMergeCount = sheet.getNumMergedRegions();
for (int i = 0; i < sheetMergeCount; i++) {
// 获得合并区域
CellRangeAddress cellAddresses = sheet.getMergedRegion(i);
int firstColumn = cellAddresses.getFirstColumn();
int lastColumn = cellAddresses.getLastColumn();
int firstRow = cellAddresses.getFirstRow();
int lastRow = cellAddresses.getLastRow();
/*判断传入的单元格的行号列号是否在合并单元格的范围内,
如果在合并单元格的范围内,择返回合并区域的首单元格格值
*/
if (row >= firstRow && row <= lastRow) {
if (column >= firstColumn && column <= lastColumn) {
Row firRow = sheet.getRow(firstRow);
/* 合并行使用的获取单元格内容方法
Cell firCell = firRow.getCell(firstColumn);
return getCellValue(firCell);
*/
return getCellValue(firRow, firstColumn).toString();//改为使用 若依自带获取单元格内容方法
}
}
}
// 如果该单元格行号列号不在任何一个合并区域,则返回null
return null;
}
3. ExcelUtil.java的importExcel()方法中 遍历行内所有单元格内容下,新增: 合并行的判断 和 其内单元格内容获取

// ============== 新增 合并行相关代码块 ================
// 判断是否合并行 isMergedRow(sheet, rowNum, column):是合并行,则获取合并行数据 重新赋值给当前列
if (isMergedRow(sheet, i, entry.getKey())) val = getMergedRegionValue(sheet, i, entry.getKey());
// ============== 新增 合并行相关代码块 ================
importExcel()方法完整代码
/**
* 对excel表单指定表格索引名转换成list
*
* @param sheetName 表格索引名
* @param titleNum 标题占用行数
* @param is 输入流
* @return 转换后集合
*/
public List<T> importExcel(String sheetName, InputStream is, int titleNum) throws Exception
{
this.type = Type.IMPORT;
this.wb = WorkbookFactory.create(is);
List<T> list = new ArrayList<T>();
// 如果指定sheet名,则取指定sheet中的内容 否则默认指向第1个sheet
Sheet sheet = StringUtils.isNotEmpty(sheetName) ? wb.getSheet(sheetName) : wb.getSheetAt(0);
if (sheet == null)
{
throw new IOException("文件sheet不存在");
}
boolean isXSSFWorkbook = !(wb instanceof HSSFWorkbook);
//获取文档指定sheet中所有图片:图片位置、文件流
Map<String, PictureData> pictures;
if (isXSSFWorkbook)
{
pictures = getSheetPictures07((XSSFSheet) sheet, (XSSFWorkbook) wb);
}
else
{
pictures = getSheetPictures03((HSSFSheet) sheet, (HSSFWorkbook) wb);
}
// 获取最后一个非空行的行下标,比如总行数为n,则返回的为n-1
int rows = sheet.getLastRowNum();
if (rows > 0)
{
// 定义一个map用于存放excel列的序号和field.
Map<String, Integer> cellMap = new HashMap<String, Integer>();
// 获取表头
Row heard = sheet.getRow(titleNum);
for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++)
{
Cell cell = heard.getCell(i);
if (StringUtils.isNotNull(cell))
{
String value = this.getCellValue(heard, i).toString();
cellMap.put(value, i);
}
else
{
cellMap.put(null, i);
}
}
// 有数据时才处理 得到类的所有field.
List<Object[]> fields = this.getFields();
Map<Integer, Object[]> fieldsMap = new HashMap<Integer, Object[]>();
for (Object[] objects : fields)
{
Excel attr = (Excel) objects[1];
Integer column = cellMap.get(attr.name());
if (column != null)
{
fieldsMap.put(column, objects);
}
}
//遍历每一行
for (int i = titleNum + 1; i <= rows; i++)
{
// 从第2行开始取数据,默认第一行是表头.
Row row = sheet.getRow(i);
// 判断当前行是否是空行
if (isRowEmpty(row))
{
continue;
}
T entity = null;
//遍历当前行所有列 逐列字段值获取并赋值给entity对象的各属性
for (Map.Entry<Integer, Object[]> entry : fieldsMap.entrySet())
{
Object val = this.getCellValue(row, entry.getKey());//获取当前列 默认值
// ============== 新增 合并行相关代码块 ================
// 判断是否合并行 isMergedRow(sheet, rowNum, column):是合并行,则获取合并行首列数据 重新赋值给当前列
if (isMergedRow(sheet, i, entry.getKey())) val = getMergedRegionValue(sheet, i, entry.getKey());
// ============== 新增 合并行相关代码块 ================
// 如果不存在实例则新建.
entity = (entity == null ? clazz.newInstance() : entity);
// 从map中得到对应列的field.
Field field = (Field) entry.getValue()[0];
Excel attr = (Excel) entry.getValue()[1];
// 取得类型,并根据对象类型设置值.
Class<?> fieldType = field.getType();
if (String.class == fieldType)
{
String s = Convert.toStr(val);
if (StringUtils.endsWith(s, ".0"))
{
val = StringUtils.substringBefore(s, ".0");
}
else
{
String dateFormat = field.getAnnotation(Excel.class).dateFormat();
if (StringUtils.isNotEmpty(dateFormat))
{
val = parseDateToStr(dateFormat, val);
}
else
{
val = Convert.toStr(val);
}
}
}
else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val)))
{
val = Convert.toInt(val);
}
else if ((Long.TYPE == fieldType || Long.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val)))
{
val = Convert.toLong(val);
}
else if (Double.TYPE == fieldType || Double.class == fieldType)
{
val = Convert.toDouble(val);
}
else if (Float.TYPE == fieldType || Float.class == fieldType)
{
val = Convert.toFloat(val);
}
else if (BigDecimal.class == fieldType)
{
val = Convert.toBigDecimal(val);
}
else if (Date.class == fieldType)
{
if (val instanceof String)
{
val = DateUtils.parseDate(val);
}
else if (val instanceof Double)
{
val = DateUtil.getJavaDate((Double) val);
}
}
else if (Boolean.TYPE == fieldType || Boolean.class == fieldType)
{
val = Convert.toBool(val, false);
}
if (StringUtils.isNotNull(fieldType))
{
String propertyName = field.getName();
if (StringUtils.isNotEmpty(attr.targetAttr()))
{
propertyName = field.getName() + "." + attr.targetAttr();
}
if (StringUtils.isNotEmpty(attr.readConverterExp()))
{
val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator());
}
else if (StringUtils.isNotEmpty(attr.dictType()))
{
val = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator());
}
else if (!attr.handler().equals(ExcelHandlerAdapter.class))
{
val = dataFormatHandlerAdapter(val, attr, null);
}
else if (ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures))
{
//获取指定行指定列中的图片文件:从获取的文件集合中获取
PictureData image = pictures.get(row.getRowNum() + "_" + entry.getKey());
if (image == null)
{
val = "";
}
else
{
byte[] data = image.getData();
val = FileUtils.writeImportBytes(data);//图片文件写入到 application.yml文件 ruoyi.profile属性对应的文件目录下
}
}
ReflectUtils.invokeSetter(entity, propertyName, val);
}
}
list.add(entity);
}
}
return list;
}
最终,工具类 ExcelUtil.java:
package com.ruoyi.common.utils.poi;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.RegExUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFPicture;
import org.apache.poi.hssf.usermodel.HSSFPictureData;
import org.apache.poi.hssf.usermodel.HSSFShape;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationConstraint;
import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Name;
import org.apache.poi.ss.usermodel.PictureData;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDataValidation;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFPicture;
import org.apache.poi.xssf.usermodel.XSSFShape;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.annotation.Excel.ColumnType;
import com.ruoyi.common.annotation.Excel.Type;
import com.ruoyi.common.annotation.Excels;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.exception.UtilException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileTypeUtils;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.common.utils.file.ImageUtils;
import com.ruoyi.common.utils.reflect.ReflectUtils;
/**
* Excel相关处理
*
* @author ruoyi
*/
public class ExcelUtil<T>
{
private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
public static final String FORMULA_REGEX_STR = "=|-|\\+|@";
public static final String[] FORMULA_STR = { "=", "-", "+", "@" };
/**
* 用于dictType属性数据存储,避免重复查缓存
*/
public Map<String, String> sysDictMap = new HashMap<Str

最低0.47元/天 解锁文章
2259

被折叠的 条评论
为什么被折叠?



