轻松处理来自Excel文件的大数据

当您只需要数据时,为什么还要上传文件? 更加清洁,更快,只需添加excel_uploader js即可避免连接超时,数据损坏

1.概述

有时可靠地从excel文件批量上传数据可能是一件小事。 这是通过简单的JavaScript库驯服野兽的方法。

通过先在本地计算机上处​​理文件,然后将提取的数据(实际上是您想要的)批量上传到服务器,而不是先将整个文件上传到服务器再进行处理,此库将为您节省一些带宽。

因为它可以批量上传,所以可以解决诸如连接超时之类的问题。 除此之外,它还会报告导致服务器异常的数据,并使其可以作为Excel文件下载。

2.问题

我需要从3000到16000行的Excel文件中批量上传用户记录。 每个excel记录(一行)将用于在系统中创建一个用户帐户。 这涉及到不止一个数据库表的访问,发送电子邮件,数据验证和一个或多个循环。

首先想到的技术是寻找一个excel库,将excel文件上传到服务器,处理excel文件,最后返回成功或错误消息—全部在一个HTTP请求中!

该方法的缺点是:

-HTTP请求超时,尤其是使用非多线程的编程语言时

-错误的错误报告

等等。

3.解决方案

我要做的是在客户端浏览器上使用JavaScript提取数据,然后将这些数据批量推送到服务器。

在服务器端,接收到的数据在try…catch块中处理,引发异常的数据存储在错误数组中。 一旦服务器完成对当前批处理的处理,它将向客户端发送OK响应,并向错误数据(如果有)发送。

此过程的另一个关键技术是数据库事务管理 。 特定记录的所有数据库交互都是在服务器事务的数据库事务范围内完成的。 如果在数据库交互期间发生错误,则事务将回滚,否则将被提交。

在编程中,通常有不止一种方法来实现这一壮举,每种方法都有其自身的缺点。 但是,此技术在错误报告和HTTP连接管理方面是可靠的。

4.使用excel_uploader.js JavaScript库

我在一个名为excel_uploader.js的简单JavaScript文件中实现了上述解决方案。 要在项目中使用JavaScript文件:我们需要从Github存储库中获取该库,并将其与jQuery,xlsx.min.js,FileSaver.js以及可选的bootstrap 4和sweetalert.js一起包含在项目中:

<!-- required -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<!--- optional -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
<!-- needed by older browsers -->
<script src="https://github.com/eligrey/Blob.js"></script>
<!-- Required -->
<script src="https://rawgit.com/eligrey/FileSaver.js/src/FileSaver.js"></script>
<script src="https://unpkg.com/xlsx/dist/xlsx.full.min.js"></script>
<script src="https://cdn.rawgit.com/SeunMatt/excel_uploader/4f4ebd93/src/excel_uploader.js"></script>

请注意, 旧版本的浏览器需要 Blob.js 才能运行FileSaver.js。

接下来,我们将其添加到我们希望excel上传的HTML页面中:

<script>
$(document).ready( function () {
new ExcelUploader({
maxInAGroup: 1000,
serverColumnNames: ["Name", "Email", "Phone Number"],
importTypeSelector: "#dataType",
fileChooserSelector: "#fileUploader",
outputSelector: "#tableOutput",
extraData: {_token: "23333323323223323232"}
});
});
</script>

从上面的代码片段中,我们使用配置参数实例化ExcelUploader对象。 以下是每个参数及其作用的说明。

maxInAGroup:此参数控制每次要发送到服务器的记录数量。 默认值为1000,因此如果源excel文件中有5000条记录,则数据将分5批上传到服务器。 可以根据可用资源微调到我们的口味。

serverColumnNames :这是服务器期望的列的数组。 每次excel_uploader将数据推送到服务器时,它也会发送column_map

通过使用serverColumnNames中元素的小写形式作为键并使用相应excel列的索引作为值来生成列映射。

例如,如果服务器期望上载的excel数据包含3列-名称,电子邮件和电话号码。

