poi匯入匯出完整實現 包含工具類

2021-03-10 12:00:05

匯出excel

首先了解下Jakarta POI HSSF API常用元件和樣式

類名作用
HSSFWorkbookexcel的檔案物件
HSSFSheetexcel的表單
HSSFRowexcel的行
HSSFCellexcel的格子單元
HSSFFontexcel字型
HSSFDataFormat日期格式
HSSFHeadersheet頭
HSSFFootersheet尾(只有列印的時候才能看到效果)
HSSFCellStylecell樣式

一、匯入poi所需要的jar包
這兩個jar包的版本一定要一致,不然可能會報異常java.lang.NoClassDefFoundError: org/apache/poi/UnsupportedFileFormatException

<dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi</artifactId>
      <version>3.11</version>
</dependency>
<dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi-ooxml</artifactId>
      <version>3.11</version>
</dependency>

二、編寫匯出excel的工具類

1、HSSFWorkbook建立Excel檔案物件
2、HSSFWorkbook物件返回或者建立Sheet物件
3、Sheet物件返回行物件,用行物件得到Cell物件
4、對Cell物件進行讀寫操作

public class ExcelUtil {
    /**
     * 匯出excel
     * @param title  匯出表的標題
     * @param rowsName 匯出表的列名
     * @param dataList  需要匯出的資料
     * @param fileName  生成excel檔案的檔名
     * @param response
     */
    public void exportExcel(String title,String[] rowsName,List<Object[]> dataList,String fileName,HttpServletResponse response) throws Exception{
        OutputStream output = response.getOutputStream();
        response.reset();
        response.setHeader("Content-disposition", "attachment; filename="+fileName);
        response.setContentType("application/msexcel");
        this.export(title,rowsName,dataList,fileName,output);
        this.close(output);

    }


