PhpOffice實現Excel表格匯入的解耦方法

前言:

在業務中開發中,表格的匯入匯出功能很常見。但是這裡主要是使用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。 消費業務邏輯。

PhpOffice實現Excel表格匯入的解耦方法