前言:

在业务中开发中,表格的导入导出性能很常见。然而这里次要是应用PhpOffice类库介绍实现导入表格数据的性能。 

抵触:

大部分的导入性能,就是通过点击按钮上传一张表格,而后后盾读取表格数据依据业务整顿后直接插入到数据库,最初再返回给前端。然而如果表格数据宏大,业务逻辑简单的时候,就会导致导入那一块很臃肿不好保护。 

解决办法:

解决形式是把导入与业务数据插入拆散,所以在二者之间增加一个队列就能够了。导入只负责将表格数据存入队列。业务局部能够是独自的零碎,最初就是生产队列中的数据了。这样一来,岂但晋升了导入速度,而且还让导入与零碎解耦,不会因为异样而影响到其余业务。 

编码:

1.下载PhpOffice。
composer repuire phpoffice/phpspreadsheet
2.导入导出代码。

<?phpnamespace 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.生产业务逻辑。