Signed-off-by: chy <chy@163.com>

This commit is contained in:
chy
2026-02-02 23:21:53 +08:00
commit 1c212fb3b3
3683 changed files with 136251 additions and 0 deletions

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.lideeyunji</groupId>
<artifactId>lidee-tool</artifactId>
<version>2.2.4</version>
</parent>
<groupId>com.lideeyunji</groupId>
<artifactId>tool-spring-boot-starter-excel</artifactId>
<version>2.2.4</version>
<name>${project.artifactId}</name>
<description>Excel 拓展</description>
<dependencies>
<dependency>
<groupId>com.lideeyunji</groupId>
<artifactId>tool-common</artifactId>
</dependency>
<dependency>
<groupId>com.lideeyunji</groupId>
<artifactId>tool-spring-boot-starter-yunji</artifactId>
</dependency>
<dependency>
<groupId>com.lideeyunji</groupId>
<artifactId>tool-spring-boot-starter-dict</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,56 @@
<?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>
<groupId>com.lideeyunji</groupId>
<artifactId>lidee-tool</artifactId>
<version>${lidee.version}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>tool-spring-boot-starter-excel</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<description>Excel 拓展</description>
<dependencies>
<dependency>
<groupId>com.lideeyunji</groupId>
<artifactId>tool-common</artifactId>
</dependency>
<dependency>
<groupId>com.lideeyunji</groupId>
<artifactId>tool-spring-boot-starter-yunji</artifactId>
</dependency>
<!-- 业务组件 -->
<dependency>
<groupId>com.lideeyunji</groupId>
<artifactId>tool-spring-boot-starter-dict</artifactId>
<optional>true</optional> <!-- 如果希望使用 @DictFormat 注解,需要引入该依赖 -->
</dependency>
<!-- Web 相关 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<scope>provided</scope> <!-- 设置为 provided只有 ExcelUtils 使用 -->
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<scope>provided</scope> <!-- 设置为 provided只有 ExcelUtils 使用 -->
</dependency>
<!-- 工具类相关 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,22 @@
package com.lideeyunji.tool.framework.excel.core.annotations;
import java.lang.annotation.*;
/**
* 字典格式化
*
* 实现将字典数据的值,格式化成字典数据的标签
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface DictFormat {
/**
* 例如说SysDictTypeConstants、InfDictTypeConstants
*
* @return 字典类型
*/
String value();
}

View File

@@ -0,0 +1,72 @@
package com.lideeyunji.tool.framework.excel.core.convert;
import cn.hutool.core.convert.Convert;
import com.lideeyunji.tool.framework.dict.core.util.DictFrameworkUtils;
import com.lideeyunji.tool.framework.excel.core.annotations.DictFormat;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import lombok.extern.slf4j.Slf4j;
/**
* Excel 数据字典转换器
*
* @author 金灯剑客
*/
@Slf4j
public class DictConvert implements Converter<Object> {
@Override
public Class<?> supportJavaTypeKey() {
throw new UnsupportedOperationException("暂不支持,也不需要");
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
throw new UnsupportedOperationException("暂不支持,也不需要");
}
@Override
public Object convertToJavaData(ReadCellData readCellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
// 使用字典解析
String type = getType(contentProperty);
String label = readCellData.getStringValue();
String value = DictFrameworkUtils.parseDictDataValue(type, label);
if (value == null) {
log.error("[convertToJavaData][type({}) 解析不掉 label({})]", type, label);
return null;
}
// 将 String 的 value 转换成对应的属性
Class<?> fieldClazz = contentProperty.getField().getType();
return Convert.convert(fieldClazz, value);
}
@Override
public WriteCellData<String> convertToExcelData(Object object, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
// 空时,返回空
if (object == null) {
return new WriteCellData<>("");
}
// 使用字典格式化
String type = getType(contentProperty);
String value = String.valueOf(object);
String label = DictFrameworkUtils.getDictDataLabel(type, value);
if (label == null) {
log.error("[convertToExcelData][type({}) 转换不了 label({})]", type, value);
return new WriteCellData<>("");
}
// 生成 Excel 小表格
return new WriteCellData<>(label);
}
private static String getType(ExcelContentProperty contentProperty) {
return contentProperty.getField().getAnnotation(DictFormat.class).value();
}
}

View File

