1、bootstrap-fileinpu的简单介绍

在前面的随笔,我介绍了Bootstrap-table表格插件的具体项目应用过程,本篇随笔介绍另外一个Bootstrap FieInput插件的使用,整合两者可以实现我们常规的Web数据导入操作,导入数据操作过程包括有上传文件,预览数据,选择并提交记录等一系列操作。

关于这个插件,我在早期随笔《Bootstrap文件上传插件File Input的使用》也做了一次介绍,这是一个增强的 HTML5 文件输入控件,是一个 Bootstrap 3.x 的扩展,实现文件上传预览,多文件上传等功能。

bootstrap-fileinput源码:https://github.com/kartik-v/bootstrap-fileinput

bootstrap-fileinput在线API:http://plugins.krajee.com/file-input

bootstrap-fileinput Demo展示:http://plugins.krajee.com/file-basic-usage-demo

这个插件主要是介绍如何处理图片上传的处理操作,原先我的Excel导入操作使用的是Uploadify插件,可以参考我随笔《附件上传组件uploadify的使用》,不过这个需要Flash控件支持,在某些浏览器(如Chrome)就比较麻烦了,因此决定使用一种较为通用的上传插件,这次首先对基于Bootstrap前端架构的框架系统进行升级,替代原来的Uploadify插件,这样页面上传功能,在各个浏览器就可以无差异的实现了。

一般情况下,我们需要引入下面两个文件,插件才能正常使用:

bootstrap-fileinput/css/fileinput.min.css
bootstrap-fileinput/js/fileinput.min.js

在File input 插件使用的时候,如果是基于Asp.NET MVC的,那么我们可以使用BundleConfig.cs进行添加对应的引用,加入到Bundles集合引用即可。

    //添加对bootstrap-fileinput控件的支持
css_metronic.Include("~/Content/MyPlugins/bootstrap-fileinput/css/fileinput.min.css");
js_metronic.Include("~/Content/MyPlugins/bootstrap-fileinput/js/fileinput.min.js");
js_metronic.Include("~/Content/MyPlugins/bootstrap-fileinput/js/locales/zh.js");

在页面中,我们使用以下HTML代码实现界面展示,主要的bootstrap fileinput插件声明,主要是基础的界面代码

<input id="excelFile" type="file"> 

Excel导入的的界面展示如下所示。

选择指定文件后,我们可以看到Excel的文件列表,如下界面所示。

上传文件后,数据直接展示在弹出层的列表里面,这里直接使用了 Bootstrap-table表格插件进行展示。

这样我们就可以把Excel的记录展示出来,实现了预览的功能,勾选必要的记录,然后保存即可提交到服务器进行保存,实现了Excel数据的真正导入数据库处理。

2、Excel导出操作详细介绍

我们在实际导入Excel的界面中,HTML代码如下所示。

<!--导入数据操作层-->
<div id="import" class="modal fade bs-modal-lg" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header bg-primary">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"></button>
<h4 class="modal-title">文件导入</h4>
</div>
<div class="modal-body">
<div style="text-align:right;padding:5px">
<a href="~/Content/Template/TestUser-模板.xls" onclick="javascript:Preview();">
<img alt="测试用户信息-模板" src="~/Content/images/ico_excel.png" />
<span style="font-size:larger;font-weight:200;color:red">TestUser-模板.xls</span>
</a>
</div>
<hr/>
<form id="ffImport" method="post">
<div title="Excel导入操作" style="padding: 5px">
<input type="hidden" id="AttachGUID" name="AttachGUID" />
<input id="excelFile" type="file">
</div>
</form> <!--数据显示表格-->
<table id="gridImport" class="table table-striped table-bordered table-hover" cellpadding="0" cellspacing="0" border="0">
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" onclick="SaveImport()">保存</button>
</div>
</div>
</div>
</div>

对于bootstrap fileinput的各种属性,我们这里使用JS进行初始化,这样方便统一管理和修改。

        //初始化Excel导入的文件
