将Excel数据批量导入到数据库(项目案例)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 我们今天就给大家介绍一个用途非常广泛的功能:批量导入,在很多系统中,这也是必须实现的功能。而且当Excel表结构越复杂时,实现的难度就越高。不管项目如何复杂,原理却基本相同,一般是前台页面选择Excel文件,后台获取后进行数据转化,然后循环执行Sql语句即可,了解这些原理后,一切也就变得简单。

我们今天就给大家介绍一个用途非常广泛的功能:批量导入,在很多系统中,这也是必须实现的功能。而且当Excel表结构越复杂时,实现的难度就越高。


不管项目如何复杂,原理却基本相同,一般是前台页面选择Excel文件,后台获取后进行数据转化,然后循环执行Sql语句即可,了解这些原理后,一切也就变得简单。


下面为了重点演示,项目进行简化,只有批量导入功能,将Excel数据导入到Mysql数据库中。


Mysql数据库user表结构



20210118110454197.png


Excel中数据



20210118110516838.png


如果Excel中必填项数据为空,提示导入失败,报告错误信息及位置,项目演示图:


20210118110329530.gif


如果数据正确,提示导入数据库成功:


20210118110712664.gif



具体实现过程



首先是JSP页面,name的名称是重点:


<form action="${pageContext.request.contextPath }/excelsave.action" method="post" enctype="multipart/form-data">
    <input type="file" name="fileinput" multiple="multiple"/>
    <button type="submit" name="subimit">上传</button>
</form>


前台点击上传后跳转到action处理,action中首先定义:


//这里特别注意获取fileinput要和页面的导入时name属性一致。
private File fileinput;
//文件名用得到就获取,一般用不到。
private String fileinputFileName;
//下面是get和set方法,省略
然后在方法体中直接调用:
//参数为获取到的文件
ExcelUtil(fileinput);


ExcelUtil是处理Excel工具类,直接使用,代码如下:


