天天看點

Java之POI的excel導入導出

  一、Apache POI是一種流行的API,它允許程式員使用Java程式建立,修改和顯示MS Office檔案。這由Apache軟體基金會開發使用Java分布式設計或修改Microsoft Office檔案的開源庫。它包含類和方法對使用者輸入資料或檔案到MS Office文檔進行解碼。

  二、基本結構

  HSSF - 提供讀寫

Microsoft Excel

格式檔案的功能。

  XSSF - 提供讀寫

Microsoft  Excel  OOXML   HWPF - 提供讀寫 Microsoft Word

  HSLF - 提供讀寫Microsoft PowerPoint格式檔案的功能。

  HDGF - 提供讀寫

Microsoft Visio

  三、這裡我們隻介紹xls,2003版的excel導入導出

  1)導入需要的依賴包(pom.xml)

  <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.17</version>
        </dependency>      

  2)簡單介紹一下excel的導入方式

public static void main(String[] args) throws Exception {
        //讀取檔案
        File file = new File("d:\\test.xls");
        InputStream inputStream = new FileInputStream(file);
        //使用POI的流處理資料
        POIFSFileSystem poifsFileSystem = new POIFSFileSystem(inputStream);
        //聲明2003版excel的檔案讀取方式
        HSSFWorkbook hssfWorkbook = new HSSFWorkbook(poifsFileSystem);
        //擷取第一個sheet頁
        HSSFSheet sheetAt = hssfWorkbook.getSheetAt(0);
        //擷取資料總行數
        int rows = sheetAt.getPhysicalNumberOfRows();
        //每行資料處理
        for (int i = 0; i < rows; i++) {
            //擷取一行資料
            HSSFRow row = sheetAt.getRow(i);
            if (i == 0) {
                //這個主要用于标題
                System.out.println(row.getCell(0));
                continue;
            }
            //擷取一行資料
            Iterator<Cell> cellIterator = row.cellIterator();
            List<Cell> cells = IteratorUtils.toList(cellIterator);
            System.out.println(cells);
        }

    }      

  3)根據上面的基本實作功能封裝了一些,工具類,主要目的是友善應用

  a、加入需要的工具依賴包(pom.xml)

    <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.9.3</version>
        </dependency>      

  說明:這個東西主要是用來做資料對考的

  b、需要的實體類(這個類的目的就是用來儲存excel中需要修改的一些參數位置)

import java.util.List;
import java.util.Map;

public class ExcelParams {

    //sheet頁數目
    private Integer sheetNum = 0;
    //實體名稱
    private String entityName;
    //儲存實體名稱行數
    private Integer clazzNum = 0;
    //字段行數
    private Integer columnNum = 1;
    //開始資料讀取的行數
    private Integer dataNum = 3;
    //開始讀取列
    private Integer readColNum = 0;
    //讀取的excel資料
    private List<Map<String, Object>> excelList;
    //最終資料處理
    private List<Map<String, Object>> excelHandleList;

    public Integer getSheetNum() {
        return sheetNum;
    }

    public void setSheetNum(Integer sheetNum) {
        this.sheetNum = sheetNum;
    }

    public String getEntityName() {
        return entityName;
    }

    public void setEntityName(String entityName) {
        this.entityName = entityName;
    }

    public Integer getClazzNum() {
        return clazzNum;
    }

    public void setClazzNum(Integer clazzNum) {
        this.clazzNum = clazzNum;
    }

    public Integer getColumnNum() {
        return columnNum;
    }

    public void setColumnNum(Integer columnNum) {
        this.columnNum = columnNum;
    }

    public Integer getDataNum() {
        return dataNum;
    }

    public void setDataNum(Integer dataNum) {
        this.dataNum = dataNum;
    }

    public Integer getReadColNum() {
        return readColNum;
    }

    public void setReadColNum(Integer readColNum) {
        this.readColNum = readColNum;
    }

    public List<Map<String, Object>> getExcelList() {
        return excelList;
    }

    public void setExcelList(List<Map<String, Object>> excelList) {
        this.excelList = excelList;
    }

    public List<Map<String, Object>> getExcelHandleList() {
        return excelHandleList;
    }

    public void setExcelHandleList(List<Map<String, Object>> excelHandleList) {
        this.excelHandleList = excelHandleList;
    }

}      

  excel模闆的基本方式:

  

Java之POI的excel導入導出

   說明:1、前面的序列号,是我為了友善了解加上去的,實際中不用加

      2、第一行中的資料為需要儲存的實體名路徑,後續再儲存的時候需要用到

      3、第二行是字段主要用于資料的對考,對考到具體的實體中

      4、第三行就是給輸入資料的人員展示的,第四行開始就是具體的資料了

  c、資料處理接口

import com.troy.excel.domain.ExcelParams;

public interface ExcelHandle {