    /**
     * 匯出資料
     * @param title 匯出表的標題
     * @param rowName 匯出表的列名
     * @param dataList 需要匯出的資料
     * @param fileName 生成excel檔案的檔名
     * @param out
     * @throws Exception
     */
    private void export(String title,String[] rowName,List<Object[]> dataList,String fileName,OutputStream out) throws Exception {
        try {
            // 建立工作簿物件
            HSSFWorkbook workbook = new HSSFWorkbook();
            // 建立工作表
            HSSFSheet sheet = workbook.createSheet(title);
            // 產生表格標題行
            HSSFRow rowm = sheet.createRow(0);
            //建立表格標題列(需要的可以放開,這裡不使用標題列)
            //HSSFCell cellTiltle = rowm.createCell(0);
            // sheet樣式定義;    getColumnTopStyle();    getStyle()均為自定義方法 --在下面,可延伸
            // 獲取列頭樣式物件
            HSSFCellStyle columnTopStyle = this.getColumnTopStyle(workbook);
            // 獲取單元格樣式物件
            HSSFCellStyle style = this.getStyle(workbook);
            //合併表格標題行,合併列數為列名的長度,第一個0為起始行號,第二個1為終止行號,第三個0為起始列好,第四個引數為終止列號
            //合併單元格(需要的可以放開,這裡不合並單元格)
            //sheet.addMergedRegion(new CellRangeAddress(0, 1, 0, (rowName.length - 1)));
            //設定標題行樣式(需要的可以放開,這裡不使用標題列)
            //cellTiltle.setCellStyle(columnTopStyle);
            //設定標題行值(需要的可以放開,這裡不使用標題列)
            //cellTiltle.setCellValue(title);
            // 定義所需列數
            int columnNum = rowName.length;
            // 在索引2的位置建立行(最頂端的行開始的第二行)
            HSSFRow rowRowName = sheet.createRow(0);
            // 將列頭設定到sheet的單元格中
            for (int n = 0; n < columnNum; n++) {
                // 建立列頭對應個數的單元格
                HSSFCell cellRowName = rowRowName.createCell(n);
                // 設定列頭單元格的資料型別
                cellRowName.setCellType(HSSFCell.CELL_TYPE_STRING);
                HSSFRichTextString text = new HSSFRichTextString(rowName[n]);
                // 設定列頭單元格的值
                cellRowName.setCellValue(text);
                // 設定列頭單元格樣式
                cellRowName.setCellStyle(columnTopStyle);
            }

            // 將查詢出的資料設定到sheet對應的單元格中
            for (int i = 0; i < dataList.size(); i++) {
                Object[] obj = dataList.get(i);
                // 建立所需的行數,排除掉標題行的數量
                HSSFRow row = sheet.createRow(i + 1);
                for (int j = 0; j < obj.length; j++) {
                    // 設定單元格的資料型別
                    HSSFCell cell = null;
                    if (j == 0) {
                        cell = row.createCell(j, HSSFCell.CELL_TYPE_NUMERIC);
                        cell.setCellValue(i + 1);
                    } else {
                        cell = row.createCell(j, HSSFCell.CELL_TYPE_STRING);
                        if (!"".equals(obj[j]) && obj[j] != null) {
                            // 設定單元格的值
                            cell.setCellValue(obj[j].toString());
                        }
                    }
                    // 設定單元格樣式
                    cell.setCellStyle(style);
                }
            }

            // 讓列寬隨著匯出的列長自動適應
            for (int colNum = 0; colNum < columnNum; colNum++) {
                int columnWidth = sheet.getColumnWidth(colNum) / 256;
                for (int rowNum = 0; rowNum < sheet.getLastRowNum(); rowNum++) {
                    HSSFRow currentRow;
                    // 當前行未被使用過
                    if (sheet.getRow(rowNum) == null) {
                        currentRow = sheet.createRow(rowNum);
                    } else {
                        currentRow = sheet.getRow(rowNum);
                    }
                    if (currentRow.getCell(colNum) != null) {
                        HSSFCell currentCell = currentRow.getCell(colNum);
                        if (currentCell.getCellType() == HSSFCell.CELL_TYPE_STRING) {
                            int length = currentCell.getStringCellValue()
                                    .getBytes().length;
                            if (columnWidth < length) {
                                columnWidth = length;
                            }
                        }
                    }
                }
                if (colNum == 0) {
                    //設定寬度
                    sheet.setColumnWidth(colNum, (columnWidth - 2) * 256);
                } else {
                    sheet.setColumnWidth(colNum, (columnWidth + 4) * 256);
                }
            }
            workbook.write(out);
            //檔案自定義存放位置(不寫預設在下載裡,這裡不使用)
            //workbook.write(new FileOutputStream(new File("D://test"+".xls")));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 列頭單元格樣式
     * @param workbook
     * @return
     */
    private HSSFCellStyle getColumnTopStyle(HSSFWorkbook workbook) {

        // 設定字型
        HSSFFont font = workbook.createFont();
        // 設定字型大小
        font.setFontHeightInPoints((short) 11);
        // 字型加粗
        font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        // 設定字型名字
        font.setFontName("Courier New");
        // 設定樣式;
        HSSFCellStyle style = workbook.createCellStyle();
        // 設定底邊框;
        style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        // 設定底邊框顏色;
        style.setBottomBorderColor(HSSFColor.BLACK.index);
        // 設定左邊框;
        style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        // 設定左邊框顏色;
        style.setLeftBorderColor(HSSFColor.BLACK.index);
        // 設定右邊框;
        style.setBorderRight(HSSFCellStyle.BORDER_THIN);
        // 設定右邊框顏色;
        style.setRightBorderColor(HSSFColor.BLACK.index);
        // 設定頂邊框;
        style.setBorderTop(HSSFCellStyle.BORDER_THIN);
        // 設定頂邊框顏色;
        style.setTopBorderColor(HSSFColor.BLACK.index);
        // 在樣式用應用設定的字型;
        style.setFont(font);
        // 設定自動換行;
        style.setWrapText(false);
        // 設定水平對齊的樣式為居中對齊;
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        // 設定垂直對齊的樣式為居中對齊;
        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);

        return style;

    }

    /**
     * 列資料資訊單元格樣式
     * @param workbook
     * @return
     */
    private HSSFCellStyle getStyle(HSSFWorkbook workbook) {
        // 設定字型
        HSSFFont font = workbook.createFont();
        // 設定字型大小
        // font.setFontHeightInPoints((short)10);
        // 字型加粗
        // font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
        // 設定字型名字
        font.setFontName("Courier New");
        // 設定樣式;
        HSSFCellStyle style = workbook.createCellStyle();
        // 設定底邊框;
        style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        // 設定底邊框顏色;
        style.setBottomBorderColor(HSSFColor.BLACK.index);
        // 設定左邊框;
        style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        // 設定左邊框顏色;
        style.setLeftBorderColor(HSSFColor.BLACK.index);
        // 設定右邊框;
        style.setBorderRight(HSSFCellStyle.BORDER_THIN);
        // 設定右邊框顏色;
        style.setRightBorderColor(HSSFColor.BLACK.index);
        // 設定頂邊框;
        style.setBorderTop(HSSFCellStyle.BORDER_THIN);
        // 設定頂邊框顏色;
        style.setTopBorderColor(HSSFColor.BLACK.index);
        // 在樣式用應用設定的字型;
        style.setFont(font);
        // 設定自動換行;
        style.setWrapText(false);
        // 設定水平對齊的樣式為居中對齊;
        style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        // 設定垂直對齊的樣式為居中對齊;
        style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
        return style;
    }

    /**
     * 關閉輸出流
     * @param os
     */
    private void close(OutputStream os) {
        if (os != null) {
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

三、使用測試

@RequestMapping("exportWordData")
    public void exportExcelData(HttpServletRequest request, HttpServletResponse response){
        // 定義表的標題
        String title = "員工列表一覽";
        //定義表的列名
        String[] rowsName = new String[] { "序號", "姓名", "性別", "特長", "學歷", "入職時間", "簡歷", "照片", "部門" };
        List<Object[]> dataList = new ArrayList<Object[]>();
        //定義表的內容第一行
        Object[] objs = new Object[9];
        objs[0] = "測試";
        objs[1] = 11;
        objs[2] = "111";
        objs[3] = "測試";
        objs[4] = "測試";
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        String date = df.format(2018-12-24);
        objs[5] = date;
        objs[6] = "測試";
        objs[7] = "測試";
        objs[8] = "測試";
        //定義表的內容第二行
        Object[] objs1 = new Object[9];
        objs1[0] = "測試";
        objs1[1] = 11;
        objs1[2] = "111";
        objs1[3] = "測試";
        objs1[4] = "測試";
        SimpleDateFormat df1 = new SimpleDateFormat("yyyy-MM-dd");
        String date1 = df1.format(2019-12-24);
        objs1[5] = date1;
        objs1[6] = "測試";
        objs1[7] = "測試";
        objs1[8] = "測試";
        dataList.add(objs);
        dataList.add(objs1);
        // 建立ExportExcel物件
        ExcelUtil excelUtil = new ExcelUtil();

        try{
            //生成word檔案的檔名
            String fileName= new String("測試excel檔案.xlsx".getBytes("UTF-8"),"iso-8859-1");
            excelUtil.exportExcel(title,rowsName,dataList,fileName,response);
            System.out.println(true);
        }catch(Exception e){
            e.printStackTrace();
        }
    }

四、效果展示
在這裡插入圖片描述
匯入excel

匯入與匯出的基本步驟相似,關鍵要了解要匯入excel的結構,比如資料列、讀取資料的起始位置等,理解了匯出那麼匯入也就沒什麼難處了

一、控制層

@PostMapping("/import")
    public boolean addUser(@RequestParam("file") MultipartFile file) {
        boolean a = false;
        String fileName = file.getOriginalFilename();
        try {
            a = userService.batchImport(fileName, file);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(a);
        return  a;
    }

二、實現層

boolean batchImport(String fileName, MultipartFile file) throws Exception;



@Override
    @Transactional(rollbackFor = RuntimeException.class)
    public boolean batchImport(String fileName, MultipartFile file) throws Exception {
        boolean notNull = false;
        List<User> userList = new ArrayList<User>();
        //正則驗證上傳檔案格式
        if (!fileName.matches("^.+\\.(?i)(xls)$") && !fileName.matches("^.+\\.(?i)(xlsx)$")) {
            return false;
        }
        boolean isExcel = true;
        if (fileName.matches("^.+\\.(?i)(xlsx)$")) {
            isExcel = false;
        }
        InputStream is = file.getInputStream();
        Workbook wb = WorkbookFactory.create(is);
        Sheet sheet = wb.getSheetAt(0);
        if(sheet!=null){
            notNull = true;
        }
        User user;
        //遍歷當前頁所有行
        for (int r = 1; r <= sheet.getLastRowNum(); r++) {
            Row row = sheet.getRow(r);
            if (row == null){
                continue;
            }
            user = new User();
            if( row.getCell(0).getCellType() !=1){
                return false;
            }
            String name = row.getCell(0).getStringCellValue();
            if(name == null || name.isEmpty()){
                return false;
            }
            row.getCell(1).setCellType(Cell.CELL_TYPE_STRING);
            String phone = row.getCell(1).getStringCellValue();
            if(phone==null || phone.isEmpty()){
                return false;
            }
            String add = row.getCell(2).getStringCellValue();
            if(add==null){
                return false;
            }
            Date date=new Date();
            if(row.getCell(3).getCellType() !=0){
                return false;
            }else{
                date = row.getCell(3).getDateCellValue();
            }
            String des = row.getCell(4).getStringCellValue();
            user.setName(name);
            user.setPhone(phone);
            user.setAddress(add);
            user.setEnrolDate(date);
            user.setDes(des);
            userList.add(user);
        }
        for (User userResord : userList) {
            userDao.addUser(userResord);
            System.out.println(" 插入 "+userResord);
            
        }
        return notNull;
    }

三、前端傳入檔案

必須使用post方式傳入

<form method="post" enctype="multipart/form-data" action="user/import" >
    <input type="file" name="file"/>
    <input type="submit" value="提交">
</form>

四、使用測試
在這裡插入圖片描述
在這裡插入圖片描述
匯入功能要根據具體的業務實現,為了方便小夥伴使用我整理了檔案讀取功能,儲存就需要自己實現啦!附上excel讀取工具類:

public class ImportExcelUtil {
    /**
     * 獲取excel資料
     * 檔案字尾只能是xls、xlsx
     *
     * @param inputStream
     * @param fileName
     * @return
     * @throws IOException
     */
    public static List<Map<String, Object>> getExcelData(InputStream inputStream, String fileName) throws IOException {
        Map<String, Object> resultMap = new HashMap<>();
        String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
        suffix = suffix.toLowerCase();
        List<String> sheetNameList = new ArrayList<>();
        List<Map<String, Object>> listDataMap = new ArrayList<>();
        if ("xls".equals(suffix)) {
            HSSFWorkbook workbook = new HSSFWorkbook(inputStream);
            HSSFSheet sheet = null;
            //獲取每個Sheet表
            for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                sheetNameList.add(workbook.getSheetName(i));
                sheet = workbook.getSheetAt(i);
                List<List<String>> sheetList = new ArrayList<>();
                Map<String, Object> sheetDataMap = new HashMap<>();
                //獲取每行
                for (int j = 1; j < sheet.getPhysicalNumberOfRows(); j++) {
                    HSSFRow row = sheet.getRow(j);
                    List<String> rowList = new ArrayList<String>();
                    //獲取每個單元格
                    for (int k = 0; k < row.getPhysicalNumberOfCells(); k++) {
                        rowList.add(String.valueOf(row.getCell(k)));
                    }
                    sheetList.add(rowList);
                }
                System.out.println(workbook.getSheetName(i) + "表資料:" + sheetList);
                sheetDataMap.put("sheetName", workbook.getSheetName(i).trim());
                sheetDataMap.put("data", sheetList);
                listDataMap.add(sheetDataMap);
            }
        } else if ("xlsx".equals(suffix)) {
            XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
            XSSFSheet sheet = null;
            //獲取每個Sheet表
            for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                sheetNameList.add(workbook.getSheetName(i));
                sheet = workbook.getSheetAt(i);
                List<List<String>> sheetList = new ArrayList<>();
                Map<String, Object> sheetDataMap = new HashMap<>();
                //獲取每行
                for (int j = 2; j < sheet.getPhysicalNumberOfRows(); j++) {
                    XSSFRow row = sheet.getRow(j);
                    List<String> rowList = new ArrayList<String>();
                    //獲取每個單元格
                    for (int k = 0; k < row.getPhysicalNumberOfCells(); k++) {
                        rowList.add(String.valueOf(row.getCell(k)));
                    }
                    sheetList.add(rowList);
                }
                sheetDataMap.put("sheetName", workbook.getSheetName(i).trim());
                sheetDataMap.put("data", sheetList);
                listDataMap.add(sheetDataMap);
            }
            System.out.println("---所有資料:" + listDataMap);
        }
        return listDataMap;
    }
}