@@ -0,0 +1,34 @@
package com.lideeyunji.tool.framework.excel.core.convert;
import com.lideeyunji.tool.framework.common.util.json.JsonUtils;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
/**
* Excel Json 转换器
*
* @author 金灯剑客
*/
public class JsonConvert implements Converter<Object> {
@Override
public Class<?> supportJavaTypeKey() {
throw new UnsupportedOperationException("暂不支持,也不需要");
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
throw new UnsupportedOperationException("暂不支持,也不需要");
}
@Override
public WriteCellData<String> convertToExcelData(Object value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
// 生成 Excel 小表格
return new WriteCellData<>(JsonUtils.toJsonString(value));
}
}

View File

@@ -0,0 +1,39 @@
package com.lideeyunji.tool.framework.excel.core.convert;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* 金额转换器
*
* 金额单位:分
*
* @author 金灯剑客
*/
public class MoneyConvert implements Converter<Integer> {
@Override
public Class<?> supportJavaTypeKey() {
throw new UnsupportedOperationException("暂不支持,也不需要");
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
throw new UnsupportedOperationException("暂不支持,也不需要");
}
@Override
public WriteCellData<String> convertToExcelData(Integer value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
BigDecimal result = BigDecimal.valueOf(value)
.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
return new WriteCellData<>(result.toString());
}
}

View File

@@ -0,0 +1,51 @@
package com.lideeyunji.tool.framework.excel.core.util;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.converters.longconverter.LongStringConverter;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
/**
* Excel 工具类
*
* @author 金灯剑客
*/
public class ExcelUtils {
/**
* 将列表以 Excel 响应给前端
*
* @param response 响应
* @param filename 文件名
* @param sheetName Excel sheet 名
* @param head Excel head 头
* @param data 数据列表哦
* @param <T> 泛型,保证 head 和 data 类型的一致性
* @throws IOException 写入失败的情况
*/
public static <T> void write(HttpServletResponse response, String filename, String sheetName,
Class<T> head, List<T> data) throws IOException {
// 输出 Excel
EasyExcel.write(response.getOutputStream(), head)
.autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 基于 column 长度,自动适配。最大 255 宽度
.registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度
.sheet(sheetName).doWrite(data);
// 设置 header 和 contentType。写在最后的原因是避免报错时响应 contentType 已经被修改了
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8.name()));
response.setContentType("application/vnd.ms-excel;charset=UTF-8");
}
public static <T> List<T> read(MultipartFile file, Class<T> head) throws IOException {
return EasyExcel.read(file.getInputStream(), head, null)
.autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理
.doReadAllSync();
}
}

View File

@@ -0,0 +1,30 @@
package com.lideeyunji.tool.framework.excel.handler;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.xssf.streaming.SXSSFSheet;
/**
*
*/
public class CustomSheetWriteHandler implements SheetWriteHandler {
private static final Integer COLUMN = 26;
@Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
for (int i = 0; i < COLUMN; i++) {
// 设置为文本格式
SXSSFSheet sxssfSheet = (SXSSFSheet) writeSheetHolder.getSheet();
CellStyle cellStyle = writeWorkbookHolder.getCachedWorkbook().createCellStyle();
// 49为文本格式
cellStyle.setDataFormat((short) 49);
// i为列一整列设置为文本格式
sxssfSheet.setDefaultColumnStyle(i, cellStyle);
}
}
}

View File

