专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

jxl导入Excel 切割List 并使用MyBatis批量插入数据库

需求:从Excel导入大量客户数据。

项目环境:Spring+SpringMVC+MyBatis。

技术:使用jxl实现Excel数据导入。

方案:上传Excel文件,Controller层读取每行的内容保存到对象中,存储到List中。将保存数据的List每100个对象切割并存放到一个新的List 中的,然后使用一个大的List保存这些切割好的List组,传递到Service层遍历大List,将每组List传入的Dao层,让MyBatis批量插入数据。

废话不多说,上代码

Controller层

 //获取用户上传的文件
            Workbook workbook = Workbook.getWorkbook(file.getInputStream());
            //获取工作簿sheet
            Sheet sheet = workbook.getSheet(0);
            //获取总行数
            int rows = sheet.getRows();

            //获取数据表中的数据
            List<Product> productList = new ArrayList<>();
            Cell cell;

            for (int i = 1; i < rows; i++) {
                //该对象请放在循环内部,让GC进行回收,放在循环外面。List集合中的所有对象引用相同,保存的所有对象都是同一个引用
                Product product = new Product();
                //判断名称是否为空,如果为空结束遍历
                if (StringUtil.isEmpty(sheet.getCell(0, i).getContents())) {
                    break;
                }

                product.setId(sheet.getCell(0, i).getContents());
                product.setContent(sheet.getCell(1, i).getContents());
                //读取时间类型
                cell = sheet.getCell(2, i);
                if (cell.getType() == CellType.DATE) {
                    DateCell dc = (DateCell) cell;
                    Date date = dc.getDate();
                    Calendar c = Calendar.getInstance();
                    c.setTime(date);
                    //解析excel的时候会默认当前输入的时间为格林威治时间,需要转为当前时区的时间(之前8小时)
                    c.add(Calendar.HOUR, -8);
                    product.setSr_material_date(c.getTime());
                }
                //读取时间类型
                cell = sheet.getCell(3, i);
                if (cell.getType() == CellType.DATE) {
                    DateCell dc = (DateCell) cell;
                    Date date = dc.getDate();
                    Calendar c = Calendar.getInstance();
                    c.setTime(date);
                    //解析excel的时候会默认当前输入的时间为格林威治时间,需要转为当前时区的时间(之前8小时)
                    c.add(Calendar.HOUR, -8);
                    product.setDate(c.getTime());
                }
                product.setAddress(sheet.getCell(4, i).getContents());
                product.setTel(sheet.getCell(5, i).getContents());

                //将当前对象保存的productList中
                productList.add(product);
            }
            //关闭资源
            workbook.close();

            //List切割
            List<List<Product>> dataList = new ArrayList<>();
            int listSize = productList.size();
            int toIndex = 100;
            int keyToken = 0;
            for (int i = 0; i < productList.size(); i += 100) {
                // 作用为toIndex最后没有100条数据则剩余几条newList中就装几条
                if (i + 100 > listSize) {
                    toIndex = listSize - i;
                }
                List<Product> newList = productList.subList(i, i + toIndex);
                dataList.add(newList);
            }
         //将切割并打包好的List集合传递到Service层进行处理
          productService.importFromExcel(dataList);

Service层

 @Override
    @Transactional
    public int importFromExcel(List<List<Product>> dataList) throws Exception {
        int result = 0;
        try {
            if (dataList != null) {
                for (List<SafeRepository> list : dataList) {
                    result += productMapper.batchInsertProduct(list);
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage());
            throw e;
        }
        return result;
    }

MyBatis 批量插入

<insert id="batchInsertProduct" parameterType="java.util.List">
        INSERT INTO t_product
        (
        id,
        content,
        date,
        address,
        tel
        )
        VALUES
        <foreach collection="list" item="pd" index="index" separator=",">
            (#{pd.id},
            #{pd.content},
            #{pd.date},
            #{pd.address},
            #{pd.tel})
        </foreach>
    </insert>

遇到的问题

刚开始想使用Lambda的partition进行List切割的,但是发现切割后返回的是List的父类Collection,看了下ArrayList源码,在将Collection转换为List操作是使用的遍历转换,先转换为对象数组。如果我这里要这么实现需要将切割后得到的Collection遍历转换为对象数组,再将对象数组中的多个元素中的多个对象转换出来,就会出现n*x的时间复杂度,并不是我需要的方式。就暂时使用上述的方法进行List切割。

ArrayList源码

    /**
     * Constructs a list containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     *
     * @param c the collection whose elements are to be placed into this list
     * @throws NullPointerException if the specified collection is null
     */
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

我写的Lambda切割List代码

        List<List<Product>> dataList = new ArrayList<>();
        Collection<List<Product>> partition = partition(productList, 100);

技术一般般,文章中有什么说的不对的地方,或者有更好的解决办法,还望多指教。谢谢。

文章永久链接:https://tech.souyunku.com/47549

未经允许不得转载:搜云库技术团队 » jxl导入Excel 切割List 并使用MyBatis批量插入数据库

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们