excel匯入工具

雲梟發表於2018-08-09

1 介紹

excel匯入工具

整個專案的程式碼結構如下

    \---excelExport # 匯出工具包
        |   AsyncExportExcel.java #多執行緒匯出
        |   ExcelImport.java # 匯出工具類
        |
        +---data
        |       BaseParam.java # 基礎匯出引數類
        |
        +---dataConversion
        |       DataExportConversion.java # 屬性匯出轉換介面
        |
        +---defaultDataHandle # 預設的資料處理
        |       AbstractDataHandler.java
        |       BooleanDataHandler.java
        |       DataHandlerFactory.java
        |       DateDataHandler.java
        |       StringDataHandler.java
        |
        \---style # 預設的樣式
                AbstractCellStyle.java
                DefaultDataCellStyle.java
                DefaultTitleCellStyle.java

com
\---utils
    +---demo # 案例相關
    |   |   ExcelImportApplication.java # springboot啟動類
    |   |
    |   +---bean
    |   |       DemoBean.java # 測試bean
    |   |
    |   +---controller
    |   |       ExcelImportController.java # 測試從web匯入excel和從檔案匯入excel
    |   |
    |   \---importParam
    |       |   DemoImportParam.java # 匯入引數
    |       |
    |       \---dataConversion
    |               HobbyConversion.java # 愛好屬性匯入轉換類
    |
    \---excelImport # 匯入工具包
        |   ExcelImport.java # 匯入工具類
        |
        +---data
        |       CellParam.java # 匯入列引數類
        |
        \---dataConversion
            |   DataImportConversion.java # 屬性匯入轉換介面
            |
            \---impl
                    DateConversion.java # 日期屬性匯入轉換介面
                    MapConversion.java  # 鍵值對屬性匯入轉換介面              
複製程式碼

簡單的來說excel匯入可以分為幾步

  1. 上傳excel檔案
  2. 將excel轉換為資料,有需要的資料進行轉換

2 使用

2.1 ExcelImport工具類

首先例項化ExcelImport工具類,我這裡提供了一個建構函式

public ExcelImport(Class<T> clazz, List<CellParam> cellParams)
複製程式碼
引數 含義
clazz Class物件(需要轉換為Bean的Class物件)
cellParams CellParam的list列表(每一列對應的欄位及資料轉換類)

例項化ExcelImport工具類之後,需要呼叫importExcel方法,方法定義如下

public List<T> importExcel(InputStream is)
複製程式碼

只需要傳入InputStream即可。

2.2 匯入列引數類CellParam

CellParam類程式碼如下

public class CellParam {
	private String fieldName;
    private DataImportConversion conversion;
	
	//Set Get Constructor
}
複製程式碼

2.2.1 屬性

可以看到CellParam類有兩個屬性

private String fieldName;
private DataImportConversion conversion;
複製程式碼
引數 含義
fieldName 列對應Bean的屬性
conversion 資料轉換類

2.3 資料轉換介面DataImportConversion

public interface DataImportConversion<T> {
    T transferData(Object data);
}
複製程式碼

我這裡預設提供了兩種資料轉換,一個是鍵值對,另一個是日期

2.3.1 鍵值對資料轉換

鍵值對資料轉換類是為了將一些通用資料轉換而提供的。
例如:男女、是否和一些不同名稱對應的不同數字(正常-->0,異常-->1,其他-->2)

使用者可以通過傳入的map的泛型決定返回值的型別。

public class MapConversion<K,V> implements DataImportConversion<V> {

    private Map<K,V> map ;

    private V defaultReturnValue;

    public MapConversion(Map<K, V> map) {
        this(map,null);
    }

    public MapConversion(Map<K, V> map,V defaultReturnValue) {
        this.map = map;
        this.defaultReturnValue = defaultReturnValue;
    }

    @Override
    public V transferData(Object data) {
        if (map == null) return null;

        //如果data為null且map的null對應的值不為null,則直接返回map中null對應的值
        if (data == null && map.get(null) != null){
            return map.get(null);
        }

        //迴圈查詢對應的key
        for (Map.Entry<K,V> entry:map.entrySet()){
            if (entry.getKey() != null && entry.getKey().equals(data)){
                return entry.getValue();
            }
        }
        //如果map裡面找不到對應的資料,則返回defaultReturnValue
        return defaultReturnValue;
    }
}
複製程式碼

2.3.2 日期資料轉換