@@ -0,0 +1,133 @@
package com.lideeyunji.tool.framework.excel.handler;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.lideeyunji.tool.framework.yunji.utils.FuncBase;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.DefaultIndexedColorMap;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFColor;
import java.awt.Color;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 单元格设置文本格式
*/
public class RowFormatSetTextHandler implements CellWriteHandler {
Map<Integer, List<String>> dropdownOptionsMap=new HashMap<>();
Map<Integer, CellStyle> cellStyleMap = new HashMap<>();
public RowFormatSetTextHandler() {
}
@Override
public void beforeCellCreate(CellWriteHandlerContext context) {
WriteSheetHolder writeSheetHolder = context.getWriteSheetHolder();
Sheet sheet = writeSheetHolder.getSheet();
Integer rowIndex = context.getRowIndex();
if(rowIndex!=0){
return;
}
Integer columnIndex = context.getColumnIndex();
//下拉列表
List<String> dropdownOptionList = dropdownOptionsMap.get(columnIndex);
if(FuncBase.isEmpty(dropdownOptionList)){
return;
}
createDropdownList(sheet,dropdownOptionList,columnIndex);
}
@Override
public void afterCellDispose(CellWriteHandlerContext context) {
WriteCellData<?> cellData = context.getFirstCellData();
// 清除原有单元格颜色
WriteCellStyle writeCellStyle = cellData.getWriteCellStyle();
writeCellStyle.setFillForegroundColor(null);
// 重新设置自定义RGB颜色
CellStyle cellStyle;
int cellStyleKey;
Integer rowIndex = context.getRowIndex();
if (rowIndex == 0) {
// 第0行即表头
cellStyleKey = 0;
cellStyle = cellStyleMap.computeIfAbsent(cellStyleKey,
value -> getCellStyle(cellData, context, new Color(115, 174, 76)));
} else if ((rowIndex & 1) == 0) {
// 偶数行
cellStyleKey = 2;
cellStyle = cellStyleMap.computeIfAbsent(cellStyleKey,
value -> getCellStyle(cellData, context, new Color(255, 255, 255)));
} else {
// 奇数行
cellStyleKey = 1;
cellStyle = cellStyleMap.computeIfAbsent(cellStyleKey,
value -> getCellStyle(cellData, context, new Color(227, 239, 219)));
}
cellData.setOriginCellStyle(cellStyle);
}
/**
* 单元格样式
*/
private CellStyle getCellStyle(WriteCellData<?> cellData, CellWriteHandlerContext context, Color color) {
CellStyle style = cellData.getOriginCellStyle();
if (FuncBase.isEmpty(style)) {
style = context.getWriteWorkbookHolder().getWorkbook().createCellStyle();
}
XSSFColor xssfColor = new XSSFColor(color, new DefaultIndexedColorMap());
((XSSFCellStyle) style).setFillForegroundColor(xssfColor);
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
return style;
}
/**
* 下拉
* @param sheet
* @param dropdownOptionList
*/
public void createDropdownList( Sheet sheet, List<String> dropdownOptionList, int firstCol) {
if(FuncBase.isEmpty(dropdownOptionList)){
return;
}
DataValidationHelper helper = sheet.getDataValidationHelper();
String[] dropdownOptionsArray = dropdownOptionList.toArray(new String[0]);
// 创建下拉列表的约束
DataValidationConstraint constraint = helper.createExplicitListConstraint(dropdownOptionsArray);
// 设置下拉列表应用的单元格区域例如第2行到最后一行的第2列
int firstRow = 1; // 通常Excel中第一行是1这里假设第一行为表头
int lastRow=65536;
int lastCol = firstCol;
CellRangeAddressList regions = new CellRangeAddressList(firstRow, lastRow, firstCol, lastCol);
// 创建数据验证规则并添加到工作表
DataValidation validation = helper.createValidation(constraint, regions);
sheet.addValidationData(validation);
}
public Map<Integer, List<String>> getDropdownOptionsMap() {
return dropdownOptionsMap;
}
public void setDropdownOptionsMap(Map<Integer, List<String>> dropdownOptionsMap) {
this.dropdownOptionsMap = dropdownOptionsMap;
}
}

View File

@@ -0,0 +1,65 @@
package com.lideeyunji.tool.framework.excel;
import com.lideeyunji.tool.framework.excel.model.ExcelTitleModel;
import com.lideeyunji.tool.framework.excel.model.MoreSheetConfig;
import com.lideeyunji.tool.framework.excel.read.ExcelImportUtils;
import com.lideeyunji.tool.framework.excel.write.ExcelExportUtils;
import org.apache.commons.collections4.map.LinkedMap;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class lideeYunJiExcelUtils {
/**
* 导出 Excel-单个 sheet
* @param response
* @param sheetName
* @param headMap
* @param dataList
*/
public static void exportExcel(HttpServletResponse response, String sheetName, LinkedMap<String, ExcelTitleModel> headMap, List<Map<String, Object>> dataList) {
MoreSheetConfig moreSheetConfig=new MoreSheetConfig();
moreSheetConfig.setSheetName(sheetName);
moreSheetConfig.setHeadMap(headMap);
moreSheetConfig.setDataList(dataList);
List<MoreSheetConfig> sheetConfigList=new ArrayList<>();
sheetConfigList.add(moreSheetConfig);
ExcelExportUtils.exportExcel(response,sheetName,sheetConfigList);
}
/**
* 多个 sheet
* @param response
* @param sheetName
*/
public static void exportExcel(HttpServletResponse response, String sheetName, List<MoreSheetConfig> sheetConfigList) {
ExcelExportUtils.exportExcel(response,sheetName,sheetConfigList);
}
/**
* 导入Excel
* @param inputStream
* @param headerCou 表头所在的行数
* @return
*/
public static List<Map<String, Object>> importExcel(InputStream inputStream, Integer headerCou, Map<String, String> fieldNameAndCodeMap){
return ExcelImportUtils.importExcel(inputStream,headerCou,fieldNameAndCodeMap);
}
/**
* 导入Excel
* @param inputStream
* @param headerCou 表头所在的行数
* @return
*/
public static List<Map<String, Object>> importExcel(InputStream inputStream, Integer headerCou,Integer sheet, Map<String, String> fieldNameAndCodeMap){
return ExcelImportUtils.importExcel(inputStream,headerCou,fieldNameAndCodeMap,sheet);
}
}

