美文网首页
java基于poi操作Excel

java基于poi操作Excel

作者: 一晴爸爸 | 来源:发表于2021-03-23 01:53 被阅读0次

    一、环境配置

    我们通过学习知道,java操作Excel时需要在maven工程中的pom.xml文件添加poi-ooxml的依赖包,眼下我们选择的版本是3.17,因为相对稳定且使用率较高。配置路径以及结果如下:

    二、poi-ooxml源码类学习

    我们安装好依赖后按照业务需要,即操作Excel表格(当前不涉及Excel的写入,只有读取操作),会学习到四个源码类,分别是XSSFWorkbook源码类、XSSFSheet源码类、XSSFRow源码类和XSSFCell源码类。学习源码的一个大体节奏是通过源码类先学习类的构造方法,然后是普通方法最后汇总源码方法,进行流水线开发。现在我先把四个源码类的常用方法总结下来,具体如下。

    2.1 XSSFWorkbook源码类[public class XSSFWorkbook extends POIXMLDocument implements Workbook]。(路径:poi-ooxml-3.17.jar-->org.apache.poi.xssf.usermodel-->XSSFWorkbook.clss):

    //构造方法

    public XSSFWorkbook();

    public XSSFWorkbook(XSSFWorkbookType workbookType);

    // public XSSFWorkbook(OPCPackage pkg) throws IOException;

    // public XSSFWorkbook(InputStream is) throws IOException;

    public XSSFWorkbook(File file) throws IOException, InvalidFormatException;

    ---上面构造方法引出File源码类,通过实例话File类拿到File类的对象,传参,获取XSSFWorkbook的对象。

    public XSSFWorkbook(String path) throws IOException;

    //普通方法

    public XSSFSheet cloneSheet(int sheetNum);

    public XSSFSheet cloneSheet(int sheetNum, String newName);

    public XSSFSheet createSheet();

    public XSSFSheet createSheet(String sheetname);

    public XSSFSheet getSheet(String name);

    public XSSFSheet getSheetAt(int index);

    public int getSheetIndex(String name);

    public int getSheetIndex(Sheet sheet);

    public String getSheetName(int sheetIx);

    public void removeSheetAt(int index);

    public void setSheetName(int sheetIndex, String sheetname);

    2.2 XSSFSheet源码类[public class XSSFSheet extends POIXMLDocumentPart implements Sheet]。上面我们观察到普通方法内创建Sheet、获取Sheet等方法最终都会得到一个sheet对象,那么XSSFSheet源码类又有哪些方法提供给我们使用呢?

    // 构造方法

    protected XSSFSheet();

    protected XSSFSheet(PackagePart part);

    注意:XSSFSheet源码类的构造方法都是被保护类型的,不能直接调用,我们可以通过XSSFWorkbook源码类拿到sheet对象,操作XSSFSheet源码类中的方法。

    // 普通方法

    public XSSFWorkbook getWorkbook();

    public String getSheetName();

    public int getColumnWidth(int columnIndex);

    public int getDefaultColumnWidth();

    public boolean isColumnHidden(int columnIndex);

    public void setColumnHidden(int columnIndex, boolean hidden);

    public void setColumnWidth(int columnIndex, int width);

    public void setDefaultColumnWidth(int width)

    public int getFirstRowNum();

    public int getLastRowNum();

    public short getDefaultRowHeight();

    public void setDefaultRowHeight(short height);

    public XSSFRow createRow(int rownum);

    public XSSFRow getRow(int rownum);

    public void removeRow(Row row)

    2.3 XSSFRow源码类[public class XSSFRow implements Row, Comparable<XSSFRow>]。上面我们可以看到由XSSFWorkbook类对象操作XSSFSheet类中的方法可以得到XSSFRow类的对象。得到行对象后就可以操作XSSFRow源码类中的方法。

    // 构造方法

    protected XSSFRow(CTRow row, XSSFSheet sheet);

    同XSSFSheet源码类,XSSFRow源码类的构造方法也是被保护的,解决方法类似。

    // 普通方法

    public XSSFSheet getSheet();

    public XSSFCell createCell(int columnIndex);

    public XSSFCell createCell(int columnIndex, CellType type);

    public XSSFCell getCell(int cellnum);

    public short getFirstCellNum();

    public short getLastCellNum();  // 特殊点:从1开始计数。

    public int getRowNum();

    public void setRowNum(int rowIndex);

    public void removeCell(Cell cell);

    2.4 XSSFCell源码类[public final class XSSFCell implements Cell ]。同样的道理,我们来看一下XSSFCell源码类中都有哪些构造方法和普通方法。

    // 构造方法

    protected XSSFCell(XSSFRow row, CTCell cell);

    // 普通方法

    public XSSFSheet getSheet();

    public XSSFRow getRow();

    public boolean getBooleanCellValue();

    public void setCellValue(boolean value);

    public double getNumericCellValue();

    public void setCellValue(double value);

    public String getStringCellValue();

    public void setCellValue(String str);

    public XSSFRichTextString getRichStringCellValue();

    public void setCellValue(RichTextString str);

    public String getCellFormula();

    public void setCellFormula(String formula);

    public Date getDateCellValue();

    public void setCellValue(Date value);

    public String getErrorCellString() throws IllegalStateException;

    public void setCellErrorValue(byte errorCode);

    public int getColumnIndex();

    public int getRowIndex();

    public CellType getCellTypeEnum();

    三、现在我们已经总结了以上四个源码类中的方法,下面我们就可以写流水线代码了。

    import java.io.IOException;

    import java.util.Date;

    import org.apache.poi.ss.usermodel.CellType;

    import org.apache.poi.xssf.usermodel.XSSFCell;

    import org.apache.poi.xssf.usermodel.XSSFRow;

    import org.apache.poi.xssf.usermodel.XSSFSheet;

    import org.apache.poi.xssf.usermodel.XSSFWorkbook;

    //流水线代码

    public class TestUtil {

    public static void main(String[] args) throws Exception {

    XSSFWorkbook wb = new XSSFWorkbook("/Users/xxxxxxxxx/testdata/app_testcase.xlsx");

    XSSFSheet getSheet = wb.getSheetAt(3);

    XSSFRow getRow = getSheet.getRow(1);

    XSSFCell getCell = getRow.getCell(2);

    CellType cellType = getCell.getCellTypeEnum();

    System.out.println(getSheet.getLastRowNum());

    System.out.println(getRow.getFirstCellNum());

    System.out.println(getRow.getLastCellNum());

    switch(cellType) {

    case _NONE:

    System.out.println("_NONEvalue为空。");

    break;

    case NUMERIC:

    double numValue = getCell.getNumericCellValue();

    System.out.println("numValue = " + numValue);

    break;

    case STRING:

    String strValue = getCell.getStringCellValue();

    System.out.println("strValue = " + strValue);

    break;

    case FORMULA:

    String formulaValue = getCell.getCellFormula();

    System.out.println("formulaValue = " + formulaValue);

    case BLANK:

    System.out.println("BLANKvalue为空。");

    break;

    case BOOLEAN:

    boolean booleanValue = getCell.getBooleanCellValue();

    System.out.println("booleanValue = " + booleanValue);

    break;

    case ERROR:

    System.out.println("没见过这种格式的单元格。");

    break;

    default:

    Date dateValue = getCell.getDateCellValue();

    System.out.println("dateValue = " + dateValue);

    break;

    }

    }

    }

    四、第一次封装代码。原则上一个源码类我们封装成一个方法,不同的源码类封装成不同的方法。此次封装得到3个方法,分别是:获取workbook、获取sheet、获取单元格的值。

    import java.io.IOException;

    import java.util.Date;

    import org.apache.poi.ss.usermodel.CellType;

    import org.apache.poi.xssf.usermodel.XSSFCell;

    import org.apache.poi.xssf.usermodel.XSSFRow;

    import org.apache.poi.xssf.usermodel.XSSFSheet;

    import org.apache.poi.xssf.usermodel.XSSFWorkbook;

    //第一次封装流水线代码

    public class TestUtil2 {

    //私有属性

    private String filePath;

    //构造方法

    public TestUtil2(String filePath) {

    this.filePath = filePath;

    }

    //普通方法,获取workbook

    public XSSFWorkbook getWb() throws Exception {

    XSSFWorkbook wb = new XSSFWorkbook(this.filePath);

    return wb;

    }

    //普通方法,获取sheet。通过workbook,根据下标拿到excel表格,即sheet。

    public XSSFSheet getSheet(int sheetIndex) throws Exception {

    XSSFWorkbook wb = getWb();

    XSSFSheet sheet = wb.getSheetAt(sheetIndex);

    return sheet;

    }

    //普通方法,获取某一个单元格的值。通过拿到的sheet表格,拿到某一行;通过这一行拿到这一行的某一列的单元格;通过该单元格属性,使用不同方法获取该单元格的值。

    public Object getCellValue(int sheetIndex, int rowIndex, int cellIndex) throws Exception {

    Object value = null;

    XSSFSheet sheet = getSheet(sheetIndex);

    XSSFRow row = sheet.getRow(rowIndex);

    XSSFCell cell = row.getCell(cellIndex);

    CellType cellType = cell.getCellTypeEnum();

    switch(cellType) {

    case _NONE:

    value = "";

    break;

    case NUMERIC:

    value = cell.getNumericCellValue();

    break;

    case STRING:

    value = cell.getStringCellValue();

    break;

    case FORMULA:

    value = cell.getCellFormula();

    case BLANK:

    value = "";

    break;

    case BOOLEAN:

    value = cell.getBooleanCellValue();

    break;

    case ERROR:

    System.out.println("没见过这种格式的单元格。");

    break;

    default:

    value = cell.getDateCellValue();

    break;

    }

    return value;

    }

    public static void main(String[] args) throws Exception {

    TestUtil2 tu2 = new TestUtil2("/Users/xxxxxxx/testdata/app_testcase.xlsx");

    Object value = tu2.getCellValue(1, 1, 3);

    System.out.println("第2个表格的第二行第四列的值是:" + value);

    }

    }

    五、第二次封装代码。此次封装主要针对上面获取单元格的值做了拆解。由一个方法拆分成两个方法,抽离出直接通过cell对象就能直接返回单元格的值的方法。

    import java.io.IOException;

    import java.util.Date;

    import org.apache.poi.ss.usermodel.CellType;

    import org.apache.poi.xssf.usermodel.XSSFCell;

    import org.apache.poi.xssf.usermodel.XSSFRow;

    import org.apache.poi.xssf.usermodel.XSSFSheet;

    import org.apache.poi.xssf.usermodel.XSSFWorkbook;

    //第二次封装流水线代码

    public class TestUtil3 {

    //私有属性

    private String filePath;

    //构造方法

    public TestUtil3(String filePath) {

    this.filePath = filePath;

    }

    //普通方法,获取workbook

    public XSSFWorkbook getWb() throws Exception {

    XSSFWorkbook wb = new XSSFWorkbook(this.filePath);

    return wb;

    }

    //普通方法,获取sheet。通过workbook,根据下标拿到excel表格,即sheet。

    public XSSFSheet getSheet(int sheetIndex) throws Exception {

    XSSFWorkbook wb = getWb();

    XSSFSheet sheet = wb.getSheetAt(sheetIndex);

    return sheet;

    }

    //普通方法,获取某一个单元格的值。通过拿到的sheet表格,拿到某一行;通过这一行拿到这一行的某一列的单元格;通过该单元格属性,使用不同方法获取该单元格的值。

    public Object getCellValue(int sheetIndex, int rowIndex, int cellIndex) throws Exception {

    XSSFSheet sheet = getSheet(sheetIndex);

    XSSFRow row = sheet.getRow(rowIndex);

    XSSFCell cell = row.getCell(cellIndex);

    Object value = fromCellGetCellValue(cell);

    return value;

    }

    //普通方法,获取单元格的值。通过只传一个cell单元格对象就能返回单元格的值

    public Object fromCellGetCellValue(XSSFCell cell) {

    Object value = null;

    CellType cellType = cell.getCellTypeEnum();

    switch(cellType) {

    case _NONE:

    value = "";

    break;

    case NUMERIC:

    value = cell.getNumericCellValue();

    break;

    case STRING:

    value = cell.getStringCellValue();

    break;

    case FORMULA:

    value = cell.getCellFormula();

    case BLANK:

    value = "";

    break;

    case BOOLEAN:

    value = cell.getBooleanCellValue();

    break;

    case ERROR:

    System.out.println("没见过这种格式的单元格。");

    break;

    default:

    value = cell.getDateCellValue();

    break;

    }

    return value;

    }

    public static void main(String[] args) throws Exception {

    TestUtil3 tu2 = new TestUtil3("/Users/xxxxxxx/testdata/app_testcase.xlsx");

    Object value = tu2.getCellValue(1, 1, 3);

    System.out.println("第2个表格的第二行第四列的值是:" + value);

    }

    }

    六、第三次封装代码。第三次封装主要是根据二维数组和Excel表格的相似性(都是通过两个坐标来定位一个元素)来把Excel表格的数据存储到二维数组内,再通过二维数组坐标取值,或者通过两层for循环拿到二维数组的全部值。

    import org.apache.poi.ss.usermodel.CellType;

    import org.apache.poi.xssf.usermodel.XSSFCell;

    import org.apache.poi.xssf.usermodel.XSSFRow;

    import org.apache.poi.xssf.usermodel.XSSFSheet;

    import org.apache.poi.xssf.usermodel.XSSFWorkbook;

    //第三次封装流水线代码

    public class TestUtil4 {

    //私有属性

    private String filePath;

    //构造方法

    public TestUtil4(String filePath) {

    this.filePath = filePath;

    }

    //普通方法,获取workbook

    public XSSFWorkbook getWb() throws Exception {

    XSSFWorkbook wb = new XSSFWorkbook(this.filePath);

    return wb;

    }

    //普通方法,获取sheet。通过workbook,根据下标拿到excel表格,即sheet。

    public XSSFSheet getSheet(int sheetIndex) throws Exception {

    XSSFWorkbook wb = getWb();

    XSSFSheet sheet = wb.getSheetAt(sheetIndex);

    return sheet;

    }

    //普通方法,获取某一个单元格的值。通过拿到的sheet表格,拿到某一行;通过这一行拿到这一行的某一列的单元格;通过该单元格属性,使用不同方法获取该单元格的值。

    public Object getCellValue(int sheetIndex, int rowIndex, int cellIndex) throws Exception {

    XSSFSheet sheet = getSheet(sheetIndex);

    XSSFRow row = sheet.getRow(rowIndex);

    XSSFCell cell = row.getCell(cellIndex);

    Object value = fromCellGetCellValue(cell);

    return value;

    }

    //普通方法,获取单元格的值。通过只传一个cell单元格对象就能返回单元格的值

    public Object fromCellGetCellValue(XSSFCell cell) {

    Object value = null;

    CellType cellType = cell.getCellTypeEnum();

    switch(cellType) {

    case _NONE:

    value = "";

    break;

    case NUMERIC:

    value = cell.getNumericCellValue();

    break;

    case STRING:

    value = cell.getStringCellValue();

    break;

    case FORMULA:

    value = cell.getCellFormula();

    case BLANK:

    value = "";

    break;

    case BOOLEAN:

    value = cell.getBooleanCellValue();

    break;

    case ERROR:

    System.out.println("没见过这种格式的单元格。");

    break;

    default:

    value = cell.getDateCellValue();

    break;

    }

    return value;

    }

    //普通方法,获取整个Excel的数据。通过Excel的坐标定位到cell单元格对象,由上面的fromCellGetCellValue方法得到该单元格的值;再定义一个二维数组接收所有单元格的值。

    //注意:二位数组的下表要和excel中想要获取的值的下表对应。

    public Object[][] getArrayExcelValue(int sheetIndex) throws Exception{

    XSSFSheet sheet =getSheet(sheetIndex);

    int lastRowNum = sheet.getLastRowNum();

    // int lastCellnum = sheet.getl

    Object[][] testData = new Object[lastRowNum][11];

    for(int i=1;i<lastRowNum+1;i++) {

    XSSFRow row = sheet.getRow(i);

    if(row==null) {continue;}

    for(int j=row.getFirstCellNum();j<row.getLastCellNum();j++) {

    XSSFCell cell = row.getCell(j);

    if(cell==null) {continue;}

    testData[i-1][j] = fromCellGetCellValue(cell);

    // testData[i-1][j] = getCellValue(sheetIndex, i, j);

    }

    }

    return testData;

    }

    //普通方法,输出二维数组

    public static void outPutArray(Object[][] data){

    for(int i=0;i<data.length;i++) {

    for(int j=0;j<data[i].length;j++) {

    Object value = data[i][j];

    System.out.print(value + " ");

    }

    System.out.print("\n");

    }

    }

    public static void main(String[] args) throws Exception {

    // TestUtil4 tu2 = new TestUtil4("/Users/zhaoxiaodong/testdata/app_testcase.xlsx");

    // Object value = tu2.getCellValue(1, 1, 3);

    // System.out.println("第2个表格的第二行第四列的值是:" + value);

    TestUtil4 tu4 = new TestUtil4("/Users/zhaoxiaodong/testdata/app_testcase.xlsx");

    Object[][] testData = tu4.getArrayExcelValue(3);

    // System.out.println(testData);

    System.out.println(testData[1][1]);

    outPutArray(testData);

    }

    }

    完美,完毕!

    相关文章

      网友评论

          本文标题:java基于poi操作Excel

          本文链接:https://www.haomeiwen.com/subject/rddxhltx.html