Asp.NET MVC 导入Excel数据教程详解

先上一张小弟的思路图:

(说明:没有安装做流程图的软件!凑合着看吧)


 

2 进入正题 

首先跟着小弟先创建一个默认的MVC项目(相信大家都会创建,这里就不演示了)


 

 

 第一步

 创建一个实体类,这个类是要导入数据库的对象。为了简单起见 小弟创建了个学生对象(记录了他的名字、年龄、各科成绩分数)。

 先声明这只是教学代码,完全是为了演示用的,你真正做产品的代码可没这么简单的定义实体。

public class Student
    {

       public Student()
       {
           Id = Guid.NewGuid();
       }

        //姓名
        public string Name { get; set; }

        //年龄
        public int Age { get; set; }

        //语文成绩
        public int ChineseScore { get; set; }
        //英文成绩
        public int EnglishScore { get; set; }

        //数学成绩
        public int MathScore { get; set; }
       24
}
 

第二步

实体创建完了,接下来我们创建一个Empty的控制器(名字取自己喜欢的),(这个也太简单了,我这里就不演示了)直接上结果:

 
public class UploadExcelController : Controller
  {
        // GET: /UploadExcel
        public ActionResult Index()
        {
            return View();
        }
  }

 第三步

控制器创建完了接下来做什么呢?估计你也猜到了,所有的不是从界面开始吗!用户访问/UploadExcel/Index 的时候总要出来个交互的东西吧。那就先创建一个交互的视图,光标移到return View();右键创建添加视图


 

 

创建视图有很多种方法,我这里只是选择了种简单的具体看个人习惯创建。

 视图创建完毕后,我们先构造一个浏览文件的html标记

 @{
    ViewBag.Title = "View";
}

<h1>Select the Excel file</h1>

<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>&nbsp;&nbsp;&nbsp;浏览文件
    </span>
</div>

 

  小弟这里使用的是MVC自带的bootstrap框架,相信大家也都能看懂,如果看不懂那些标记的话!建议你先花1天时间入门bootstap框架。

在上传文件到服务器有个常用的html标记是  <input id="fileUpload" type="file" >,没错小弟也用的这个标记,只是它太丑了我把它给隐藏了!用我上面的html标记给替换了。接下来我们开始创建它。

<h1>Select the Excel file</h1>

<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>&nbsp;&nbsp;&nbsp;浏览文件
    </span>
</div>

<br /><br />

@using (Html.BeginForm("Browse", "UploadExcel", FormMethod.Post, new { enctype = "multipart/form-data", id = "form_Upload" }))
{
    @Html.AntiForgeryToken() //防止跨站请求伪造(CSRF:Cross-site request forgery)攻击
    <input id="fileUpload" type="file" name="file" style="display:none"> //把fileUpload隐藏,原因它太难看了
}

 红色的代码是新增的,Html.BeginForm的扩展方法如果大家不熟悉的话,你就把它看成form表单,因为它最后会生成form表单

 <form  id="form_Upload" action="/UploadExcel/Browse" method="post"  enctype="multipart/form-data">

  .......

 </form>

  哦!这个是基础知识,相信大家也都知道,(题外话:在能使用@HTML扩展方法的时候,我建议大家不要使用原生的HTML标记,为什么呢?因为如果你了解@HTML扩展方法的运行机制的话你就知道我的用意了,   就比如Html.BeginForm它是根据路由去生成的URL,智能的!安全的!如果自己写原生HTML标记的话,难免会产生不安全的URL!)

 

  这个form表单就是我们把Excel文件上传到服务器用的,  

看见form表单的 action="/UploadExcel/Browse",所以我们还要在UploadExcelController控制器里创建第二个名称叫Browse的Action操作