View File

@@ -0,0 +1,43 @@
package com.lideeyunji.tool.framework.excel.listener;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 自定义监听器
*/
public class lideeYunJiExcelListener extends AnalysisEventListener<Map<Integer, String>> {
//表头数据(存储所有的表头数据)
private List<Map<Integer, String>> headList = new ArrayList<>();
//数据体
private List<Map<Integer, String>> dataList = new ArrayList<>();
@Override//这里会一行行的返回头
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
//存储全部表头数据
headList.add(headMap);
}
@Override// 处理每一行数据
public void invoke(Map<Integer, String> data, AnalysisContext context) {
dataList.add(data);
}
@Override// 全部处理结束执行
public void doAfterAllAnalysed(AnalysisContext context) {
}
public List<Map<Integer, String>> getHeadList() {
return headList;
}
public List<Map<Integer, String>> getDataList() {
return dataList;
}
}

View File

@@ -0,0 +1,33 @@
package com.lideeyunji.tool.framework.excel.model;
import java.util.List;
public class ExcelTitleModel {
private String title;//标题
private List<String> dropdownOptionList;//下拉列表
public ExcelTitleModel() {
}
public ExcelTitleModel(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public List<String> getDropdownOptionList() {
return dropdownOptionList;
}
public void setDropdownOptionList(List<String> dropdownOptionList) {
this.dropdownOptionList = dropdownOptionList;
}
}

View File

@@ -0,0 +1,36 @@
package com.lideeyunji.tool.framework.excel.model;
import org.apache.commons.collections4.map.LinkedMap;
import java.util.List;
import java.util.Map;
public class MoreSheetConfig {
private String sheetName;
private LinkedMap<String, ExcelTitleModel> headMap;
private List<Map<String, Object>> dataList;
public String getSheetName() {
return sheetName;
}
public void setSheetName(String sheetName) {
this.sheetName = sheetName;
}
public LinkedMap<String, ExcelTitleModel> getHeadMap() {
return headMap;
}
public void setHeadMap(LinkedMap<String, ExcelTitleModel> headMap) {
this.headMap = headMap;
}
public List<Map<String, Object>> getDataList() {
return dataList;
}
public void setDataList(List<Map<String, Object>> dataList) {
this.dataList = dataList;
}
}

View File

@@ -0,0 +1,4 @@
/**
* 基于 EasyExcel 实现 Excel 相关的操作
*/
package com.lideeyunji.tool.framework.excel;

View File

@@ -0,0 +1,93 @@
package com.lideeyunji.tool.framework.excel.read;
import cn.hutool.core.util.IdUtil;
import com.lideeyunji.tool.framework.excel.listener.lideeYunJiExcelListener;
import com.lideeyunji.tool.framework.exception.lideeYunJiException;
import com.lideeyunji.tool.framework.yunji.constant.lideeYunjiCodeConstant;
import com.lideeyunji.tool.framework.yunji.utils.FuncBase;
import com.alibaba.excel.EasyExcelFactory;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 处理导入数据
*/
public class ExcelImportUtils {
/**
* 动态表头导入功能
*
* @param inputStream 文件
* @return
*/
public static List<Map<String, Object>> importExcel(InputStream inputStream,Integer headerCou, Map<String, String> fieldNameAndCodeMap) {
return importExcel(inputStream,headerCou,fieldNameAndCodeMap,0);
}
public static List<Map<String, Object>> importExcel(InputStream inputStream,Integer headerCou, Map<String, String> fieldNameAndCodeMap,Integer sheet) {
try {
// 首先校验传入文件是否为空
if (inputStream == null) {
throw new lideeYunJiException("文件源为空");
}
// 引入监听器此处需注意监听器不可被Spring管理
lideeYunJiExcelListener readListener = new lideeYunJiExcelListener();
// 开始处理excel
EasyExcelFactory.read(inputStream, readListener)
.sheet(sheet)
.headRowNumber(headerCou)
.doRead();
// 获取表头(验空)
List<Map<Integer, String>> headList = readListener.getHeadList();
if (FuncBase.isEmpty(headList)) {
throw new lideeYunJiException("Excel表头不能为空");
}
//获取头部,取最后一次解析的列头数据
Map<Integer, String> excelHeadIdxNameMap = headList.get(headList.size() - 1);
// 获取表数据(验空)
List<Map<Integer, String>> dataList = readListener.getDataList();
if (FuncBase.isEmpty(dataList)) {
throw new lideeYunJiException("Excel数据内容不能为空");
}
//封装数据体
AtomicInteger atomicInteger= new AtomicInteger(1);
List<Map<String, Object>> excelDataList = new ArrayList<Map<String, Object>>();
for (Map<Integer, String> dataRow : dataList) {
HashMap<String, Object> rowData = new HashMap<>();
int step =atomicInteger.getAndIncrement();
rowData.put(lideeYunjiCodeConstant.EXCEL_IMPORT_STEP,step);//处理序号
rowData.put(lideeYunjiCodeConstant.EXCEL_IMPORT_ID,IdUtil.getSnowflakeNextId());//id
excelHeadIdxNameMap.entrySet().forEach(columnHead -> {
String value = columnHead.getValue();
String fieldCode = fieldNameAndCodeMap.get(value);
if(FuncBase.isNotEmpty(fieldCode)){
rowData.put(fieldCode, dataRow.get(columnHead.getKey()));
}
});
if(FuncBase.isEmpty(rowData)){
continue;
}
excelDataList.add(rowData);
}
return excelDataList;
} catch (Exception e) {
e.printStackTrace();
throw new lideeYunJiException(e.getMessage());
}
}
}

View File

@@ -0,0 +1,121 @@
package com.lideeyunji.tool.framework.excel.write;
import com.alibaba.excel.metadata.data.DataFormatData;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import org.apache.poi.ss.usermodel.*;
public class CellStyleUtils {
/**
* 对行使用相同的样式<br/>
* 头和内容分别使用不同样式
*/
public static HorizontalCellStyleStrategy getCellStyleStrategy(){
// List<WriteCellStyle> contentStyleList = new ArrayList<>();// 内容奇偶数行样式不一致
// contentStyleList.add(getOddRowContentStyle());
// contentStyleList.add(getEvenRowContentStyle());
return new HorizontalCellStyleStrategy(getHeadStyle(), getContentStyle());
}
/**
* 头样式
*/
public static WriteCellStyle getHeadStyle() {
WriteCellStyle style = new WriteCellStyle();
DataFormatData dataFormatData = new DataFormatData();
dataFormatData.setFormat("@");
style.setDataFormatData(dataFormatData);// 单元格格式
WriteFont font = new WriteFont();
font.setFontHeightInPoints((short) 12);
font.setBold(false);
font.setColor(IndexedColors.WHITE.getIndex());
style.setWriteFont(font);// 字体
style.setHorizontalAlignment(HorizontalAlignment.CENTER);// 水平对齐方式
style.setVerticalAlignment(VerticalAlignment.CENTER);// 垂直对齐方式
style.setBorderTop(BorderStyle.THIN);
style.setBorderBottom(BorderStyle.THIN);// 边框样式
style.setBorderLeft(BorderStyle.THIN);
style.setBorderRight(BorderStyle.THIN);
style.setTopBorderColor(IndexedColors.BLACK.getIndex());// 边框颜色
style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
style.setRightBorderColor(IndexedColors.BLACK.getIndex());
return style;
}
/**
* 内容样式
*/
public static WriteCellStyle getContentStyle() {
WriteCellStyle style = new WriteCellStyle();
DataFormatData dataFormatData = new DataFormatData();
dataFormatData.setFormat("@");
style.setDataFormatData(dataFormatData);// 单元格格式
WriteFont font = new WriteFont();
font.setFontHeightInPoints((short) 12);
style.setWriteFont(font);// 字体
style.setHorizontalAlignment(HorizontalAlignment.CENTER);// 水平对齐方式
style.setVerticalAlignment(VerticalAlignment.CENTER);// 垂直对齐方式
style.setBorderTop(BorderStyle.THIN);
style.setBorderBottom(BorderStyle.THIN);// 边框样式
style.setBorderLeft(BorderStyle.THIN);
style.setBorderRight(BorderStyle.THIN);
style.setTopBorderColor(IndexedColors.BLACK.getIndex());// 边框颜色
style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
style.setRightBorderColor(IndexedColors.BLACK.getIndex());
return style;
}
/**
* 奇数行内容样式
*/
public static WriteCellStyle getOddRowContentStyle() {
WriteCellStyle style = new WriteCellStyle();
DataFormatData dataFormatData = new DataFormatData();
dataFormatData.setFormat("@");
style.setDataFormatData(dataFormatData);// 单元格格式
WriteFont font = new WriteFont();
font.setFontHeightInPoints((short) 12);
style.setWriteFont(font);// 字体
style.setHorizontalAlignment(HorizontalAlignment.CENTER);// 水平对齐方式
style.setVerticalAlignment(VerticalAlignment.CENTER);// 垂直对齐方式
style.setBorderTop(BorderStyle.THIN);
style.setBorderBottom(BorderStyle.THIN);// 边框样式
style.setBorderLeft(BorderStyle.THIN);
style.setBorderRight(BorderStyle.THIN);
style.setTopBorderColor(IndexedColors.BLACK.getIndex());// 边框颜色
style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
style.setRightBorderColor(IndexedColors.BLACK.getIndex());
return style;
}
/**
* 偶数行内容样式
*/
public static WriteCellStyle getEvenRowContentStyle() {
WriteCellStyle style = new WriteCellStyle();
WriteFont font = new WriteFont();
DataFormatData dataFormatData = new DataFormatData();
dataFormatData.setFormat("@");
style.setDataFormatData(dataFormatData);// 文本格式
font.setFontHeightInPoints((short) 12);
style.setWriteFont(font);// 字体
style.setHorizontalAlignment(HorizontalAlignment.CENTER);// 水平对齐方式
style.setVerticalAlignment(VerticalAlignment.CENTER);// 垂直对齐方式
style.setBorderTop(BorderStyle.THIN);
style.setBorderBottom(BorderStyle.THIN);// 边框样式
style.setBorderLeft(BorderStyle.THIN);
style.setBorderRight(BorderStyle.THIN);
style.setTopBorderColor(IndexedColors.BLACK.getIndex());// 边框颜色
style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
style.setRightBorderColor(IndexedColors.BLACK.getIndex());
return style;
}
}

View File

@@ -0,0 +1,31 @@
package com.lideeyunji.tool.framework.excel.write;
import com.alibaba.excel.write.handler.context.CellWriteHandlerContext;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.Sheet;
/**
* 列宽样式策略
*/
public class CustomColumnWidthStyleStrategy extends AbstractColumnWidthStyleStrategy {
@Override
protected void setColumnWidth(CellWriteHandlerContext context) {
// 只需设置首行
if (context.getRowIndex() != 0) {
return;
}
DataFormatter dataFormatter = new DataFormatter();
Cell cell = context.getCell();
int length = dataFormatter.formatCellValue(cell).length();
if (length < 6) {
length = 6;
}
Sheet sheet = context.getWriteSheetHolder().getSheet();
sheet.setColumnWidth(context.getColumnIndex(), length * 1000);
}
}

View File

@@ -0,0 +1,145 @@
package com.lideeyunji.tool.framework.excel.write;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.lideeyunji.tool.framework.excel.handler.CustomSheetWriteHandler;
import com.lideeyunji.tool.framework.excel.handler.RowFormatSetTextHandler;
import com.lideeyunji.tool.framework.excel.model.ExcelTitleModel;
import com.lideeyunji.tool.framework.excel.model.MoreSheetConfig;
import com.lideeyunji.tool.framework.exception.lideeYunJiException;
import com.lideeyunji.tool.framework.yunji.utils.FuncBase;
import org.apache.commons.collections4.map.LinkedMap;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.util.*;
public class ExcelExportUtils {
/**
* 封装表头信息
*
* @param headMap {name:姓名} {age:年龄}
* @return
*/
private static List<List<String>> getExcelHeaderList(LinkedMap<String, ExcelTitleModel> headMap) {
//处理头部
List<List<String>> head = new ArrayList<>();
headMap.forEach((code, model) -> {
List<String> headList = new ArrayList<>();
headList.add(model.getTitle());
head.add(headList);
});
return head;
}
/**
* 封装表数据
*
* @param headMap
* @param dataList name:张三age:18
* @return
*/
private static List<List<Object>> getExcelDataList(LinkedMap<String, ExcelTitleModel> headMap, List<Map<String, Object>> dataList) {
List<List<Object>> data = new ArrayList<>();
//处理数据
dataList.stream().forEach(dataMap -> {
List<Object> tmpList = new ArrayList<>();
headMap.forEach((code, title) -> {
Object tmpVal = dataMap.get(code);
try {
tmpList.add(FuncBase.json2Str(tmpVal));
} catch (Exception e) {
tmpList.add(tmpVal);
}
});
data.add(tmpList);
});
return data;
}
public static void exportExcel(HttpServletResponse response, String fileName, List<MoreSheetConfig> sheetConfigList) {
try {
if (FuncBase.isEmpty(sheetConfigList)) {
throw new lideeYunJiException("sheets数据不允许为空");
}
// 设置mime类型
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
// 设置编码
response.setCharacterEncoding("utf-8");
// 防止中文乱码
String outFileName = URLEncoder.encode(fileName, "UTF-8");
// 设置响应头信息 Content-disposition
response.setHeader("Content-disposition", "attachment;filename=" + outFileName + ".xlsx");
// 创建ExcelWriter
ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();
// 遍历每个sheet
for (MoreSheetConfig moreSheetConfig : sheetConfigList) {
List<Map<String, Object>> dataList = moreSheetConfig.getDataList();
LinkedMap<String, ExcelTitleModel> headMap = moreSheetConfig.getHeadMap();
String sheetName = moreSheetConfig.getSheetName();
if (FuncBase.isEmpty(headMap)) {
continue; // 跳过空表头的sheet
}
// 处理头部
List<List<String>> head = getExcelHeaderList(headMap);
// 处理表数据
List<List<Object>> data = getExcelDataList(headMap, dataList);
// 处理下拉内容
Map<Integer, List<String>> dropdownOptionsMap = getDropdownOptionsMap(headMap);
RowFormatSetTextHandler rowFormatSetTextHandler = new RowFormatSetTextHandler();
rowFormatSetTextHandler.setDropdownOptionsMap(dropdownOptionsMap);
// 创建WriteSheet
WriteSheet writeSheet = EasyExcel.writerSheet(sheetName)
.head(head)
.registerWriteHandler(rowFormatSetTextHandler)
.registerWriteHandler(new CustomSheetWriteHandler())
.registerWriteHandler(new CustomColumnWidthStyleStrategy())
.registerWriteHandler(CellStyleUtils.getCellStyleStrategy())
.build();
// 写入数据
excelWriter.write(data, writeSheet);
}
// 关闭ExcelWriter
excelWriter.finish();
} catch (Exception e) {
throw new lideeYunJiException(e.getMessage());
}
}
/**
* 处理下拉列表
*
* @param headMap
* @return
*/
private static Map<Integer, List<String>> getDropdownOptionsMap(LinkedMap<String, ExcelTitleModel> headMap) {
Map<Integer, List<String>> dropdownOptionsMap = new HashMap<>();
int index = 0; // 初始化序号变量
Iterator<Map.Entry<String, ExcelTitleModel>> iterator = headMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, ExcelTitleModel> entry = iterator.next();
ExcelTitleModel model = entry.getValue();
List<String> dropdownOptionList = model.getDropdownOptionList();
if (FuncBase.isNotEmpty(dropdownOptionList)) {
dropdownOptionsMap.put(index, dropdownOptionList);
}
++index;
}
return dropdownOptionsMap;
}
}

