上傳EXCEL檔案到後端,匯入並解析EXCEL的前後端實現(Vue.js + java後端)
vue.js前端,Java後端,如何匯入excel檔案,並且解析,本文給了前後端程式碼的實現,以及完美實踐OK之後的分享。
前端主要用了element-ui的upload元件。
關於這個元件的官方文件很少:http://element-cn.eleme.io/#/zh-CN/component/upload ,也沒仔細給個完整的demo,所以踩完坑寫個完整的部落格。
1.VUE前端demo
<el-upload class="upload-demo" ref="upload" :action="uploadUrl()" :data="uploadData" name="excelFile" :on-preview="handlePreview" :on-remove="handleRemove" :file-list="fileList" :on-error="uploadFalse" :on-success="uploadSuccess" :auto-upload="false" :before-upload="beforeAvatarUpload"> <el-button slot="trigger" size="small" type="primary">選取檔案</el-button> <el-button style="margin-left: 10px;" size="small" type="success" @click="submitUpload">批量匯入</el-button> <div slot="tip" class="el-upload__tip">只能上傳excel檔案</div> </el-upload>
關於每個欄位的意思:
-
uploadUrl() 是後臺介面(接受上傳的檔案並做後端的邏輯處理)
!!!注意:uploadUrl方法中,直接return的是你的後端URL介面,可以是相對路徑,也可以是絕對路徑
取相對路徑的時候,會自動加上請求所在頁面的字首htpp://XXX作為請求URL的字首,如果這樣拼接的不對,自己就加上絕對路徑:http://localhost:8080/XX 這樣類似的URL
-
upLoadData是上傳檔案時要上傳的額外引數,也可以不寫,將引數直接帶在URL請求中,見下面的demo
形似: url + "?businessName=" + this.businessName
-
uploadError是上傳檔案失敗時的回掉函式,uploadSuccess是檔案上傳成功時的回掉函式,
-
beforeAvatarUpload是在上傳檔案之前呼叫的函式,可以在這裡進行檔案型別的判斷,對上傳格式及大小作限制
-
:auto-upload="false"是停止檔案自動上傳模式
-
name="excelFile"這裡是將匯入的EXCEL檔案命名,並傳給後端,所以後端介面的入參也要是這個名字,下面會貼程式碼。
-
:file-list="fileList" 顯示已上傳的檔案列表,效果見下圖3
-
<el-button slot="trigger" size="small" type="primary">選取檔案</el-button>
<el-button style="margin-left: 10px;" size="small" type="success" @click="submitUpload">批量匯入</el-button>
是為了實現將選取檔案和上傳分開,效果如下:
-
關於上傳多個檔案
-
首先是設定是否可以同時選中多個檔案上傳,這個也是<input type='file'>的屬性,新增multiple即可。另外el-upload元件提供了:limit屬性來設定最多可以上傳的檔案數量,超出此數量後選擇的檔案是不會被上傳的。:on-exceed繫結的方法則是處理超出數量後的動作。(但一般單個檔案批量匯入夠用了)程式碼如下:
<el-upload multiple :limit="3" :on-exceed="handleExceed"> </el-upload>
上面每個方法對應的實現:
methods: {
uploadUrl: function() {
return (
"/fanxing/import/batchInsertShops" +
"?businessName=" +
this.businessName +
"&businessStatus=" +
this.businessStatus +
"&businessType=" +
this.businessType
);
},
uploadSuccess(response, file, fileList) {
if (response.status) {
alert("檔案匯入成功");
} else {
alert("檔案匯入失敗");
}
},
uploadFalse(response, file, fileList) {
alert("檔案上傳失敗!");
},
// 上傳前對檔案的大小的判斷
beforeAvatarUpload(file) {
const extension = file.name.split(".")[1] === "xls";
const extension2 = file.name.split(".")[1] === "xlsx";
const extension3 = file.name.split(".")[1] === "doc";
const extension4 = file.name.split(".")[1] === "docx";
const isLt2M = file.size / 1024 / 1024 < 10;
if (!extension && !extension2 && !extension3 && !extension4) {
alert("上傳模板只能是 xls、xlsx、doc、docx 格式!");
}
if (!isLt2M) {
console.log("上傳模板大小不能超過 10MB!");
}
return extension || extension2 || extension3 || (extension4 && isLt2M);
},
submitUpload() {
if (this.businessType != null) {
//觸發元件的action
this.$refs.upload.submit();
}
if (this.businessType == null) {
this.businessType = "businessType不能為空";
}
},
handleRemove(file, fileList) {
console.log(file, fileList);
},
handlePreview(file) {
if (file.response.status) {
alert("此檔案匯入成功");
} else {
alert("此檔案匯入失敗");
}
}
}
貼上效果圖:
2.後端介面的實現
controller層的實現,主要看介面如何定義
@Controller
@RequestMapping(value = "/fanxing/import")
public class ImportController {
@Resource
ImportDataService importDataService;
@RequestMapping(value = "/batchInsertShops", method = RequestMethod.POST)
@ResponseBody
public ResultData<Integer> batchInsert(@RequestParam("excelFile") MultipartFile excelFile,
@RequestParam(value = "businessName", required = true ) String businessName,
@RequestParam(value = "businessStatus", required = true) Integer businessStatus,
@RequestParam(value = "businessType", required = true) Integer businessType) throws IOException {
String name = excelFile.getOriginalFilename();
if (name.length() < 6 || !name.substring(name.length() - 5).equals(".xlsx")) {
return ResultDataBuilder.failWithNull("檔案格式錯誤", ResultCode.FILE_FORMAT_ERROR.getCode());
}
//TODO 業務邏輯,通過excelFile.getInputStream(),處理Excel檔案
ExcelUtils.excelToShopIdList(excelFile.getInputStream());
}
}
後端如何解析Excel檔案
package com.dianping.fanxing.system.admin.web.util;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ExcelUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(ExcelUtils.class);
public static List<Integer> excelToShopIdList(InputStream inputStream) {
List<Integer> list = new ArrayList<>();
Workbook workbook = null;
try {
workbook = WorkbookFactory.create(inputStream);
inputStream.close();
//工作表物件
Sheet sheet = workbook.getSheetAt(0);
//總行數
int rowLength = sheet.getLastRowNum() + 1;
//工作表的列
Row row = sheet.getRow(0);
//總列數
int colLength = row.getLastCellNum();
//得到指定的單元格
Cell cell = row.getCell(0);
for (int i = 1; i < rowLength; i++) {
row = sheet.getRow(i);
for (int j = 0; j < colLength; j++) {
cell = row.getCell(j);
if (cell != null) {
cell.setCellType(Cell.CELL_TYPE_STRING);
String data = cell.getStringCellValue();
data = data.trim();
if (StringUtils.isNumeric(data))
list.add(Integer.parseInt(data));
}
}
}
} catch (Exception e) {
LOGGER.error("parse excel file error :", e);
}
return shopIds;
}
}
3.漢字傳輸的亂碼問題
關於前端輸入漢字,傳到後端的controller層亂碼問題,確定前端頁面設定的是UTF-8
原因:Spring MVC 是基於Servlet,在Http請求到達Servlet解析之前,GET過來的URL已經被Tomcat先做了一次URLDecode。
Tomcat對GET方式預設的URL解碼結果是iso-8859-1而不是UTF-8!
解決辦法1:
decodeFName = new String(fName.getBytes("iso-8859-1"),"utf-8");
解決方法2:
進入Tomcat的安裝目錄下,conf目錄下找到server.xml檔案,配置如下,主要新增 URIEncoding="UTF-8"就好了
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
URIEncoding="UTF-8" />
建議第二種,一勞永逸
參考連結:https://segmentfault.com/a/1190000013796215#articleHeader5
主要遇到的問題:
1.前端元件使用問題
2.前端請求的相對路徑,被upload元件自動補全了字首,導致請求到不了後端
3.post請求的漢字到了後端的controller層亂碼。
至此,前後端聯調完畢,done。後端的去寫前端真的心累,此文記錄下這兩天的摸索吧。