李成石

导航

 

实验采用Mybatis+POI+JSON 完成解析Excel数据,并将数据批量插入数据库。

1.POI+JSON 提取Excel中数据,同时映射实体类。

 /**
     *
     * @param   is  输入流
     * @return  输入流创建XSSFWorkBook对象
     */
     public  XSSFWorkbook XSSFReadFile(InputStream is) {

         XSSFWorkbook wb=null;
         try {
             wb=new XSSFWorkbook(is);
         } catch (IOException e) {
             e.printStackTrace();
         }
          return wb;
     }


    /**
     * @param wb XSSFWorkBook对象
     * @return 读取文件的sheet名与首行Title组装为json对象
     */
    public  JSONObject getTable(XSSFWorkbook wb){

        JSONObject obj=new JSONObject();

        JSONArray array=new JSONArray();

        int SheetSum = wb.getNumberOfSheets();

        for(int i=0;i<SheetSum;i++){

             String sheetName=wb.getSheetName(i);

             XSSFSheet sheet = wb.getSheetAt(i);

            XSSFRow row = sheet.getRow(0);

            if(row!=null) {

                int cellsSum = row.getPhysicalNumberOfCells();
                array.clear();
                for (int j = 0; j < cellsSum; j++) {

                    array.add(row.getCell(j).getStringCellValue().trim());
                }
                obj.put(sheetName,array);
            }
        }

       return obj;
    }
     /**
      * @param   poi 类对象
      * @return  获取sheet页的全部数据
      */

    public  JSONArray getTableData(POIHelper poi){

        JSONObject table = getTable(poi.getWb());

        JSONArray array = JSONArray.fromObject(table.get(poi.getSheetName()));

        JSONArray arr=new JSONArray();

        JSONObject obj_sun =new JSONObject();

        for(int i=1;i<poi.getRowSum();i++){

            XSSFSheet sheet = poi.getSheet();
            XSSFRow row = sheet.getRow(i);
            obj_sun.clear();
            for(int j=0;j<poi.getCellSum();j++){

                XSSFCell cell = row.getCell(j);
                //设置单元格类型
                cell.setCellType(CellType.STRING);
                obj_sun.put(array.get(j),cell.getStringCellValue().trim());
            }
            arr.add(obj_sun);
        }
        return arr;
    }

 将一张表的数据,每行数据读成一个JSON对象放入JSONArray中,类似下面的形式:

 [{"id":"1","userName":"东邪","passWord":"123","gender":"男"},{"id":"2","userName":"西毒","passWord":"124","gender":"男"}]

 JSONArray的好处是可以将其转化为映射类的List:

List user = JSONArray.toCollection(JSONArray对象, 映射类Class对象);

 在映射类时,Excel sheet页和首行Title习惯上都会是汉字,而数据库和数据传输都是英语,中间存在一种映射,类似于国际化的转换。

 Sheet页名与实体类名存在映射关系,sheet中首行字段转化 为英语后与实体类的属性存在映射。

 在将JSONArray转化为List<类>时,需要根据sheet页名获取实体类名,通过Class.forName(固定实体类包名+类名)

    public Class<?> getClazz(String entityName){
        Class<?> clazz=null;
        try {
            clazz =Class.forName("com.soft.entity." + entityName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return clazz;
    }

在service中进行批量插入时,调用DAO中方法,因为许多张表进行批量插入,所以不可避免地进行了硬编码

根据sheet名,选择不同的Dao接口批处理方法。另外有一个不好的地方,如果有十张表,但是只更新了两张表,依然会将十张表插入数据库。在后续进行扩展时,添加实体类时,同时需要修改业务部分的if条件判断,

是一个问题。写了两个类,User和product。

public void BatchInsertData(MultipartFile file){
        try {
            XSSFWorkbook wb = poiHelper.XSSFReadFile(file.getInputStream());
            JSONObject table = poiHelper.getTable(wb);
            Set<String> set = table.keySet();
            for (String sheetName:set) {
                POIHelper poi=new POIHelper(wb,sheetName);
                JSONArray tableData = poi.getTableData(poi);
                Class<?> clazz = entitymapper.getClazz(sheetName);
                List list =(List) JSONArray.toCollection(tableData,clazz);
                if(sheetName.equals("User")){
                    userDao.batchInsert(list);
                }else if(sheetName.equals("Product")){
                    productDao.batchInsert(list);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

在最后献上mybatis,批量插入的经典SQL语句:ignore 可以避免多次重复插入相同数据时的冲突,相同时不进行插入。

 <insert id="batchInsert" parameterType="java.util.List">

     insert ignore into product(id,productName,price,description)
             VALUES
                 <foreach collection="list" item="item" index="index" separator=",">
                     (
                      #{item.id},#{item.productName},#{item.price},#{item.description}
                     )
                 </foreach>
 </insert>  

异常点:

          在页面进行上传Excel时出现   exception is org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.soft.dao.UserDao.batchInsert。

         检查mapper.xml后发现,mapper的namespace写的是实体类路径,应该是其对应DAO接口路径。修改后,问题排除。

         另外,注意在maven项目中,mapper.xml 放置在resources下,不能放在java路径下。放错位置,也会导致上面找不到接口方法的问题。

需要完善点:

                文件数据上传数据库前,文件格式、Sheet页、首行字段、数据等校验.

              上文提到的硬编码问题

posted on 2017-12-10 03:15  李成石  阅读(407)  评论(0编辑  收藏  举报