View File

@@ -0,0 +1,3 @@
artifactId=tool-spring-boot-starter-excel
groupId=com.lideeyunji
version=2.2.4

View File

@@ -0,0 +1,15 @@
com\lideeyunji\tool\framework\excel\core\annotations\DictFormat.class
com\lideeyunji\tool\framework\excel\handler\CustomSheetWriteHandler.class
com\lideeyunji\tool\framework\excel\listener\lideeYunJiExcelListener.class
com\lideeyunji\tool\framework\excel\write\CustomColumnWidthStyleStrategy.class
com\lideeyunji\tool\framework\excel\core\convert\MoneyConvert.class
com\lideeyunji\tool\framework\excel\read\ExcelImportUtils.class
com\lideeyunji\tool\framework\excel\model\ExcelTitleModel.class
com\lideeyunji\tool\framework\excel\model\MoreSheetConfig.class
com\lideeyunji\tool\framework\excel\core\convert\DictConvert.class
com\lideeyunji\tool\framework\excel\write\ExcelExportUtils.class
com\lideeyunji\tool\framework\excel\core\convert\JsonConvert.class
com\lideeyunji\tool\framework\excel\write\CellStyleUtils.class
com\lideeyunji\tool\framework\excel\core\util\ExcelUtils.class
com\lideeyunji\tool\framework\excel\lideeYunJiExcelUtils.class
com\lideeyunji\tool\framework\excel\handler\RowFormatSetTextHandler.class

