Files
juipnet/Infrastructure/Hncore.Infrastructure/Common/ExcelHelper.cs

644 lines
24 KiB
C#
Raw Normal View History

2024-04-10 13:55:27 +08:00
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;
using AngleSharp;
using AngleSharp.Dom;
using Hncore.Infrastructure.Data;
using Hncore.Infrastructure.Extension;
using Microsoft.AspNetCore.Mvc;
using NPOI.HSSF.UserModel;
namespace Hncore.Infrastructure.Common
{
public static class ExcelHelper
{
public static async Task<Stream> GetStreamFromHtml(string html)
{
MemoryStream ms = new MemoryStream();
HSSFWorkbook book = new HSSFWorkbook();
var context = BrowsingContext.New(Configuration.Default);
var document = await context.OpenAsync(req => req.Content(html));
try
{
var tables = document.GetElementsByTagName("table");
foreach (var table in tables)
{
var sheetName = table.GetAttribute("sheetname");
var sheet = book.CreateSheet(sheetName);
var trs = table.GetElementsByTagName("tr");
var rowIndex = 0;
foreach (var tr in trs)
{
var row = sheet.CreateRow(rowIndex);
var tds = tr.GetElementsByTagName("td");
var columnIndex = 0;
foreach (var td in tds)
{
row.CreateCell(columnIndex).SetCellValue(td.InnerHtml.Trim());
columnIndex++;
}
rowIndex++;
}
}
book.Write(ms);
ms.Position = 0;
}
finally
{
document.Close();
document.Dispose();
context.Active.Close();
context.Active.Dispose();
document = null;
context = null;
book.Clear();
book.Close();
book = null;
}
return ms;
}
public static async Task ResponseExcelFromHtml(this ControllerBase controllerBase, string fileName, string html)
{
using (var ms = await GetStreamFromHtml(html))
{
var bytes = ms.StreamToBytes();
var response = controllerBase.HttpContext.Response;
response.ContentType = "application/octet-stream";
response.Headers.Add("Content-Disposition", $"attachment; filename={fileName.UrlEncode()}");
response.Headers.Add("X-Suggested-Filename", fileName.UrlEncode());
response.Headers.Add("Content-Length", bytes.Length.ToString());
await response.Body.WriteAsync(bytes, 0, bytes.Length);
await response.Body.FlushAsync();
}
}
/// <summary>
/// excel二进制文件转二维string结合
/// </summary>
/// <param name="stream"></param>
/// <param name="st"></param>
/// <returns></returns>
public static List<List<string>> ReadFromStream(Stream stream, int st = 0)
{
//根据路径通过已存在的excel来创建HSSFWorkbook即整个excel文档
HSSFWorkbook workbook;
try
{
workbook = new HSSFWorkbook(stream);
}
catch (Exception ex)
{
LogHelper.Error("ReadFromStream",ex);
throw new BusinessException("文件读取错误!");
}
List<List<string>> lis1 = new List<List<string>>();
{
//获取excel的第一个sheet
var sheet = workbook.GetSheetAt(st);
if (sheet == null)
throw new BusinessException("该文件内没有包含任何工作簿");
//获取sheet的首行
var headerRow = sheet.GetRow(0);
//一行最后一个方格的编号 即总的列数
int cellCount = headerRow.LastCellNum;
try
{
for (int i = 0; i <= sheet.LastRowNum; i++)
{
List<string> lis = new List<string>();
var row = sheet.GetRow(i);
if (row == null)
continue;
for (int j = 0; j < cellCount; j++)
{
var cell = row.GetCell(j);
if (cell == null)
{
lis.Add("");
continue;
}
try
{
switch (cell.CellType)
{
case NPOI.SS.UserModel.CellType.Unknown:
lis.Add("Unknown");
break;
case NPOI.SS.UserModel.CellType.Numeric:
if (HSSFDateUtil.IsCellDateFormatted(cell))//对日期格式进行特殊对待
lis.Add(HSSFDateUtil.GetJavaDate(cell.NumericCellValue).ToString());
else
lis.Add(cell.NumericCellValue.ToString());
break;
case NPOI.SS.UserModel.CellType.String:
lis.Add(cell.StringCellValue.ToString());
break;
case NPOI.SS.UserModel.CellType.Formula:
lis.Add(cell.CellFormula.ToString());
break;
case NPOI.SS.UserModel.CellType.Blank:
lis.Add("");
break;
case NPOI.SS.UserModel.CellType.Boolean:
lis.Add(cell.BooleanCellValue.ToString());
break;
case NPOI.SS.UserModel.CellType.Error:
lis.Add(cell.ErrorCellValue.ToString());
break;
default:
break;
}
}
catch
{
lis.Add("");
}
}
//如果本行所有单元格都是空,就跳过本行
if (lis.All(item => string.IsNullOrEmpty(item)))
continue;
lis1.Add(lis);
}
}
catch(Exception ex)
{
LogHelper.Error("ReadFromStream", ex);
throw new BusinessException("文件格式错误!");
}
}
#region
lis1 = lis1.Where(s => !s.TrueForAll(f => string.IsNullOrWhiteSpace(f))).ToList();//去除全是空格的空行。
lis1 = lis1.Select(s => s = s.Select(y => y = y.Trim()).ToList()).ToList();//去除空格
if (lis1.Count == 1) throw new Exception("Excel中无有效数据");
#endregion
return lis1;
}
/// <summary>
/// 导出列表到excel
/// 导出到sheet的数据一致
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="excelData">每一个sheet的数据</param>
/// <param name="excelTitle">列表的属性和名称值</param>
/// <returns></returns>
public static byte[] ExportListToExcel<T>(List<ExcelData<T>> excelData, List<ExcelTitle> excelTitle)
{
var workbook = new NPOI.XSSF.UserModel.XSSFWorkbook();
var entityType = typeof(T);
PropertyInfo[] entityProperties = entityType.GetProperties();
if (excelData == null || excelData.Count == 0)
{
return null;
}
try
{
foreach (var item in excelData)
{
#region MyRegion
//var sheet = workbook.CreateSheet(item.SheetName.Replace('/','-'));
//var titleRow = sheet.CreateRow(0);
//for (int i = 0; i < excelTitle.Count; i++)
//{
// titleRow.CreateCell(i).SetCellValue(excelTitle[i].Title);
//}
//var sheetData = item.Data;
//for (int j = 0; j < sheetData.Count; j++)
//{
// var dataRow = sheet.CreateRow(j + 1);
// for (int i = 0; i < excelTitle.Count; i++)
// {
// if (excelTitle[i].Property.ToUpper().Equals("ID"))
// {
// var num = j + 1;
// dataRow.CreateCell(i).SetCellValue(num);
// continue;
// }
// var entityProperty = entityProperties.FirstOrDefault(m => m.Name == excelTitle[i].Property);
// var cellVal = entityProperty?.GetValue(sheetData[j]);
// if (cellVal?.GetType().Name == "DateTime")
// {
// dataRow.CreateCell(i).SetCellValue(((DateTime?)cellVal)?.ToString("yyyy/MM/dd HH:mm:ss"));
// }
// else
// {
// dataRow.CreateCell(i).SetCellValue(cellVal?.ToString());
// }
// //dataRow.CreateCell(i).SetCellValue(cellVal?.ToString());
// }
//}
#endregion
CreateSheetData(workbook, item, excelTitle, entityProperties);
}
using (var ms = new MemoryStream())
{
workbook.Write(ms);
var bytes = ms.ToArray();
return bytes;
}
}
catch(Exception ex)
{
LogHelper.Error("ExportListToExcel=>" + ex);
throw ex;
}
finally
{
workbook.Clear();
workbook.Close();
workbook = null;
}
}
public static byte[] ExportListToExcel<T>(ExcelData<T> excelData, List<ExcelTitle> excelTitle)
{
var workbook = new NPOI.XSSF.UserModel.XSSFWorkbook();
var entityType = typeof(T);
PropertyInfo[] entityProperties = entityType.GetProperties();
try
{
#region MyRegion
//var sheet = workbook.CreateSheet(excelData.SheetName.Replace('/', '-'));
//var titleRow = sheet.CreateRow(0);
//for (int i = 0; i < excelTitle.Count; i++)
//{
// titleRow.CreateCell(i).SetCellValue(excelTitle[i].Title);
//}
//var sheetData = excelData.Data;
//for (int j = 0; j < sheetData.Count; j++)
//{
// var dataRow = sheet.CreateRow(j + 1);
// for (int i = 0; i < excelTitle.Count; i++)
// {
// var cellVal = entityProperties.FirstOrDefault(m => m.Name == excelTitle[i].Property)?.GetValue(sheetData[j]);
// if (cellVal?.GetType().Name == "DateTime")
// {
// dataRow.CreateCell(i).SetCellValue(((DateTime?)cellVal)?.ToString("yyyy/MM/dd HH:mm:ss"));
// }
// else
// {
// dataRow.CreateCell(i).SetCellValue(cellVal?.ToString());
// }
// }
//}
#endregion
CreateSheetData(workbook, excelData, excelTitle, entityProperties);
using (var ms = new MemoryStream())
{
workbook.Write(ms);
var bytes = ms.ToArray();
return bytes;
}
}
catch (Exception ex)
{
LogHelper.Error("ExportListToExcel=>" + ex);
throw ex;
}
finally
{
workbook.Clear();
workbook.Close();
workbook = null;
}
}
/// <summary>
/// 创建excel表单数据
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="workbook"></param>
/// <param name="excelData"></param>
/// <param name="excelTitle"></param>
/// <param name="entityProperties"></param>
private static void CreateSheetData<T>(NPOI.XSSF.UserModel.XSSFWorkbook workbook,
ExcelData<T> excelData, List<ExcelTitle> excelTitle,PropertyInfo[] entityProperties)
{
var sheet = workbook.CreateSheet(excelData.SheetName.Replace('/', '-'));
var titleRow = sheet.CreateRow(0);
for (int i = 0; i < excelTitle.Count; i++)
{
titleRow.CreateCell(i).SetCellValue(excelTitle[i].Title);
}
var sheetData = excelData.Data;
for (int j = 0; j < sheetData.Count; j++)
{
var dataRow = sheet.CreateRow(j + 1);
for (int i = 0; i < excelTitle.Count; i++)
{
var currentTitle = excelTitle[i];
if (currentTitle.Property.Equals("序号"))
{
var num = j + 1;
dataRow.CreateCell(i).SetCellValue(num);
continue;
}
var cellVal = entityProperties.FirstOrDefault(m => m.Name == currentTitle.Property)?.GetValue(sheetData[j]);
if (currentTitle.Format != null)
{
cellVal = currentTitle.Format(cellVal);
}
if (currentTitle.Expr != null)
{
cellVal = currentTitle.Expr(sheetData[j]);
}
else if (cellVal?.GetType().Name == "DateTime")
{
dataRow.CreateCell(i).SetCellValue(((DateTime?)cellVal)?.ToString("yyyy/MM/dd HH:mm:ss"));
}
dataRow.CreateCell(i).SetCellValue(cellVal?.ToString());
}
}
}
#region DownloadAsync()
/// <summary>
/// 下载
/// </summary>
/// <param name="stream">流</param>
/// <param name="fileName">文件名,包含扩展名</param>
public static async Task DownloadAsync(this ControllerBase controllerBase, Stream stream, string fileName)
{
await DownloadAsync(controllerBase,stream, fileName, Encoding.UTF8);
}
/// <summary>
/// 下载
/// </summary>
/// <param name="stream">流</param>
/// <param name="fileName">文件名,包含扩展名</param>
/// <param name="encoding">字符编码</param>
public static async Task DownloadAsync(this ControllerBase controllerBase, Stream stream, string fileName, Encoding encoding)
{
stream.Seek(0, SeekOrigin.Begin);
var buffer = new byte[stream.Length];
stream.Read(buffer, 0, buffer.Length);
await DownloadAsync(controllerBase, buffer, fileName, encoding);
}
/// <summary>
/// 下载
/// </summary>
/// <param name="bytes">字节流</param>
/// <param name="fileName">文件名,包含扩展名</param>
public static async Task DownloadAsync(this ControllerBase controllerBase, byte[] bytes, string fileName)
{
await DownloadAsync(controllerBase,bytes, fileName, Encoding.UTF8);
}
/// <summary>
/// 下载
/// </summary>
/// <param name="bytes">字节流</param>
/// <param name="fileName">文件名,包含扩展名</param>
/// <param name="encoding">字符编码</param>
public static async Task DownloadAsync(this ControllerBase controllerBase,byte[] bytes, string fileName, Encoding encoding)
{
var response = controllerBase.HttpContext.Response;
if (bytes == null || bytes.Length == 0)
return;
fileName = fileName.Replace(" ", "");
fileName = HttpUtility.UrlEncode(fileName, encoding);
response.ContentType = "application/octet-stream";
response.Headers.Add("Content-Disposition", $"attachment; filename={fileName}");
response.Headers.Add("Content-Length", bytes.Length.ToString());
response.Headers.Add("X-Suggested-Filename", fileName);
await response.Body.WriteAsync(bytes, 0, bytes.Length);
await response.Body.FlushAsync();
}
#endregion
}
public class ExcelTitle
{
/// <summary>
/// 导出数据对应的 属性字段名
/// </summary>
public string Property { get; set; }
/// <summary>
/// excel 的title
/// </summary>
public string Title { get; set; }
public Func<object, object> Format { get; set; }
public Func<object, object> Expr { get; set; }
}
public class ExcelData<T>
{
/// <summary>
/// 导出数据对应的 属性字段名
/// </summary>
public string SheetName { get; set; }
/// <summary>
/// excel 的title
/// </summary>
public List<T> Data { get; set; }
}
#region Excel导入验证
/// <summary>
/// Excel导入验证
/// </summary>
public static class ValidForExcel
{
/// <summary>
/// 解析字符串到int32、double、datetime...
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="str"></param>
/// <param name="rowNo"></param>
/// <param name="message"></param>
/// <param name="isCanNullOrEmpty"></param>
/// <param name="isPositiveOrZero">自然数0,1,2,3...</param>
/// <returns></returns>
public static T ValidParseStr<T>(string str,string message = "数据", bool isCanNullOrEmpty = true, bool isPositiveOrZero = true)
{
var val = default(T);
if (string.IsNullOrEmpty(str))
{
if (isCanNullOrEmpty)
{
return default(T);
}
else
{
throw new Exception($"{message}不能为空");
}
}
else
{
if (typeof(T).Name == typeof(int).Name || typeof(T).FullName == typeof(int?).FullName)
{
if (int.TryParse(str, out var valueInt))
{
if (isPositiveOrZero && valueInt < 0)
{
goto error;
}
return (T)Convert.ChangeType(valueInt, TypeCode.Int32);
}
else
{
goto error;
}
}
if (typeof(T).Name == typeof(Decimal).Name || typeof(T).FullName == typeof(Decimal?).FullName)
{
if (Decimal.TryParse(str, out var valueInt))
{
if (isPositiveOrZero && valueInt < 0)
{
goto error;
}
return (T)Convert.ChangeType(valueInt, TypeCode.Decimal);
}
else
{
goto error;
}
}
if (typeof(T).Name == typeof(Double).Name || typeof(T).FullName == typeof(Double?).FullName)
{
if (Double.TryParse(str, out var valueInt))
{
if (isPositiveOrZero && valueInt < 0)
{
goto error;
}
return (T)Convert.ChangeType(valueInt, TypeCode.Double);
}
else
{
goto error;
}
}
if (typeof(T).Name == typeof(Single).Name || typeof(T).FullName == typeof(Single?).FullName)
{
if (Single.TryParse(str, out var valueInt))
{
if (isPositiveOrZero && valueInt < 0)
{
goto error;
}
return (T)Convert.ChangeType(valueInt, TypeCode.Single);
}
else
{
goto error;
}
}
if (typeof(T).Name == typeof(DateTime).Name || typeof(T).FullName == typeof(DateTime?).FullName)
{
if (DateTime.TryParse(str, out var valueInt))
{
return (T)Convert.ChangeType(valueInt, TypeCode.DateTime);
}
else
{
goto error;
}
}
}
return val;
error: throw new Exception($"{message}的值有误");
}
/// <summary>
/// 提供正则、提示信息,返回验证结果
/// </summary>
/// <param name="str"></param>
/// <param name="rowNo"></param>
/// <param name="pattern"></param>
/// <param name="message"></param>
/// <param name="isCanNullOrEmpty"></param>
/// <returns></returns>
public static string ValidByPattern(string str,string pattern, string message = "数据", bool isCanNullOrEmpty = true)
{
if (string.IsNullOrEmpty(str))
{
if (isCanNullOrEmpty)
{
return str;
}
else
{
throw new BusinessException($"{message}不能为空");
}
}
else
{
if (!Regex.IsMatch(str, pattern)) throw new BusinessException($"{message}输入有误");
return str;
}
}
/// <summary>
/// 根据枚举判断
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="str"></param>
/// <param name="message"></param>
/// <param name="isCanNullOrEmpty"></param>
/// <returns></returns>
public static int? ValidByEnum<T>(string str, string message, bool isCanNullOrEmpty = true) //where T:Enum
{
if (string.IsNullOrEmpty(str))
{
if (isCanNullOrEmpty)
{
return null;
}
else
{
throw new BusinessException($"{message}不能为空");
}
}
else
{
var value = EnumExtension.EnumToList<T>().Find(s => s.Name == str)?.Value;
if (value == null) throw new BusinessException($"未知的数据:{str}");
return Convert.ToInt32(value);
}
}
}
#endregion
}