function InitExcelFile() {
//记录GUID
$("#AttachGUID").val(newGuid()); $("#excelFile").fileinput({
uploadUrl: "/FileUpload/Upload",//上传的地址
uploadAsync: true, //异步上传
language: "zh", //设置语言
showCaption: true, //是否显示标题
showUpload: true, //是否显示上传按钮
showRemove: true, //是否显示移除按钮
showPreview : true, //是否显示预览按钮
browseClass: "btn btn-primary", //按钮样式
dropZoneEnabled: false, //是否显示拖拽区域
allowedFileExtensions: ["xls", "xlsx"], //接收的文件后缀
maxFileCount: 1, //最大上传文件数限制
previewFileIcon: '<i class="glyphicon glyphicon-file"></i>',
allowedPreviewTypes: null,
previewFileIconSettings: {
'docx': '<i class="glyphicon glyphicon-file"></i>',
'xlsx': '<i class="glyphicon glyphicon-file"></i>',
'pptx': '<i class="glyphicon glyphicon-file"></i>',
'jpg': '<i class="glyphicon glyphicon-picture"></i>',
'pdf': '<i class="glyphicon glyphicon-file"></i>',
'zip': '<i class="glyphicon glyphicon-file"></i>',
},
uploadExtraData: { //上传的时候,增加的附加参数
folder: '数据导入文件', guid: $("#AttachGUID").val()
}
}) //文件上传完成后的事件
.on('fileuploaded', function (event, data, previewId, index) {
var form = data.form, files = data.files, extra = data.extra,
response = data.response, reader = data.reader; var res = data.response; //返回结果
if (res.Success) {
showTips('上传成功');
var guid = $("#AttachGUID").val(); //提示用户Excel格式是否正常,如果正常加载数据
$.ajax({
url: '/TestUser/CheckExcelColumns?guid=' + guid,
type: 'get',
dataType: 'json',
success: function (data) {
if (data.Success) {
InitImport(guid); //重新刷新表格数据
showToast("文件已上传,数据加载完毕!"); //重新刷新GUID,以及清空文件,方便下一次处理
RefreshExcel();
}
else {
showToast("上传的Excel文件检查不通过。请根据页面右上角的Excel模板格式进行数据录入。", "error");
}
}
});
}
else {
showTips('上传失败');
}
});
}

上面的逻辑具体就是,设置上传文件的后台页面为:/FileUpload/Upload,以及各种插件的配置参数,uploadExtraData里面设置的是提交的附加参数,也就是后台控制器接收的参数,其中