/**解析excel 工具类*/
@SuppressWarnings("rawtypes")
public class ExcelUtil {
  public FileInputStream fis ;
  public HSSFWorkbook workBook;
  public HSSFSheet sheet;
  public XMLUtil parseXmlUtil;
  public StringBuffer errorString;
  /**当前实体类的code**/
  public String curEntityCode;
  /**表头map对象:key:entityCode, value:headMap(index,headTitle)**/
  public Map curEntityHeadMap ;
  /**字段的必填:key:entityCode+headTitle, value:true(必填),false(不必填)**/
  public Map curEntityColRequired;
  /**存放每一行的数据**/
  public  List listDatas ;
  public ExcelUtil(File excelFile){
    try {
      if(excelFile == null){
        throw new FileNotFoundException();
      }
       fis = new FileInputStream(excelFile);       
       workBook = new HSSFWorkbook(fis);
       parseXmlUtil = new XMLUtil();
       errorString = new StringBuffer();
       readExcelData();
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    }catch (IOException e) {
      e.printStackTrace();
    } 
  }
  /**开始从excel读取数据**/  
  public void readExcelData(){
    int sheetSize = workBook.getNumberOfSheets();
    for(int i=0;i<sheetSize;i++){
      sheet = workBook.getSheetAt(i);
      String entityName = workBook.getSheetName(i);
      readSheetData(sheet,entityName);
    }
  }
  /**读每个sheet页的数据**/
  public void readSheetData(HSSFSheet sheet,String entityName){
       int rowNumbers = sheet.getPhysicalNumberOfRows();
       Map ent = (Map) parseXmlUtil.getEntityMap().get(entityName);
       this.setCurEntityCode((String) ent.get("code"));
       if(rowNumbers == 0){
         System.out.println("excel中数据为空!");
         errorString.append(Constans.ERROR_EXCEL_NULL);
       }      
       List colList = (List) parseXmlUtil.getColumnListMap().get(entityName);
       int xmlRowNum = colList.size();
       HSSFRow excelRow = sheet.getRow(0);
       int excelFirstRow = excelRow.getFirstCellNum();
       int excelLastRow = excelRow.getLastCellNum();
       if(xmlRowNum  != (excelLastRow-excelFirstRow)){
           System.out.println("xml列数与excel列数不相符,请检查");
           errorString.append(Constans.ERROR_EXCEL_COLUMN_NOT_EQUAL);
       }
       readSheetHeadData(sheet);
       readSheetColumnData(sheet,entityName);
     }
 /**读取sheet页中的表头信息**/
   @SuppressWarnings({ "unchecked", "static-access"})
  public void readSheetHeadData(HSSFSheet sheet){
       Map headMap = new HashMap();
       curEntityHeadMap = new HashMap();
       curEntityColRequired = new HashMap();
       HSSFRow excelheadRow = sheet.getRow(0);
       int excelLastRow = excelheadRow.getLastCellNum();
       String headTitle = "";
       for(int i=0;i<excelLastRow;i++){
         HSSFCell cell = excelheadRow.getCell(i);
         headTitle = this.getStringCellValue(cell).trim();
         if(headTitle.endsWith("*")){
           curEntityColRequired.put(this.getCurEntityCode()+"_"+headTitle,true);
         }else{
           curEntityColRequired.put(this.getCurEntityCode()+"_"+headTitle,false);
         }
         headMap.put(i, headTitle);
       }
       curEntityHeadMap.put(this.getCurEntityCode(), headMap);
     }
   /**读取sheet页里面的数据**/
   @SuppressWarnings({ "unchecked", "static-access" })
   public void readSheetColumnData(HSSFSheet sheet,String entityName){
     HSSFRow excelheadRow = sheet.getRow(0);
     int excelLastcell = excelheadRow.getLastCellNum();   //excel总列数
     int excelRowNum = sheet.getLastRowNum();  //excel总行数
     Map headMap = (Map) this.getCurEntityHeadMap().get(this.getCurEntityCode());    
     Map colMap = parseXmlUtil.getColumnMap();
     listDatas =new ArrayList();
     for(int i=1;i<excelRowNum+1;i++){//行循环            
       HSSFRow columnRow = sheet.getRow(i); 
       if(columnRow != null){
         Map curRowCellMap = new HashMap();
         for(int j =0; j<excelLastcell;j++){ //列循环
           int cout =  headMap.get(j).toString().indexOf("*");
           String headTitle ="";
           if(cout == -1){
            headTitle = headMap.get(j).toString();
           }else{
             headTitle =  headMap.get(j).toString().substring(0, cout);
           }                
           Map curColMap =  (Map) colMap.get(entityName+"_"+headTitle);
           String curColCode = (String) curColMap.get("code");
           String curColType = (String) curColMap.get("type");
           HSSFCell colCell = columnRow.getCell(j);
           String value =this.getStringCellValue(colCell);
           if(value != null){
             value = value.trim();
           }        
           String xmlColType = (String) curColMap.get("type");
           int intVal = 0;
           if(xmlColType.equals("int")){
             if(value != null) {
               intVal = Integer.valueOf(value);
             }
             curRowCellMap.put(curColCode, intVal);  //将这一行的数据以code-value的形式存入map
           }else{
              curRowCellMap.put(curColCode, value); 
           }
           /**验证cell数据**/
           validateCellData(i+1,j+1,colCell,entityName,headTitle,curColType,listDatas);
         }
         listDatas.add(curRowCellMap);
       } 
     }
     if(this.getErrorString().length() ==0){//如果没有任何错误,就保存
       saveExcelData(entityName);
       System.out.println("导入数据库成功");
     }else{
       //清理所有的缓存clearMap();现在暂时未清理
       String[] strArr = errorString.toString().split("<br>");
       for(String s: strArr){
         System.out.println(s);
       }
     }
   }
   /**验证单元格数据**/
   @SuppressWarnings("static-access")
   public void validateCellData(int curRow,int curCol,HSSFCell colCell,String entityName,String headName,String curColType,List listDatas){
     List rulList = (List) parseXmlUtil.getColumnRulesMap().get(entityName+"_"+headName);
     if(rulList != null && rulList.size()>0){
       for(int i=0 ; i<rulList.size() ; i++){
         Map rulM = (Map) rulList.get(i);
         String rulName = (String) rulM.get("name");
         String rulMsg = (String) rulM.get("message");
         String cellValue = "";
         if(this.getStringCellValue(colCell)==null) {
           //System.out.println("第"+curRow+"行,第"+curCol+"列:"+rulMsg);
         }else {
           cellValue = this.getStringCellValue(colCell).trim();
         }
         if(rulName.equals(Constans.RULE_NAME_NULLABLE)){      
           if(cellValue.equals("")||cellValue == null){
             errorString.append("导入失败,错误信息:第"+curRow+"行,第"+curCol+"列:"+rulMsg+"<br>");
           }
         }
      //这里写其他的验证规则。。。
      }
     }
   }
   /**保存excel里面的数据**/
   @SuppressWarnings("unchecked")
   public void saveExcelData(String entityName){
       List<User> users= new ArrayList();
     for(int i = 0 ; i<this.getListDatas().size();i++){
       Map excelCol = (Map) this.getListDatas().get(i);  //得到第 i 行的数据    
       User user = new User();
       try {
      User obj = (User) BeanToMapUtil.convertMap(user.getClass(), excelCol);
      users.add(obj);  
    } catch (IntrospectionException e) {      
      e.printStackTrace();
    } catch (IllegalAccessException e) {    
      e.printStackTrace();
    } catch (InstantiationException e) {    
      e.printStackTrace();
    } catch (InvocationTargetException e) {
      e.printStackTrace();
    }
     }
     /**批量保存数据**/
     Dao dao = new Dao();
     for(int i = 0;i<users.size();i++){
       try{
       dao.saveUser(users.get(i));
       }catch(Exception e){
         e.printStackTrace();
       }
     }
   }
   /**
   * 获得单元格字符串
   * @throws UnSupportedCellTypeException 
   */
  public static String getStringCellValue(HSSFCell cell) {
    if (cell == null){
      return null;
    }
    String result = "";
    switch (cell.getCellType()) {
      case HSSFCell.CELL_TYPE_BOOLEAN:
        result = String.valueOf(cell.getBooleanCellValue());
        break;
      case HSSFCell.CELL_TYPE_NUMERIC:
        if (HSSFDateUtil.isCellDateFormatted(cell)) {
          java.text.SimpleDateFormat TIME_FORMATTER = new java.text.SimpleDateFormat(
              "yyyy-MM-dd");
          result = TIME_FORMATTER.format(cell.getDateCellValue());
        }
        else{
          double doubleValue = cell.getNumericCellValue();
          result = "" + doubleValue;
        }
        break;
      case HSSFCell.CELL_TYPE_STRING:
        if (cell.getRichStringCellValue() == null){
          result = null;
        }
        else{
          result = cell.getRichStringCellValue().getString();
        }
        break;
      case HSSFCell.CELL_TYPE_BLANK:
        result = null;
        break;
      case HSSFCell.CELL_TYPE_FORMULA:
        try{
          result = String.valueOf(cell.getNumericCellValue());   
            }catch(Exception e){
              result = cell.getRichStringCellValue().getString();
            }
        break;
      default:
        result = "";
    }
    return result;
  }
  public String getCurEntityCode() {
    return curEntityCode;
  }
  public void setCurEntityCode(String curEntityCode) {
    this.curEntityCode = curEntityCode;
  }
  public Map getCurEntityHeadMap() {
    return curEntityHeadMap;
  }
  public void setCurEntityHeadMap(Map curEntityHeadMap) {
    this.curEntityHeadMap = curEntityHeadMap;
  }
  public XMLUtil getParseXmlUtil() {
    return parseXmlUtil;
  }
  public void setParseXmlUtil(XMLUtil parseXmlUtil) {
    this.parseXmlUtil = parseXmlUtil;
  }
  public Map getCurEntityColRequired() {
    return curEntityColRequired;
  }
  public void setCurEntityColRequired(Map curEntityColRequired) {
    this.curEntityColRequired = curEntityColRequired;
  }
  public List getListDatas() {
    return listDatas;
  }
  public void setListDatas(List listDatas) {
    this.listDatas = listDatas;
  }
  public StringBuffer getErrorString() {
    return errorString;
  }
  public void setErrorString(StringBuffer errorString) {
    this.errorString = errorString;
  }
}


项目中定义一个XML文件,主要做一些条件限制,比如用户名不能为空,email不能重复等,所以就有一个XML解析类:

/**解析xml工具类*/
@SuppressWarnings("rawtypes")
public class XMLUtil {
   /**entity map对象,key:name ,value:entity的属性map集**/
  public Map entityMap ;
  /**column map 对象,key:entityName_colName , value:column的属性map集 **/
  public Map columnMap;
  /**rule map 对象,key:entityName_colName_ruleName, value: rule 的map集:找到一行rule**/
  public Map ruleMap ;
  /**rules map 对象, key:entityName_colName, value: rules 的map集:找到该column下所有的rule**/
  public Map  columnRulesMap ;
  /**entity--column map: key:entityName, value: column list:根据实体类名得到所有的列**/
  public Map columnListMap ;
   /**column list**/
  public List columnList ;
    /**开始解析xml文件**/
  public XMLUtil(){
    SAXReader reader = new SAXReader();
    InputStream in = getClass().getClassLoader().getResourceAsStream("user.xml");//读取文件流,Url为controller.xml文件
    try {
      Document doc = reader.read(in);//获得文件实例
      Element root = doc.getRootElement();  
      Iterator itEntity = root.elements("entity").iterator();
      while(itEntity.hasNext()){
        Element entity = (Element) itEntity.next();
        parseEntity(entity);
      }
      /**测试entityMap 是否正确**/
      Map enMap = (Map) this.getEntityMap().get("用户表");
      Set<?> set = enMap.keySet();
      Iterator it = set.iterator();
      while(it.hasNext()){
        String uu = (String) it.next();
      }
    }catch(Exception e){
      e.printStackTrace();
    }
  }
   /**开始解析entity**/
  @SuppressWarnings("unchecked")
  public void parseEntity(Element entity){
    if(entity != null){
      /**对数据进行初始化设置**/
      columnListMap = new HashMap();
      columnMap = new HashMap();
      entityMap = new HashMap();
      ruleMap = new HashMap();
      columnRulesMap = new HashMap();
      columnList = new ArrayList();
      setEntityMap(entity);     
      String entityName = entity.attributeValue("name");
      Iterator itColumn = entity.elements("column").iterator();
      while(itColumn.hasNext()){
        Element column = (Element) itColumn.next();
        setColumnMap(entityName,column);
      }
      columnListMap.put(entityName, columnList);
    }
  }
  /**将entity放入entityMap中**/
  @SuppressWarnings("unchecked")
  public void setEntityMap(Element entity){   
    Map ent = new HashMap();
    String name = entity.attributeValue("name");
    String code = entity.attributeValue("code");
    ent.put("name", name);
    ent.put("code", code);
    entityMap.put(name, ent);     
  }
  /**将column放入columnMap中**/
  @SuppressWarnings("unchecked")
  public void setColumnMap(String entityName,Element column){
    if(column != null){   
      Map col = new HashMap();
      String name = column.attributeValue("name");
      String code = column.attributeValue("code");
      String type = column.attributeValue("type");
      col.put("name", name);
      col.put("code", code);
      col.put("type", type);
      String columnMapKey = entityName+"_"+name;    //eg:  用户表_用户名
      columnMap.put(columnMapKey, col);   
      columnList.add(col);
      Iterator ruleIt = column.elements("rules").iterator();  //获得rules
      while(ruleIt.hasNext()){
        Element rules = (Element)ruleIt.next(); 
          Iterator rule  = rules.elements("rule").iterator();   //获得 rule
          while(rule.hasNext()){
            Element ruleValid = (Element) rule.next();     //获得每一行rule
            setRuleMap(entityName,name,ruleValid);            
          }
      }
    }
  }
    /**将 rule 验证规则放入ruleMap中**/
  @SuppressWarnings("unchecked")
  public void setRuleMap(String entityName,String columnName,Element ruleValid){
    if(ruleValid != null){      
      String ruleName = ruleValid.attributeValue("name");
      String ruleMsg = ruleValid.attributeValue("message");
      Map ruleValidMap = new HashMap();
      ruleValidMap.put("name", ruleName);
      ruleValidMap.put("message", ruleMsg);
      String ruleStrKey = entityName+"_"+columnName+"_"+ruleName;
      String colStrKey = entityName+"_"+columnName;
      if(this.getColumnRulesMap().containsKey(colStrKey)){
          List valids = (List) this.getColumnRulesMap().get(colStrKey);
          valids.add(ruleValidMap);
        }else{
          List valids = new ArrayList();
          valids.add(ruleValidMap);
          this.columnRulesMap.put(colStrKey, valids);  //将每个column下的所有rules存入该map中
        }
      ruleMap.put(ruleStrKey, ruleValidMap); //将每个column下的一条rule存入该map中
    }
  }
  /**所有的get set 方法**/
  public Map getEntityMap() {
    return entityMap;
  }
  public void setEntityMap(Map entityMap) {
    this.entityMap = entityMap;
  }
  public Map getColumnMap() {
    return columnMap;
  }
  public void setColumnMap(Map columnMap) {
    this.columnMap = columnMap;
  }
  public Map getRuleMap() {
    return ruleMap;
  }
  public void setRuleMap(Map ruleMap) {
    this.ruleMap = ruleMap;
  }
  public Map getColumnRulesMap() {
    return columnRulesMap;
  }
  public void setColumnRulesMap(Map columnRulesMap) {
    this.columnRulesMap = columnRulesMap;
  }
  public Map getColumnListMap() {
    return columnListMap;
  }
  public void setColumnListMap(Map columnListMap) {
    this.columnListMap = columnListMap;
  }
}


