前言:
在业务中开发中,表格的导入导出性能很常见。然而这里次要是应用 PhpOffice 类库介绍实现导入表格数据的性能。
抵触:
大部分的导入性能,就是通过点击按钮上传一张表格,而后后盾读取表格数据依据业务整顿后直接插入到数据库,最初再返回给前端。然而如果表格数据宏大,业务逻辑简单的时候,就会导致导入那一块很臃肿不好保护。
解决办法:
解决形式是把导入与业务数据插入拆散,所以在二者之间增加一个队列就能够了。导入只负责将表格数据存入队列。业务局部能够是独自的零碎,最初就是生产队列中的数据了。这样一来,岂但晋升了导入速度,而且还让导入与零碎解耦,不会因为异样而影响到其余业务。
编码:
1. 下载 PhpOffice。
composer repuire phpoffice/phpspreadsheet
2. 导入导出代码。
<?php
namespace app\common\helper;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use think\Exception;
class Excel
{
// 导出
public function outPut($data, $columns, $table = '导出文件')
{$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
// 设置第一栏的题目
foreach ($columns as $k => $v) {$sheet->setCellValue($k . "1", $v['title']);
}
// 第二行起 设置内容
$baseRow = 2; // 数据从 N - 1 行开始往下输入 这里是防止头信息被笼罩
foreach ($data as $key => $value) {foreach ($columns as $k1 => $v1) {
$i = $key + $baseRow;
$sheet->setCellValue($k1 . $i, $value[$v1['field']]);
}
}
$writer = new Xlsx($spreadsheet);
$filename = $table . date("Y-m-d", time()) . '_' . time() . '.xlsx';
$writer->save('./excel/' . $filename);
return '/excel/' . $filename;
}
// 导入
public function importExcel($file = '', $sheet = 0, $columnCnt = 0, &$options = [])
{
try {$file = iconv("utf-8", "gb2312", $file);
if (empty($file) OR !file_exists($file)) {throw new \Exception('文件不存在!');
}
$objRead = IOFactory::createReader('Xlsx');
if (!$objRead->canRead($file)) {$objRead = IOFactory::createReader('Xls');
if (!$objRead->canRead($file)) {throw new \Exception('只反对导入 Excel 文件!');
}
}
/* 如果不须要获取非凡操作,则只读内容,能够大幅度晋升读取 Excel 效率 */
empty($options) && $objRead->setReadDataOnly(true);
/* 建设 excel 对象 */
$obj = $objRead->load($file);
/* 获取指定的 sheet 表 */
$currSheet = $obj->getSheet($sheet);
//$currSheet = $obj->getSheetByName($sheet); // 依据名字
if (isset($options['mergeCells'])) {
/* 读取合并行列 */
$options['mergeCells'] = $currSheet->getMergeCells();}
if (0 == $columnCnt) {
/* 获得最大的列号 */
$columnH = $currSheet->getHighestColumn();
/* 兼容原逻辑,循环时应用的是小于等于 */
$columnCnt = Coordinate::columnIndexFromString($columnH);
}
/* 获取总行数 */
$rowCnt = $currSheet->getHighestRow();
$data = [];
/* 读取内容 */
for ($_row = 1; $_row <= $rowCnt; $_row++) {
$isNull = true;
for ($_column = 1; $_column <= $columnCnt; $_column++) {$cellName = Coordinate::stringFromColumnIndex($_column);
$cellId = $cellName . $_row;
$cell = $currSheet->getCell($cellId);
if (isset($options['format'])) {
/* 获取格局 */
$format = $cell->getStyle()->getNumberFormat()->getFormatCode();
/* 记录格局 */
$options['format'][$_row][$cellName] = $format;
}
if (isset($options['formula'])) {
/* 获取公式,公式均为 = 号结尾数据 */
$formula = $currSheet->getCell($cellId)->getValue();
if (0 === strpos($formula, '=')) {$options['formula'][$cellName . $_row] = $formula;
}
}
if (isset($format) && 'm/d/yyyy' == $format) {
/* 日期格局翻转解决 */
$cell->getStyle()->getNumberFormat()->setFormatCode('yyyy/mm/dd');
}
$data[$_row][$cellName] = trim($currSheet->getCell($cellId)->getFormattedValue());
if (!empty($data[$_row][$cellName])) {$isNull = false;}
}
if ($isNull) {unset($data[$_row]);
}
}
return $data;
} catch (\Exception $e) {throw $e;}
}
}
3. 抽取指定的字段格式化 Excel 数据。
return [
// 导入的表格题目
"bidding" => [
"stock_no" => "编号",
"price" => "价格",
"mobile" => "手机",
"nickname" => "姓名"
]
];
// 格式化指定列数据 (默认第一行表头)
public static function formattingCells(array $data, array $cellConfig)
{$res = array_values($data);
// 表头
$header = $res[0];
$cellKeys = [];
foreach ($header as $key => $value) {foreach ($cellConfig as $k => $v) {if ($value == $v) {$cellKeys[$key] = $k;
}
}
}
if (count($cellKeys) != count($cellConfig)) {throw new Exception('表格不残缺');
}
// 须要增加过滤
$temp = [];
for ($i = 1; $i <= count($res) - 1; $i++) {foreach ($cellKeys as $m => $n) {$temp[$i][$n] = $res[$i][$m];
}
}
return array_values($temp);
}
4. 导入局部,上传接口。
// 导入表格,上传接口
public function importExcel()
{$upload_file = $_FILES['files']['tmp_name'];
$input = $this->input;
// ID
$id = isset($input['id']) ? $input['id'] : 0;
// 默认取第一工作表
$excelData = (new Excel())->importExcel($upload_file, 0);
// 取 Excel 字段
$config = config('excel_export.bidding');
$price_offer = Excel::formattingCells($excelData, $config);
// 判断每条记录的手机和价格格局
// ……
$jsonList = json_encode(compact('id', 'price_offer'));
//$jsonList = json_encode($price_offer);
// 入 MQ
$host = config("mq.host");
$options = config("mq.price_offer_import");
try {$mq = new ProductMQ($host, $options);
$mq->publish($jsonList);
$mq->close();} catch (\Exception $e) {return $this->jsonData(200, $e->getMessage());
}
// 入 MQ
return $this->jsonData(200, '导入胜利');
}
5. 生产业务逻辑。