用户将首先上传一个excel文件,然后映射哪个列代表excel中的数据。 然后excel_uploader将使用serverColumnNames的小写字母来组成服务器列名称并用下划线(_)字符替换空格。

因此,最后的服务器将收到这样的JSON有效负载:

{
"column_map":{"name":0,"email":2,"phone_number":1},
"data":[
["name1", "08010xxx", "email1@g.com"],
["name2", "08020xxx", "email2@g.com"],
["name3", "08030xxx", "email3@g.com"],
...
]
}

可以将其解释为列位于数据的索引零(0), 电子邮件位于索引二(2),电话号码位于索引1。

importTypeSelector :这是HTML 选择字段的jQuery选择器。 如果选择该选项,则“选择”选项的值是将excel数据发送到的实际URL。 这样,可以将同一页面用于多次上传。 只需在导入类型选择器中将目标URL添加为选项即可。

fileChooserSelector:这是HTML文件输入字段的jQuery选择器。 用于由用户实际从本地存储中选择excel文件。

outputSelector :这是HTML div的jQuery选择器,用于显示进度,状态和错误消息。

extraData :这是与上载数据和列映射一起发送到服务器的数据。 例如,CSRF令牌。 它是一个可选参数。

现在我们已经研究了选项,我们一定已经注意到我们需要在我们的网页上添加一些标记才能使它起作用。

因此,需要以下HTML:

<!--This is the import type selector-->
<div class="form-group">
<select class="form-control" id="dataType">
<option value="-1" disabled selected>Select Data to Import</option>
<option selected value="http://localhost/excel_uploader/demo/php/demo.php">Import Posts Data</option>
</select>
</div>
<!-- This is the file chooser input field-->
<div class="form-group">
<input type="file" id="fileUploader" class="btn btn-fill btn-primary btn-large" />
</div>
<!-- This is the Blank output/progress div-->
<div id="tableOutput"></div>

完整的HTML可以在demo.html页面上找到。

注意:HTML元素的相应ID用于配置上述JavaScript代码段中的ExcelUploader对象。 这就是我们在前端要做的所有事情。 是不是很简单?

5.一点服务器端处理

excel_uploader.js库与服务器端无关! 它将与几乎所有服务器端技术一起使用。 它只需要知道URL即可通过importTypeSelector推送数据,仅此而已

它将使用jQuery ajax在POST请求中将数据推送到服务器。 POST请求有效负载将包含两个强制性条目: datacolumn_map

data :此数组的一个数组—表示用户上传的excel文件中的数据。 它采用JSON格式,应将其解码为键值数据结构,例如PHP中的关联数组或Java中的Map或其他服务器端编程语言中的等效项。

外部数组代表整体,而内部数组代表excel文件每一行上的数据。 因此, data [0]的长度数是上载期间映射的列数,而数据数组本身的长度是上载文件中可用的行/记录的总数。

这是发布请求中收到的示例数据:

{
"column_map":{"name":0,"email":2,"phone_number":1},
"data":[
["name1", "08010xxx", "email1@g.com"],
["name2", "08020xxx", "email2@g.com"],
["name3", "08030xxx", "email3@g.com"],
...
]
}
5.1。 存取资料

从上一节中我们了解到, column_map将列名与数据中包含的数组中的相应索引相关联

因此,我们可以通过将JSON有效负载解析为键值数据结构(如关联数组(PHP)或地图(Java))来访问数据。

在PHP CodeIgniter中,我们可以这样做:

$columnMap = json_decode($this->input->post("column_map"), true);
//to get the name of the first row
$name = $data[0][$columnMap["name"]];
//to get the email of the first row
$email = $data[0][$columnMap["email"]];
//to get the phone_number in first row
$phoneNumber = $data[0][$columnMap["phone_number"]];
//we can definitely use a loop to process all the data

如果您从上面的代码段中注意到,我们不必记住数据数组中每一列的对应索引。 我们只使用column_map ,这要容易得多。

如果服务器端在诸如Spring Boot之类的框架中使用Java编程语言,则同样适用:

//extract the index of the columns we're expecting from the map
int nameIndex = Integer.parseInt(columnMap.get("name").toString());
int emailIndex = Integer.parseInt(columnMap.get("email").toString());
int phoneIndex = Integer.parseInt(columnMap.get("phone_number").toString());
//save a user
User user = new User();
user.setName(data.get(nameIndex));
user.setEmail(data.get(emailIndex));
user.setPhone(data.get(phoneIndex));
user.setPassword("newHashedPassword");
User savedUser = userRepository.save(user);

有关PHPJava的完整演示代码,请参见此处

5.2。 处理数据

处理传入的帖子数据的最佳方法之一是具有两种方法(或函数)。

一种方法,其中将对POST有效负载进行解码,并将数据数组循环遍历,我们将其称为uploadUserData()

在此函数中,将有一个$ errorArray变量,该变量本身必须是一个数组数组。 从POST有效负载解码的数据数组将被循环,并且该数据的每个元素(对应于excel文件的一行)将由另一个方法doUserUpload()处理

doUserUpload方法将在包装在数据库事务中的try … catch块中执行数据库交互。 如果任何数据库交互失败,它将回滚数据库更改并返回false,否则返回true。

如果doUserUpload返回false ,则正在处理的特定记录/行将添加到$ errorArray中。

PHP中uploadUserData()的示例实现:

$errorArray = [];
//this is where the data will be handled and process
foreach ($data as $datum) {
if(!empty($datum) && !$this->doUserUpload($datum, $columnMap)) {
//that means there was an error processing the file
//so we will just add this $datum to the errorArray
array_push($errorArray, $datum);
}
}
//....
//after all the data has been processed, let's respond to the client
if(!empty($errorArray)) {
//there was an error somewhere. Let's send the client the affected data
$this->respond(json_encode(["data" => $errorArray]));
} else{
$this->respond(json_encode(["success" => "OK"]));
}

完整的示例服务器端处理可以在 demo.php中 找到 相应的Java演示也可以在 这里 找到

5.3。 服务器响应

该流程的关键步骤是服务器响应。 服务器应以JSON响应,并且内容类型应为application / json

如果任何上传的数据在处理时导致错误,并且已将其添加到errorArray ,则应将所得的错误Array发送到excel_uploader.js,否则,应发送成功消息:

if(!empty($errorArray)) {
//there was an error somewhere. Let's send the user some data that are affected.
$this->respond(json_encode(["data" => $errorArray]));
} else{
$this->respond(json_encode(["success" => "OK"]));
}

或在Java中:

if(errors.isEmpty()) {
//all is well during the process
responseMap.put("success", "OK");
return ResponseEntity.ok(responseMap);
}
//there are errors and some data are not processed.
// Let's send those data back to the client
//note that we're sending the OK response 200
//it's just that we're appending some error data that might have been present
responseMap.put("data", errors);
return ResponseEntity.ok(mapper.writeValueAsString(responseMap));

如果我们发现发送的数据无效,并且希望通知用户,我们可以发送带有错误条目和200状态代码的JSON响应-因为我们实际上是自己处理错误的:

if(count($data[0]) < 3 || count($columnMap) < 3) {
$this->respond(json_encode([
"error" => "The Data Seems not to be complete! " . count($columnMap) . " columns were mapped instead of 3"]), 200);
}

注意:JSON响应的STATUS代码应为200,以便excel_uploader.js能够对其进行处理。

如果还有其他服务器生成的错误,则将在ajax方法的fail()回调中对其进行处理。

6.汤准备好了!

只需少量的JavaScript,少量的配置和HTML,我们就可以开始了。 好消息是,即使有额外的负载,我们也可以使用同一页面将数据上传到许多端点。 只需将URL作为importTypeSelector中的另一个选项添加即可 ,我们很好。

我想听听您将这个简单工具集成到您的项目中的经验。 如果发现任何错误,请将其报告给Github。

GitHub: https : //github.com/SeunMatt/excel_uploader

From: https://hackernoon.com/process-large-data-from-excel-file-with-a-breeze-3db39e189c82

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值