一、前端vue+element
1.前端使用element的upload組件來實現文件的上傳
<el-upload style="display: inline-flex;margin-right: 8px" :show-file-list="false" :before-upload="beforeUpload" :on-success="onSuccess" :on-error="onError" accept=".xls" :disabled="importDataButtonDisabled" action="/employee/basic/import"> <el-button :disabled="importDataButtonDisabled" type="success" size="small" :icon="importDataButtonIcon"> {{importDataButtonMsg}} </el-button> </el-upload>
show-file-list:是否顯示已選擇文件列表
before-upload:文件上傳以前調用的鈎子
on-error:文件上傳失敗后的鈎子
on-success:文件上傳成功后的鈎子
accept:接受的文件類型
action:上傳的地址
2.回調函數的處理
//批量導入用戶分為兩個步驟:1.上傳Excel文件 2.將Excel的數據轉換后插入數據庫 //**注意:這里的上傳成功的回調只是指Excel文件上傳成功,並不意味着整個批量導入用戶的操作是成功的 onSuccess(response, file, fileList){ //上傳成功后的回調 更改《導入數據》的按鈕顯示的值以及圖標 this.importDataButtonMsg='導入數據'; this.importDataButtonIcon='el-icon-upload2'; this.importDataButtonDisabled=false; //文件上傳成功后,判斷員工數據插入數據庫的結果(也相當於批量導入用戶的操作結果) if (response.status == 200){ Message.success({message:response.msg}) }else if (response.status == 500){ Message.error({message:response.msg}) }else { Message.error({message:'未知錯誤'}) } }, //上傳文件失敗后的回調 更改《導入數據》的按鈕顯示的值以及圖標 onError(err, file, fileList){ this.importDataButtonMsg='導入數據'; this.importDataButtonIcon='el-icon-upload2'; this.importDataButtonDisabled=false; this.$message.error(err); }, //上傳文件之前的回調 更改《導入數據》的按鈕顯示的值以及圖標 以使用戶可以區分按鈕的狀態 beforeUpload(){ this.importDataButtonMsg='正在上傳'; this.importDataButtonIcon='el-icon-loading'; this.importDataButtonDisabled=true; },
批量導入數據分為兩個步驟:1.上傳Excel文件 2.將Excel的數據轉換后插入數據庫。
為了防止點擊了導入數據后再次重復點擊導入按鈕以及區分未點擊按鈕和點擊導入數據的感官,設置導入數據的按鈕的顯示值和圖標為動態的,通過鈎子更新按鈕的顯示的值和圖標。
注意:這里的上傳成功的回調只是指Excel文件上傳成功,並不意味着整個批量導入用戶的操作是成功的
二、后端spring boot + mybatis
1.controller接受層
@PostMapping("/import") public RespBean importEmp(MultipartFile file){ // 拿到 file 對象 List<Employee> employees = EmpUtils.excelToObj(file,nationService.getAllNations(),departmentService.getAllDepartmentWithoutChild(),jobLevelService.getAllJobLevels(), politicsstatusService.getAllPoliticsstatuss(),positionService.getAllPositions()); if (employeeService.importEmp(employees) == employees.size()){ return RespBean.ok("導入成功!"); } return RespBean.error("導入失敗!"); }
controller層接收文件使用MultipartFile類來接收,忽略其他參數。
2.處理MultipartFile類對象
public static List<Employee> excelToObj(MultipartFile file, List<Nation> allNations, List<Department> allDepartment, List<JobLevel> allJobLevels,
List<Politicsstatus> allPoliticsstatuss, List<Position> allPositions) { List<Employee> employeeList = new ArrayList<>(); InputStream inputStream = null; try { //1.獲取文件的輸入流 inputStream = file.getInputStream(); //2.獲取Excel工作簿對象 HSSFWorkbook workbook = new HSSFWorkbook(inputStream); //3.獲取Excel工作表對象 因為此時只有一個工作表對象所以取第一個對象即可 //如果是多個工作表對象 可以通過如下方式獲取后進行遍歷 // int numberOfSheets = workbook.getNumberOfSheets(); HSSFSheet sheetAt = workbook.getSheetAt(0); //4.循環讀取表格的數據 for (Row row : sheetAt) { //表頭(標題) 跳過 if (row.getRowNum() == 0) { continue; } //空行直接跳過 if (row == null) { continue; } Employee employee = new Employee(); //獲取列數 int physicalNumberOfCells = row.getPhysicalNumberOfCells(); for (int k = 0; k < physicalNumberOfCells; k++) { Cell cell = row.getCell(k); //先通過表格列的類型進行分類 switch (cell.getCellType()) { //處理string類型 case STRING: switch (k) { case 1: employee.setName(cell.getStringCellValue()); break; case 2: employee.setWorkID(cell.getStringCellValue()); break; default: { break; } } break; default: { switch (k) { case 4: //處理日期類型的列 employee.setBirthday(cell.getDateCellValue()); break; case 20: employee.setBeginDate(cell.getDateCellValue()); break; case 22: employee.setBeginContract(cell.getDateCellValue()); break; case 23: employee.setEndContract(cell.getDateCellValue()); break; case 24: //處理double類型的列 employee.setContractTerm(cell.getNumericCellValue()); break; case 25: employee.setConversionTime(cell.getDateCellValue()); break; default: break; } break; } } } employeeList.add(employee); } } catch (IOException e) { e.printStackTrace(); } return employeeList; }
//1.獲取文件的輸入流
inputStream = file.getInputStream();
//2.獲取Excel工作簿對象 HSSFWorkbook workbook = new HSSFWorkbook(inputStream);
//3.獲取Excel工作表對象 因為此時只有一個工作表對象所以取第一個對象即可
//如果是多個工作表對象 可以通過如下方式獲取后進行遍歷
// int numberOfSheets = workbook.getNumberOfSheets();
HSSFSheet sheetAt = workbook.getSheetAt(0);
//4.循環讀取表格行的數據進行處理
3.在mybatis的mapper.xml中使用foreach批量插入數據
<insert id="importEmp" parameterType="com.hopec.vhr.bean.Employee"> insert into employee (name, gender, birthday, idCard, wedlock, nationId ) values <foreach collection="emps" separator="," item="emp"> (#{emp.name,jdbcType=VARCHAR}, #{emp.gender,jdbcType=CHAR}, #{emp.birthday,jdbcType=DATE}, #{emp.idCard,jdbcType=CHAR}, #{emp.wedlock,jdbcType=CHAR}, #{emp.nationId,jdbcType=INTEGER} ) </foreach> </insert>
批量插入的返回值為插入數據庫的記錄數,批量插入要么全部成功,要么全部失敗。