最近正在完善以前和小夥伴假期作的一個項目的一些小功能,其中一個就是上傳excel文件而且將excel文件中的數據導入到指定數據庫中。在這其中有遇到一些很小的細節的問題,因此決定將這個實現過程記錄下來。前端
(1)先後臺分離,前端使用form表單提交,直接將文件流傳遞給後臺,後臺經過poi進行解析。java
(2)在Excel中,有幾個基礎的概念web
(3)實現思路:在讀取Excel文件的過程當中,咱們能夠首先構造一個Workbook實例,而後遍歷每個Sheet,對於每個sheet,咱們再遍歷每個row,基於預先設定好的列名,讀取每一個cell的值。將讀取到的每個cell值,放進預先建立好的對象實例中去。【每個row就至關於一個實例對象】,最後咱們將這些實例對象組成一個對象列表,批量插入到數據庫中。spring
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.8</version> <exclusions> <exclusion> <artifactId>commons-codec</artifactId> <groupId>commons-codec</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.8</version> </dependency> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.3</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.5</version> </dependency>
在spring-mvc.xml中添加代碼數據庫
<bean id="multipartResolve" class="org.springframework.web.multipart.support.StandardServletMultipartResolver"> </bean>
在web.xml中央控制器中添加支持apache
2.Controller層代碼數組
後臺使用MultipartFile來獲取上傳的文件。須要注意的是其中的@RequestParam中的參數值須要與前端頁面表單中type="file"的name的屬性值相同。spring-mvc
//導入excel用戶信息 @ResponseBody @RequestMapping(value = "/importUserInfo.do", method = RequestMethod.POST) public ResultModel importUserInfo(@RequestParam("file") MultipartFile file) throws Exception { if (!file.isEmpty()) { InputStream inputStream = file.getInputStream(); return ResultModel.builder() .data(userService.importUserInfo(inputStream, file.getOriginalFilename())) .code(SUCCESS) .build(); } else return ResultModel.builder() .data("File is empty!") .code(SUCCESS) .build(); }
3.userService中的實現方法importUserInfomvc
@Override public Integer importUserInfo(InputStream filePath, String file) { List<User> list = new ArrayList<>(); String[] s; if (!file.endsWith(".xls") && !file.endsWith(".xlsx")) { //文件上傳格式出錯 return -2; } Workbook workbook = null; try { //獲取Workbook實例 workbook = ExcelUtil.getWorkBook(file, filePath); } catch (Exception e) { e.printStackTrace(); } Sheet sheet = workbook.getSheetAt(0); //去除sheet中的一些無效行,好比值爲空可是有格式的空白行 sheet = ExcelUtil.resetSheet(sheet); int lastRowNum = sheet.getLastRowNum(); for (int i = 1; i <= lastRowNum; i++) { Row row = sheet.getRow(i); int cells = sheet.getRow(i).getPhysicalNumberOfCells(); //獲取每一行的數值,並將其填入一個字符串的數組 s = ExcelUtil.getExcelRows(row, cells); User user = new User(); for (int j = 0; j < s.length; j++) { if (j == 0 && !s[j].equals("")) user.setInstitute(s[j]); else if (j == 1 && !s[j].equals("")) user.setMajor(s[j]); else if (j == 2 && !s[j].equals("")) user.setClassId(Integer.getInteger(s[j])); else if (j == 3 && !s[j].equals("")) user.setUsername(s[j]); else if (j == 4 && !s[j].equals("")) user.setRealName(s[j]); else if (j == 5 && !s[j].equals("")) user.setBirthday(DateUtil.parseYYYYMMDDDate(s[j])); else if (j == 6 && !s[j].equals("")) user.setQq(s[j]); else if (j == 7 && !s[j].equals("")) user.setTieba(s[j]); else if (j == 8 && !s[j].equals("")) user.setWeibo(s[j]); else if (j == 9 && !s[j].equals("")) user.setBlog(s[j]); user.setPassword("huhugty7tgf6f"); } list.add(user); } return userDao.insertList(list); }
4.Excel讀取類ExcelUtilapp
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellReference; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import java.io.InputStream; public class ExcelUtil { //判斷文件類型是否知足要求 public static Workbook getWorkBook(String file, InputStream fis)throws Exception{ Workbook workbook = null; if(!file.endsWith(".xls") && !file.endsWith(".xlsx")){ throw new Exception("上傳表格的格式錯誤!"); } if(file.endsWith(".xls")){ workbook = new HSSFWorkbook(fis,true); } if(file.endsWith(".xlsx")){ workbook = new XSSFWorkbook(fis); } return workbook; } //獲取每一行的數據,而且返回一個字符串數組 public static String[] getExcelRows(Row row , int columuNum){ String[] s ; StringBuilder builder = new StringBuilder(); for(int x = 0;x<columuNum;x++){ Cell cell = row.getCell(x); builder.append(getStringCellValue(cell)+","); } s = builder.toString().split(","); return s; } //獲取單元內的有效數據 public static String getStringCellValue(Cell cell){ StringBuilder sb = new StringBuilder(); switch (cell.getCellType()){ //數字 case Cell.CELL_TYPE_NUMERIC: if(DateUtil.isCellDateFormatted(cell)){ sb.append(cell.getDateCellValue()); }else { //將該數字強制轉化爲字符串類型獲取 cell.setCellType(Cell.CELL_TYPE_STRING); sb.append(cell.getStringCellValue()); } break; //字符串 case Cell.CELL_TYPE_STRING: sb.append(cell.getStringCellValue()); break; //布爾 case Cell.CELL_TYPE_BOOLEAN: sb.append(cell.getBooleanCellValue()); break; //公式 case Cell.CELL_TYPE_FORMULA: sb.append(cell.getCellFormula()); break; //空值 case Cell.CELL_TYPE_BLANK: sb.append(""); break; //故障 case Cell.CELL_TYPE_ERROR: sb.append(""); break; default: sb.append(""); break; } return sb.toString(); } //過濾掉表中的無心義空白行,由於getLastRowNum()在獲取Row行數時,對於表中沒有值但卻有格式的無心義空白行也將計入 public static Sheet resetSheet(Sheet sheet){ CellReference cellReference = new CellReference("A4"); boolean flag; for(int i=cellReference.getRow();i<=sheet.getLastRowNum();){ Row r = sheet.getRow(i); if(r == null){ sheet.shiftRows(i+1,sheet.getLastRowNum(),-1); continue; } flag = false; for(Cell c : r){ if(c.getCellType()!=Cell.CELL_TYPE_BLANK){ flag = true; break; } } if(flag){ i++; continue; } else{ //若是是空白行,沒有數據,可是有格式 if(i == sheet.getLastRowNum()) sheet.removeRow(r); else sheet.shiftRows(i+1,sheet.getLastRowNum(),-1); } } return sheet; } }
三.測試
這裏我使用postman來測試後臺接口:
測試結果: