Asp.net Core MVC 导出execl
Asp.net Core MVC 导出execl
分享话语
之前不知道做了多少导入导出文档的功能,最熟悉的就是 通过post提交到后台,后台语言来处理。不过遇到很坑,博文写的很少,还请大家多多指教,一起学习,共同进步。
来吧,先上图
说一下功能,点击导入,选择要导入的exel文档,把execl中的文档插入到数据库中,在显示到页面中
- 首先说一下思路哈
-
A 通过
<input type='file'>
表单form 来提交文档到后台 - B 后台接收文档,保存到服务器
- C 对文档进行处理,拿到数据,存储到数据
前台代码
@*
For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860
*@
@{
ViewData["Title"] = "经营计划";
var date = ViewBag.dateTime;
}
@section Header{
<style>
tr td {
border:1px solid black;
}
td {
text-align:center;
height:40px;
}
tbody input {
width:100%;
border:none;
height:100%;
text-align:center;
}
.boxtobdy {
border:2px solid red;
}
</style>
}
<section class="content">
<div class="box box-success condition">
<div class="box-header with-border">
<h5 class="box-title"><i class="fa fa-book"></i> 查询条件</h5>
</div>
<!-- 查询条件表单 -->
<div class="box-body">
<div class="row">
<input type="hidden" id="reportname" name="reportname" value="" />
<input type="hidden" id="htmlTableStr" name="htmlTableStr" value="" />
<div class="col-md-3">
<div class="input-group">
<div class="input-group-addon">
<i class="fa"><span>计划年份</span></i>
</div>
<div>
<input class="layui-input" id="datetime" name="datetime" value="@date" onfocus="WdatePicker({ dateFmt: 'yyyy', readOnly: true });" type="text">
</div>
</div>
</div>
<div class="col-md-1">
<button class="btn btn-primary" type="button" id="btnSearch"><i class='fa fa-search'></i>查询</button>
</div>
@*<div class="col-md-4">
<div class="input-group ">
<input id="txt_Path" type="text" class="form-control">
<span id="btn_Browse" style="cursor:pointer;" onclick="$('input[id=fileUpload]').click();" class="input-group-addon">
<i class="glyphicon glyphicon-folder-open"></i> 浏览文件
</span>
</div>
</div>*@
<div class="col-md-1">
<form id="exelform" enctype="multipart/form-data" method="post" action="/Operate/Report/ExportExecl" >
<input id="fileUpload" type="file" name="file" style="display:none">
<button class="btn btn-primary" type="button" id="btnReport"><i class='fa fa-search'></i>导入</button>
</form>
</div>
<div class="col-md-2">
<button class="btn btn-primary" type="button" id="btnEdit"><i class='fa fa-pencil'></i>编辑(开始、结束)</button>
</div>
</div>
</div>
</div>
<form id="planSubmit" name="planSubmit" method="post" action="/Operate/Report/SubmitProdPlan">
<div class="box result tab-content" style="border-top:0" id="review">
<table id="prodplan" style="width:100%">
<thead>
<tr>
<td rowspan="2" style="width:200px">年月</td>
<td colspan="2">能源生产计划</td>
<td colspan="3">能源消耗计划</td>
<td colspan="8">经营计划</td>
</tr>
<tr>
<td>发电(kWh)</td>
<td>供冷(kWh)</td>
<td>耗气(Nm3)</td>
<td>耗电(kWh)</td>
<td>耗水(Nm3)</td>
<td>收入计划(元)</td>
<td>支出计划(元)</td>
<td>边际贡献计划(元)</td>
<td>补贴收入(元)</td>
<td>固定成本(元)</td>
<td>人工成本(元)</td>
<td>四项费用(元)</td>
<td>管理费用(元)</td>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</form>
</section>
@section Scripts{
<script src="~/lib/My97DatePicker/WdatePicker.js"></script>
<script src="~/js/web/operate/report/prodplan.js"></script>
<script src="~/lib/jquery-other/jquery.form.js"></script>
<script src="~/lib/moment/moment.js"></script>
}
脚注
这里说明一下,因为原本的<input type='file'>
很丑,基本上没有愿意用,所有把他给隐藏了,只是一个承载文档容器,用form 提交到后台,在这里我遇到很多问题,给大家展示一下
先上图
注意:这里如果用 HttpPostedFileBase 来接收的话,会报错,因为这个是ASP.net FrameWork 支持的方法,先给大家展示一下错误,如下图
看到没有,练后台都不会进,直接就报错,在给你们截一下后台调试的图片
经过仔细研究.Net Core 里面没有HttpPostedFileBase 这个类,所以不能用这个方法接收,后来,我用想,要不要用HttpContext 来接收一下,看行不行,继续上图
换成HttpContext 来试试,看看能不能得到execl文档,调试走去
同样不进后台直接报错,错误信息如上图,面对这个问题,我查看关于.net Core 的资料,终于懂了,把正确的代码贴个大家,如下:
/// <summary>
/// execl导入
/// </summary>
/// <returns></returns>
[HttpPost]
public ActionResult ExportExecl()
{
var file = Request.Form.Files;
var filename = ContentDispositionHeaderValue.Parse(file[0].ContentDisposition).FileName.Trim('"');
if (string.Empty.Equals(filename) || ".xlsx" != Path.GetExtension(filename))
{
throw new ArgumentException("当前文件格式不正确,请确保正确的Excel文件格式!");
}
var severPath = FileHelper.MapPath("~/wwwroot/prodplanfile/");//获取当前虚拟文件路径
var savePath = Path.Combine(severPath, filename); //拼接保存文件路径
try
{
using (FileStream fs = System.IO.File.Create(savePath))
{
file[0].CopyTo(fs);
fs.Flush();
}
var stus = ReadExcelToEntityList<prodplan>(savePath);//插入数据
if (stus != null)
{
string time = stus[0].plan_date;
ViewBag.dateTime = Convert.ToDateTime(time).ToString("yyyy");
}
return View("PordPlan");
}
finally
{
System.IO.File.Delete(savePath);//每次上传完毕删除文件
}
}
注意:这用不用给方法带什么参数,直接用 Request.Form.Files 就能接收到你想要的文档,这个就Core类库的改变,第一个问题算是解决了。还有就是 把文件保存在服务器上不能用file.save()方法了,要换种思维using (FileStream fs = System.IO.File.Create(savePath))
这样可以了。
{
file[0].CopyTo(fs);
fs.Flush();
}
下面的问题就好说了,贴代码
把execl中的数据读取到table中
/// <summary>
/// 把Execl中的代码读取到table中
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="filePath"></param>
/// <returns></returns>
public IList<T> ReadExcelToEntityList<T>(string filePath) where T : class, new()
{
System.Data.DataTable tbl = ReadExcelToDataTable(filePath);//读取Excel数据到DataTable
IList<T> list = DataTableToList<T>(tbl);
return list;
}
//Excel数据转DataTable 使用的oledb读取方式
public System.Data.DataTable ReadExcelToDataTable(string filePath)
{
if (filePath == string.Empty) throw new ArgumentNullException("路径参数不能为空");
string ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0; Persist Security Info=False;Data Source=" + filePath + "; Extended Properties='Excel 8.0;HDR=Yes;IMEX=1'";
OleDbDataAdapter adapter = new OleDbDataAdapter("select * From[Sheet1$]", ConnectionString); //默认读取的Sheet1,你也可以把它封装变量,动态读取你的Sheet工作表
System.Data.DataTable table = new System.Data.DataTable("TempTable");
adapter.Fill(table);
System.Data.DataTable newTable = new System.Data.DataTable();
newTable = table.Clone();//克伦架子
foreach (DataColumn col in newTable.Columns)
{
if (col.DataType.FullName == "System.Double")
{
col.DataType = Type.GetType("System.Decimal");
}
}
newTable.Columns["计划日期"].ColumnName = "plan_date";
newTable.Columns["发电量"].ColumnName = "power";
newTable.Columns["供冷"].ColumnName = "cooling";
//table.Columns["供冷"].DataType = Type.GetType("System.Decimal");
newTable.Columns["耗气"].ColumnName = "gas_consumption";
//table.Columns["耗气"].DataType = Type.GetType("System.Decimal");
newTable.Columns["耗电"].ColumnName = "power_consumption";
//table.Columns["耗电"].DataType = Type.GetType("System.Decimal");
newTable.Columns["耗水"].ColumnName = "water_consumption";
//table.Columns["耗水"].DataType = Type.GetType("System.Decimal");
newTable.Columns["收入计划"].ColumnName = "income_plan";
//table.Columns["收入计划"].DataType = Type.GetType("System.Decimal");
newTable.Columns["支出计划"].ColumnName = "expenditure_paln";
//table.Columns["支出计划"].DataType = Type.GetType("System.Decimal");
newTable.Columns["边际贡献计划"].ColumnName = "contribution";
//table.Columns["边际贡献计划"].DataType = Type.GetType("System.Decimal");
newTable.Columns["供热量"].ColumnName = "heatingload";
//table.Columns["供热量"].DataType = Type.GetType("System.Decimal");
newTable.Columns["供蒸汽"].ColumnName = "steam_supply";
//table.Columns["供蒸汽"].DataType = Type.GetType("System.Decimal");
newTable.Columns["供热水"].ColumnName = "heatingwater";
//table.Columns["供热水"].DataType = Type.GetType("System.Decimal");
newTable.Columns["耗蒸汽"].ColumnName = "steam_consumption";
//table.Columns["耗蒸汽"].DataType = Type.GetType("System.Decimal");
newTable.Columns["补贴收入"].ColumnName = "subincome";
//table.Columns["补贴收入"].DataType = Type.GetType("System.Decimal");
newTable.Columns["固定成本"].ColumnName = "fixedcost";
//table.Columns["固定成本"].DataType = Type.GetType("System.Decimal");
newTable.Columns["人工成本"].ColumnName = "labourcost";
//table.Columns["人工成本"].DataType = Type.GetType("System.Decimal");
newTable.Columns["四项成本"].ColumnName = "fourcost";
//table.Columns["四项成本"].DataType = Type.GetType("System.Decimal");
newTable.Columns["管理费用"].ColumnName = "managecost";
//table.Columns["管理费用"].DataType = Type.GetType("System.Decimal");
newTable.Columns.Add("year");
newTable.Columns.Add("month");
//往新的table中添加数据
foreach (DataRow row in table.Rows)
{
DataRow rowNew = newTable.NewRow();
rowNew["plan_date"] = row["计划日期"];
rowNew["power"] = row["发电量"];
rowNew["cooling"] = row["供冷"];
rowNew["gas_consumption"] = row["耗气"];
rowNew["power_consumption"] = row["耗电"];
rowNew["water_consumption"] = row["耗水"];
rowNew["income_plan"] = row["收入计划"];
rowNew["expenditure_paln"] = row["支出计划"];
rowNew["contribution"] = row["边际贡献计划"];
rowNew["heatingload"] = row["供热量"];
rowNew["steam_supply"] = row["供蒸汽"];
rowNew["heatingwater"] = row["供热水"];
rowNew["steam_consumption"] = row["耗蒸汽"];
rowNew["subincome"] = row["补贴收入"];
rowNew["fixedcost"] = row["固定成本"];
rowNew["labourcost"] = row["人工成本"];
rowNew["fourcost"] = row["四项成本"];
rowNew["managecost"] = row["管理费用"];
rowNew["year"] = row["计划日期"].ToString().Split('-')[0];
rowNew["month"] = Convert.ToInt32(row["计划日期"].ToString().Split('-')[1]).ToString();
newTable.Rows.Add(rowNew);
}
return newTable;
}
注意:因为execl中的列类型和实体列的类型不一致,所有我特意新建一个datatable,把列的类型也顺便修改了
//DataTable转List<T>
public List<T> DataTableToList<T>(System.Data.DataTable dt) where T : class, new()
{
if (dt == null) return null;
List<T> list = new List<T>();
//遍历DataTable中所有的数据行
foreach (DataRow dr in dt.Rows)
{
T t = new T();
PropertyInfo[] propertys = t.GetType().GetProperties();
foreach (PropertyInfo pro in propertys)
{
//检查DataTable是否包含此列(列名==对象的属性名)
if (dt.Columns.Contains(pro.Name))
{
try
{
if (pro.Name == "year")
{
object value = dr["plan_date"];
//value = Convert.ChangeType(value, pro.PropertyType);//强制转换类型
//如果非空,则赋给对象的属性 PropertyInfo
if (value != DBNull.Value)
{
string year = value.ToString().Trim().Split('-')[0];
pro.SetValue(t, year, null);
}
}
else if (pro.Name == "month")
{
object value = dr["plan_date"];
//value = Convert.ChangeType(value, pro.PropertyType);//强制转换类型
//如果非空,则赋给对象的属性 PropertyInfo
if (value != DBNull.Value)
{
string month = Convert.ToInt32(value.ToString().Trim().Split('-')[1]).ToString();
pro.SetValue(t, month, null);
}
}
else
{
object value = dr[pro.Name];
if (value != null)
{
//value = Convert.ChangeType(value, pro.PropertyType);//强制转换类型
//如果非空,则赋给对象的属性 PropertyInfo
if (value != DBNull.Value)
{
if (pro.PropertyType.FullName == "System.String")
{
pro.SetValue(t, Convert.ToString(value), null);
}
else
{
pro.SetValue(t, Convert.ToDecimal(value), null);
}
//if (pro.PropertyType.FullName == "System.Decimal")
//{
//}
}
}
}
}
catch (Exception ex)
{
throw;
}
}
}
//对象添加到泛型集合中
list.Add(t);
}
return list;
}
注意:不能使用value = Convert.ChangeType(value, pro.PropertyType);//强制转换类型
这样强转的话会报错,要改成if (pro.PropertyType.FullName == "System.String") { pro.SetValue(t, Convert.ToString(value), null); }
这种方式去写,就会避免报错。
好了,就写到这里了,第一次,写的不好,请大家见谅!这个编辑器还没有用熟,多写写可能就好了。
欢迎大家批评和指导!
推荐阅读
-
ASP.NET Core MVC(一)
-
Asp.net Core MVC 导出execl
-
从零开始实现ASP.NET Core MVC的插件式开发(五) - 插件的删除和升级
-
从零开始实现ASP.NET Core MVC的插件式开发(六) - 如何加载插件引用
-
从零开始实现ASP.NET Core MVC的插件式开发(四) - 插件安装
-
.NET Core 1.0学习(4)粗略看了一下ASP.NET Core MVC例子
-
asp.net core mvc 表单太重
-
asp.net core mvc 入门demo
-
ASP.NET中 Execl导出的六种方法实例
-
ASP.NET中使用开源组件NPOI快速导入导出Execl数据