当前位置:首页 > PHP教程 > php高级应用 > 列表

详解如何实现phpoffice的excel导入功能解耦

发布:smiling 来源: PHP粉丝网  添加日期:2023-08-19 16:27:59 浏览: 评论:0 

在业务中开发中,表格的导入导出功能很常见。但是这里主要是使用PhpOffice类库介绍实现导入表格数据的功能。

冲突:

大部分的导入功能,就是通过点击按钮上传一张表格,然后后台读取表格数据根据业务整理后直接插入到数据库,最后再返回给前端。但是如果表格数据庞大,业务逻辑复杂的时候,就会导致导入那一块很臃肿不好维护。

解决方法:

处理方式是把导入与业务数据插入分离,所以在二者之间添加一个队列就可以了。导入只负责将表格数据存入队列。业务部分可以是单独的系统,最后就是消费队列中的数据了。这样一来,不但提升了导入速度,而且还让导入与系统解耦,不会因为异常而影响到其他业务。

编码:

1.下载PhpOffice。

composer repuire phpoffice/phpspreadsheet

2.导入导出代码。

  1. <?php 
  2. namespace app\common\helper; 
  3. use PhpOffice\PhpSpreadsheet\Spreadsheet; 
  4. use PhpOffice\PhpSpreadsheet\Writer\Xlsx; 
  5. use PhpOffice\PhpSpreadsheet\IOFactory; 
  6. use PhpOffice\PhpSpreadsheet\Cell\Coordinate; 
  7. use think\Exception; 
  8. class Excel 
  9. { 
  10.     // 导出 
  11.     public function outPut($data, $columns, $table = '导出文件') 
  12.     { 
  13.         $spreadsheet = new Spreadsheet(); 
  14.         $sheet = $spreadsheet->getActiveSheet(); 
  15.         // 设置第一栏的标题 
  16.         foreach ($columns as $k => $v) { 
  17.             $sheet->setCellValue($k . "1", $v['title']); 
  18.         } 
  19.         //第二行起 设置内容 
  20.         $baseRow = 2; //数据从N-1行开始往下输出 这里是避免头信息被覆盖 
  21.         foreach ($data as $key => $value) { 
  22.             foreach ($columns as $k1 => $v1) { 
  23.                 $i = $key + $baseRow; 
  24.                 $sheet->setCellValue($k1 . $i, $value[$v1['field']]); 
  25.             } 
  26.         } 
  27.         $writer = new Xlsx($spreadsheet); 
  28.         $filename = $table . date("Y-m-d", time()) . '_' . time() . '.xlsx'; 
  29.         $writer->save('./excel/' . $filename); 
  30.         return '/excel/' . $filename; 
  31.     } 
  32.     // 导入 
  33.     public function importExcel($file = '', $sheet = 0, $columnCnt = 0, &$options = []) 
  34.     { 
  35.         try { 
  36.             $file = iconv("utf-8", "gb2312", $file); 
  37.             if (emptyempty($file) OR !file_exists($file)) { 
  38.                 throw new \Exception('文件不存在!'); 
  39.             } 
  40.             $objRead = IOFactory::createReader('Xlsx'); 
  41.             if (!$objRead->canRead($file)) { 
  42.                 $objRead = IOFactory::createReader('Xls'); 
  43.                 if (!$objRead->canRead($file)) { 
  44.                     throw new \Exception('只支持导入Excel文件!'); 
  45.                 } 
  46.             } 
  47.             /* 如果不需要获取特殊操作,则只读内容,可以大幅度提升读取Excel效率 */ 
  48.             emptyempty($options) && $objRead->setReadDataOnly(true); 
  49.             /* 建立excel对象 */ 
  50.             $obj = $objRead->load($file); 
  51.             /* 获取指定的sheet表 */ 
  52.             $currSheet = $obj->getSheet($sheet); 
  53.             //$currSheet = $obj->getSheetByName($sheet);      // 根据名字 
  54.             if (isset($options['mergeCells'])) { 
  55.                 /* 读取合并行列 */ 
  56.                 $options['mergeCells'] = $currSheet->getMergeCells(); 
  57.             } 
  58.             if (0 == $columnCnt) { 
  59.                 /* 取得最大的列号 */ 
  60.                 $columnH = $currSheet->getHighestColumn(); 
  61.                 /* 兼容原逻辑,循环时使用的是小于等于 */ 
  62.                 $columnCnt = Coordinate::columnIndexFromString($columnH); 
  63.             } 
  64.             /* 获取总行数 */ 
  65.             $rowCnt = $currSheet->getHighestRow(); 
  66.             $data = []; 
  67.             /* 读取内容 */ 
  68.             for ($_row = 1; $_row <= $rowCnt; $_row++) { 
  69.                 $isNull = true; 
  70.                 for ($_column = 1; $_column <= $columnCnt; $_column++) { 
  71.                     $cellName = Coordinate::stringFromColumnIndex($_column); 
  72.                     $cellId = $cellName . $_row; 
  73.                     $cell = $currSheet->getCell($cellId); 
  74.                     if (isset($options['format'])) { 
  75.                         /* 获取格式 */ 
  76.                         $format = $cell->getStyle()->getNumberFormat()->getFormatCode(); 
  77.                         /* 记录格式 */ 
  78.                         $options['format'][$_row][$cellName] = $format; 
  79.                     } 
  80.                     if (isset($options['formula'])) { 
  81.                         /* 获取公式,公式均为=号开头数据 */ 
  82.                         $formula = $currSheet->getCell($cellId)->getValue(); 
  83.                         if (0 === strpos($formula, '=')) { 
  84.                             $options['formula'][$cellName . $_row] = $formula; 
  85.                         } 
  86.                     } 
  87.                     if (isset($format) && 'm/d/yyyy' == $format) { 
  88.                         /* 日期格式翻转处理 */ 
  89.                         $cell->getStyle()->getNumberFormat()->setFormatCode('yyyy/mm/dd'); 
  90.                     } 
  91.                     $data[$_row][$cellName] = trim($currSheet->getCell($cellId)->getFormattedValue()); 
  92.                     if (!emptyempty($data[$_row][$cellName])) { 
  93.                         $isNull = false; 
  94.                     } 
  95.                 } 
  96.                 if ($isNull) { 
  97.                     unset($data[$_row]); 
  98.                 } 
  99.             } 
  100.             return $data; 
  101.         } catch (\Exception $e) { 
  102.             throw $e; 
  103.         } 
  104.     } 
  105. } 

3.抽取指定的字段格式化Excel数据。

  1. return [ 
  2.     // 导入的表格标题 
  3.     "bidding" => [ 
  4.         "stock_no" => "编号", 
  5.         "price" => "价格", 
  6.         "mobile" => "手机", 
  7.         "nickname" => "姓名" 
  8.     ] 
  9. ]; 
  10. // 格式化指定列数据(默认第一行表头) 
  11. public static function formattingCells(array $data, array $cellConfig) 
  12. { 
  13.     $res = array_values($data); 
  14.     // 表头 
  15.     $header = $res[0]; 
  16.     $cellKeys = []; 
  17.     foreach ($header as $key => $value) { 
  18.         foreach ($cellConfig as $k => $v) { 
  19.             if ($value == $v) { 
  20.                 $cellKeys[$key] = $k; 
  21.             } 
  22.         } 
  23.     } 
  24.     if (count($cellKeys) != count($cellConfig)) { 
  25.         throw new Exception('表格不完整'); 
  26.     } 
  27.     // 需要添加过滤 
  28.     $temp = []; 
  29.     for ($i = 1; $i <= count($res) - 1; $i++) { 
  30.         foreach ($cellKeys as $m => $n) { 
  31.             $temp[$i][$n] = $res[$i][$m]; 
  32.         } 
  33.     } 
  34.     return array_values($temp); 
  35. } 

4.导入部分,上传接口。

  1. // 导入表格,上传接口 
  2. public function importExcel() 
  3. { 
  4.     $upload_file = $_FILES['files']['tmp_name']; 
  5.     $input = $this->input; 
  6.     // ID 
  7.     $id = isset($input['id']) ? $input['id'] : 0; 
  8.     // 默认取第一工作表 
  9.     $excelData = (new Excel())->importExcel($upload_file, 0); 
  10.     // 取Excel字段 
  11.     $config = config('excel_export.bidding'); 
  12.     $price_offer = Excel::formattingCells($excelData, $config); 
  13.     // 判断每条记录的手机和价格格式 
  14.     // …… 
  15.     $jsonList = json_encode(compact('id', 'price_offer')); 
  16.     //$jsonList = json_encode($price_offer); 
  17.     // 入MQ 
  18.     $host = config("mq.host"); 
  19.     $options = config("mq.price_offer_import"); 
  20.     try { 
  21.         $mq = new ProductMQ($host, $options); 
  22.         $mq->publish($jsonList); 
  23.         $mq->close(); 
  24.     } catch (\Exception $e) { 
  25.         return $this->jsonData(200, $e->getMessage()); 
  26.     } 
  27.     // 入MQ 
  28.     return $this->jsonData(200, '导入成功'); 
  29. } 

5.消费业务逻辑。

详解如何实现phpoffice的excel导入功能解耦

Tags: phpoffice excel导入

分享到: