在早期 Bootstrap 框架介绍中, 我的随笔结合 bootstrap fileinput 插件和 Bootstrap-table 表格插件, 实现文件上传, 预览, 提交的导入 Excel 数据操作流程中介绍了利用 Bootstrap FieInput 插件上传 Excel 文件到服务器, 然后利用 Bootstrap-table 表格插件进行展示数据, 最后导入到系统里面中, 这个导入过程中可以预览到要导入的数据, 而且可以选择性的导入. 在实际使用过程中, 发现使用 Ajax 导入大批量 (几百条记录数据) 的情况下, 页面就会罢工, 估计和提交的数据大小限制有关, 为了解决这个问题, 并结合导入数据一般都是全部导入的情况下, 我们修改下数据导入的过程, 从而实现大量数据量的 Excel 数据导入.
1, 使用预览数据, 并勾选导入的处理方式
Excel 导入的的界面展示如下所示.
上传文件后, 数据直接展示在弹出层的列表里面, 这里直接使用了 Bootstrap-table 表格插件进行展示.
这样我们就可以把 Excel 的记录展示出来, 实现了预览的功能, 勾选必要的记录, 然后保存即可提交到服务器进行保存, 实现了 Excel 数据的真正导入数据库处理.
实际的代码就比较多一点点, 详细可以参考下随笔结合 bootstrap fileinput 插件和 Bootstrap-table 表格插件, 实现文件上传, 预览, 提交的导入 Excel 数据操作流程, 这里就主要简要介绍下导入的处理逻辑即可, 由于是在客户端组装列表数据, 然后通过 ajax 提交的, 它的的代码如下所示.(这个也就是后面需要解决的问题).
- // 保存导入的数据
- function SaveImport() {
- var list = [];// 构造集合对象
- var rows = $import.bootstrapTable('getSelections');
- for (var i = 0; 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 == 0) {
- 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
- });
- }
在实际使用过程中, 发现数据几百条的时候, 页面就罢工了, 不能正常插入, 搜索下解决问题说是大小受限的问题, 但是我在 web.Config 里面也设置了上传文件的大小, 最终没有找到配置解决思路.
- <httpRuntime executionTimeout="600" maxRequestLength="951200"
- useFullyQualifiedRedirectUrl="true" minFreeThreads="8"
- minLocalRequestFreeThreads="4" appRequestQueueLimit="100" enableVersionHeader="true"/>
最终这个配置项也无法解决, 那么我们只能找其他方式来避免数据大量提交了.
2, 使用在控制器后台读取 Excel 文件导入数据库
以上的数据导入方式, 在一般数据比较少的时候, 体验还是不错的, 不过它的过程也是先上传 Excel 文件, 然后读取 Excel 里面的记录, 转换为对应的 List<T > 类型, 在序列号 JSON 列表在前端界面展示.
既然我们文件在服务器上, 并且也可以通过把 Excel 文件转换为对应的 List<T>, 那么我们减少用户勾选的步骤, 确认后直接读取导入即可, 这样处理应该就没有这样的受限于页面数据大小的问题的.
这样我们以设备信息导入为案例, 介绍这个处理过程, 如下前端代码是在文件上传到服务器后, 用户确认后负责导入的逻辑的.
- // 保存导入的数据
- function SaveImport() {
- var postData = { 'guid': importGuid };
- postData = JSON.stringify(postData);
- $.ajax({
- url: '/Device/SaveExcelByGuid',
- type: 'post',
- dataType: 'json',
- contentType: 'application/json;charset=utf-8',
- traditional: true,
- success: function (data) {
- if (data.Success) {
- Refresh();
- // 保存成功 1. 关闭弹出层, 2. 清空记录显示 3. 刷新主列表
- showToast("保存成功");
- $("#import").modal("hide");
- $(bodyTag).html("");
- }
- else {
- showToast("保存失败:" + data.ErrorMessage, "error");
- }
- },
- data: postData
- });
最终我们是看到处理方式是在 SaveExcelByGuid 的控制器方法里面的, 这个方法根据服务器的 GUID, 获取对应 Excel 文件的信息, 然后进行读取和导入操作.
这个方法的详细代码如下所示.
- /// <summary>
- /// 在服务端保存 Excel
- /// </summary>
- /// <param name="guid"></param>
- /// <returns></returns>
- public ActionResult SaveExcelByGuid(string guid)
- {
- CommonResult result = new CommonResult();
- if(!string.IsNullOrEmpty(guid))
- {
- var list = GetDevice(guid);// 根据 guid 获取对应的 Excel 文件, 并把内容转换为对应的 List<T>
- if (list != null)
- {
- foreach (DeviceInfo detail in list)
- {
- var isExist = BLLFactory<Device>.Instance.IsExistKey("DeviceId", detail.DeviceId);
- if (!isExist)
- {
- BLLFactory<Device>.Instance.Insert(detail);
- }
- }
- // 成功操作
- result.Success = true;
- }
- else
- {
- result.ErrorMessage = "导入信息不能为空";
- }
- }
- else
- {
- result.ErrorMessage = "导入信息不能为空";
- }
- return ToJsonContent(result);
- }
其中我们看到 GetDevice(guid) 就是获取 Excel 文件内容并转换为对应的实体类列表过程的.
其中的 GetDevice 就是转换为对应实体类集合的过程, 代码如下所示.
- /// <summary>
- /// 获取设备导入文件, 转换为对应的实体类集合
- /// </summary>
- /// <param name="guid">附件 GUID</param>
- /// <returns></returns>
- private List<DeviceInfo> GetDevice(string guid)
- {
- List<DeviceInfo> list = new List<DeviceInfo>();
- DataTable table = ConvertExcelFileToTable(guid);
- if (table != null)
- {
- #region 数据转换
- foreach (DataRow dr in table.Rows)
- {
- DeviceInfo info = new DeviceInfo();
- info.DeviceId = dr["设备 ID"].ToString();
- info.VersionInfo = dr["版本信息"].ToString();
- info.MinitorInfo = dr["预留监控信息"].ToString();
- info.DeviceMsisdn = dr["公话手机号"].ToString();
- list.Add(info);
- }
- #endregion
- }
- return list;
- }
而 ConvertExcelFileToTable 就是利用 aspose.Cell 的 Excel 操作控件, 实现数据转换的.
- /// <summary>
- /// 从附件列表中获取第一个 Excel 文件, 并转换 Excel 数据为对应的 DataTable 返回
- /// </summary>
- /// <param name="guid">附件的 Guid</param>
- /// <returns></returns>
- protected DataTable ConvertExcelFileToTable(string guid)
- {
- DataTable dt = null;
- if (!string.IsNullOrEmpty(guid))
- {
- // 获取上传附件的路径
- string serverRealPath = BLLFactory<FileUpload>.Instance.GetFirstFilePath(guid);
- if (!string.IsNullOrEmpty(serverRealPath))
- {
- // 转换 Excel 文件到 DatTable 里面
- string error = "";
- dt = new DataTable();
- AsposeExcelTools.ExcelFileToDataTable(serverRealPath, out dt, out error);
- }
- }
- return dt;
- }
这样实现效果, 不考虑用户勾选记录的情况, 确认后直接对整个 Excel 文件进行判断导入操作, 一般也是符合我们实际的导入过程的, 这样处理起来, 再也不会有前面介绍的那种情况了, 至少我们能够顺利上传 Excel 文件, 在后台读取 Excel 文件并转换是没有什么压力的, 而且体验效果也很不错, 非常快速.
最后看看大量数据导入后, 也能够快速刷新, 并能够在分页控件进行展示了.
来源: https://www.cnblogs.com/wuhuacong/p/9566946.html