    ExcelParams excelDataHanle(ExcelParams excelParams);
}      

  說明:這個接口目前沒有實作方法。提供出來的目前是用于資料處理。自己在處理資料的時候寫入資料處理的方式

  d、具體的解析過程和實體儲存過程

  /**
     * excel導入功能
     * @param file
     * @param excelParams
     * @param excelHandle
     * @return
     * @throws Exception
     */
    public static ExcelParams excelImport(File file, ExcelParams excelParams, ExcelHandle excelHandle) throws Exception {
        //擷取檔案流
        InputStream inputStream = new FileInputStream(file);
        //通過poi的方式進行讀取
        POIFSFileSystem poifsFileSystem = new POIFSFileSystem(inputStream);
        //聲明工作簿
        HSSFWorkbook hssfWorkbook = new HSSFWorkbook(poifsFileSystem);
        //進入sheet頁
        HSSFSheet hssfSheet = hssfWorkbook.getSheetAt(excelParams.getSheetNum());
        //讀取實體名稱資料
        HSSFRow entityRow = hssfSheet.getRow(excelParams.getClazzNum());
        HSSFCell entityName = entityRow.getCell(excelParams.getReadColNum());
        excelParams.setEntityName(entityName.getStringCellValue());
        //讀取資料儲存到list中
        List<Map<String,Object>> excelList = new ArrayList<>();
        //擷取字段資料
        HSSFRow colunmRow = hssfSheet.getRow(excelParams.getColumnNum());
        List<Cell> colums = IteratorUtils.toList(colunmRow.cellIterator());
        //讀取excel資料
        for (int i = excelParams.getDataNum(); i < hssfSheet.getPhysicalNumberOfRows(); i++) {
            //擷取某一行的資料
            HSSFRow excelRow = hssfSheet.getRow(i);
            Map<String, Object> map = new HashMap<>();
            for (int j = 0; j < excelRow.getPhysicalNumberOfCells(); j++) {
                if (colums != null && colums.size() > j) {
                    HSSFCell rowCell = excelRow.getCell(j);
                    //設定類型的目的友善資料裝換
                    rowCell.setCellType(CellType.STRING);
                    map.put(colums.get(j).getStringCellValue(), rowCell.getStringCellValue());
                }
            }
            excelList.add(map);
        }
        //放入資料放入下一步處理
        excelParams.setExcelList(excelList);
        //ExcelHandle接口用來做進一步資料處理,要求必須重寫
        excelHandle.excelDataHanle(excelParams);
        return excelParams;
    }      

  說明:ExcelHandle 為接口在使用的時候必須重寫才可以實作

  /**
     * 儲存excel資料
     * @param excelParams
     * @return
     */
    public static void saveExcelList(ExcelParams excelParams, EntityManager entityManager) throws Exception {
        //1、擷取儲存的對象
        Class<?> clazz = Class.forName(excelParams.getEntityName());
        //2、儲存資料
        for (Map<String, Object> map:excelParams.getExcelHandleList()) {
            //對考資料
            Object object = clazz.newInstance();
            BeanUtils.populate(object, map);
            //儲存資料
            entityManager.persist(object);
        }
    }      

  說明:BeanUtils提供了map到實體的拷貝,當然其他Gson,Fastjson也是可以實作的。

       entityManager.persist(object)是hibernate中儲存對象的方法

   e、測試方法

public static void main(String[] args) throws Exception {
        //讀取檔案
        File file = new File("d:\\test.xls");
        //聲明參數
        ExcelParams excelParams = new ExcelParams();
        excelParams.setSheetNum(0);
        excelParams.setClazzNum(0);
        excelParams.setColumnNum(1);
        excelParams.setDataNum(3);
        excelParams.setReadColNum(0);
        //導如資料
        ExcelParams excelData = ExcelUtil.excelImport(file, excelParams, (ep) -> {
            //重寫具體的實作方法
            ep.setExcelHandleList(excelParams.getExcelList());
            return ep;
        });
        //儲存實體,這裡需要加入到事物中,我這裡沒有具體測試
        ExcelUtil.saveExcelList(excelData, null);
        System.out.println(excelParams.getExcelList());
    }      

  4)導出功能,導出功能相對簡單。我就寫了一個簡單的實作過程,供了解。當然裡面的樣式這些,我不細說,自己研究

  /**
     * excel資料導出
     * @param title
     * @param datas
     * @param out
     * @param <T>
     * @throws Exception
     */
    public static <T> void excelExport(String title, List<T> datas, OutputStream out) throws Exception {
        //聲明一個工作簿
        HSSFWorkbook hssfWorkbook = new HSSFWorkbook();
        //設定一個sheet名詞
        HSSFSheet hssfSheet = hssfWorkbook.createSheet(title);
        //資料處理,通過out寫出
        for (int i = 0; i < datas.size(); i++) {
            //建立行數,主要是建立在第幾行
            HSSFRow hssfRow = hssfSheet.createRow(i);
            //擷取T的字段數
            Field[] fields = datas.get(i).getClass().getDeclaredFields();
            for (int j = 0; j < fields.length; j++) {
                //擷取字段名稱
                String fieldName = fields[j].getName();
                //擷取get方法
                String methodName = "get"+ fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
                Method method = datas.get(i).getClass().getMethod(methodName);
                //執行get方法擷取對應資料
                Object text = method.invoke(datas.get(i));
                //加入到對應單元格
                HSSFCell hssfCell = hssfRow.createCell(j);
                if (text != null) {
                    hssfCell.setCellValue(text.toString());
                }
            }
        }
        //寫入到輸出流中
        hssfWorkbook.write(out);
    }      

  測試方法:

   public static void main(String[] args) throws Exception {
        OutputStream outputStream = new FileOutputStream("d:\\1.xls");
        String title = "使用者資料";
        List<User> users = new ArrayList<>();
        for (int i = 1; i <= 10; i++) {
            User user = new User();
            user.setId(i);
            user.setName("name"+i);
            users.add(user);
        }
        ExcelUtil.excelExport(title, users, outputStream);
    }      

  四、基本上實作過程都在裡面,具體的封裝過程可以自己參考一下

  五、源碼下載下傳:

https://pan.baidu.com/s/1dahdRS

繼續閱讀