最近公司有個需求就是將excel的數(shù)據(jù)存儲到數(shù)據(jù)庫,不過數(shù)據(jù)庫有三百多張表馍乙,不同的excel存在不同的表中侨艾,如果每張表都建個實體去映射需要建三百多個實體,代碼大量重復不說羡滑,工程量太大菇爪,所以想到去動態(tài)拼接sql,批量上傳柒昏。持久層框架選擇了強大的mybatis凳宙,因為動態(tài)拼接,不采用預編譯职祷,變量用${}代替氏涩。
將excel文件名和對應數(shù)據(jù)庫表名存儲在一張表里,每次導入時候先去查找相應表名有梆。再根據(jù)表名查找表所有的字段名(通過MetaData)是尖。
自己建一個轉化工具類:
@Slf4j
@Component
public class GetCuloumListUtil {
@Value("${spring.datasource.url}")
private String datasource;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
public List<String> getCuloumList(String tableName) throws SQLException {
List<String> list = null;
Connection conn = DriverManager
.getConnection(datasource+"?user="+username+"&password="+password);
DatabaseMetaData metaData = conn.getMetaData();
ResultSet resultSet = metaData.getColumns(null, "%", tableName, "%");
list = new ArrayList<>();
while (resultSet.next()) {
String columnName = resultSet.getString("COLUMN_NAME");
list.add(columnName);
}
log.info(tableName+"表字段名:{}", list.toString());
return list;
}
}
由于動態(tài)構建sql不創(chuàng)建實體,所以將讀取每一列的值放到一個map中泥耀,key是列的序號析砸,value是列的值,由于要求map中值有序爆袍,所以采用TreeMap實例化首繁。讀取的每一行是一個map,再將每一行的map放到一個list中陨囊。poi導入就不介紹了弦疮,這里部分代碼如下:
for(int r=1;r<totalRows;r++){
Map<Integer,String> map=new TreeMap();//要求map有序
Row row = sheet.getRow(r);
if (row == null) continue;
//循環(huán)Excel的列
for(int c = 0; c <this.totalCells; c++){
if(row.getCell(c)!=null&&!row.getCell(c).equals("")){
if (row.getCell(c).getCellType()== HSSFCell.CELL_TYPE_NUMERIC){
log.info("cell類型是:{}",row.getCell(c).getCellStyle().getDataFormatString());
if(HSSFDateUtil.isCellDateFormatted(row.getCell(c))){//時間類型的列
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = HSSFDateUtil.getJavaDate(row.getCell(c).getNumericCellValue());
map.put(c,dateFormat.format(date));
}else {
row.getCell(c).setCellType(Cell.CELL_TYPE_STRING);
map.put(c,row.getCell(c).getStringCellValue());
}
}else {
row.getCell(c).setCellType(Cell.CELL_TYPE_STRING);//列類型轉為String
map.put(c,row.getCell(c).getStringCellValue());//列值存在map中
}
}else {
map.put(c,"");
}
}
list.add(map);
}
mapping.xml配置文件:
<insert id="add">
INSERT INTO ${tableName}
<foreach collection="culoum" item="item" separator="," open="(" close=")">
${item}
</foreach>
VALUES
<foreach collection="value" item="list" separator=",">
<foreach collection="list.values" item="val" separator="," open="(" close=")">
'${val}'
</foreach>
</foreach>
</insert>
這里采用了嵌套foreach循環(huán),里面的collection可以直接用list.values取出map的value值蜘醋,如果想取出map的key值可以用list.key胁塞,這也是mybatis的強大之處啊。
dao層代碼:
void add(@Param("tableName") String tableName, @Param("culoum") List culoum, @Param("value") List<Map<Integer, String>> value);
注意:
1、由于動態(tài)sql沒有采用預編譯啸罢,所以需要我們手動處理sql注入的問題编检。
2、由于mysql默認接受data最大是1M扰才,也就是超過了就會失敗允懂。所以excel文件過大時候要設置max_allow_packet。