Excel通用工具

guoyuchuan發表於2019-03-03

[TOC]

前言

最近專案中遇到要將MySQL資料庫中的某些資料匯出為Excel格式儲存,在以前也寫過這樣的功能,這次就準備用以前的程式碼,但是看了一下,這次卻不一樣,因為在以前用到的都是匯出一種或幾種資料,種類不多,但是這次匯出的種類比較多,相當於就是每一種型別的資料得單獨寫一些程式碼,而且重複的比較多;就想寫一個通用的,不管什麼種類,直接傳入資料就行了;

正文

想法

因為資料的種類是不同的,裡面的屬性也各不相同,如何用同一段程式碼去處理這些不同種類的屬性,讓我第一時間想到了Java的泛型和反射;因為之前的筆記中就寫到了反射,這時候剛好派上用場,就來實際操作一下;

程式碼部分

首先匯入poi相應的jar包:

        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.17</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.17</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml-schemas</artifactId>
            <version>3.17</version>
        </dependency>
        
複製程式碼
  1. 實體類
    有兩個實體類:pojoA 和pojoBB,主要是為了測試不同實體類的不同屬性是否有效;
    pojoA:

 /**
 * @author gyc
 * @date 2018/10/26  21:50
 */
 
public class PojoA {
    private String name;
    private int num;
    private double price;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getNum() {
        return num;
    }
    public void setNum(int num) {
        this.num = num;
    }
    public double getPrice() {
        return price;
    }
    public void setPrice(double price) {
        this.price = price;
    }
}
    
複製程式碼

pojoB:


/**
 * @author gyc
 * @date 2018/10/26  21:51
 */
public class PojoB {
    private String userName;
    private int age;
    private Date birthday;
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
}

複製程式碼
  1. 核心程式碼部分
    使用該類時,需要傳入每列得列名,為String陣列,以及資料的List集合物件;還有一個Excel的title名;其中每列自動適應寬度,這個屬性得將資料存入Excel之後才能呼叫,如果在資料存入之前呼叫,則不會取作用;

/**
 * @author gyc
 * @date 2018/10/26  21:45
 */
public class ExcelUtil<T> {

    public HSSFWorkbook setExcel(String title,String[] columnNames, List<T> tList) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, IOException {
//        1.建立Excel工作薄物件
        HSSFWorkbook workbook=new HSSFWorkbook();
//        2.建立Excel工作表物件
        HSSFSheet sheet=workbook.createSheet(title);
        HSSFRow row=null;
//        3.建立Excel工作表的第一行,並填充列名
        row=sheet.createRow(0);
        for(int i=0;i<columnNames.length;i++){
            row.createCell(i).setCellValue(columnNames[i]);
        }
        Field[] declaredFields = tList.get(0).getClass().getDeclaredFields();
//        4.將資料填充至表格中
        for(int j=1;j<=tList.size();j++){
            T t= tList.get(j-1);
            row=sheet.createRow(j);
            for(int i=0;i<declaredFields.length;i++){
                // 通過反射獲取屬性值
                String fieldName = declaredFields[i].getName();
                String getMethodName="get"+fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
                Method declaredMethod = t.getClass().getDeclaredMethod(getMethodName);
                //執行方法
                Object fieldValue = declaredMethod.invoke(t);
                //判斷是否為空
                if(fieldValue!=null &&  !"".equals(fieldValue)){
                    //判斷屬性值型別
                    if(fieldValue instanceof Integer){
                        row.createCell(i).setCellValue(Integer.valueOf(fieldValue.toString()));
                    }else if(fieldValue instanceof Double){
                     row.createCell(i).setCellValue(Double.valueOf(fieldValue.toString()));
                    }else if(fieldValue instanceof Date){
                        row.createCell(i).setCellValue(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(fieldValue));
                    }else {
                       row.createCell(i).setCellValue(fieldValue.toString());
                    }
                }else {
                    row.createCell(i).setCellValue("");
                }
            }
        }
//       自動設定列寬,要在在資料讀入之後設定;
        for (int i = 0; i < columnNames.length; i++) {
            sheet.autoSizeColumn(i);
            //在自動適應的基礎上增加寬度
//            sheet.setColumnWidth(i,sheet.getColumnWidth(i)*17/10);
        }
        return workbook;
    }
}

複製程式碼

測試

測試程式碼


/**
 * @author gyc
 * @date 2018/10/26  21:52
 */
public class Test {
    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException, IOException {
        PojoA pojoA=new PojoA();
        pojoA.setName("a");
        pojoA.setNum(1);
        pojoA.setPrice(1.1234);
        List<PojoA> lista=new ArrayList<>();
        lista.add(pojoA);

        PojoB pojoB=new PojoB();
        pojoB.setUserName("b");
        pojoB.setAge(2);
        pojoB.setBirthday(new Date());
        List<PojoB> listb=new ArrayList<>();
        listb.add(pojoB);

        HSSFWorkbook workbooka = new ExcelUtil().setExcel("pojoA", new String[]{"名稱", "數量", "價格"}, lista);
        HSSFWorkbook workbookb = new ExcelUtil().setExcel("pojoB", new String[]{"名稱", "年齡", "時間"}, listb);

        workbooka.write(new FileOutputStream(new File("/Users/rose/IdeaProjects/java-study/smalltools/pojoA.xls")));
        workbookb.write(new FileOutputStream(new File("/Users/rose/IdeaProjects/java-study/smalltools/pojoB.xls")));
    }
}

複製程式碼

GitHub地址:

總結

本篇筆記中使用了Java泛型和反射,但都是用得比較淺,只是最基礎的使用;主要解決了處理資料種類繁多的的問題,不用單獨處理;
其中也有很多不足之處,如下:

  • 資料集合只支援List集合
  • 用到了反射,速率可能比單獨處理的低
  • 需要手動傳入列名,比較硬編碼

相關文章