數(shù)據(jù)的導(dǎo)入導(dǎo)出堤结,在很多系統(tǒng)里面都比較常見,這個(gè)導(dǎo)入導(dǎo)出的操作煌贴,在Winform里面比較容易實(shí)現(xiàn)蜻展,我曾經(jīng)在之前的一篇文章《Winform開發(fā)框架之通用數(shù)據(jù)導(dǎo)入導(dǎo)出操作》介紹了在Winform里面的通用導(dǎo)入導(dǎo)出模塊的設(shè)計(jì)和開發(fā)過程,但在Web上我們應(yīng)該如何實(shí)現(xiàn)呢渔隶?本文主要介紹利用MVC4+EasyUI的特點(diǎn)羔挡,并結(jié)合文件上傳控件Uploadify 的使用,實(shí)現(xiàn)文件上傳后馬上進(jìn)行處理并顯示间唉,然后確認(rèn)后把數(shù)據(jù)寫入數(shù)據(jù)庫的過程绞灼。
我們知道,Web上對Excel的處理和Winform的有所差異呈野,如果是在Web上處理低矮,我們需要把Excel文檔上傳到服務(wù)器上,然后讀取文件進(jìn)行顯示被冒,所以第一步是實(shí)現(xiàn)文件的上傳操作军掂,關(guān)于文件上傳控件,具體可以參考我的文章《基于MVC4+EasyUI的Web開發(fā)框架形成之旅--附件上傳組件uploadify的使用》昨悼。
1蝗锥、導(dǎo)入數(shù)據(jù)的界面效果展示
在Winform里面,我們處理Excel數(shù)據(jù)導(dǎo)入的界面如下所示率触。
在Web上的主界面如下所示终议。
導(dǎo)入界面如下所示。
2葱蝗、Web數(shù)據(jù)導(dǎo)入的處理邏輯和代碼
為了實(shí)現(xiàn)Web上的數(shù)據(jù)導(dǎo)入導(dǎo)出操作痊剖,我們需要增加兩個(gè)按鈕,一個(gè)是導(dǎo)入按鈕垒玲,一個(gè)是導(dǎo)出按鈕。
<a href="javascript:void(0)" class="easyui-linkbutton" id="btnImport" iconcls="icon-excel" onclick="ShowImport()">導(dǎo)入</a>
<a href="javascript:void(0)" class="easyui-linkbutton" id="btnExport" iconcls="icon-excel" onclick="ShowExport()">導(dǎo)出</a>
導(dǎo)入的JS處理代碼如下所示找颓。
//顯示導(dǎo)入界面
function ShowImport() {
$.showWindow({
title: '客戶聯(lián)系人-Excel數(shù)據(jù)導(dǎo)入',
useiframe: true,
width: 1024,
height: 700,
content: 'url:/Contact/Import',
buttons: [{
text: '取消',
iconCls: 'icon-cancel',
handler: function (win) {
win.close();
}
}]
});
}
上面主要就是彈出一個(gè)窗口(上面的導(dǎo)入數(shù)據(jù)窗口)合愈,用來方便客戶選擇Excel文件并保存數(shù)據(jù)或者下載導(dǎo)入模板等操作的。
然后在Import.cshtml的視圖代碼里面,我們需要初始化Datagrid和相關(guān)的界面元素佛析,初始化DataGrid的代碼如下所示益老。
//實(shí)現(xiàn)對DataGird控件的綁定操作
function InitGrid() {
var guid = $("#AttachGUID").val();
$('#grid').datagrid({ //定位到Table標(biāo)簽,Table標(biāo)簽的ID是grid
url: '/Contact/GetExcelData?guid=' + guid, //指向后臺的Action來獲取當(dāng)前用戶的信息的Json格式的數(shù)據(jù)
title: '客戶聯(lián)系人-Excel數(shù)據(jù)導(dǎo)入',
iconCls: 'icon-view',
height: 400,
width: function () { return document.body.clientWidth * 0.9 },//自動寬度
..................
上面紅色部分的內(nèi)容寸莫,就是我們在文件順利上傳到服務(wù)器上的時(shí)候捺萌,根據(jù)一個(gè)guid的參數(shù)初始化DataGrid的列表數(shù)據(jù)。
下面是附件上傳控件uploadify的初始化腳本代碼膘茎,其中紅色部分注意一下桃纯,我們需要上傳的是一個(gè)文件,并且不允許多選披坏,限定上傳文件的類型為xls态坦。
文件上傳完成后,首先調(diào)用CheckExcelColumns控制器函數(shù)來檢查是否匹配導(dǎo)入模板的字段棒拂,如果匹配通過伞梯,加載Excel并展示數(shù)據(jù)到Datagrid里面,否則提示用戶按模板格式錄入數(shù)據(jù)帚屉。
<script type="text/javascript">
$(function () {
//添加界面的附件管理
$('#file_upload').uploadify({
'swf': '/Content/JQueryTools/uploadify/uploadify.swf', //FLash文件路徑
'buttonText': '瀏 覽', //按鈕文本
'uploader': '/FileUpload/Upload', //處理ASHX頁面
'queueID': 'fileQueue', //隊(duì)列的ID
'queueSizeLimit': 1, //隊(duì)列最多可上傳文件數(shù)量谜诫,默認(rèn)為999
'auto': false, //選擇文件后是否自動上傳,默認(rèn)為true
'multi': false, //是否為多選攻旦,默認(rèn)為true
'removeCompleted': true, //是否完成后移除序列喻旷,默認(rèn)為true
'fileSizeLimit': '10MB', //單個(gè)文件大小,0為無限制敬特,可接受KB,MB,GB等單位的字符串值
'fileTypeDesc': 'Excel Files', //文件描述
'fileTypeExts': '*.xls', //上傳的文件后綴過濾器
'onQueueComplete': function (event, data) { //所有隊(duì)列完成后事件
var guid = $("#AttachGUID").val();
ViewUpFiles(guid, "div_files");
//提示用戶Excel格式是否正常掰邢,如果正常加載數(shù)據(jù)
$.ajax({
url: '/Contact/CheckExcelColumns?guid=' + guid,
type: 'get',
dataType:'json',
success: function (data) {
if (data.Success) {
InitGrid(); //重新刷新表格數(shù)據(jù)
$.messager.alert("提示", "文件已上傳,數(shù)據(jù)加載完畢伟阔!");
}
else {
$.messager.alert("提示", "上傳的Excel文件檢查不通過辣之。請根據(jù)頁面右上角的Excel模板格式進(jìn)行數(shù)據(jù)錄入。");
}
}
});
},
'onUploadStart': function (file) {
InitUpFile();//上傳文件前 皱炉,重置GUID怀估,每次不同
$("#file_upload").uploadify("settings", 'formData', { 'folder': '數(shù)據(jù)導(dǎo)入文件', 'guid': $("#AttachGUID").val() }); //動態(tài)傳參數(shù)
},
'onUploadError': function (event, queueId, fileObj, errorObj) {
//alert(errorObj.type + ":" + errorObj.info);
}
});
});
為了有效處理數(shù)據(jù)的導(dǎo)入,我們需要嚴(yán)格保證導(dǎo)入的數(shù)據(jù)是和模板的字段是匹配的合搅,否則處理容易出錯(cuò)多搀,也沒有任何意義。為了實(shí)現(xiàn)這個(gè)目的灾部,框架里面提供方法對字段進(jìn)行檢查康铭,主要是確保Excel里面包含了完整的字段即可。
/// <summary>
/// 檢查Excel文件的字段是否包含了必須的字段
/// </summary>
/// <param name="guid">附件的GUID</param>
/// <returns></returns>
public ActionResult CheckExcelColumns(string guid)
{
CommonResult result = new CommonResult();
try
{
DataTable dt = ConvertExcelFileToTable(guid);
if (dt != null)
{
//檢查列表是否包含必須的字段
result.Success = DataTableHelper.ContainAllColumns(dt, columnString);
}
}
catch (Exception ex)
{
LogTextHelper.Error(ex);
result.ErrorMessage = ex.Message;
}
return ToJsonContent(result);
}
而在InitGrid的初始化中的這個(gè)GetExcelData的控制器方法如下所示赌髓。主要的邏輯就是獲取到Excel从藤,并把Excel里面的數(shù)據(jù)轉(zhuǎn)換為DataTable催跪,最后初始化為實(shí)體類列表,并返回給調(diào)用頁面就可以了夷野。
/// <summary>
/// 獲取服務(wù)器上的Excel文件懊蒸,并把它轉(zhuǎn)換為實(shí)體列表返回給客戶端
/// </summary>
/// <param name="guid">附件的GUID</param>
/// <returns></returns>
public ActionResult GetExcelData(string guid)
{
if (string.IsNullOrEmpty(guid))
{
return null;
}
List<ContactInfo> list = new List<ContactInfo>();
DataTable table = ConvertExcelFileToTable(guid);
if (table != null)
{
#region 數(shù)據(jù)轉(zhuǎn)換
int i = 1;
foreach (DataRow dr in table.Rows)
{
string customerName = dr["客戶名稱"].ToString();
if (string.IsNullOrEmpty(customerName))
{
continue;//客戶名稱為空,記錄跳過
}
CustomerInfo customerInfo = BLLFactory<Customer>.Instance.FindByName(customerName);
if (customerInfo == null)
{
continue;//客戶名稱不存在悯搔,記錄跳過
}
ContactInfo info = new ContactInfo();
info.Customer_ID = customerInfo.ID;//客戶ID
info.HandNo = dr["編號"].ToString();
info.Name = dr["姓名"].ToString();
..............................//增加一個(gè)特殊字段的轉(zhuǎn)義
info.Data1 = BLLFactory<Customer>.Instance.GetCustomerName(info.Customer_ID);
list.Add(info);
}
#endregion
}
var result = new { total = list.Count, rows = list };
return JsonDate(result);
}
3骑丸、Web上數(shù)據(jù)的導(dǎo)出操作
剛才介紹了數(shù)據(jù)的導(dǎo)入操作,數(shù)據(jù)的導(dǎo)出操作相對簡單一些妒貌,它的JS函數(shù)操作如下所示通危。
//導(dǎo)出Excel數(shù)據(jù)
var exportCondition;
function ShowExport() {
var url = "/Contact/Export";
$.ajax({
type: "POST",
url: url,
data: exportCondition,
success: function (filePath) {
var downUrl = '/FileUpload/DownloadFile?file=' + filePath;
window.location = downUrl;
}
});
}
雖然數(shù)據(jù)的導(dǎo)出比較簡單一點(diǎn),但是由于我們需要使用POST方式對數(shù)據(jù)條件進(jìn)行提交苏揣,因此不像普通的方式下載文件Window.Open(url)就可以實(shí)現(xiàn)文件下載了黄鳍。如果POST方式提交了參數(shù),那么返回的數(shù)據(jù)即使是文件流平匈,也無法進(jìn)行有效的下載框沟。
從上面的腳本我們可以看到,里面的exportCondition就是我們需要提交到服務(wù)器的條件增炭,服務(wù)器根據(jù)這個(gè)條件進(jìn)行檢索數(shù)據(jù)忍燥,并返回一個(gè)Excel文件就可以了。
由于使用ajax這種POST方式無法直接下載文件流隙姿,因此梅垄,我們需要先根據(jù)條件,在服務(wù)器上生成文件输玷,返回一個(gè)文件路徑队丝,再次通過DownloadFile方法進(jìn)行文件的下載才可以。
因此這個(gè)傳遞的條件也是很重要的欲鹏,在查詢操作的時(shí)候机久,我們可以把對應(yīng)的條件傳遞給它。
//綁定搜索按鈕的的點(diǎn)擊事件
function BindSearchEvent() {
//按條件進(jìn)行查詢數(shù)據(jù)赔嚎,首先我們得到數(shù)據(jù)的值
$("#btnSearch").click(function () {
//得到用戶輸入的參數(shù)
//取值有幾種方式:$("#id").combobox('getValue'), $("#id").datebox('getValue'), $("#id").val(),combotree('getValue')
//字段增加WHC_前綴字符膘盖,避免傳遞如URL這樣的Request關(guān)鍵字沖突
var queryData = {
WHC_Name: $("#txtName").val(),
WHC_OfficePhone: $("#txtOfficePhone").val(),
WHC_Mobile: $("#txtMobile").val(),
WHC_Address: $("#txtAddress").val(),
WHC_Email: $("#txtEmail").val(),
WHC_Note: $("#txtNote").val()
}
//將值傳遞給DataGrid
InitGrid(queryData);
//傳遞給導(dǎo)出操作
exportCondition = queryData;
return false;
});
}
在我們選定某個(gè)樹的節(jié)點(diǎn)的時(shí)候,我們也可以傳遞自定義的條件給它尤误。
//根據(jù)消息分組加載指定列表
function loadByGroupTree(node) {
//賦值給特殊字段侠畔,公司和部門查詢的時(shí)候選擇其中一個(gè)
var queryParams = $('#grid').datagrid('options').queryParams;
var condition = "{ id: \"" + node.id +"\", groupname:\"" + node.text +"\", userid:\"" + @Session["UserId"] + "\" }";
queryParams.CustomedCondition = condition;//提供給datagrid的條件
exportCondition = { CustomedCondition: condition };//提供給導(dǎo)出的條件
$("#grid").datagrid("reload");
$('#grid').datagrid('uncheckAll');
}
后臺的Export控制器方法主要的邏輯如下所示。
最終是返回一個(gè)生成好的文件地址损晤。
最后給一個(gè)方法直接下載文件就可以了软棺。
/// <summary>
/// 根據(jù)路徑下載文件,主要用于生成的文件的下載
/// </summary>
/// <param name="filePath">文件路徑</param>
/// <returns></returns>
public ActionResult DownloadFile(string file)
{
string realPath = Server.MapPath(file);
string saveFileName = FileUtil.GetFileName(realPath);
Response.WriteFile(realPath);
Response.Charset = "GB2312";
Response.ContentEncoding = Encoding.GetEncoding("GB2312");
Response.ContentType = "application/ms-excel/msword";
Response.AppendHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(saveFileName));
Response.Flush();
Response.End();
return new FileStreamResult(Response.OutputStream, "application/ms-excel/msword");
}
導(dǎo)出的Excel界面效果如下所示尤勋。
由于篇幅的原因喘落,這個(gè)導(dǎo)入導(dǎo)出的操作就介紹到這里德崭,希望有問題大家共同探討。