环境VS2022+.NET6,Nuget引用包NPOI(2.5.6)
创建类ExcelHelper
using NPOI.SS.UserModel;
using NPOI.SS.Util;
using NPOI.XSSF.UserModel;
namespace Demo.Common
{
public class ExcelHelper
{
/// <summary>
/// 获取Excel模板
/// </summary>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public XSSFWorkbook GetTemplate()
{
string typeSheetName = "Type";
//列名集合
var clmList = GetColumnTitileList();
//下拉选项字典集合
var ddlDic = GetDDLDic();
//创建工作簿
XSSFWorkbook workbook = new XSSFWorkbook();
//创建模板Sheet页
ISheet useSheet = workbook.CreateSheet("导入模板");
//创建下拉框Sheet页并隐藏
ISheet typeSheet = workbook.CreateSheet(typeSheetName);
workbook.SetSheetHidden(workbook.GetSheetIndex(typeSheet), true);
//创建下拉框Sheet页行
IRow row = useSheet.CreateRow(0);
int maxRowNum = ddlDic.Max(t => t.Value.Count);
for (int i = 0; i < maxRowNum + 1; i++)
{
IRow typeRow = typeSheet.CreateRow(i);
}
if (clmList == null || clmList.Count == 0)
throw new Exception("列名集合不能为空");
//循环每一列进行添加操作
for (int i = 0; i < clmList.Count; i++)
{
//在模板页添加表头
row.CreateCell(i).SetCellValue(clmList[i]);
//如果再下拉框字典中存在这个列则需要将值放到下拉框Sheet页里面,然后在模板页绑定下拉框并加上验证
if (ddlDic.ContainsKey(clmList[i]))
{
IRow tmpRow = typeSheet.GetRow(0);
tmpRow.CreateCell(i).SetCellValue(clmList[i]);
string[] tmpArr = ddlDic[clmList[i]].ToArray();
for (int j = 0; j < tmpArr.Length; j++)
{
typeSheet.GetRow(j + 1).CreateCell(i).SetCellValue(tmpArr[j]);
}
string colName = GetExcelColumnName(i + 1);
XSSFDataValidationHelper dvHelper = new XSSFDataValidationHelper(useSheet as XSSFSheet);
XSSFDataValidationConstraint dvConstraint = (XSSFDataValidationConstraint)dvHelper.CreateFormulaListConstraint(string.Format("{2}!${0}$2:${0}${1}", colName, tmpArr.Length+1, typeSheetName));
CellRangeAddressList cellRegions = new CellRangeAddressList(1, 500, i, i);
XSSFDataValidation validation = (XSSFDataValidation)dvHelper.CreateValidation(dvConstraint, cellRegions);
validation.SuppressDropDownArrow = true;
validation.CreateErrorBox("输入不合法", "请选择下拉列表中的值。");
validation.ShowErrorBox = true;
useSheet.AddValidationData(validation);
}
}
useSheet.DefaultColumnWidth = 20;
return workbook;
}
/// <summary>
/// 构建下拉选项的数据--测试数据,手动构建,可以替换成从数据库取数
/// </summary>
/// <returns></returns>
private Dictionary<string, List<string>> GetDDLDic()
{
Dictionary<string, List<string>> keyValues = new Dictionary<string, List<string>>();
keyValues.Add("年级", new List<string>() { "一年级", "二年级", "三年级" });
keyValues.Add("性别", new List<string>() { "男", "女" });
keyValues.Add("学校", new List<string>() { "学校1", "学校2", "学校3", "学校4" });
return keyValues;
}
/// <summary>
/// 获取Excel标题行名称集合
/// </summary>
/// <returns></returns>
private List<string> GetColumnTitileList()
{
return new List<string>() { "学号", "姓名", "性别", "学校", "年级" };
}
/// <summary>
/// 获取Excel列名
/// </summary>
/// <param name="columnNumber">列的序号,如:A、B、C、AA、BB</param>
/// <returns></returns>
private static string GetExcelColumnName(int columnNumber)
{
int dividend = columnNumber;
string columnName = String.Empty;
int modulo;
while (dividend > 0)
{
modulo = (dividend - 1) % 26;
columnName = Convert.ToChar(65 + modulo).ToString() + columnName;
dividend = (int)((dividend - modulo) / 26);
}
return columnName;
}
}
}
创建控制器TemplateController
using Demo.Common;
using Microsoft.AspNetCore.Mvc;
namespace Demo.Controllers
{
public class TemplateController : Controller
{
public IActionResult Index()
{
return View();
}
/// <summary>
/// 下载模板
/// </summary>
/// <returns></returns>
public FileResult Download()
{
var workbook = new ExcelHelper().GetTemplate();
var ms = new NpoiMemoryStream();
ms.AllowClose = false;
workbook.Write(ms);
ms.Flush();
ms.Seek(0, SeekOrigin.Begin);
ms.AllowClose = true;
string filename = "模板" + "_" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + ".xlsx";
return File(ms, "application/vnd.ms-excel", filename);
}
}
}
添加类NpoiMemoryStream
namespace Demo.Common
{
public class NpoiMemoryStream : MemoryStream
{
public NpoiMemoryStream()
{
AllowClose = true;
}
public bool AllowClose { get; set; }
public override void Close()
{
if (AllowClose)
base.Close();
}
}
}