创建一个.NET Web API项目,这里使用的是.NET Core 3.1框架,导出Excel这里使用开源组件NPOI,常规的导入导出,肯定得不陌生,今天,我们讲一讲,复杂的单元格合并,样式如下:

Android 简单的table合并单元格_net

 可以看到,设备类型,这一块是一个合并的,那么在.NET Core中,如何实现呢?通过SQL语句,我们得到如下的数据:

Android 简单的table合并单元格_System_02



 

  1.  我们首先第一步,查询出数据,记作【equipmentResps】
List<EquipmentResp> equipmentResps = _equipmentService.GetEquipmentResps().ToList();
  1. 使用NPOI手动创建一个Excel,引入NPOI,本次使用NPOI, Version=2.5.3.0

    完整导出代码如下:
//创建Workbook
IWorkbook workbook = new HSSFWorkbook();
//创建一个sheet
workbook.CreateSheet("设备管理");
//设置一个随机用户名
string path = $"{Guid.NewGuid().ToString()}.xls";
//找到当前项目所在文件夹,需要注入IWebHostEnvironment
string filePath = $"{_webHostEnvironment.ContentRootPath}\\Export\\";
if (!System.IO.Directory.Exists(filePath))
 {
   Directory.CreateDirectory(filePath);
 }
using (FileStream fs = System.IO.File.Create(filePath + path))
{
  ISheet sheet = workbook.GetSheetAt(0);//获取sheet
  IRow rowHeader = sheet.CreateRow(0);
   //创建头部
  rowHeader.CreateCell(0).SetCellValue("设备类型");
  rowHeader.CreateCell(1).SetCellValue("设备分类");
 rowHeader.CreateCell(2).SetCellValue("设备数量(台)"); rowHeader.CreateCell(3).SetCellValue("完好设备数量(台)");
rowHeader.CreateCell(4).SetCellValue("完好率(%)");
//创建头部样式和列宽度
 ICellStyle titleStyle = workbook.CreateCellStyle();
  titleStyle.Alignment = HorizontalAlignment.Center; // 居中
 IFont titleFont = workbook.CreateFont();
  titleFont.IsBold = true;
   titleFont.FontHeightInPoints = 12;
 titleFont.Color = HSSFColor.Black.Index;//设置字体颜色
    titleStyle.SetFont(titleFont);
heet.GetRow(0).GetCell(0).CellStyle = titleStyle;
sheet.GetRow(0).GetCell(1).CellStyle = titleStyle;
sheet.GetRow(0).GetCell(2).CellStyle = titleStyle;
sheet.GetRow(0).GetCell(4).CellStyle = titleStyle;
sheet.SetColumnWidth(0, 3000);
sheet.SetColumnWidth(1, 3000);
sheet.SetColumnWidth(2, 5000);
sheet.SetColumnWidth(3, 5000);
sheet.SetColumnWidth(4, 4000);
    //创建内容样式
ICellStyle style = workbook.CreateCellStyle();
style.Alignment = HorizontalAlignment.Center;
style.VerticalAlignment = VerticalAlignment.Center; ;//垂直居中   
IFont font = workbook.CreateFont();
font.IsBold = false;
font.FontHeightInPoints = 12;
font.Color = HSSFColor.Black.Index;
 style.SetFont(font);
//赋值
for (int i = 0; i < equipmentResps.ToList().Count(); i++)
 {
IRow rowData = sheet.CreateRow(i + 1);
rowData.CreateCell(0).SetCellValue(equipmentResps[i].type);
if (!keyValues.ContainsKey(equipmentResps[i].type))
{
  keyValues.Add(equipmentResps[i].type, equipmentResps[i].type);
}
rowData.GetCell(0).CellStyle = style;
rowData.CreateCell(1).SetCellValue(equipmentResps[i].Grade);
rowData.GetCell(1).CellStyle = style; rowData.CreateCell(2).SetCellValue(equipmentResps[i].Number);
rowData.GetCell(2).CellStyle = style;
rowData.CreateCell(3).SetCellValue(equipmentResps[i].perfectNumber);
rowData.GetCell(3).CellStyle = style;
rowData.CreateCell(4).SetCellValue(equipmentResps[i].IntactRate.ToString() + "%");
rowData.GetCell(4).CellStyle = style;
 }
  foreach (var item in keyValues)
{
    int start = equipmentResps.IndexOf(equipmentResps.FirstOrDefault(x => x.type == item.Key));
    int end = equipmentResps.IndexOf(equipmentResps.LastOrDefault(x => x.type == item.Key));
     sheet.AddMergedRegion(new CellRangeAddress(start + 1, end + 1, 0, 0));
}
   MemoryStream ms = new MemoryStream();
   workbook.Write(ms);
   ms.Seek(0, SeekOrigin.Begin);
   string fileName = $"{DateTime.Now.ToString("yyyy-MM")}设备完好率.xls";
   return File(ms, "application/vnd.ms-excel", fileName);
 }

  1. 合并单元格子解析

通过NPOI官网,我们可以看到,合并单元格,需要使用AddMergedRegion函数,AddMergedRegion有四个参数,

分别是:【开始行、结束行、开始列、结束列】,其实很好记,就是从哪一行开始,合并到哪一行,包含那些列,通过对上面excel分析,我们得出【电气设备】在第2行,记作N,需要合并3行,即N+1,其余需要合并的以此类推,我们可以通过代码做如下分析:

// Dictionary<string, string> keyValues = new Dictionary<string, string>();
//keyValues 里面其实只记录了type的值,通过循环这个值,进行合并
foreach (var item in keyValues)
{
//IndexOf 找到列表出现相同信息的下标,使用FirstOrDefault是为了找到第一次出现此数据的行号
 int start = equipmentResps.IndexOf(equipmentResps.FirstOrDefault(x => x.type == item.Key));
//同样的方式,通过LastOrDefault是为了找到第=最后一次出现此数据的行号
 int end = equipmentResps.IndexOf(equipmentResps.LastOrDefault(x => x.type == item.Key));
//然后使用NPOI合并的方式进行合并,因为本次我们都是出现在第一列(excel从0开始),所以后面两个参数都
//是0
 sheet.AddMergedRegion(new CellRangeAddress(start + 1, end + 1, 0, 0));
}

前端可以使用<a>标签,比如【<a href='我们部署的接口地址'>导出</a>】可直接导出,也可以使用请求接口,然后回调的方式进行导出。