.on('fileuploaded', function (event, data, previewId, index) {

的函数处理文件上传后的处理函数,如果上传文件返回的结果是成功的,那么我们再次调用ajax来检查这个Excel的字段是否符合要求,如下地址:

url: '/TestUser/CheckExcelColumns?guid=' + guid,

如果这个检查的后台返回成功的记录,那么再次需要把Excel记录提取出来预览,并清空bootstrap fileinput文件上传插件,方便下次上传文件。如下代码所示。

    if (data.Success) {
InitImport(guid); //重新刷新表格数据
showToast("文件已上传,数据加载完毕!"); //重新刷新GUID,以及清空文件,方便下一次处理
RefreshExcel();
}
else {
showToast("上传的Excel文件检查不通过。请根据页面右上角的Excel模板格式进行数据录入。", "error");
}

其中RefreshExcel就是重新更新上传的附加参数值,方便下次上传,否则附加参数的值一直不变化,就会导致我们设置的GUID没有变化而出现问题。

        //重新更新GUID的值,并清空文件
function RefreshExcel() {
$("#AttachGUID").val(newGuid());
$('#excelFile').fileinput('clear');//清空所有文件 //附加参数初始化后一直不会变化,如果需要发生变化,则需要使用refresh进行更新
$('#excelFile').fileinput('refresh', {
uploadExtraData: { folder: '数据导入文件', guid: $("#AttachGUID").val() },
});
}

而其中InitImport就是获取预览数据并展示在Bootstrap-table表格插件上的,关于这个插件的详细使用,可以回顾下随笔《基于Metronic的Bootstrap开发框架经验总结(16)-- 使用插件bootstrap-table实现表格记录的查询、分页、排序等处理》进行了解即可。

        //根据条件查询并绑定结果
var $import;
function InitImport(guid) {
var url = "/TestUser/GetExcelData?guid=" + guid;
$import = $('#gridImport').bootstrapTable({
url: url, //请求后台的URL(*)
method: 'GET', //请求方式(*)
striped: true, //是否显示行间隔色
cache: false, //是否使用缓存,默认为true,所以一般情况下需要设置一下这个属性(*)
pagination: false, //是否显示分页(*)
sidePagination: "server", //分页方式:client客户端分页,server服务端分页(*)
pageNumber: 1, //初始化加载第一页,默认第一页,并记录
pageSize: 100, //每页的记录行数(*)
pageList: [10, 25, 50, 100], //可供选择的每页的行数(*)
search: false, //是否显示表格搜索
strictSearch: true,
showColumns: true, //是否显示所有的列(选择显示的列)
showRefresh: true, //是否显示刷新按钮
minimumCountColumns: 2, //最少允许的列数
clickToSelect: true, //是否启用点击选中行
uniqueId: "ID", //每一行的唯一标识,一般为主键列
queryParams: function (params) { },
columns: [{
checkbox: true,
visible: true //是否显示复选框
}, {
field: 'Name',
title: '姓名'
}, {
field: 'Mobile',
title: '手机'
}, {
field: 'Email',
title: '邮箱',
formatter: emailFormatter
}, {
field: 'Homepage',
title: '主页',
formatter: linkFormatter
}, {
field: 'Hobby',
title: '兴趣爱好'
}, {
field: 'Gender',
title: '性别',
formatter: sexFormatter
}, {
field: 'Age',
title: '年龄'
}, {
field: 'BirthDate',
title: '出生日期',
formatter: dateFormatter
}, {
field: 'Height',
title: '身高'
}, {
field: 'Note',
title: '备注'
}],
onLoadSuccess: function () {
},
onLoadError: function () {
showTips("数据加载失败!");
},
});
}

最后就是确认提交后,会通过JS提交数据到后台进行处理,如下代码所示。

        //保存导入的数据
function SaveImport() { var list = [];//构造集合对象
var rows = $import.bootstrapTable('getSelections');
for (var i = ; i < rows.length; i++) {
list.push({
'Name': rows[i].Name, 'Mobile': rows[i].Mobile, 'Email': rows[i].Email, 'Homepage': rows[i].Homepage,
'Hobby': rows[i].Hobby, 'Gender': rows[i].Gender, 'Age': rows[i].Age, 'BirthDate': rows[i].BirthDate,
'Height': rows[i].Height, 'Note': rows[i].Note
});
} if (list.length == ) {
showToast("请选择一条记录", "warning");
return;
} var postData = { 'list': list };//可以增加其他参数,如{ 'list': list, 'Rucanghao': $("#Rucanghao").val() };
postData = JSON.stringify(postData); $.ajax({
url: '/TestUser/SaveExcelData',
type: 'post',
dataType: 'json',
contentType: 'application/json;charset=utf-8',
traditional: true,
success: function (data) {
if (data.Success) {
//保存成功 1.关闭弹出层,2.清空记录显示 3.刷新主列表
showToast("保存成功"); $("#import").modal("hide");
$(bodyTag).html("");
Refresh();
}
else {
showToast("保存失败:" + data.ErrorMessage, "error");
}
},
data: postData
});
}

3、后台控制器代码分析

这里我们的JS代码里面,涉及了几个MVC后台的方法处理:Upload、CheckExcelColumns、GetExcelData、SaveExcelData。这里分别进行介绍。

文件上传的后台控制器方法如下所示。

        /// <summary>
/// 上传附件到服务器上
/// </summary>
/// <param name="fileData">附件信息</param>
/// <param name="guid">附件组GUID</param>
/// <param name="folder">指定的上传目录</param>
/// <returns></returns>
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Upload(string guid, string folder)
{
CommonResult result = new CommonResult(); HttpFileCollectionBase files = HttpContext.Request.Files;
if (files != null)
{
foreach (string key in files.Keys)
{
try
{
#region MyRegion
HttpPostedFileBase fileData = files[key];
if (fileData != null)
{
HttpContext.Request.ContentEncoding = Encoding.GetEncoding("UTF-8");
HttpContext.Response.ContentEncoding = Encoding.GetEncoding("UTF-8");
HttpContext.Response.Charset = "UTF-8"; // 文件上传后的保存路径
string filePath = Server.MapPath("~/UploadFiles/");
DirectoryUtil.AssertDirExist(filePath); string fileName = Path.GetFileName(fileData.FileName); //原始文件名称
string fileExtension = Path.GetExtension(fileName); //文件扩展名
//string saveName = Guid.NewGuid().ToString() + fileExtension; //保存文件名称 FileUploadInfo info = new FileUploadInfo();
info.FileData = ReadFileBytes(fileData);
if (info.FileData != null)
{
info.FileSize = info.FileData.Length;
}
info.Category = folder;
info.FileName = fileName;
info.FileExtend = fileExtension;
info.AttachmentGUID = guid; info.AddTime = DateTime.Now;
info.Editor = CurrentUser.Name;//登录人 result = BLLFactory<FileUpload>.Instance.Upload(info);
if (!result.Success)
{
LogTextHelper.Error("上传文件失败:" + result.ErrorMessage);
}
}
#endregion
}
catch (Exception ex)
{
result.ErrorMessage = ex.Message;
LogTextHelper.Error(ex);
}
}
}
else
{
result.ErrorMessage = "fileData对象为空";
} return ToJsonContent(result);
}

文件上传处理后,返回一个通用的CommonResult 的结果对象,也方便我们在JS客户端进行判断处理。

而其中检查我们导入Excel的数据是否满足列要求的处理,就是判断它的数据列和我们预先设置好的列名是否一致即可。

        //导入或导出的字段列表
string columnString = "姓名,手机,邮箱,主页,兴趣爱好,性别,年龄,出生日期,身高,备注"; /// <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);
}

而GetExcelData则是格式化Excel数据到具体的List<TestUserInfo>集合里面,这样我们方便在客户端进行各种属性的操作,它的代码如下所示。

        /// <summary>
/// 获取服务器上的Excel文件,并把它转换为实体列表返回给客户端
/// </summary>
/// <param name="guid">附件的GUID</param>
/// <returns></returns>
public ActionResult GetExcelData(string guid)
{
if (string.IsNullOrEmpty(guid))
{
return null;
} List<TestUserInfo> list = new List<TestUserInfo>(); DataTable table = ConvertExcelFileToTable(guid);
if (table != null)
{
#region 数据转换
int i = ;
foreach (DataRow dr in table.Rows)
{
bool converted = false;
DateTime dtDefault = Convert.ToDateTime("1900-01-01");
DateTime dt;
TestUserInfo info = new TestUserInfo(); info.Name = dr["姓名"].ToString();
info.Mobile = dr["手机"].ToString();
info.Email = dr["邮箱"].ToString();
info.Homepage = dr["主页"].ToString();
info.Hobby = dr["兴趣爱好"].ToString();
info.Gender = dr["性别"].ToString();
info.Age = dr["年龄"].ToString().ToInt32();
converted = DateTime.TryParse(dr["出生日期"].ToString(), out dt);
if (converted && dt > dtDefault)
{
info.BirthDate = dt;
}
info.Height = dr["身高"].ToString().ToDecimal();
info.Note = dr["备注"].ToString(); info.Creator = CurrentUser.ID.ToString();
info.CreateTime = DateTime.Now;
info.Editor = CurrentUser.ID.ToString();
info.EditTime = DateTime.Now; list.Add(info);
}
#endregion
} var result = new { total = list.Count, rows = list };
return ToJsonContent(result);
}

另一个SaveExcelData的函数就是处理数据导入的最终处理函数,主要就是把集合写入到具体的数据库里面即可,具体代码如下所示。

        /// <summary>
/// 保存客户端上传的相关数据列表
/// </summary>
/// <param name="list">数据列表</param>
/// <returns></returns>
public ActionResult SaveExcelData(List<TestUserInfo> list)
{
CommonResult result = new CommonResult();
if (list != null && list.Count > )
{
#region 采用事务进行数据提交 DbTransaction trans = BLLFactory<TestUser>.Instance.CreateTransaction();
if (trans != null)
{
try
{
//int seq = 1;
foreach (TestUserInfo detail in list)
{
//detail.Seq = seq++;//增加1
detail.CreateTime = DateTime.Now;
detail.Creator = CurrentUser.ID.ToString();
detail.Editor = CurrentUser.ID.ToString();
detail.EditTime = DateTime.Now; BLLFactory<TestUser>.Instance.Insert(detail, trans);
}
trans.Commit();
result.Success = true;
}
catch (Exception ex)
{
LogTextHelper.Error(ex);
result.ErrorMessage = ex.Message;
trans.Rollback();
}
}
#endregion
}
else
{
result.ErrorMessage = "导入信息不能为空";
} return ToJsonContent(result);
}

上面这几个函数的代码一般是比较有规律的,不需要一个个去编写,一般通过代码生成工具Database2Sharp批量生成即可。这样可以有效提高Web的界面代码和后台代码的开发效率,减少出错的机会。

整个导入Excel数据的处理过程,所有代码都贴出来了,基本上整个逻辑了解了就可以很好的了解这个过程的代码了。

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

  1. 基于bootstrap的上传插件fileinput实现ajax异步上传功能(支持多文件上传预览拖拽)

    首先需要导入一些js和css文件 ? 1 2 3 4 5 6 <link href="__PUBLIC__/CSS/bootstrap.css" rel="exte ...

  2. jQuery插件ImgAreaSelect 实例讲解一(头像上传预览和裁剪功能)

    上一节随笔中,我们已经知道了关于jQuery插件ImgAreaSelect基本的知识:那么现在看一下实例: 首先,要知道我们应该实现什么功能? (1)图片能够实现上传预览功能 (2)拖拽裁剪图片,使其 ...

  3. 上传预览图片的插件jquery-fileupload

    上传预览图片的插件jquery-fileupload github地址:https://github.com/blueimp/jQuery-File-Upload 中文文档:http://www.jq ...

  4. jquery.form.js官方插件介绍Form插件,支持Ajax,支持Ajax文件上传

    jquery.form.js官方插件介绍Form插件,支持Ajax,支持Ajax文件上传 http://www.malsup.com/jquery/form/#getting-started [JQu ...

  5. JS图片上传预览插件制作(兼容到IE6)

    其实,图片预览功能非常地常见.很意外,之前遇到上传图片的时候都不需要预览,也一直没有去实现过.现在手上的项目又需要有图片预览功能,所以就动手做了一个小插件.在此分享一下思路. 一.实现图片预览的一些方 ...

  6. 支持图片上传预览的 uploadPreview.js 插件

    原文链接:http://www.lanrenzhijia.com/others/3148.html

  7. dropify,不错的图片上传预览插件

    引言 传统的图片上传,很丑.点击选择之后,还无法预览. 有一种方案是传到服务器,然后返回地址,然后显示,比较麻烦. 用这个dropify,就可以解决之歌问题. 看效果 用法 1.引入文件,需要jque ...

  8. 基于Metronic的Bootstrap开发框架经验总结(5)--Bootstrap文件上传插件File Input的使用

    Bootstrap文件上传插件File Input是一个不错的文件上传控件,但是搜索使用到的案例不多,使用的时候,也是一步一个脚印一样摸着石头过河,这个控件在界面呈现上,叫我之前使用过的Uploadi ...

  9. Bootstrap文件上传插件File Input的使用

    基于Metronic的Bootstrap开发框架经验总结(5)--Bootstrap文件上传插件File Input的使用 Bootstrap文件上传插件File Input是一个不错的文件上传控件, ...

随机推荐

  1. war包中少了class文件

    用eclipse的maven工具打包(执行mvn clean install  和   mvn package)后,再启动wildfly, war包应该会自动复制到wildfly的deployment ...

  2. 大话Python中*args和**kargs的使用

    对于初学者来说,看到*args和**kargs就头大,到底它们有何用处,怎么使用?这篇文章将为你揭开可变参数的神秘面纱 1.*args 实质就是将函数传入的参数,存储在元组类型的变量args当中 de ...

  3. linux 权限字母含义

    查看某一文件夹下所有文件夹的权限情况:ls -l分别是:所有者(user)-所有者(user)-其他人(other)r 表示文件可以被读(read)w 表示文件可以被写(write)x 表示文件可以被 ...

  4. SOD开源框架MSF(消息服务框架)进阶篇

    复习:在上一篇我介绍了MSF的基本订阅,模式就是,客户端A,订阅服务器.客户端B,订阅服务器.通过服务器广播消息, 所有订阅过的客户端都能接到消息. 进阶:在上一篇的基础上,增加客户端A,发送信息到服 ...

  5. oracle11g的内存分配不当,导致的错误ORA-01034,ORA-00838,ORA-27101

    由于开发需要,oracle11g被应用于虚拟机,所以系统资源显得弥足珍贵,百度了一下就有答案. 用dba身份进入Oracle,笔者在plsql中对数据库进行管理: show parameter sga ...

  6. 解决ubuntu不能安装g++的问题

    下面提供一种解决方法,解决方法不唯一 首先贴出错误原因: 上文是g++-4.8不能下载,所以退而求其次,指定版本4.7,不下载最新的 解决方法如下: 安装成功后而已查看版本信息确认 使用g++-4.7 ...

  7. meta小结

    mate 标签定义及使用说明 元数据(Metadata)是数据的数据信息. 标签提供了 HTML 文档的元数据.元数据不会显示在客户端,当时会被浏览器解析. META元素通常用于指定网页的描述,关键词 ...

  8. Java IO设计模式(装饰模式与适配器模式)

    01. 装饰模式 1. 定义 Decorator装饰器,就是动态地给一个对象添加一些额外的职责,动态扩展,和下面继承(静态扩展)的比较.因此,装饰器模式具有如下的特征: 它必须持有一个被装饰的对象(作 ...

  9. Java探秘之基本数据类型和包装类(int,Integer)(一)

    最近闲来无聊打算做一个博客网,没事记记笔记什么,可是网站不好做,需要点时间,就先写写笔记来练练手. 可是要写什么呢,太难的好像我也写不出来,万一写错了误导别人就不好了. 哈哈,不多说,直奔主题,要是写 ...

  10. [问题解决]linux sudo xxx:command not found

    题外话 软件的安装在linux下主要分为两种.一种是通过包管理器例如ubuntu的apt-get xxx,另一种是自己手动安装.通过包管理器安装的,基本开箱即用,无需配置,但是存在一个问题,有时候无法 ...