public class UploadExcelController : Controller
 {
        // GET: /UploadExcel
        public ActionResult Index()
        {
            return View();
        }

       10
        [HttpPost]
        [ValidateAntiForgeryToken]
        [HandleError(View = "~/Views/Shared/Error.cshtml")]
        public ActionResult Browse(HttpPostedFileBase file)
        {

        }
}

 红色部分是我新增加的Action操作,前面说了竟然创建的form表单是上传文件到服务器的,那么这个操作就是处理上传文件用的Action,因为它会改变服务器状态,所以我定义成Post方法。其余2个特性是配合@Html扩展方法用的,一个是防止跨站请求伪造(CSRF:Cross-site request forgery)攻击,一个是统一处理异常页。你也可以不加,跟我们今天的例子没关系。我们先不写这个Action操作的代码,让我们再次回到我们创建的视图页 。

 
 竟然我们要使用 <input id="fileUpload" type="file" name="file">的功能,但是又嫌弃它太难看了!怎么办呢? So easy 只需把我们构造的html标记绑定它就行了。在视图页添加如下JS代码

@section scripts{

<script type="text/javascript">
$('input[id=fileUpload]').change(function () {
$('#txt_Path').val($(this).val());
$('#form_Upload').submit();
});

</script>}

 

 这段JS代码功能就是在<input id="fileUpload" type="file" name="file" style="display:none">选择文件后就把文件路径赋给我们自己构造的文本框里,然后就是提交表单,上传它的选择的文件到我们的服务器。

 请注意灰色那段代码是如何用我们自己构建的按钮绑定到fileUpload的功能上

1  @*浏览本地文件按钮*@
2 <span id="btn_Browse" style="cursor:pointer;" onclick="$('input[id=fileUpload]').click();" class="input-group-addon">
3 <i class="glyphicon glyphicon-folder-open"></i>&nbsp;&nbsp;&nbsp;浏览文件
4 </span>
 

为了浏览文件有响应的效果,我们在视图页加一小段CSS代码

@section scripts{

    <style type="text/css">
        #btn_Browse:hover {
            color: #3C763D;
        }
    </style>

    <script type="text/javascript">
        $('input[id=fileUpload]').change(function () {
            $('#txt_Path').val($(this).val());
            $('#form_Upload').submit();
        });

   
    </script>}
 

 第五步

 到了这里我们的文件已经可以上传到我们服务了,如果不信你在Browse操作打个断点,看看file参数是不是已经接受了文件,如果接受到了说明已经成功一半了!我们还是先不写Browse操作处理Excel文件的代码,焦点还是在视图页上,在本博客第一张效果图里,大家看到浏览文件下面有张table表格吗?小弟创建这个表格只是为了更好的交互效果,让使用的人更直观而已。而且也很简单!

 接下来我们来构建它,在视图页新增table表格的代码

@model Student
@using School.Entity

<table class="table  table-striped  table-hover table-bordered">
<tr>
<th>@Html.DisplayNameFor(model => model.Name)</th>
<th>@Html.DisplayNameFor(model => model.Age)</th>
<th>@Html.DisplayNameFor(model => model.ChineseScore)</th>
<th>@Html.DisplayNameFor(model => model.EnglishScore)</th>
<th>@Html.DisplayNameFor(model => model.MathScore)</th>
</tr>

@if (ViewBag.Data != null)
{
//生成前10条数据 填充表格table
foreach (var item in (ViewBag.Data as IEnumerable<Student>).Take(10))
{
<tr>
<td>@Html.DisplayFor(model => item.Name)</td>
<td>@Html.DisplayFor(model => item.Age)</td>
<td>@Html.DisplayFor(model => item.ChineseScore)</td>
<td>@Html.DisplayFor(model => item.EnglishScore)</td>
<td>@Html.DisplayFor(model => item.MathScore)</td>
</tr>
}
}
</table>
<h5 class="text-info">
默认显示前10条记录
</h5>

  在这里我依然用的@HTML辅助方法,如果你还不会使用它,赶紧花一天学习它,入门非常简单!非常强大! 设想如果没有@Html扩展方法 小弟得写多少硬编码啊!

