Asp.NET MVC 導入Excel數據教程 手把手教你系列!!!

来源:http://www.cnblogs.com/Lxy-/archive/2016/08/21/5791721.html
-Advertisement-
Play Games

小弟最近接了個大學生的畢業設計,收了100塊錢讓做一個ASP.NET MVC導入Excel到資料庫的功能,由於以前沒做過就到處搜索資料,但是發現網上的資料不是直接貼一大堆亂起八遭的源碼,就是需要借用NPOI第三方類庫太麻煩了,況且預算才100RMB簡直不值得,所以小弟嘗試自己動手豐衣足食,所以就有了 ...




先上效果圖



1.引言


    小弟最近接了個大學生的畢業設計,收了100塊錢讓做一個ASP.NET MVC導入Excel到資料庫的功能,由於以前沒做過就到處搜索資料,但是發現網上的資料不是直接貼一大堆亂起八遭的源碼,就是需要借用NPOI第三方類庫太麻煩了,況且預算才100RMB簡直不值得,所以小弟嘗試自己動手豐衣足食,所以就有了這篇博客。

    先上一張小弟的思路圖:

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

      

 

2 進入正題

 


 

首先跟著小弟先創建一個預設的MVC項目(相信大家都會創建,這裡就不演示了)

 

 第一步

 創建一個實體類,這個類是要導入資料庫的對象。為了簡單起見 小弟創建了個學生對象(記錄了他的名字、年齡、各科成績分數)。

 先聲明這隻是教學代碼,完全是為了演示用的,你真正做產品的代碼可沒這麼簡單的定義實體。

 1  public class Student
 2     {
 3 
 4        public Student()
 5        {
 6            Id = Guid.NewGuid();
 7        }
 8 
 9         //姓名
10         public string Name { get; set; }
11 
12         //年齡
13         public int Age { get; set; }
14 
15         //語文成績
16         public int ChineseScore { get; set; }
17 //英文成績 19 public int EnglishScore { get; set; } 20 21 //數學成績 22 public int MathScore { get; set; } 23 24 25 }

 

第二步

實體創建完了,接下來我們創建一個Empty的控制器(名字取自己喜歡的),(這個也太簡單了,我這裡就不演示了)直接上結果:

 

小弟在這裡創建了個名為UploadExcelController的控制器

1  public class UploadExcelController : Controller
2   {
3         // GET: /UploadExcel
4         public ActionResult Index()
5         {
6             return View();
7         }
8   }

  第三步

    控制器創建完了接下來做什麼呢?估計你也猜到了,所有的不是從界面開始嗎!用戶訪問/UploadExcel/Index 的時候總要出來個交互的東西吧。那就先創建一個交互的視圖,游標移到return View();右鍵創建添加視圖

     

 

      

 

      創建視圖有很多種方法,我這裡只是選擇了種簡單的具體看個人習慣創建。

      視圖創建完畢後,我們先構造一個瀏覽文件的html標記

      

 1 @{
 2     ViewBag.Title = "View";
 3 }
 4 
 5 <h1>Select the Excel file</h1>
 6 
 7 
 8 <div class="input-group ">
 9      @*文件路徑的文本框*@
10     <input id="txt_Path" type="text" class="form-control">  
11 
12      @*瀏覽本地文件按鈕*@
13     <span id="btn_Browse" style="cursor:pointer;" onclick="$('input[id=fileUpload]').click();" class="input-group-addon">
14         <i class="glyphicon glyphicon-folder-open"></i>&nbsp;&nbsp;&nbsp;瀏覽文件
15     </span>
16 </div>

 

          小弟這裡使用的是MVC自帶的bootstrap框架,相信大家也都能看懂,如果看不懂那些標記的話!建議你先花1天時間入門bootstap框架。

    這個時候的效果圖應該是這樣的

    

       在上傳文件到伺服器有個常用的html標記是  <input id="fileUpload" type="file" >,沒錯小弟也用的這個標記,只是它太醜了我把它給隱藏了!用我上面的html標記給替換了。接下來我們開始創建它。

 

 

 1 <h1>Select the Excel file</h1>
 2 
 3 
 4 <div class="input-group ">
 5      @*文件路徑的文本框*@
 6     <input id="txt_Path" type="text" class="form-control">  
 7 
 8      @*瀏覽本地文件按鈕*@
 9     <span id="btn_Browse" style="cursor:pointer;" onclick="$('input[id=fileUpload]').click();" class="input-group-addon">
10         <i class="glyphicon glyphicon-folder-open"></i>&nbsp;&nbsp;&nbsp;瀏覽文件
11     </span>
12 </div>
13 
14 <br /><br />
15 
16 
17 @using (Html.BeginForm("Browse", "UploadExcel", FormMethod.Post, new { enctype = "multipart/form-data", id = "form_Upload" }))
18 {
19     @Html.AntiForgeryToken() //防止跨站請求偽造(CSRF:Cross-site request forgery)攻擊
20     <input id="fileUpload" type="file" name="file" style="display:none"> //把fileUpload隱藏,原因它太難看了
21 }

 

   紅色的代碼是新增的,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操作

 1 public class UploadExcelController : Controller
 2  {
 3         // GET: /UploadExcel
 4         public ActionResult Index()
 5         {
 6             return View();
 7         }
 8 
 9        10 
11         [HttpPost]
12         [ValidateAntiForgeryToken]
13         [HandleError(View = "~/Views/Shared/Error.cshtml")]
14         public ActionResult Browse(HttpPostedFileBase file)
15         {
16 
17         }
18 }

     紅色部分是我新增加的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>

 

現在就來測試下我們寫的代碼能不能跑!F5運行!如果是以下效果就是正確的

 

 

 

為了瀏覽文件有響應的效果,我們在視圖頁加一小段CSS代碼

 1 @section scripts{
 2 
 3 
 4     <style type="text/css">
 5         #btn_Browse:hover {
 6             color: #3C763D;
 7         }
 8     </style>
 9 
10     <script type="text/javascript">
11         $('input[id=fileUpload]').change(function () {
12             $('#txt_Path').val($(this).val());
13             $('#form_Upload').submit();
14         });
15 
16 
17     
18     </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擴展方法 小弟得寫多少硬編碼啊!

     

然後再次按F5運行先看看效果

 

 

           這裡的表頭是英文的,如果你想變成中文的話,可以在實體上加上數據註解特性(如下)

                 

1 public class Student
2   {
3 
4         [Display(Name="中文成績")]
5         public int ChineseScore { get; set; }
6 
7    }

 

 

 

        對了還忘了一個東西,就是上傳提交按鈕,我們現在來構建它!在視圖頁form表單下麵添加如下代碼

      

1 @using (Html.BeginForm("Browse", "UploadExcel", FormMethod.Post, new { enctype = "multipart/form-data", id = "form_Upload" }))
2 {
3     @Html.AntiForgeryToken()
4     <input id="fileUpload" type="file" name="file" style="display:none"> 
5 }
6 
//紅色部分是我構建的上傳提交按鈕 7 <div class="input-group pull-right" style="margin:0 0 5px 0"> 8 @Html.RouteLink("開始提交", new { action = "Upload" }, new { id="submit", @class = "btn btn-primary ladda-button ", data_style = "expand-right" }) 9 </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"); //導入成功的頁面 這個頁面就留給大家自己設計吧
        }

      }

 

 

          現在我們來檢查下我們構造好的頁面,F5運行。如果是下麵的樣子我們就全部完成視圖頁面了

         

 

  

     現在我們把重點放在Excel文件的邏輯處理上了,我們先從Browse操作下手,因為此操作負責把我們上傳的Excel文件轉換成List Entity對象,只要轉換成這個集合對象你後面就可以想怎麼插入就怎麼插入了 !想插入MSSQL MYSQL 等不同數據都可以呵呵!因為我們用的ORM框架!

      按照我上傳的那個思維圖,我想我先處理驗證!先判斷文件的格式是不是Excel的格式。(Excel的格式是根據版本來的 2007-2010 是xlsx,2003是xls)這裡我只預設了2007-2010 。

      在Browse操作添加如下代碼

      

 1         [HttpPost]
 2         [ValidateAntiForgeryToken]
 3         [HandleError(View = "~/Views/Shared/Error.cshtml")]
 4         public ActionResult Browse(HttpPostedFileBase file)
 5         {
 6 
 7             if (string.Empty.Equals(file.FileName) || ".xlsx" != Path.GetExtension(file.FileName))
 8             {
 9                 throw new ArgumentException("當前文件格式不正確,請確保正確的Excel文件格式!");
10             }
11 
12             var severPath = this.Server.MapPath("/files/"); //獲取當前虛擬文件路徑
13 
14             var savePath = Path.Combine(severPath, file.FileName); //拼接保存文件路徑
15 
16             try
17             {
18                 file.SaveAs(savePath);
19                 stus = ExcelHelper.ReadExcelToEntityList<Student>(savePath);
20                 ViewBag.Data = stus;
21                 return View("Index");
22             }
23             finally
24             {
25                 System.IO.File.Delete(savePath);//每次上傳完畢刪除文件
26             }
27 
28         }

 

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

        }

 

 

 


 

