在項目開發中,開發人員在編寫代碼過程中或多或少都要涉及到直接將固定格式的數據文件內容導入到系統中,例如將一個存放員工信息的Excel文件導入到系統中。以員工信息導入爲例,大部分程序員的做法步驟如下:
- 在員工管理頁面提供導入功能,讓用戶可以上傳員工Excel文件;
- 服務器端採用POI或其它工具讀取Excel工作表中每行數據;
- 創建一個User對象,讀取每行單元格內容,驗證單元格數據是否合法,如果合法調用User對象對應setter方法進行賦值;
- 保存User對象,繼續處理下一行數據。
一般項目都會涉及到至少一個以上的導入,每個導入功能都要重複上述步驟,特別是在對第三步中讀取轉換時,涉及的代碼會更多、更爲複雜。爲了減少開發人員重複編寫數據導入代碼的負擔,增強導入代碼可讀性,作者結合本人經驗開發了一套excel-data-transformer工具用於簡化在步驟2、3中的代碼編寫複雜度。
excel-data-transformer是什麼?
- 遵循Apache 2.0協議;
- 非常方便的將Excel、CSV及其它文件中的數據直接轉換爲指定對象;
- 直接在轉換類的setter上增加驗證註解,無需對字符、數字等硬編碼驗證;
- 採用流式方式處理,支持對大文件的解析、轉換;
- 擴展方便,可以輕鬆的增加自定義的文件解析類;
excel-data-transformer如何簡化代碼?
- 實現了對Excel和CSV格式文件的解析,無需編寫文件讀取代碼;
- 採用註解方式實現對解析數據的合法性認證,自動將文件表頭列名映射到類下;
excel-data-transformer如何使用?
- 在轉換類的setter方法上增加@ExcelColumn(指定對應轉換文件的列名)、@NumberDesc(數字轉換、驗證)、@StringDesc(字符串轉換、驗證)、@DateDesc(日期轉換、驗證)、@CustomDesc(自定義驗證器)等註解;其中@ExcelColumn是必須要增加的;
public class User {
private String name;
private int age;
private Date birthday;
private String email;
public String getName() {
return name;
}
@ExcelColumn(name = "姓名", required = true, trim = true)
@CustomDesc(handler = "nameHandler")
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
@ExcelColumn(name = "年齡", trim = true)
@NumberDesc(min = "0", max = "100")
public void setAge(int age) {
this.age = age;
}
public Date getBirthday() {
return birthday;
}
@ExcelColumn(name = "出生日期", trim = true)
@DateDesc(pattern = "yyyy年MM月dd日")
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getEmail() {
return email;
}
@ExcelColumn(name = "Email", trim = true)
@StringDesc(pattern = StringRegex.EMAIL)
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User [name=" + name + ", age=" + age + ", birthday=" + birthday + ", email=" + email + "]";
}
}
- 如果有自定義轉換類,需要將自定義轉換類放到Map中,且key對應的值和@CustomDesc註解中的handler一致。如果沒有可忽略此步。
/**
* 員工姓名自定義轉換器
*
* @author wangguobin
*
*/
public class NameHandler extends CustomTypeHandler<String> {
public NameHandler() {
}
public NameHandler(Method method) {
super(method);
}
@Override
protected String transform(Object value) {
return "Ext" + value;
}
}
- 對數據進行轉換。
public class DataTransformerTest {
@Test
public void transform() {
try (InputStream in = new FileInputStream(new File("/home/wangguobin/test/用戶.xlsx"))) {
// Excel數據轉換
TableFileReader excelReader = new POIXLSXExcelReader(in);
transform(excelReader);
System.out.println("----------------------------");
// CSV數據轉換
TableFileReader csvReader = new CSVFileReader("/home/wangguobin/test/用戶.csv");
transform(csvReader);
} catch (Exception e) {
e.printStackTrace();
}
}
private void transform(TableFileReader excelReader)
throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException,
NotFoundColumnException, IllegalParameterNumException, NotSupportTypeException, TransformerException {
Map<String, CustomTypeHandler<?>> mapTypeHandler = new HashMap<String, CustomTypeHandler<?>>();
// 將自定義轉換器放到map中,key值必須和@CustomDesc(handler = "nameHandler")中的handler值一致
mapTypeHandler.put("nameHandler", new NameHandler());
// 逐行讀取文件數據,並將數據轉換爲指定的類
DataTransformer.transform(excelReader, User.class, new TransformHandler<User>() {
@Override
public void success(User rst) {
// 處理轉換成功的後續處理代碼...
}
/**
* @param pos 行號
* @param rowData 錯誤行原始數據
* @param errorMsg 錯誤消息
*/
@Override
public void error(int pos, Object[] rowData, String errorMsg) {
// 轉換失敗的後續代碼...
}
}, mapTypeHandler);
}
}
通過上述簡單操作即可快速、方便的將文件數據轉換爲對象,excel-data-transformer下載地址:
https://github.com/binxigogo/excel-data-transformer
歡迎大家下載並提出指導意見。