All Downloads are FREE. Search and download functionalities are using the official Maven repository.

icu.easyj.poi.excel.model.ExcelCellMapping Maven / Gradle / Ivy

/*
 * Copyright 2021-2024 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package icu.easyj.poi.excel.model;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import icu.easyj.core.util.ReflectionUtils;
import icu.easyj.core.util.StringUtils;
import icu.easyj.poi.excel.annotation.Excel;
import icu.easyj.poi.excel.annotation.ExcelCell;
import icu.easyj.poi.excel.annotation.ExcelCells;
import icu.easyj.poi.excel.style.ExcelFormats;
import icu.easyj.poi.excel.util.ExcelColorUtils;
import org.apache.commons.lang3.ArrayUtils;

/**
 * model中的属性和excel表格中的列的映射关系
 *
 * @author wangliang181230
 */
public class ExcelCellMapping implements Serializable {
	private static final long serialVersionUID = 1L;

	//******************************** fields *********************************/

	// 对应的属性
	private Field field; // 注解在的那个字段对象
	private String column; // 所要展示的数据字段名,可以是多级的,如:obj.field1.field2

	// 注解信息
	private ExcelCell anno;
	// 解析注解信息
	private String headName; // 列头
	private String headComment; // 列头注释
	private int cellNum; // 列号(值从0开始,除了序号列外)
	private int width = -1; // 列宽(-1表示让excel自动分配宽度)
	private boolean wrapText = false; // 是否允许换行
	private boolean hidden = false; // 是否隐藏列
	private String color; // 字体颜色
	private short colorIndex; // 字体颜色的索引
	private String backgroundColor; // 背景颜色
	private short backgroundColorIndex; // 背景颜色的索引
	private String format; // 格式化(应用于Date数据、数字等等的格式化输出)
	private String align; // 水平位置:left、center、right
	private String verAlign; // 竖直位置:top、middle|center、bottom
	private String trueText; // boolean型数据为true时,显示的文字
	private String falseText; // boolean型数据为false时,显示的文字
	private Map convertMap; // 值转换
	private Map convertMap2; // 值反向转换

	//******************************** getter and setter *********************************/

	public Field getField() {
		return field;
	}

	public void setField(Field field) {
		this.field = field;
	}

	public String getColumn() {
		return column;
	}

	public void setColumn(String column) {
		this.column = column;
	}

	public ExcelCell getAnno() {
		return anno;
	}

	public void setAnno(ExcelCell anno) {
		this.anno = anno;
	}

	public String getHeadName() {
		return headName;
	}

	public void setHeadName(String headName) {
		this.headName = headName;
	}

	public String getHeadComment() {
		return headComment;
	}

	public void setHeadComment(String headComment) {
		this.headComment = headComment;
	}

	public int getCellNum() {
		return cellNum;
	}

	public void setCellNum(int cellNum) {
		this.cellNum = cellNum;
	}

	public int getWidth() {
		return width;
	}

	public void setWidth(int width) {
		this.width = width;
	}

	public boolean isWrapText() {
		return wrapText;
	}

	public void setWrapText(boolean wrapText) {
		this.wrapText = wrapText;
	}

	public boolean isHidden() {
		return hidden;
	}

	public void setHidden(boolean hidden) {
		this.hidden = hidden;
	}

