項目架構:spring+struts2+hibernate4+oracle
需求:用戶導入excel文件,導入到相應的數據表中,要求提供導入模板,支持xls和xlsx文件
思路分析:
1、提供一個下載鏈接,點擊下載,可以使超鏈接,src直接是項目路徑加文件名。
2、通過上傳文件,服務器接收上傳,返回一個上傳后的服務器本地路徑,通過ajax異步賦值到jsp的路徑隱藏域。
3、ajax異步提交導入請求,后台處理,將路徑轉換成File,File轉換成MultipartFile,將文件讀取轉換成一個數組類型的集合。
4、循環集合這種的數據,每一行excel數據,是一個元素,將元素轉換成相應的java對象進行保存。
一、所需jar包
一共是6個jar包。
二、前端jsp代碼部分
<input type="hidden" id="excelFilePath" name="excelFilePath" value="" /> <tr> <td>選擇文件:</td> <td><input type="file" name="uploadFile" id="excelFile"></input></input> <span id="uploadMsg"></span></td> </tr> <tr> <td></td> <td> <input type="button" value="上傳" onclick="fileUpload()"> <input type="button" value="導入" id="btnOk" disabled="true" onclick="importEmp()"/> </td> </tr>
<script type="text/javascript"> // 文件上傳 function fileUpload(){ $("#fileTypeError").html(""); $("#btnOk").attr("disabled",true); var fileName = $("#excelFile").val(); var fileType = fileName.substr(fileName.length-4,fileName.length); if(fileType == ".xls" || fileType == "xlsx"){ var uploadFileUrl = "${basePath}/public/uploadFile.action"; var formData = new FormData($("#mainForm")[0]); $.ajax({ type: "POST", url: uploadFileUrl, data: formData, cache: false, processData: false, contentType: false, dataType : "json", success: function(data){ if(null != data){ if (data.dataStatus == "1") { $("#uploadMsg").html("<font color='green'>上傳成功!</font>"); $("#btnOk").attr("disabled",false); $("#excelFilePath").attr("value",data.dataMain); //alert($("#excelFilePath").val()); } else { if (data.errorMsg != null && data.errorMsg.length > 0) { alert(data.errorMsg); $("#uploadMsg").html("<font color='red'>" +data.errorMsg + "請仔細閱讀操作說明!</font>"); } } } }, error : function(XMLHttpRequest, textStatus, errorThrown) { alert("系統異常[" + textStatus + "]:" + errorThrown); } }); }else{ $("#uploadMsg").html("<font color='red'>上傳文件類型錯誤,支持類型: .xls .xlsx</font>"); } } //Excel文件導入到數據庫中 function importEmp(){ var importExcelURL = "${basePath}/public/importResultExaminee.action"; var excelFilePath = $("#excelFilePath").val(); $.ajax({ type: "POST", url: importExcelURL, data: {"excelFilePath":excelFilePath}, cache: false, dataType : "json", success: function(data){ if(null != data){ if (data.dataStatus == "1") { $("#btnOk").attr("disabled",false); alert("本次成功導入數量:" + data.dataMain); }else{ if (data.errorMsg != null && data.errorMsg.length > 0) { alert(data.errorMsg); } } } }, error : function(XMLHttpRequest, textStatus, errorThrown) { alert("系統異常[" + textStatus + "]:" + errorThrown); } }) } </script>
三、核心處理類POIUtils代碼:
package com.sinotn.utils; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.springframework.web.multipart.MultipartFile; /** * excel導出導入工具類 * Copyright (c) 2018 by Sinotn * @author Libin * @date 2018年4月8日 上午9:39:50 */ public class POIUtils { private static Logger logger = Logger.getLogger(POIUtils.class); private final static String XLS = "xls"; private final static String XLSX = "xlsx"; /** * 讀取excel文件 * @param formFile * @return * @throws IOException */ public static List<String[]> readExcel(MultipartFile formFile) throws IOException { // 檢查文件 checkFile(formFile); //獲得Workbook工作薄對象 Workbook workbook = getWorkBook(formFile); //創建返回對象,把每行中的值作為一個數組,所有行作為一個集合返回 List<String[]> list = new ArrayList<String[]>(); if (null != workbook) { for (int sheetNum = 0; sheetNum < workbook.getNumberOfSheets();sheetNum++) { //獲得當前sheet工作表 Sheet sheet = workbook.getSheetAt(sheetNum); if (null == sheet) { continue; } //獲得當前sheet的開始行 int firstRowNum = sheet.getFirstRowNum(); //獲得當前sheet的結束行 int lastRowNum = sheet.getLastRowNum(); //循環除了第一行的所有行 for (int rowNum = firstRowNum + 1;rowNum <= lastRowNum;rowNum++) { //獲得當前行 Row row = sheet.getRow(rowNum); if(row == null){ continue; } //獲得當前行的開始列 int firstCellNum = row.getFirstCellNum(); //獲得當前行的列數 int lastCellNum = row.getPhysicalNumberOfCells(); String[] cells = new String[row.getPhysicalNumberOfCells()]; //循環當前行 for (int cellNum = firstCellNum; cellNum < lastCellNum;cellNum++) { Cell cell = row.getCell(cellNum); cells[cellNum] = getCellValue(cell); } list.add(cells); } } workbook.close(); } return list; } /** * 獲取當前行數據 * @param cell * @return */ @SuppressWarnings("deprecation") private static String getCellValue(Cell cell) { String cellValue = ""; if(cell == null){ return cellValue; } //把數字當成String來讀,避免出現1讀成1.0的情況 if(cell.getCellType() == Cell.CELL_TYPE_NUMERIC){ cell.setCellType(Cell.CELL_TYPE_STRING); } //判斷數據的類型 switch (cell.getCellType()){ case Cell.CELL_TYPE_NUMERIC: //數字 cellValue = String.valueOf(cell.getNumericCellValue()); break; case Cell.CELL_TYPE_STRING: //字符串 cellValue = String.valueOf(cell.getStringCellValue()); break; case Cell.CELL_TYPE_BOOLEAN: //Boolean cellValue = String.valueOf(cell.getBooleanCellValue()); break; case Cell.CELL_TYPE_FORMULA: //公式 cellValue = String.valueOf(cell.getCellFormula()); break; case Cell.CELL_TYPE_BLANK: //空值 cellValue = ""; break; case Cell.CELL_TYPE_ERROR: //故障 cellValue = "非法字符"; break; default: cellValue = "未知類型"; break; } return cellValue; } /** * 獲得Workbook工作薄對象 * @param formFile * @return */ private static Workbook getWorkBook(MultipartFile formFile) { //獲得文件名 String fileName = formFile.getName(); //創建Workbook工作薄對象,表示整個excel Workbook workbook = null; try { //獲取excel文件的io流 InputStream is = formFile.getInputStream(); //根據文件后綴名不同(xls和xlsx)獲得不同的Workbook實現類對象 if(fileName.endsWith(XLS)){ //2003 workbook = new HSSFWorkbook(is); }else if(fileName.endsWith(XLSX)){ //2007 workbook = new XSSFWorkbook(is); } } catch (IOException e) { logger.info(e.getMessage()); } return workbook; } /** * 檢查文件 * @param formFile * @throws IOException */ private static void checkFile(MultipartFile formFile) throws IOException { //判斷文件是否存在 if(null == formFile){ logger.error("文件不存在!"); throw new FileNotFoundException("文件不存在!"); } //獲得文件名 String fileName = formFile.getName(); //判斷文件是否是excel文件 if(!fileName.endsWith(XLS) && !fileName.endsWith(XLSX)){ logger.error(fileName + "不是excel文件"); throw new IOException(fileName + "不是excel文件"); } } }
四、action層代碼
POIUtil.readExcel方法讀取excel文件后,把一行中的值按先后順序組成一個數組,所有的行作為一個集合返回。我們可以在代碼中循環這個集合,把數組賦值到實體類對象中。
我在前台用form表單提交file文件,因為用的SpringMVC框架,后台用MultipartFile接收,代碼如下:
/** * 讀取excel文件中的用戶信息,保存在數據庫中 * @param excelFile */ @RequestMapping("/readExcel") public void readExcel(@RequestParam(value = "excelFile") MultipartFile excelFile,HttpServletRequest req,HttpServletResponse resp){ Map<String, Object> param = new HashMap<String, Object>(); List<User> allUsers = new ArrayList<User>(); try { List<String[]> userList = POIUtil.readExcel(excelFile); for(int i = 0;i<userList.size();i++){ String[] users = userList.get(i); User user = new User(); user.setUserName(users[0]); user.setPassword(users[1]); user.setAge(Integer.parseInt(users[2])); allUsers.add(user); } } catch (IOException e) { logger.info("讀取excel文件失敗", e); } param.put("allUsers", allUsers); this.userService.insertUsers(param); }
調用的service層方法就不貼代碼了,下面就是往數據庫插入數據了。
excel文件內容: