Asp.NET MVC 匯入Excel資料教程詳解

來源:互聯網
上載者:User

先上一張小弟的思路圖:

(說明:沒有安裝做流程圖的軟體!湊合著看吧)


 

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");

}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.