完畢 

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 對makefile文件的要點作了總結,包括變數、表達式、函數、規則等方面,並介紹了make命令的相關用法。 ...
  • 參考:www.cnblogs.com/forstudy/archive/2012/04/05/2433853.html 一 進程與線程 進程: 系統中程式執行和資源分配的基本單位 每個進程有自己的數據段、代碼段和堆棧段 在進行切換時需要有比較複雜的上下文切換 線程: 線程有獨立的棧段/errno/線 ...
  • Tomcat需要JDK的支持,所以安裝Tomcat前先安裝JDK。 一、首先到JDK官網下載與自己機器相應的JDK。註意機器位數,Linux系統的話可以用uname -a命令查看系統信息,如果是Ubuntu的系統,下載尾碼為.tar.gz的就行。 我64位的機器下的是這個JDK:wget http: ...
  • 1 位置 使用vim /usr/sysconfig/iptables 2 啟動、關閉、保存 service iptables stop service iptables start service iptables restart service iptables save 3 結構 iptable... ...
  • 環境 CentOS 7內核版本為 3.10.0-327.el7.x86_64JDK8(jdk1.8.0_101)+Tomcat7.0.67+MySQL5.6.32XWIKI 8.2.1 xwiki-enterprise-web-8.2.1.war 一、安裝JDK8 JDK包下載回來jdk-8u101 ...
  • 作者:楓雪庭 出處:http://www.cnblogs.com/FengXueTing-px/ 歡迎轉載 前言 本篇博客是對 每日一linux命令(http://www.cnblogs.com/peida/archive/2012/12/05/2803591.html)的學習總結。 正文 對於li ...
  • RHEL7用戶管理 本節所講內容: 用戶和組的相關配置文件 管理用戶和組 RHEL7破解root密碼 與windows 相比 LINUX中的用戶和賬號的作用是一樣的. 都是基於用戶對訪問的資源做控制,只不過在表示的細節上有差異. 用戶賬號: 超級用戶: root 至高無上 本地用戶: 由管理員創建, ...
  • . 下載Linux iso文件,官方下載鏈接中有Mirror,選擇一個合適的鏈接 http://mirrors.163.com/centos/7/isos/x86_64/CentOS-7-x86_64-Minimal-1511.iso . 燒錄成光碟,使用USBWriter寫入到U盤,或者使用虛擬軟 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...