- 通过已下步骤进行写入如有报错或缺少方法请在下方留言
- 我这里使用的是Sql Server数据库
- EXCEL文件里面的标题字段必须和代码写的字段一样否则查找不到该字段
- 数据库字段的限制:比如说你的数据库有5个字段,但是插入数据时候EXCEL只有四个字段,那么空的那个字段,一定要允许为空哦!!否则会插不进去的!!
- 大家只需要修改参数和引用,其他逻辑方法不用修改,如果您有把握可以修改再修改
- 如果您修改完参数和数据后还有方法报错,应该是您没有引用方法的命名空间,如有其他方法缺少请下方留言或私我我会更新
- 还是以我的练习数据库为例已下为大家详细展示
1、首先下面这张图片是我把数据库的数据通过MVC展示到HTML上
2、我们需要一个类,新建一个类ExcelCsvHelp(名字起什么无所谓),里面包含生成下载文档的方法和各种方法,我会在代码中给大家注释(如果报错可能是缺少引用,添加一下引用就可以了)代码直接复制贴进去就好,只需添加引用!
using ARC.Common.Extend;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
namespace ARC.Common.Help
{
/// <summary>
/// 导出CSV下载文件帮助类
/// </summary>
public static class ExcelCsvHelp
{
#region 第一种导出CSV文件 封装 只需要传入集合,标题,绑定的列名
/// <summary>
/// 生成下载文件CSV
/// </summary>
/// <typeparam name="T">泛型实体类必须为可实例化类型</typeparam>
/// <param name="list">数据集合</param>
/// <param name="titles">标题</param>
/// <param name="bindName">绑定的字段或属性名称,支持子属性字段</param>
/// <returns></returns>
public static byte[] GenerateFileContent<T>(List<T> list, string[] titles, string[] bindName) where T : new()
{
//获取到泛型的类型,通过类型可以拿到所有的属性和字段
var modelType = typeof(T);
var columnModels = bindName.Select(name => GetTypeByName(modelType, name.Split(".").ToList(), null)).ToList();
Func<T, List<string>> bindRowFunc = (m) =>
{
return columnModels.Select(item => GetValueByModel(item, m)).ToList();
};
return GenerateFileContent(list, titles, bindRowFunc);
}
/// <summary>
/// 根据实体和对应的列属性获取内容(递归算法)
/// </summary>
/// <param name="columnModel">列实体</param>
/// <param name="model">实体</param>
/// <returns></returns>
private static string GetValueByModel(ExportCsvColumnModel columnModel, object model)
{
//如果实体为空直接返回空
if (model == null)
{
return string.Empty;
}
//先获取字段或属性的内容
var value = columnModel.Type == 1 ? columnModel.PropertyInfo.GetValue(model) : columnModel.FieldInfo.GetValue(model);
//判断是否有子级,如果有子级的话直接递归接着取内容,如果没有直接直接value返回
var result = columnModel.IsChildren ? GetValueByModel(columnModel.Children, value) : value?.ToString();
return result;
}
/// <summary>
/// 根据字段或属性名称获取类型
/// </summary>
/// <param name="type">类型</param>
/// <param name="names">字段名称集合上下级关系索引列越大约在下方</param>
/// <param name="model">返回的数据集</param>
/// <returns></returns>
private static ExportCsvColumnModel GetTypeByName(Type type, List<string> names, ExportCsvColumnModel model)
{
//设置死循环
while (true)
{
if (!names.Any())
{
return null;
}
var name = names[0];
if (string.IsNullOrEmpty(name))
{
return null;
}
//声明本次会产生的对象
ExportCsvColumnModel thisModel;
//根据name 获取属性
var prop = type.GetProperty(name);
//设置字段
FieldInfo field = null;
//属性不为空
if (prop != null)
{
//该名称被检索未属性
thisModel = new ExportCsvColumnModel() { ColumnName = name, Type = 1 };
}
else
{
//获取字段
field = type.GetField(name);
//字段为空,属性和字段全部未检索到抛出异常
if (field == null)
{
throw new Exception($"在类型:{type?.FullName}下未检索到,指定名称:{name}的属性或字段");
}
//查到了字段
thisModel = new ExportCsvColumnModel() { ColumnName = name, Type = 0 };
}
//设置属性和字段
thisModel.PropertyInfo = prop;
thisModel.FieldInfo = field;
//父级属性或字段为空,则自己就是父级
if (model == null)
{
model = thisModel;
}
else
{
//设置有子级,并设置子级对应的属性还是字段
model.IsChildren = true;
model.Children = thisModel;
}
//是否未最后一级
if (names.Count == 1)
{
//最后一级直接返回内容
return model;
}
else
{
//还有子级先获取本次查询的属性或字段,他们为下次循环的父级
var t = prop == null ? field.FieldType : prop.PropertyType;
//清除第一个节点为下次循环准备
names.RemoveAt(0);
//设置下次循环的类型
type = t;
}
}
}
#endregion
/// <summary>
/// 生成下载文档
/// </summary>
/// <typeparam name="T">泛型实体类必须为可实例化类型</typeparam>
/// <param name="list">数据集合</param>
/// <param name="titles">标题</param>
/// <param name="bindRowFunc">绑定每行的数据</param>
/// <returns></returns>
public static byte[] GenerateFileContent<T>(List<T> list, string[] titles, Func<T, List<string>> bindRowFunc) where T : new()
{
var userExportRowFormatter = string.Join(",", titles.Select((m, i) => $"\"{{{i}}}\"")) + "\n";
var sb = new StringBuilder(string.Format(userExportRowFormatter, titles));
if (list != null)
{
foreach (var item in list)
{
if (bindRowFunc != null && item != null)
{
var values = bindRowFunc(item).ToArray();
if (titles.Length != values.Length)
{
throw new Exception("内容数量与标题数量不相同,请检查设置内容和标题。");
}
sb.AppendFormat(userExportRowFormatter, values);
}
}
}
var buffer = Encoding.Default.GetBytes(sb.ToString());
GC.Collect();
return Encoding.Convert(Encoding.Default, Encoding.UTF8, buffer).ToUTF8BOM();
}
/// <summary>
/// 获取csv文件名字
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public static string GetFileName(string fileName = "")
{
fileName = string.IsNullOrWhiteSpace(fileName) ? DateTime.Now.Ticks.ToString() : fileName;
return $"{DateTime.Now.ToARCBjTime().ToARCDateString()}-{fileName}.csv";
}
/// <summary>
/// 转为string 类型并增加\t
/// </summary>
/// <param name="val"></param>
/// <returns></returns>
public static string AddT(this string val)
{
return $"{val}\t";
}
/// <summary>
/// 转为string 类型并增加\t
/// </summary>
/// <param name="val"></param>
/// <returns></returns>
public static string ToStringAddT<T>(this T val) where T : struct
{
return val.ToString().AddT();
}
}
public class ExportCsvColumnModel
{
/// <summary>
/// 属性或字段名
/// </summary>
public string ColumnName { get; set; }
/// <summary>
/// 类型 是属性还是字段(1属性 2字段)
/// </summary>
public int Type { get; set; }
/// <summary>
/// 字段
/// </summary>
public FieldInfo FieldInfo { get; set; }
/// <summary>
/// 属性
/// </summary>
public PropertyInfo PropertyInfo { get; set; }
/// <summary>
/// 是否存在子级
/// </summary>
public bool IsChildren { get; set; }
/// <summary>
/// 子级的信息
/// </summary>
public ExportCsvColumnModel Children { get; set; }
}
}
3、刚才那几个类生成成功之后我们开始进行接口方法的编写,在Controllers文件夹中新建一个控制器,或者在你原有的控制器中写入已下方法。注意里面的where方法在第4点里面,如果不需要筛选可以自行调整去掉where方法
//导出EXCEL方法,里面的参数分别是分页查询的参数和我要搜索或下载的条件(看不懂参数的话算是白学了)
public async Task<ActionResult> PrintInvoiceToExcel(int pageIndex = 1, int pageSize = 20, string SearchTitle = "", string Telephone = "", string CompanyName = "", string Department = "", string Position = "", string Email = "", string Scale = "")
{
string[] headline = { "用户ID", "姓名", "电话", "密码", "公司名称", "公司规模", "部门", "职位", "图片", "邮箱", "注册时间", "状态", "修改时间" };
var headLine = new List<string>();
//查询的条件
var where = GetWhere1(SearchTitle, Telephone, CompanyName, Department, Position, Email, Scale);
var startIndex = (pageIndex - 1) * pageSize;
//生成一个根据你的实体生成的新对象
var db = await (from m in dbContext.User_tbs
select new User_tb()
{
//id
Id = m.Id,
//名字
Name = m.Name,
//电话
Telephone = m.Telephone,
//密码
Password = m.Password,
//公司名称
CompanyName = m.CompanyName,
//公司规模
Scale = m.Scale,
//部门
Department = m.Department,
//职位
Position = m.Position,
//图片
ImgUrl = m.ImgUrl,
//邮箱
Email = m.Email,
//注册时间
RegisterTime = m.RegisterTime,
//状态
userid = m.userid,
//修改时间
UpdateTime = m.UpdateTime,
}).Where(where).ToListAsync();
//下面这个里面字段的顺序必须和上方你写的字段顺序一致,否则就会数据混乱
var ms = ExcelCsvHelp.GenerateFileContent(db, headline, (item) => new List<string>()
{
//把数据映射到表中
//"用户ID", "姓名", "电话", "密码", "公司名称", "公司规模", "部门","职位","图片","邮箱","注册时间", "状态", "修改时间"
item.Id.ToString(),
item.Name.ToString(),
item.Telephone.ToString(),
item.Password.ToString(),
item.CompanyName.ToString(),
item.Scale == "10148"?"20人以下":(item.Scale == "10149"?"50-100人":(item.Scale == "10154"?"100-500人":"500-1000人")),
item.Department.ToString(),
item.Position.ToString(),
item.ImgUrl.ToString(),
item.Email.ToString(),
item.RegisterTime.ToString(),
item.userid == 0?"不显示":"显示",
item.UpdateTime.ToString()
});
if (ms != null)
{
var fileName = "练习—" + ExcelCsvHelp.GetFileName();
Response.Headers.Add("Content-Length", ms.Length.ToString());
return File(ms, "application/ms-excel", fileName);
}
else
{
return Content("");
}
}
4、在上面那个方法的下面再加一个条件方法,也就是上面的Where1方法上面那个代码里面有用到过。再次声明:如果您不需要条件,想直接全部下载的话,可以把上面条件方法去掉。下面这个方法也不用写了。方法如下:
//参数是我数据库里面有的参数,我通过目录树表达式的方法生成条件,可以查找自己所需要的,从而省略我们不需要的提高效率
public Expression<Func<User_tb, bool>> GetWhere1(string Name = "", string Telephone = "", string CompanyName = "", string Department = "", string Position = "", string Email = "", string Scale = "")
{
//声明一个初始的表达式目录树
Expression<Func<User_tb, bool>> where = b => b.userid > -1;
//如果传过来的参数不是空的
if (!string.IsNullOrEmpty(Name))
{
where = where.And(b => b.Name == Name);
}
if (!string.IsNullOrEmpty(Telephone))
{
where = where.And(b => b.Telephone.Contains(Telephone));
}
if (!string.IsNullOrEmpty(CompanyName))
{
where = where.And(b => b.CompanyName.Contains(CompanyName));
}
if (!string.IsNullOrEmpty(Department))
{
where = where.And(b => b.Department.Contains(Department));
}
if (!string.IsNullOrEmpty(Position))
{
where = where.And(b => b.Position.Contains(Position));
}
if (!string.IsNullOrEmpty(Email))
{
where = where.And(b => b.Email == Email);
}
if (!string.IsNullOrEmpty(Scale))
{
where = where.And(b => b.Scale == Scale);
}
return where;
}
6、做出以上几步后,如果没有报错那么就可以正常使用了,您可以通过一些事件来调用第三步的那个方法,从而实现把数据库的东西导出成EXCEL中的SVC格式