现有30多个省份的excel模板数据,每个excel数据的列数不统一,个别字段也不一样,现要求把数据导入系统中,后台能控制前台每个省份的字段是否展示?当按照名称搜索时,能搜索所有省份的数据。 问题是,我该如何设计这个表结构?导入的时候,能尽量少修改原模板数据,方便用户操作分别导入不同省份的数据
尝试过从30多个excel模板中抽取相同部分,形成一个excel模板数据,全部都按照统一模板导入,但是这样用户操作太累了,每次导入都要修改一下原数据形成统一模板才能导入,请教一下有什么好的办法?
模板数据是要统一的,就抽象导入接口,实现类就做差异的事情
方法只有2种
第1种你已经试了,程序省事了,用户麻烦了。
那么就换第2种,用户体验不变,程序支持多种不同模板的导入,
根据不同的省份按对应的模板进行解析即可,只要程序做完了,也就一次性工作量。
如有帮助,请采纳,十分感谢!
这个功能分为两个步骤:
现在有两个Excel表,Excel_A,Excel_B 代表两个省的模板数据,且“列数不统一,个别字段也不一样”:
Excel_A:
name | tel |
---|---|
医生 | 120 |
警察 | 110 |
Excel_B:
name | addr | age |
---|---|---|
张三 | 唐山 | 40 |
李四 | 唐山 | 45 |
一、第一步,解析数据:
这里使用POI来操作Excel表,读取单元格数据。解析数据并不需要依赖统一的表格模板,一个方法及可。通过POI的api可以直接拿到Excel的行数和列数。然后,便利每一行的每个单元,读取每个单元格以键值对保存到集合中,key为第一行列名,value为每个单元格的值。
读取到的数据结构为:
List<Map<String, String>>;
// list[i] 为第i+1行的数据(第一行是字段名)
// Map 如:{"name: 张三", "addr: 唐山", "age: 40"}
工具类依赖
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.10-FINAL</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.10-FINAL</version>
</dependency>
工具类代码:
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.util.StringUtils;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Date 2022/6/13 13:06
* @Version 1.0
*/
public class ExcelUtil {
public static List<Map<String, Object>> importExcel(InputStream inputstream)
throws IOException, InvalidFormatException {
Workbook workbook = new XSSFWorkbook(inputstream);
Sheet sheet = workbook.getSheetAt(0);
int physicalNumberofRows = sheet.getPhysicalNumberOfRows(); //封装对象List<map<map<String, Object>>>
List<Map<String, Object>> list = new ArrayList<>();
Row row1 = sheet.getRow(0);
int physicalNumberofcells = row1.getPhysicalNumberOfCells();
for (int j = 0; j < physicalNumberofRows; j++) {
Map<String, Object> map = new HashMap<>();
if (j == 0) {
continue;
}
Row row = sheet.getRow(j);
if (row == null) {
return list;
}
int isLastRowFlag = 0;
for (int cellnum = 0; cellnum < physicalNumberofcells; cellnum++) {
Cell cell = row.getCell(cellnum);
//校验获取表格中的值
String cellvalue = getValue(cell);
String key = getValue(row1.getCell(cellnum));
map.put(key, cellvalue);
if (!StringUtils.isEmpty(cellvalue)) {
isLastRowFlag++;
}
}
if (isLastRowFlag == 0) { //该行无数据, 视为最后一行
return list;
}
list.add(map);
}
return list;
}
public static String getValue (Cell cell){
String cellvalue = "";
if (cell == null) {
return cellvalue;
}
//把数字当成String来读, 避免出现1读成1.0的情况
if (cell.getCellType() == cell.CELL_TYPE_NUMERIC) {
cell.setCellType(cell.CELL_TYPE_STRING);
}
//判断数据的类型
switch (cell.getCellType()) {
case Cell.CELL_TYPE_NUMERIC:
//数字
cellvalue = String.valueOf(cell.getNumericCellValue());
break;
case Cell.CELL_TYPE_STRING:
// 字符串
cellvalue = String.valueOf(cell.getStringCellValue());
break;
case Cell.CELL_TYPE_BLANK:
// 空
cellvalue = null;
break;
case Cell.CELL_TYPE_BOOLEAN:
cellvalue = String.valueOf(cell.getBooleanCellValue());
break;
default:
cellvalue = "未知类型";
break;
}
return cellvalue;
}
// 测试工具类
public static void main(String[] args) throws IOException {
InputStream inputStream = new BufferedInputStream(
new FileInputStream(
new File("C:\\Users\\wang\\Desktop\\test.xlsx")));
List<Map<String, Object>> list = ExcelUtil.importExcel(inputStream);
for (Map<String, Object> map : list){
for (Map.Entry entry : map.entrySet()){
System.out.println(entry.getKey()+"-"+entry.getValue());
}
}
}
}
一、第二步,保存数据到数据库:
数据存储,一个表即可,字段即为30多个省份的excel模板字段的集合。如Excel_A,Excel_B两个表,表结构可创建如下:
name | addr | age | tel |
---|---|---|---|
张三 | 唐山 | 40 | null |
李四 | 唐山 | 45 | null |
医生 | null | null | 120 |
警察 | null | null | 110 |
如果该省的模板没有某些字段,设为null。保存在一个表,这样搜索也方便。
有过类似的问题,我们是这样解决的,看一下能否参照:
补充说明:
B表因为是个性表,存在数据存储的浪费,但这样逻辑简单;具体情况需要看具体的需求。