View File

@@ -0,0 +1,16 @@
F:\java_project\hngryy_report\lidee-tool\tool-spring-boot-starter-excel\src\main\java\com\lideeyunji\tool\framework\excel\handler\CustomSheetWriteHandler.java
F:\java_project\hngryy_report\lidee-tool\tool-spring-boot-starter-excel\src\main\java\com\lideeyunji\tool\framework\excel\model\ExcelTitleModel.java
F:\java_project\hngryy_report\lidee-tool\tool-spring-boot-starter-excel\src\main\java\com\lideeyunji\tool\framework\excel\core\convert\JsonConvert.java
F:\java_project\hngryy_report\lidee-tool\tool-spring-boot-starter-excel\src\main\java\com\lideeyunji\tool\framework\excel\core\convert\DictConvert.java
F:\java_project\hngryy_report\lidee-tool\tool-spring-boot-starter-excel\src\main\java\com\lideeyunji\tool\framework\excel\write\CustomColumnWidthStyleStrategy.java
F:\java_project\hngryy_report\lidee-tool\tool-spring-boot-starter-excel\src\main\java\com\lideeyunji\tool\framework\excel\core\convert\MoneyConvert.java
F:\java_project\hngryy_report\lidee-tool\tool-spring-boot-starter-excel\src\main\java\com\lideeyunji\tool\framework\excel\read\ExcelImportUtils.java
F:\java_project\hngryy_report\lidee-tool\tool-spring-boot-starter-excel\src\main\java\com\lideeyunji\tool\framework\excel\write\CellStyleUtils.java
F:\java_project\hngryy_report\lidee-tool\tool-spring-boot-starter-excel\src\main\java\com\lideeyunji\tool\framework\excel\model\MoreSheetConfig.java
F:\java_project\hngryy_report\lidee-tool\tool-spring-boot-starter-excel\src\main\java\com\lideeyunji\tool\framework\excel\write\ExcelExportUtils.java
F:\java_project\hngryy_report\lidee-tool\tool-spring-boot-starter-excel\src\main\java\com\lideeyunji\tool\framework\excel\listener\lideeYunJiExcelListener.java
F:\java_project\hngryy_report\lidee-tool\tool-spring-boot-starter-excel\src\main\java\com\lideeyunji\tool\framework\excel\core\util\ExcelUtils.java
F:\java_project\hngryy_report\lidee-tool\tool-spring-boot-starter-excel\src\main\java\com\lideeyunji\tool\framework\excel\handler\RowFormatSetTextHandler.java
F:\java_project\hngryy_report\lidee-tool\tool-spring-boot-starter-excel\src\main\java\com\lideeyunji\tool\framework\excel\lideeYunJiExcelUtils.java
F:\java_project\hngryy_report\lidee-tool\tool-spring-boot-starter-excel\src\main\java\com\lideeyunji\tool\framework\excel\package-info.java
F:\java_project\hngryy_report\lidee-tool\tool-spring-boot-starter-excel\src\main\java\com\lideeyunji\tool\framework\excel\core\annotations\DictFormat.java