这里的表头是英文的,如果你想变成中文的话,可以在实体上加上数据注解特性(如下)

 
public class Student
  {

        [Display(Name="中文成绩")]
        public int ChineseScore { get; set; }

   }

对了还忘了一个东西,就是上传提交按钮,我们现在来构建它!在视图页form表单下面添加如下代码

 
@using (Html.BeginForm("Browse", "UploadExcel", FormMethod.Post, new { enctype = "multipart/form-data", id = "form_Upload" }))
{
    @Html.AntiForgeryToken()
    <input id="fileUpload" type="file" name="file" style="display:none">
}

//红色部分是我构建的上传提交按钮
<div class="input-group pull-right" style="margin:0 0 5px 0">
    @Html.RouteLink("开始提交", new { action = "Upload" }, new { id="submit", @class = "btn  btn-primary ladda-button ", data_style = "expand-right" })
</div>

@Html.RouteLink扩展方法会根据我定义的路由生成一个<a>锚标签,最后生成如下html标记

  <a id="submit" class="btn  btn-primary ladda-button" data-style="expand-right" href="/UploadExcel/Upload" >开始提交</a>

 在这里我把它伪装成了一个button按钮

  data-style="expand-right"这些属性是我用bootstrap加了个5毛钱的特效,你也可以不用管,也可以使用自己的特效。这个上传提交按钮的功能就是最后一个功能,把经过Browse操作转换成List<T>的数  据导入到我们的数据库。到现在为止我们的导入Excel的页面已经全部完成了,当然我的审美观和前端技术就是渣渣,所以请原谅小弟! href="/UploadExcel/Upload" 这个<a>锚标签会访问UploadExcelController控制器的Upload操作,所以我再添加最后一个操作。在控制器添加如下代码

 
 public class UploadExcelController : Controller
{
// GET: /UploadExcel
public ActionResult Index()
{
return View();
}

[HttpPost]
[ValidateAntiForgeryToken]
[HandleError(View = "~/Views/Shared/Error.cshtml")]
public ActionResult Browse(HttpPostedFileBase file)
{

return null;
}

//红色部分是我新增的Action操作,这个操作的作用是把Browse操作转换好的List<T> 通过业务服务层 导入我们数据库
[HandleError(View = "~/Views/Shared/Error.cshtml")]
public ActionResult Upload()
{
return View("UploadSuccess"); //导入成功的页面 这个页面就留给大家自己设计吧
}

  }

 

 现在我们把重点放在Excel文件的逻辑处理上了,我们先从Browse操作下手,因为此操作负责把我们上传的Excel文件转换成List Entity对象,只要转换成这个集合对象你后面就可以想怎么插入就怎么插入了 !想插入MSSQL MYSQL 等不同数据都可以呵呵!因为我们用的ORM框架!

  按照我上传的那个思维图,我想我先处理验证!先判断文件的格式是不是Excel的格式。(Excel的格式是根据版本来的 2007-2010 是xlsx,2003是xls)这里我只默认了2007-2010 。

在Browse操作添加如下代码
 
[HttpPost]
        [ValidateAntiForgeryToken]
        [HandleError(View = "~/Views/Shared/Error.cshtml")]
        public ActionResult Browse(HttpPostedFileBase file)
        {

            if (string.Empty.Equals(file.FileName) || ".xlsx" != Path.GetExtension(file.FileName))
            {
                throw new ArgumentException("当前文件格式不正确,请确保正确的Excel文件格式!");
            }

            var severPath = this.Server.MapPath("/files/"); //获取当前虚拟文件路径

            var savePath = Path.Combine(severPath, file.FileName); //拼接保存文件路径

            try
            {
                file.SaveAs(savePath);
                stus = ExcelHelper.ReadExcelToEntityList<Student>(savePath);
                ViewBag.Data = stus;
                return View("Index");
            }
            finally
            {
                System.IO.File.Delete(savePath);//每次上传完毕删除文件
            }

        }