提供日期轉換功能,通過傳入的日期轉換格式進行轉換。

public class DateConversion implements DataImportConversion<Date> {
    private SimpleDateFormat format;

    public DateConversion(String pattern) {
        this.format = new SimpleDateFormat(pattern);
    }

    @Override
    public Date transferData(Object data) {
        try {
            return format.parse(data.toString());
        } catch (Exception e){
            e.printStackTrace();
        }

        return null;
    }
}
複製程式碼

3 案例

3.1 場景

原始資料如下

姓名 性別 出生日期 愛好
塵心 2018-08-08 14:59:11 舞刀,弄槍
千月 2018-08-08 14:59:11 唱歌,跳舞

需要轉換為實體bean的列表,如下

DemoBean{name='塵心', sex=0, birthday=Wed Aug 08 14:13:45 CST 2018, hobbies=[舞刀, 弄槍]}
DemoBean{name='千月', sex=1, birthday=Wed Aug 08 14:13:45 CST 2018, hobbies=[唱歌, 跳舞]}
複製程式碼

實體類如下

public class DemoBean {

    //姓名
    private String name;

    //性別,0->女,1->男
    private Integer sex;

    //出生日期
    private Date birthday;

    //愛好
    private List<String> hobbies;

    //Set Get
    
}
複製程式碼

3.2 資料轉換

可以看到有三個屬性需要轉換,分別是性別、日期和愛好。性別和日期的資料轉換可以使用預設的資料轉換。愛好需要將字串根據分割並轉換為list列表資料,下面是愛好的資料轉換,

public class HobbyConversion implements DataImportConversion<List<String>> {
    @Override
    public List<String> transferData(Object data) {
        if (data == null) return null;

        //根據,分割字串
        String hobbyStr = data.toString();
        String[] hobbyArray = hobbyStr.split(",");

        //轉換成list
        List<String> hobbies = Arrays.asList(hobbyArray);
        return hobbies;
    }
}
複製程式碼

3.3 匯入引數類

資料轉換類寫好了之後,開始編寫匯入引數類,程式碼如下

public class DemoImportParam {
    public static List<CellParam> getCellParams(){
        Map<String,Integer> sexMap = new HashMap<>();
        sexMap.put("女",0);
        sexMap.put("男",1);

        List<CellParam> cellParams = new ArrayList<>();
        cellParams.add(new CellParam("name"));
        cellParams.add(new CellParam("sex", new MapConversion(sexMap)));
        cellParams.add(new CellParam("birthday", new DateConversion("yyyy-MM-dd HH:mm:ss")));
        cellParams.add(new CellParam("hobbies", new HobbyConversion()));
        return cellParams;
    }
}
複製程式碼

在DemoImportParam類中可以看到一個靜態方法getCellParams,返回List。方法內部先定義了一個mao物件,存放性別字串對應的數字,然後就是List的定義。
可以看到總共有4個列引數

  • 第一列標題名稱為姓名,對應的屬性名稱為name
  • 第二列標題名稱為性別,對應的屬性名稱為sex,資料轉換物件MapConversion
  • 第三列標題名稱為出生日期,對應的屬性名稱為birthday,日期轉換
  • 第四列標題名稱為愛好,對應的屬性名稱為hobbies,資料轉換物件HobbyConversion

3.4 匯出

接下來有兩種資料匯出方式,一種是url訪問彈出下載excel檔案,另外一種是匯出excel到檔案

3.4.1 從web匯入excel

@ResponseBody
@PostMapping("/import")
public List<DemoBean> importByWeb(MultipartFile file) throws Exception {
    ExcelImport excelImport = new ExcelImport(DemoBean.class, DemoImportParam.getCellParams());
    List<DemoBean> list = excelImport.importExcel(file.getInputStream());

    return list;
}
複製程式碼

3.4.2 從檔案匯入excel

@Test
public void importByFile() throws Exception {
    File file = new File("F:\\匯出demo.xlsx");
    FileInputStream inputStream = new FileInputStream(file);

    //匯入轉換
    ExcelImport excelImport = new ExcelImport(DemoBean.class, DemoImportParam.getCellParams());
    List<DemoBean> list = excelImport.importExcel(inputStream);

    //輸出
    for (DemoBean bean:list){
        System.out.println(bean);
    }
}
複製程式碼

專案位置:github.com/rainbowda/u…,有需要的可以看看

相關文章