	public String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}

	public short getColorIndex() {
		return colorIndex;
	}

	public void setColorIndex(short colorIndex) {
		this.colorIndex = colorIndex;
	}

	public String getBackgroundColor() {
		return backgroundColor;
	}

	public void setBackgroundColor(String backgroundColor) {
		this.backgroundColor = backgroundColor;
	}

	public short getBackgroundColorIndex() {
		return backgroundColorIndex;
	}

	public void setBackgroundColorIndex(short backgroundColorIndex) {
		this.backgroundColorIndex = backgroundColorIndex;
	}

	public String getFormat() {
		return format;
	}

	public void setFormat(String format) {
		this.format = format;
	}

	public String getAlign() {
		return align;
	}

	public void setAlign(String align) {
		this.align = align;
	}

	public String getVerAlign() {
		return verAlign;
	}

	public void setVerAlign(String verAlign) {
		this.verAlign = verAlign;
	}

	public String getTrueText() {
		return trueText;
	}

	public void setTrueText(String trueText) {
		this.trueText = trueText;
	}

	public String getFalseText() {
		return falseText;
	}

	public void setFalseText(String falseText) {
		this.falseText = falseText;
	}

	public Map getConvertMap() {
		return convertMap;
	}

	public void setConvertMap(Map convertMap) {
		this.convertMap = convertMap;
	}

	public Map getConvertMap2() {
		return convertMap2;
	}

	public void setConvertMap2(Map convertMap2) {
		this.convertMap2 = convertMap2;
	}


	//******************************** static *********************************/


	private static void addMapping(ExcelCell[] excelCells, Class clazz, ExcelMapping mapping, Field field, List mappingList) {
		if (excelCells.length > 0) {
			ExcelCellMapping cellMapping;
			for (ExcelCell excelCell : excelCells) {
				// 注解转换为映射类对象
				cellMapping = toMapping(excelCell, clazz, field, mapping);
				// 添加到列表中
				mappingList.add(cellMapping);
			}
		}
	}

	/**
	 * 获取属性与表格的映射关系
	 *
	 * @param clazz   the clazz
	 * @param mapping excel表映射
	 * @return cellMappingList excel列映射列表
	 */
	public static List getCellMappingList(Class clazz, ExcelMapping mapping) {
		List mappingList = new ArrayList<>();

		// 获取在字段上配置的列映射
		Field[] fields = clazz.getDeclaredFields();
		ExcelCellMapping cellMapping;
		for (Field f : fields) {
			ExcelCell[] excelCells = f.getAnnotationsByType(ExcelCell.class);
			addMapping(excelCells, clazz, mapping, f, mappingList);

			ExcelCells annos = f.getAnnotation(ExcelCells.class);
			if (annos != null) {
				addMapping(annos.value(), clazz, mapping, f, mappingList);
			}
		}

		// 获取`@Excel`里配置的列映射
		if (mapping.getAnno() != null && ArrayUtils.isNotEmpty(mapping.getAnno().cells())) {
			Field f;
			for (ExcelCell cellAnno : mapping.getAnno().cells()) {
				if (StringUtils.isEmpty(cellAnno.column())) {
					throw new RuntimeException("在@" + Excel.class.getSimpleName() + "注解的cells属性中配置的列信息,column属性不能为空");
				}
				try {
					f = ReflectionUtils.getField(clazz, cellAnno.column().split("\\.")[0]);
				} catch (NoSuchFieldException e) {
					throw new RuntimeException("获取字段失败:" + cellAnno.column(), e);
				}
				// 注解转换为映射类对象
				cellMapping = toMapping(cellAnno, clazz, f, mapping);
				// 添加到列表中
				mappingList.add(cellMapping);
			}
		}

		// 根据列号排序
		mappingList.sort(Comparator.comparingInt(ExcelCellMapping::getCellNum));

		return mappingList;
	}

	/**
	 * 注解转换为映射类对象
	 *
	 * @param anno    列注解
	 * @param clazz   数据类型
	 * @param f       字段
	 * @param mapping 表映射
	 * @return 列映射
	 */
	public static ExcelCellMapping toMapping(ExcelCell anno, Class clazz, Field f, ExcelMapping mapping) {
		ExcelCellMapping cellMapping = new ExcelCellMapping();

		// 属性信息
		cellMapping.setField(f);
		if (StringUtils.isNotBlank(anno.column()) && !anno.column().equals(f.getName())) {
			String column = anno.column();
			// 拼接当前的字段名到column中
			if (column.startsWith("#") || column.startsWith("$")) {
				column = f.getName() + column.substring(1);
			} else if (column.startsWith(".")) {
				column = f.getName() + column;
			} else {
				if (!column.contains(".")) {
					column = f.getName() + "." + column;
				} else {
					if (!column.startsWith(f.getName())) {
						throw new RuntimeException("在类“" + clazz.getName() + "”的属性“" + f.getName() + "”上的注解@"
								+ ExcelCell.class.getSimpleName() + "(column=\"" + column + "\")有误");
					}
				}
			}
			cellMapping.setColumn(column);

			Field cellField;
			try {
				cellField = ReflectionUtils.getField(clazz, column); // 重新获取里面的字段
			} catch (NoSuchFieldException e) {
				throw new RuntimeException("获取字段失败:" + column, e);
			}
			cellMapping.setField(cellField);

			if (cellMapping.getField() == null) {
				throw new RuntimeException("在类“" + clazz.getName() + "”中未找到属性:" + column);
			}
		}
		// 注解信息
		cellMapping.setAnno(anno);
		// excel表格信息
		cellMapping.setHeadName(anno.headName().trim()); // 列头
		cellMapping.setHeadComment(anno.headComment()); // 列头注释
		cellMapping.setCellNum(anno.cellNum()); // 列号
		cellMapping.setWidth(anno.width()); // 列宽
		cellMapping.setWrapText(anno.wrapText()); // 是否允许自动换行
		cellMapping.setHidden(anno.hidden()); // 是否隐藏列
		cellMapping.setColor(anno.color().toUpperCase()); // 字体颜色
		cellMapping.setColorIndex(ExcelColorUtils.getColorIndex(cellMapping.getColor())); // 字体颜色的索引号
		cellMapping.setBackgroundColor(anno.backgroundColor().toUpperCase()); // 背景颜色
		cellMapping.setBackgroundColorIndex(ExcelColorUtils.getColorIndex(cellMapping.getBackgroundColor())); // 背景颜色的索引号
		cellMapping.setFormat(anno.format()); // 格式化
		cellMapping.setAlign(anno.align().toLowerCase().trim()); // 水平位置
		cellMapping.setVerAlign(anno.verAlign().toLowerCase().trim()); // 竖直位置
		cellMapping.setTrueText(anno.trueText().trim()); // boolean型数据为true时,显示的文字
		cellMapping.setFalseText(anno.falseText().trim()); // boolean型数据为false时,显示的文字
		if (StringUtils.isNotBlank(anno.convert())) {
			Map convertMap = new HashMap<>(4);
			Map convertMap2 = new HashMap<>(4);

			String splitRegex = (anno.convert().contains("|") ? "\\|" : ",");

			String[] convertArr = anno.convert().replace(",", splitRegex).split(splitRegex);
			if (ArrayUtils.isNotEmpty(convertArr)) {
				for (String convertPair : convertArr) {
					String[] convertPairArr = convertPair.split("=");
					if (convertPairArr.length == 2) {
						convertMap.put(convertPairArr[0].trim(), convertPairArr[1].trim());
						convertMap2.put(convertPairArr[1].trim(), convertPairArr[0].trim());
					}
				}
			}

			if (convertMap.keySet().isEmpty()) {
				throw new RuntimeException("在类“" + clazz.getName() + "”中的“" + f.getName() + "”属性上的@ExcelCellMapping注解所配置的convert属性有误,请检查格式。");
			}

			cellMapping.setConvertMap(convertMap);
			cellMapping.setConvertMap2(convertMap2);
		}

		// 处理映射信息,初始化部分情况的映射内容
		if (StringUtils.isEmpty(cellMapping.getFormat())) {
			if (cellMapping.getField().getType().equals(Double.class)
					|| cellMapping.getField().getType().equals(Float.class)
					|| cellMapping.getField().getType().equals(BigDecimal.class)) {
				cellMapping.setFormat(ExcelFormats.FLOAT_2); // 浮点型数据默认格式化为“0.00_ ”
			} else if (Number.class.isAssignableFrom(cellMapping.getField().getType())) {
				cellMapping.setFormat(ExcelFormats.INT);
			} else if (cellMapping.getField().getType().equals(Date.class)) {
				cellMapping.setFormat(ExcelFormats.YYYYMMDDHHMMSS);
			}
		} else {
			// 解决浮点数字格式化不成功的问题
			if (cellMapping.getFormat().endsWith("_")) { // 如果格式化以“_”结尾时
				cellMapping.setFormat(cellMapping.getFormat() + " "); // 后面需加一个空格
			}
		}
		if (cellMapping.getWidth() <= 0) { // 已自定义列宽
			if (cellMapping.getFormat().contains(ExcelFormats.YYYY)) {
				cellMapping.setWidth((int)(cellMapping.getFormat().length() * 6.8 + 8.0 * (1 + 8.0 / cellMapping.getFormat().length())));
			}
		}

		// 计算headName的大概字符宽度,如果headName的宽度比默认的宽度或已设的宽度要大,则
		if (mapping != null && mapping.isNeedHeadRow()) {
			int headCellWidth = getCellWidthByText(cellMapping.getHeadName(), 10, true) + (mapping.isNeedFilter() ? 16 : 0);
			if (headCellWidth > 63 && headCellWidth > cellMapping.getWidth()) { // 63为excel默认的宽度
				cellMapping.setWidth(headCellWidth);
			}
		}

		if (StringUtils.isEmpty(cellMapping.getAlign())) {
			if (cellMapping.getConvertMap() != null) {
				cellMapping.setAlign("center"); // 枚举默认居中
			} else if (cellMapping.getField().getType().equals(Date.class)
					|| cellMapping.getField().getType().equals(Boolean.class)) {
				cellMapping.setAlign("center"); // 日期和boolean默认居中
			} else if (Number.class.isAssignableFrom(cellMapping.getField().getType())) {
				cellMapping.setAlign("right"); // 数字默认居右
			}
		}

		return cellMapping;
	}

	/**
	 * 根据文本获取列宽
	 * 中文算两个长度
	 *
	 * @param text   文本内容
	 * @param size   字体大小
	 * @param isBold 是否为粗体
	 * @return 列宽
	 */
	public static int getCellWidthByText(String text, int size, boolean isBold) {
		int textLength = icu.easyj.core.util.StringUtils.chineseLength(text);
		return (int)(textLength * (isBold ? 7.2 : 6.8) * (size / 10)) + 10;
	}

	@Override
	public String toString() {
		return "{" +
				"headName='" + headName + '\'' +
				", cellNum=" + cellNum +
				", column='" + column + '\'' +
				'}';
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy