【前后前】導入Excel文件閉環模型:Vue3前端上傳Excel文件,【Java后端接收、解析、返回數據】,Vue3前端接收展示數據

【前后前】導入Excel文件閉環模型:Vue3前端上傳Excel文件,【Java后端接收、解析、返回數據】,Vue3前端接收展示數據

一、Vue3前端上傳(導入)Excel文件

ReagentInDialog.vue

<script setup lang="ts" name="ReagentInDialog">// 導入
const onImportClick = () => {// 模擬點擊元素if (fileInputRef.value) {// 重置以允許重復選擇相同文件fileInputRef.value.value = "";fileInputRef.value.click();}
};// 點擊【導入】觸發
const handleImport= async (e: Event) => {let dataList = [];try {tableLoading.value = true;// 獲取文件對象const input = e.target as HTMLInputElement;if (!input.files?.length) return;const file = input.files[0];// 鍵值列名映射表const keyColMap: Record<string, string> = {試劑編號: "reagentNo",試劑名稱: "reagentName",規格型號: "reagentSpec",單位: "reagentUnit",批號: "batchNo",有效期至: "validityDate",入庫數量: "amount",入庫金額: "total"};// 導入文件,由前端解析文件,獲取數據// dataList = await importExcelFileByClient(file, keyColMap);// 導入文件,由后端解析文件,獲取數據dataList = await importExcelFileByServer(file, keyColMap);} finally {tableLoading.value = false;}
}</script><template><el-button type="primary" plain @click="onImportClick">導入</el-button><!-- 文件輸入元素,不顯示,通過點擊按鈕【導入】執行 onImportClick,模擬點擊該元素,從而觸發 handleImport事件 --><inputref="fileInputRef"type="file"accept=".xls, .xlsx"style="display: none"@change="handleImport" /></template>

excelUtils.ts

import { formatJson } from "@/utils/formatter";
import { convertFileSize } from "@/utils/pubUtils";
import { ElMessage } from "element-plus";
import * as xlsx from "xlsx";
import { uploadFileService } from "@/api/upload";/*** 從Excel文件導入數據,由后端解析文件,獲取數據* @param file 導入文件* @param colKeyMap 列名鍵值映射,key --> value,如:excel中列名為【樣品編號】,其鍵值設置對應為【sampleNo】* @returns 列表數據*/
export async function importExcelFileByServer(file: any, keyColMap?: Record<string, string>) {// 定義及初始化需要返回的列表數據let dataList: any[] = [];// 文件校驗// 校驗文件名后綴if (!/\.(xls|xlsx)$/.test(file.name)) {ElMessage.warning("請導入excel文件!");return dataList;}// 校驗文件格式// application/vnd.ms-excel 為 .xls文件// application/vnd.openxmlformats-officedocument.spreadsheetml.sheet 為 .xlsx文件else if (file.type !== "application/vnd.ms-excel" &&file.type !== "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") {ElMessage.warning("excel文件已損壞,請檢查!");return dataList;}// 校驗文件大小else if (convertFileSize(file.size, "B", "MB") > 1) {ElMessage.warning("文件大小不能超過1MB!");return dataList;}// 文件讀取const fileReader = new FileReader();// 以二進制的方式讀取文件內容fileReader.readAsArrayBuffer(file);// 等待打開加載完成文件,其實就是執行 fileReader.onloadend = () => {},返回 true 表示成功,false 表示失敗const result = await loadedFile(fileReader);if (result) {// 通過 FormData 對象實現文件上傳const formData = new FormData();// 將文件對象 file 添加到 formData 對象中,uploadFile 需要與后端接口中接收文件的參數名一致formData.append("uploadFile", file);// 發送請求,上傳文件到后端服務器,后端接收文件,進行解析,并返回數據集const result = await uploadFileService(formData);dataList = keyColMap ? formatJson(result.data, keyColMap) : result.data;}// 返回列表數據return dataList;
}

upload.ts

import request from "@/utils/request";/*** 上傳文件,后端解析Excel文件,返回解析后的列表數據* @param file 文件,表單數據* @returns 列表數據*/
export const uploadFileService = (file: FormData) => {return request.post("/upload/parseExcelFile", file, {// 上傳文件,需設置 headers 信息,將"Content-Type"設置為"multipart/form-data"headers: {"Content-Type": "multipart/form-data"}});
};

二、Java后端接收、解析、返回數據

UploadController.java

package com.weiyu.controller;import com.weiyu.utils.ExcelUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import java.util.List;
import java.util.Map;/*** 上傳 Controller*/
@RestController
@RequestMapping("/upload")
@Slf4j
public class UploadController {// 上傳文件,后端解析Excel文件,返回解析后的列表數據// 因為前端是用 "Content-Type": "multipart/form-data" 的方式發送的請求,這里就不能用 @RequestBody,而是用 MultipartFile// 并且形參名稱 uploadFile 需要與前端定義的保持一致@PostMapping("/parseExcelFile")public ResponseEntity<?> uploadAndParseExcelFile(MultipartFile uploadFile) {log.info("【上傳文件】,解析Excel文件,/upload/parseExcelFile,uploadFile = {}", uploadFile);try {// 驗證文件if (uploadFile.isEmpty()) {return ResponseEntity.badRequest().body("文件為空");}// 驗證文件類型String contentType = uploadFile.getContentType();if (contentType == null || (!contentType.equals("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") && !contentType.equals("application/vnd.ms-excel"))) {return ResponseEntity.badRequest().body("僅支持 Excel 文件 (.xlsx, .xls)");}// 解析 ExcelList<Map<String, Object>> data = ExcelUtils.parseExcel(uploadFile);// 返回解析結果return ResponseEntity.ok(data);} catch (Exception e) {return ResponseEntity.internalServerError().body("解析失敗: " + e.getMessage());}}
}

三、Vue3前端接收展示數據

1、正常發送請求數據

2、正常接收響應數據

3、解析出錯

四、后端修改方案

UploadController.java

package com.weiyu.controller;import com.weiyu.pojo.Result;
import com.weiyu.utils.ExcelUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.server.ResponseStatusException;import java.util.List;
import java.util.Map;/*** 上傳 Controller*/
@RestController
@RequestMapping("/upload")
@Slf4j
public class UploadController {// 上傳文件,后端解析Excel文件,返回解析后的列表數據// 因為前端是用 "Content-Type": "multipart/form-data" 的方式發送的請求,這里就不能用 @RequestBody,而是用 MultipartFile// 并且形參名稱 uploadFile 需要與前端定義的保持一致@PostMapping("/parseExcelFile")@ResponseBody // 直接序列化返回值,使用 Result<List<Map<String, Object>>> 替換 ResponseEntity<?>public Result<List<Map<String, Object>>> uploadAndParseExcelFile(MultipartFile uploadFile) {log.info("【上傳文件】,解析Excel文件,/upload/parseExcelFile,uploadFile = {}", uploadFile);try {// 驗證文件
//            if (uploadFile.isEmpty()) {
//                return ResponseEntity.badRequest().body("文件為空");
//            }// 驗證文件類型
//            String contentType = uploadFile.getContentType();
//            if (contentType == null || (!contentType.equals("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") && !contentType.equals("application/vnd.ms-excel"))) {
//                return ResponseEntity.badRequest().body("僅支持 Excel 文件 (.xlsx, .xls)");
//            }// 解析 ExcelList<Map<String, Object>> data = ExcelUtils.parseExcel(uploadFile);// 返回解析結果
//            return ResponseEntity.ok(data);return Result.success(data);} catch (Exception e) {
//            return ResponseEntity.internalServerError().body("解析失敗: " + e.getMessage());throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "解析失敗: " + e.getMessage(), e);}}
}

前端導入效果

五、后端完善方案?

UploadController.java

package com.weiyu.controller;import com.weiyu.pojo.Result;
import com.weiyu.service.UploadService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import java.util.List;
import java.util.Map;/*** 上傳 Controller*/
@RestController
@RequestMapping("/upload")
@Slf4j
public class UploadController {@Autowiredprivate UploadService uploadService;// 上傳文件,后端解析Excel文件,返回解析后的列表數據// 因為前端是用 "Content-Type": "multipart/form-data" 的方式發送的請求,這里就不能用 @RequestBody,而是用 MultipartFile// 并且形參名稱 uploadFile 需要與前端定義的保持一致@PostMapping("/parseExcelFile")// @ResponseBody // 直接序列化返回值,使用 Result<List<Map<String, Object>>> 替換 ResponseEntity<?>public Result<List<Map<String, Object>>> uploadAndParseExcelFile(MultipartFile uploadFile) {log.info("【上傳文件】,解析Excel文件,/upload/parseExcelFile,uploadFile = {}", uploadFile);List<Map<String, Object>> data = uploadService.parseExcelFile(uploadFile);return Result.success(data);}
}

UploadServiceImpl.java

package com.weiyu.service.impl;import com.weiyu.service.UploadService;
import com.weiyu.utils.ExcelUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.util.List;
import java.util.Map;/*** 上傳 Service 接口實現*/
@Service
public class UploadServiceImpl implements UploadService {// 解析 Excel 文件@Overridepublic List<Map<String, Object>> parseExcelFile(MultipartFile uploadFile) {try {// 解析 Excelreturn ExcelUtils.parseExcel(uploadFile);} catch (IOException e) {throw new RuntimeException(e);}}
}

excel文件處理工具類 ExcelUtils.java?

package com.weiyu.utils;import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.NumberToTextConverter;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.ZoneId;
import java.util.*;/*** excel文件處理工具類*/
@Slf4j
@Component //通過@Component注解,將該工具類交給ICO容器管理,需要使用的時候不需要new,直接@Autowired注入即可
public class ExcelUtils {public static List<Map<String, Object>> parseExcel(MultipartFile file) throws IOException {try (InputStream inputStream = file.getInputStream()) {Workbook workbook = WorkbookFactory.create(inputStream);Sheet sheet = workbook.getSheetAt(0);// 獲取表頭行Row headerRow = sheet.getRow(0);if (headerRow == null) {return Collections.emptyList();}// 處理表頭(處理重復列名)List<String> headers = processHeaders(headerRow);// 解析數據行List<Map<String, Object>> data = new ArrayList<>();for (int i = 1; i <= sheet.getLastRowNum(); i++) {Row row = sheet.getRow(i);if (row == null) continue;Map<String, Object> rowData = parseRow(row, headers);if (!rowData.isEmpty()) {data.add(rowData);}}return data;}}private static List<String> processHeaders(Row headerRow) {List<String> headers = new ArrayList<>();Map<String, Integer> headerCount = new HashMap<>();for (Cell cell : headerRow) {String header = getCellValueAsString(cell).trim();// 處理空表頭if (header.isEmpty()) {header = "Column_" + (cell.getColumnIndex() + 1);}// 處理重復表頭int count = headerCount.getOrDefault(header, 0) + 1;headerCount.put(header, count);if (count > 1) {header = header + "_" + count;}headers.add(header);}return headers;}private static Map<String, Object> parseRow(Row row, List<String> headers) {Map<String, Object> rowData = new LinkedHashMap<>();DataFormatter formatter = new DataFormatter();for (int i = 0; i < headers.size(); i++) {String header = headers.get(i);Cell cell = row.getCell(i, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);// 根據單元格類型處理數據switch (cell.getCellType()) {case STRING:rowData.put(header, cell.getStringCellValue().trim());break;case NUMERIC:if (DateUtil.isCellDateFormatted(cell)) {// 日期類型處理rowData.put(header, cell.getDateCellValue().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());} else {// 數值類型處理double value = cell.getNumericCellValue();if (value == (int) value) {rowData.put(header, (int) value);} else {rowData.put(header, value);}}break;case BOOLEAN:rowData.put(header, cell.getBooleanCellValue());break;case FORMULA:// 公式單元格處理rowData.put(header, evaluateFormulaCell(cell));break;default:rowData.put(header, formatter.formatCellValue(cell));}}return rowData;}private static Object evaluateFormulaCell(Cell cell) {try {switch (cell.getCachedFormulaResultType()) {case NUMERIC:return cell.getNumericCellValue();case STRING:return cell.getStringCellValue();case BOOLEAN:return cell.getBooleanCellValue();default:return "";}} catch (Exception e) {return "FORMULA_ERROR";}}private static String getCellValueAsString(Cell cell) {if (cell == null) return "";switch (cell.getCellType()) {case STRING:return cell.getStringCellValue();case NUMERIC:return NumberToTextConverter.toText(cell.getNumericCellValue());case BOOLEAN:return String.valueOf(cell.getBooleanCellValue());case FORMULA:return evaluateFormulaCell(cell).toString();default:return "";}}
}

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/84815.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/84815.shtml
英文地址,請注明出處:http://en.pswp.cn/web/84815.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

網絡基礎入門:從OSI模型到TCP/IP協議詳解

網絡基礎入門&#xff1a;從OSI模型到TCP/IP協議詳解 一、網絡基礎概念與OSI七層模型 1.1 網絡通信的本質 計算機網絡的核心是將抽象語言轉換為二進制數據進行傳輸與計算&#xff0c;這一過程涉及多層抽象與轉換&#xff1a; 應用層&#xff1a;人機交互—抽象語言------編…

Linux致命漏洞CVE-2025-6018和CVE-2025-6019

Qualys 最近披露了兩個影響主流 Linux 發行版的本地權限提升 (LPE) 漏洞&#xff0c;分別是 CVE-2025-6018 和 CVE-2025-6019。這兩個漏洞可以被串聯利用&#xff0c;使得非特權用戶在幾秒鐘內獲得系統的 root 權限&#xff0c;從而實現對系統的完全控制。 一、漏洞詳情 這兩…

【Docker基礎】Docker鏡像管理:docker push詳解

目錄 引言 1 Docker鏡像推送基礎概念 1.1 什么是Docker鏡像推送 1.2 鏡像倉庫概述 1.3 鏡像標簽與版本控制 2 docker push命令詳解 2.1 基本語法 2.2 常用參數選項 2.3 實際命令示例 2.4 推送流程 2.5 步驟描述 3 鏡像推送實踐示例 3.1 登錄管理 3.2 標簽管理 3…

FPGA基礎 -- Verilog行為建模之循環語句

行為級建模&#xff08;Behavioral Modeling&#xff09;是 Verilog HDL 中最接近軟件編程語言的一種描述方式&#xff0c;適用于功能建模和仿真建模的初期階段。在行為級中&#xff0c;循環語句&#xff08;loop statements&#xff09;是常見且重要的控制結構&#xff0c;用于…

從C學C++(7)——static成員

從C學C(7)——static成員 若無特殊說明&#xff0c;本博客所執行的C標準均為C11. static成員和成員函數 對于特定類型的全體對象而言&#xff0c;有時候可能需要訪問一個全局的變量。比如說統計某種類型對象已創建的數量。 通常在C中使用全局變量來實現&#xff0c;如果我們…

大模型和ollama一起打包到一個docker鏡像中

如何將大模型鏡像和 Ollama 鏡像打包在一個 Docker 鏡像中 最近工作中有個需求是將ollama和大模型一起打成一個鏡像部署&#xff0c;將自己的操作步驟分享給大家。將大模型與 Ollama 服務打包在同一個 Docker 鏡像中&#xff0c;可以簡化部署流程并確保環境一致性。下面詳細介…

2025年滲透測試面試題總結-攻防研究員(應用安全)(題目+回答)

安全領域各種資源&#xff0c;學習文檔&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各種好玩的項目及好用的工具&#xff0c;歡迎關注。 目錄 攻防研究員(應用安全) 一、基礎部分 1. HTTP狀態碼對比 2. HTTP請求方法核心作用 3. 網絡分層協議速查表…

SpringBoot新聞項目學習day3--后臺權限的增刪改查以及權限管理分配

新增管理員修改管理員刪除管理員登錄 新增管理員 1.點擊新增按鈕打開一個對話框 2.確定新增對話框要顯示哪些內容 3.提交 4.后端處理、保存 5.響應前端 vue代碼 <template><!-- 新增代碼內容是比較多的,建議抽取出來,定義到一個獨立的vue文件中在列表組件中導入…

算法導論第二十五章 深度學習的倫理與社會影響

第二十五章 深度學習的倫理與社會影響 技術的光芒不應掩蓋倫理的陰影 隨著深度學習技術在各領域的廣泛應用&#xff0c;其引發的倫理和社會問題日益凸顯。本章將深入探討這些挑戰&#xff0c;并提供技術解決方案和最佳實踐&#xff0c;引導讀者構建負責任的人工智能系統。 25.…

Linux中ansible模塊補充和playbook講解

一、模塊使用 1.1 Yum模塊 功能&#xff1a;管理軟件包&#xff0c;只支持RHEL&#xff0c;CentOS&#xff0c;fedora&#xff0c;不支持Ubuntu其它版本 參數說明name要操作的軟件包名稱&#xff0c;支持通配符&#xff08;如 httpd, nginx*&#xff09;&#xff0c;也可以是…

唐代大模型:智能重構下的盛世文明圖譜

引言&#xff1a;當長安城遇見深度學習 一件唐代鎏金舞馬銜杯銀壺的虛擬復原品正通過全息投影技術演繹盛唐樂舞。這個跨越時空的場景&#xff0c;恰似唐代大模型技術的隱喻——以人工智能為紐帶&#xff0c;連接起長安城的盛世氣象與數字時代的文明重構。作為人工智能與歷史學…

國產ARM/RISCV與OpenHarmony物聯網項目(三)網關設備控制

一、設備控制界面與功能設計 程序界面運行與設計效果如下: 設備控制相關程序調用關系圖如下&#xff1a; 其中device_control.html程序為網頁界面顯示程序&#xff0c;led_alarm.cgi程序為光線數據的報警超限數據設置與管理&#xff0c;led_control.cgi程序功能為對Led燈的開…

微信小程序反編譯實戰教程

在實際滲透測試或安全分析中&#xff0c;經常會遇到微信小程序中的簽名加密&#xff08;sign&#xff09;機制&#xff0c;這些機制大多具備防重放、防篡改的特性&#xff0c;導致我們在抓包時難以直接復現請求。 &#x1f50d; 另一方面&#xff0c;一些小程序的代碼中往往會…

【NLP入門系列三】NLP文本嵌入(以Embedding和EmbeddingBag為例)

&#x1f368; 本文為&#x1f517;365天深度學習訓練營 中的學習記錄博客&#x1f356; 原作者&#xff1a;K同學啊 博主簡介&#xff1a;努力學習的22級本科生一枚 &#x1f31f;?&#xff1b;探索AI算法&#xff0c;C&#xff0c;go語言的世界&#xff1b;在迷茫中尋找光芒…

文心一言(ERNIE Bot):百度打造的知識增強大語言模型

1. 產品概述 文心一言&#xff08;ERNIE Bot&#xff09;是百度自主研發的知識增強大語言模型&#xff0c;于2023年3月16日正式發布&#xff0c;對標OpenAI的ChatGPT&#xff0c;具備文本生成、多模態交互、邏輯推理、中文理解等能力。該模型基于百度的飛槳深度學習平臺和文心…

Java-49 深入淺出 Tomcat 手寫 Tomcat 實現【02】HttpServlet Request RequestProcessor

點一下關注吧&#xff01;&#xff01;&#xff01;非常感謝&#xff01;&#xff01;持續更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持續更新中&#xff01;&#xff08;長期更新&#xff09; 目前2025年06月13日更新到&#xff1a; AI煉丹日志-28 - Aud…

在VB.net中,文本插入的幾個自定義函數

一、如果你是高手&#xff0c;一定“識貨”&#xff0c;分享給你 二、可應用于文本插入的幾種方式&#xff1a;6種 三、需要用到以下的幾個函數&#xff1a; 上代碼&#xff1a; Module TextModule <summary> 在指定位置插入文本 </summary> <p…

QC -io 服務器排查報錯方式/報錯: Failed to convert string to integer of varId variable!“

進斷點控制臺有報錯之后&#xff0c;復制報錯信息到 頭部菜單欄 1.編輯 -> 2.Find/Replace ->3.Advanced Find ->4. Project“xxxxx” 能找到問題點 再分析定位 在排查報錯時候&#xff0c;進入了這個報錯&#xff0c;msgInfo "MyTcpRedis: Failed to conver…

c++中auto與decltype使用

在 C11及后續版本中&#xff0c;關鍵字auto和decltype都是用于類型推導的&#xff0c;但它們的使用場景和行為有所不同。 1. auto 關鍵字 作用 auto 用于自動推導變量的類型&#xff0c;由編譯器根據初始化表達式來確定。 常見用法 // 基本用法 auto x 42; // int…

LabVIEW機器視覺零件檢測

基于LabVIEW 圖形化編程平臺與機器視覺技術&#xff0c;構建集圖像采集、處理、尺寸計算與合格性分析于一體的自動化檢測方案。通過模塊化硬件架構與自適應算法設計&#xff0c;實現對機械零件多維度尺寸的非接觸式高精度測量&#xff0c;相比人工檢測效率提升 12 倍&#xff0…