我在MVC项目的根目录创建了个files的文件夹,用来保存上传的Excel文件。然后读取文件转换成List Entity对象,然后把它传给我们创建的视图。这样就可以一选择Excel文件就把数据显示在页面上了,转换数据的核心是这句代码

  stus = ExcelHelper.ReadExcelToEntityList<Student>(savePath);

ExcelHelper是我自己封装的一个工具库,我现在来创建它。在根目录添加一个文件夹,然后添加一个类

ppublic class ExcelHelper
   {
   //Excel数据转List<T>
   public static IList<T> ReadExcelToEntityList<T>(string filePath) where T : class, new()
   {
   DataTable tbl = ReadExcelToDataTable(filePath);//读取Excel数据到DataTable
 
   IList<T> list = DataTableToList<T>(tbl);
 
   return list;
 
   }
 
   //Excel数据转DataTable 使用的oledb读取方式
   public static 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工作表
   DataTable table = new DataTable("TempTable");
   adapter.Fill(table);
   return table;
   }
 
 
   //DataTable转List<T>
   public static List<T> DataTableToList<T>(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))
   {
   object value = dr[pro.Name];
 
   value = Convert.ChangeType(value, pro.PropertyType);//强制转换类型
 
   //如果非空,则赋给对象的属性  PropertyInfo
   if (value != DBNull.Value)
   {
   pro.SetValue(t, value, null);
   }
   }
   }
   //对象添加到泛型集合中
   list.Add(t);
   }
 
   return list;
 
   }
   }

 

 代码很简单我就不翻译了,就是读取Excel数据转各种C#对象,但是这是教学代码不是产品代码,我很粗暴的封装了。你如果要用到生成环境,得还要加上各种逻辑验证和测试!

 

  写到这里,感觉最后一个功能把List<T>集合导入数据库大家应该都会,我就不想再继续往下写了。但是还是要说下注意的地方就是导入数据一定要支持事物回滚功能,就是哪怕前面已经导入了几十条数据了,如果发生一条脏数据导致插入异常,也必须回滚判定全部导入失败。避免重复导入,导致数据库脏数据。

 我贴最后导入数据库的代码就是Upload操作,我在DAL层是使用了事物处理的,支持回滚!

  

[HandleError(View = "~/Views/Shared/Error.cshtml")]
public ActionResult Upload()
{
var result= Ioc.Service.IocBll<IStudentBll>.Provide.Insert(stus);

if(string.Empty!=result.Success) 
ViewBag.Info = result.Info;

return View("UploadSuccess");

}

时间: 2024-11-02 02:40:45

Asp.NET MVC 导入Excel数据教程详解的相关文章

ASP.NET MVC中使用DropDownList地详解

在ASP.NET MVC中,尽管我们可以直接在页面中编写HTML控件,并绑定控件的属性,但更方便的办法还是使用HtmlHelper中的辅助方法.在View中,包含一个类型为HtmlHelper的属性Html,它为我们呈现控件提供了捷径.   我们今天主要来讨论Html.DropDownList的用法,首先从Html.TextBox开始. Html.TextBox有一个重载方法形式如下: public static string TextBox(this HtmlHelper htmlHelper

asp.net mvc4 导入excel数据到数据库显示进度条

问题描述 RT有数据在excel中,有多个sheet,每个sheet对应数据库一张表,怎么实现导入数据到数据库的时候显示百分比的进度,望各位大神指导,不甚感激.!!备注:不使用第三方上传控件 解决方案 本帖最后由 lz00728 于 2014-12-01 17:27:35 编辑解决方案二:顶解决方案三: 解决方案四: 解决方案五:没人知道怎么解决吗解决方案六:已导入数据条数/总数据条数可以吗解决方案七:引用5楼ZuoQingYi的回复: 已导入数据条数/总数据条数可以吗 关键就是不知道如何实时获

ASP.NET MVC DropDownList数据绑定及使用详解_实用技巧

一:DropDownList 1.1 DropDownList绑定数据 1.1.1 DropDownList 固定绑定 这种方式适合那些已经固定的数据绑定到DropDownList上. 例 复制代码 代码如下: <asp:DropDownList runat="server" ID="ddlArea" Width="120px" > <asp:Listitem value="0">选择性别</as

导入 excel 数据到数据库

问题描述 导入excel数据到数据库,一般都需要要求固定格式,导入前验证格式是否正确数据是否正确.关于空白行一般是由于将excel删除时只删除了数据未删除行造成的,怎么可以处理一下????能运行的具体代码?谢谢usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Web;usingSystem.Web.UI;usingSystem.Web.UI.WebControls;usingSystem.Data.O

结合bootstrap fileinput插件和Bootstrap-table表格插件,实现文件上传、预览、提交的导入Excel数据操作流程

1.bootstrap-fileinpu的简单介绍 在前面的随笔,我介绍了Bootstrap-table表格插件的具体项目应用过程,本篇随笔介绍另外一个Bootstrap FieInput插件的使用,整合两者可以实现我们常规的Web数据导入操作,导入数据操作过程包括有上传文件,预览数据,选择并提交记录等一系列操作. 关于这个插件,我在早期随笔<Bootstrap文件上传插件File Input的使用>也做了一次介绍,这是一个增强的 HTML5 文件输入控件,是一个 Bootstrap 3.x

ASP.NET MVC 5 - 将数据从控制器传递给视图

原文:ASP.NET MVC 5 - 将数据从控制器传递给视图 在我们讨论数据库和数据模型之前,让我们先讨论一下如何将数据从控制器传递给视图.控制器类将响应请求来的URL.控制器类是给您写代码来处理传入请求的地方,并从数据库中检索数据,并最终决定什么类型的返回结果会发送回浏览器.视图模板可以被控制器用来产生格式化过的HTML从而返回给浏览器. 控制器负责给任何数据或者对象提供一个必需的视图模板,用这个视图模板来Render返回给浏览器的HTML.最佳做法是:一个视图模板应该永远不会执行业务逻辑或

Struts2数据输入验证教程详解_java

一.前言 1.1.什么是输入验证?为什么需要输入验证? 在上一篇文章中,我们学习了数据类型转换,我们提到了表示层数据处理的两个方法,也提到了用户输入数据需要进行类型转换才能得到我们想要的数据,那么,我们怎么确定类型转换后的数据,是我们想要的数据呢?这里有点绕.你可以这样想:一个成年男子年龄是18岁,你现在想要得到18这个数据,但是,用户输入32,经过类型转换也是对的,但是数据不是你想要的.这时候,我们要怎么办?所以输入验证在这里就有用处了. 类型转换和输入验证的关系是:类型转换是输入验证的前提,

ASP.NET MVC中对数据进行排序的方“.NET研究”法

本系列是讲解如何在asp.net mvc中对数据进行展示.排序.分页等的系列文章.在上周的文章中,一步一步教会了大家如何使用ASP.NET MVC框架去的展示数据.在上周的文章中,我们先用Visual Studio创建了一个新的ASP.NET MVC应用程序,接着连接到了Northwind数据库,并展示了如何使用微软的LINQ-SQL的工具去访问数据库中的数据,接着指导如何去实现视图层去展示产品信息及如何设计控制器. 本文是在上一篇文章的例子基础上,展示了如何去实现数据的双向排序.如果你是已经熟

一起谈.NET技术,ASP.NET MVC中对数据进行排序的方法

本系列是讲解如何在asp.net mvc中对数据进行展示.排序.分页等的系列文章.在上周的文章中,一步一步教会了大家如何使用ASP.NET MVC框架去的展示数据.在上周的文章中,我们先用Visual Studio创建了一个新的ASP.NET MVC应用程序,接着连接到了Northwind数据库,并展示了如何使用微软的LINQ-SQL的工具去访问数据库中的数据,接着指导如何去实现视图层去展示产品信息及如何设计控制器. 本文是在上一篇文章的例子基础上,展示了如何去实现数据的双向排序.如果你是已经熟