XML解析类定义完成后,ExcelUtil会调用处理,处理完成后返回,导入结束。

至于数据库连接,任何方式都行,这里不做要求,另外需要定义一个实体User,属性根据自己的业务设置。


以上就是具体实现过程,如果有任何问题,私信,我们共同交流讨论。


相关文章
|
25天前
|
数据采集 数据可视化 数据挖掘
利用Python自动化处理Excel数据:从基础到进阶####
本文旨在为读者提供一个全面的指南,通过Python编程语言实现Excel数据的自动化处理。无论你是初学者还是有经验的开发者,本文都将帮助你掌握Pandas和openpyxl这两个强大的库,从而提升数据处理的效率和准确性。我们将从环境设置开始,逐步深入到数据读取、清洗、分析和可视化等各个环节,最终实现一个实际的自动化项目案例。 ####
|
1天前
|
存储 Java easyexcel
招行面试:100万级别数据的Excel,如何秒级导入到数据库?
本文由40岁老架构师尼恩撰写,分享了应对招商银行Java后端面试绝命12题的经验。文章详细介绍了如何通过系统化准备,在面试中展示强大的技术实力。针对百万级数据的Excel导入难题,尼恩推荐使用阿里巴巴开源的EasyExcel框架,并结合高性能分片读取、Disruptor队列缓冲和高并发批量写入的架构方案,实现高效的数据处理。此外,文章还提供了完整的代码示例和配置说明,帮助读者快速掌握相关技能。建议读者参考《尼恩Java面试宝典PDF》进行系统化刷题,提升面试竞争力。关注公众号【技术自由圈】可获取更多技术资源和指导。
|
19天前
|
关系型数据库 MySQL 数据库
数据库数据恢复—MYSQL数据库文件损坏的数据恢复案例
mysql数据库文件ibdata1、MYI、MYD损坏。 故障表现:1、数据库无法进行查询等操作;2、使用mysqlcheck和myisamchk无法修复数据库。
|
23天前
|
SQL 关系型数据库 MySQL
MySQL导入.sql文件后数据库乱码问题
本文分析了导入.sql文件后数据库备注出现乱码的原因,包括字符集不匹配、备注内容编码问题及MySQL版本或配置问题,并提供了详细的解决步骤,如检查和统一字符集设置、修改客户端连接方式、检查MySQL配置等,确保导入过程顺利。
|
29天前
|
SQL 数据库
GBase8a 数据库集群v953扩容案例问题分享
GBase8a 数据库集群v953扩容案例问题分享
|
29天前
|
SQL 数据库
gbase 8a 数据库 SQL优化案例-关联顺序优化
gbase 8a 数据库 SQL优化案例-关联顺序优化
|
1月前
|
存储 SQL 数据库
Sybase数据恢复—Sybase数据库常见问题之数据库无法启动的恢复案例
Sybase数据库数据恢复环境: Sybase数据库版本:SQL Anywhere 8.0。 Sybase数据库故障&分析: Sybase数据库无法启动。 使用Sybase Central连接报错。 数据库数据恢复工程师经过检测,发现Sybase数据库出现故障的原因是:异常断电造成Sybase数据库无法回写正常数据,导致多个存储页数据不一致,系统表描述和存储表不一致,部分存储页底层数据完全杂乱。
|
1月前
|
Oracle 关系型数据库 数据库
Oracle数据恢复—Oracle数据库文件有坏快损坏的数据恢复案例
一台Oracle数据库打开报错,报错信息: “system01.dbf需要更多的恢复来保持一致性,数据库无法打开”。管理员联系我们数据恢复中心寻求帮助,并提供了Oracle_Home目录的所有文件。用户方要求恢复zxfg用户下的数据。 由于数据库没有备份,无法通过备份去恢复数据库。
|
1月前
|
存储 Oracle 关系型数据库
oracle数据恢复—Oracle数据库文件大小变为0kb的数据恢复案例
存储掉盘超过上限,lun无法识别。管理员重组存储的位图信息并导出lun,发现linux操作系统上部署的oracle数据库中有上百个数据文件的大小变为0kb。数据库的大小缩水了80%以上。 取出&并分析oracle数据库的控制文件。重组存储位图信息,重新导出控制文件中记录的数据文件,发现这些文件的大小依然为0kb。
|
24天前
|
存储 Oracle 关系型数据库
服务器数据恢复—华为S5300存储Oracle数据库恢复案例
服务器存储数据恢复环境: 华为S5300存储中有12块FC硬盘,其中11块硬盘作为数据盘组建了一组RAID5阵列,剩下的1块硬盘作为热备盘使用。基于RAID的LUN分配给linux操作系统使用,存放的数据主要是Oracle数据库。 服务器存储故障: RAID5阵列中1块硬盘出现故障离线,热备盘自动激活开始同步数据,在同步数据的过程中又一块硬盘离线,RAID5阵列瘫痪,上层LUN无法使用。