Java导出Excel百万条数据表格数据实现分页easyexcel方法和Apach POI方法

关闭程序的查询sql语句打印日志功能,否则速度很慢

注意: 此导出excel样式只是简单设置而已

1、创建实体类 ExcelModel 导出数据库对应实体数据列表

简单样式设计

MAVEN仓库依赖或者下载依赖jar包

<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.1.1</version>
</dependency>

关于样式可以看源码默认值进行更改默认设置

参考一些样式  
https://zhuanlan.zhihu.com/p/481547301
https://blog.csdn.net/weixin_47215296/article/details/126102600

@Getter
@Setter
@ContentRowHeight(16)
@ContentStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER)
@HeadRowHeight(30)
@ColumnWidth(35)
@HeadFontStyle(fontName="宋体")
@HeadStyle(horizontalAlignment = HorizontalAlignmentEnum.CENTER,shrinkToFit = BooleanEnum.TRUE)

public class ExcelModel {
	@ExcelIgnore		//忽略此表头内容
    private Integer id;// 主键ID
    @ExcelProperty(value = "姓名") //表头内容
    private String name;// 姓名
	@ExcelProperty(value = "年龄")
    private Integer age;// age
	@ExcelProperty(value = "地址")
    private String address;// 地址
	@ExcelProperty(value = "性别")
    private String sex;// 性别
    @ExcelIgnore	
	private Integer pageStartIndex;//起始索引 查询索引位置
	@ExcelIgnore	
    private Integer pageSize;//每页数量  相当于数据库内数据步长
}

1.1创建mapper接口

@Param 选择 引入 import org.apache.ibatis.annotations.Param;

	Integer selecttxxxCount(@Param("model")ExcelModel  model);
	List<ExcelModel> selectData(@Param("model")ExcelModel   model);	

1.2创建mapper.xml

	<select id="selecttxxxCount" resultType="Integer">
		select  *
		from table_name  
		<where>
		动态sql筛选条件
		</where>
	</select>	


	<select id="selectData" resultType="ExcelModel">
		select  *
		from table_name  
		<where>
		动态sql筛选条件
		</where>
		<if test="model.pageStartIndex!=null and model.pageSize!=null">
	limit #{model.pageStartIndex},#{model.pageSize}
	</select>	

2、创建 services 实现类

客户端是下载的作用,数据的处理是在服务器端进行的

xxxClass    类   作用接收前端传递来的对应数据参数 比如 页码、每页大小 其他筛选条件等
xxxentity   类对应的实例
xxxMapper   对应的mapper文件名
//响应输出流在下方使用了  这个就不用了
ServletOutputStream outputStream = response.getOutputStream();

2.1、方法1==》核心代码 分页写入–适应数据量百万

select * from table_name  limit  startIndex,step
举例  select * from table_name  limit 15,1000

xxxentity.setPageStartIndex(i * page_size);   ---对应起始索引
xxxentity.setPageSize(page_size);			--对应查询的记录行数
//核心代码
    public void exportExcelData(HttpSession session, HttpServletResponse response, xxxClass xxxentity) throws Exception {
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        String fileName = new String(("定义导出excel名").getBytes(), "ISO8859_1");
        response.setHeader("Content-disposition", "attachment; filename=" +
                fileName + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(new Date()) + ".xlsx");
        //查询总条数
        List<Integer> total = xxxMapper.selecttxxxCount(xxxentity);       
        //计算页数
        // 定义每个sheet数据数量
        int page_size = 3000;
        //计算将分多少页
        int export_pagenumber = total % page_size > 0 ? total / page_size + 1 : total / page_size;
		//创建输出流 
        ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), xxxClass.class).build();
         WriteSheet writeSheet = new WriteSheet();	//创建工作簿
        for (int i = 0; i < export_pagenumber; i++) {           
            writeSheet.setSheetName("第"+(i+1)+"页");
            xxxentity.setPageStartIndex(i * page_size);  //某处起始索引  (固定步长行数*第几个i)
            xxxentity.setPageSize(page_size);//从起始索引开始对应的截取数据 step 步长行数
            List<xxxClass> dataList = xxxMapper.selectData(xxxentity);
            //每循环一次  查出的数据进行写入一个sheet 工作簿
            excelWriter.write(dataList,writeSheet);
        }
        //循环结束   
        excelWriter.finish();//整个Excel文件写数据结束
        response.flushBuffer();//强制刷新
    }

2.2、方法2==》一次性写入 --适应数量1万左右

//核心代码
    public void exportExcelData(HttpSession session, HttpServletResponse response, xxxClass xxxentity) throws Exception {
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename="+new Date()+"defineExcelName.xlsx");
  
	//一次性查询数据
		List<xxxClass> dataList= xxxMapper.selectData(xxxentity);
        //循环结束   
       EasyExcel.write(response.getOutputStream(), xxxClass.class).sheet("单个sheet工作簿名称").doWrite(dataList);
    }

2.3、代码误区 ----其实这种方法本质是一次性写入 --错误

导致内存溢出(OOM)

 List<xxxClass> datalist = new ArrayList<>();
       for (int i = 0; i < export_pagenumber; i++) {
            xxxentity.setPageStartIndex(i * page_size);
            xxxentity.setPageSize(page_size);
            List<xxxClass> list= xxxMapper.selectData(xxxentity);
			datalist.addAll(list.subList(0,list.size()));//将查询出的集合集中收集在datalist
        }
EasyExcel.write(response.getOutputStream(), xxxClass.class).sheet("单个sheet工作簿名称").doWrite(dataList);

3、性能比较

在这里插入图片描述

4、导出excel

在这里插入图片描述

5、oom 内存溢出

6、sax模式

SAX解析器读取输入文档并在处理文档时将每个事件推给文档处理器(MyContentHandler)。与DOM相比,SAX解析器能提供更好的性能优势,它提供对XML文档内容的有效低级访问。SAX模型最大的优点是内存消耗小,因为整个文档无需一次加载到内存中,这使SAX解析器可以解析大于系统内存的文档。另外,你无需像在DOM中那样为所有节点创建对象。最后,SAX“推”模型可用于广播环境,能够同时注册多个ContentHandler,并行接收事件,而不是在一个管道中一个接一个地进行处理。

7、Apach POI --大数据量—写不好容易内存溢出

//核心代码
    public void exportExcelData(HttpSession session, HttpServletResponse response, xxxClass xxxentity) throws Exception {
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        String fileName = new String(("定义导出excel名").getBytes(), "ISO8859_1");
        response.setHeader("Content-disposition", "attachment; filename=" +
                fileName + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(new Date()) + ".xlsx");
        //查询总条数
        List<Integer> total = xxxMapper.selecttxxxCount(xxxentity);       
        //计算页数
        // 定义每个sheet数据数量
        int page_size = 3000;
        //计算将分多少页
        int export_pagenumber = total % page_size > 0 ? total / page_size + 1 : total / page_size;
		//创建输出流 
		SXSSFWorkbook wbook = new SXSSFWorkbook(1500);	//	1500表示1500行数据时进行写到磁盘不至于内存溢出
 		Sheet sheet = null;
        for (int i = 0; i < export_pagenumber; i++) {      
            sheet = wbook.createSheet("第"+(i+1)+"页");//新建一个sheet
            xxxentity.setPageStartIndex(i * page_size);  //某处起始索引  (固定步长行数*第几个i)
            xxxentity.setPageSize(page_size);//从起始索引开始对应的截取数据 step 步长行数
            List<xxxClass> dataList = xxxMapper.selectData(xxxentity);
            //每循环一次  查出的数据进行写入一个sheet 工作簿
			writeDataToExcel(sheet,dataList);
        }
        //循环结束    
        wbook.write(response.getOutputStream());//写出数据到输出流
        wbook.dispose();
    }


private int currRow = 0;
private void writeDataToExcel(Sheet sheet ,List<xxxClass> xxxentityList){
 for( int j=0;j<xxxentityList.size();j++){
  	Row row = sheet.createRow(currRow++);
  	int k = 0;
   row.createCell(k++).setCellValue(xxxentity.get(j).getId());
   row.createCell(k++).setCellValue(xxxentity.get(j).getUserName());
   row.createCell(k++).setCellValue(xxxentity.get(j).getAge());
 }
}

8 当一个sheet数据量大于100000百万行数据进行分工作簿

    @SneakyThrows(IOException.class)
    @ApiOperation(value = "xxxx记录导出")
    @PostMapping("/xxxxxx")
    public void exporportEasyExcel(HttpServletResponse response,@RequestBody xxxClass xxxentity) {
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        String fileName = new String(("定义导出excel名").getBytes(), "ISO8859_1");
        response.setHeader("Content-disposition", "attachment; filename=" +
                fileName + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")).format(new Date()) + ".xlsx");
        List<xxxClass > total = xxxMapper.pageExcel(xxxentity);
        int sheet_max_row = 4;
        int pageNumber = 0;
        int writeCount = 0;
        int step = 2;
        int export_pagenumber = total.size() % step > 0 ? total.size() / step + 1 : total.size() / step;
        ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(),
         xxxClass.class).build();
        WriteSheet writeSheet = new WriteSheet();
        int i =0;
        for (int i = 0; i < export_pagenumber; i++) {
            xxxentity.setPageStartIndex(i * step);
            xxxentity.setPageSize(step);
            List<xxxClass> dataList = xxxMapper.pageExcel(xxxentity);
            writeCount += dataList.size();
            if (writeCount > sheet_max_row*pageNumber){
               // writeSheet.setSheetName("xxx记录"+pageNumber+"页");
                writeSheet = EasyExcel.writerSheet("第"+(pageNumber++)+"页记录").build();
            }
            excelWriter.write(dataList,writeSheet);
        }
        excelWriter.finish();
        response.flushBuffer();
    }

前端浏览器也可以进行接收并导出下载

import axios from "axios";
import dayjs from "dayjs";

/*Axios 是一个流行的基于 Promise 的 JavaScript HTTP 客户端库,用于在浏览器和Node.js环境中进行HTTP请求。
它提供了一种简单、直观的方式来发送异步 HTTP 请求,并支持处理请求和响应的拦截器、数据转换、取消请求等功能。
使用 Axios 可以轻松地发送 GET、POST、PUT、DELETE 等各种类型的请求,并处理服务器返回的响应数据。*/

function exprotExcelData(url: string, data: object,excelExportName: string = "") {//data? 为需要导出哪些条件的数据 需要进行筛选
    axios({
        method: "POST",
        url: url,
        baseURL: '',//基础api
        data: data,
        responseType: "blob", //定义为blob  二进制文件
    }).then((data) => {
        if (!data) {
            console.error("数据文件下载失败")
        }
        let url = window.URL.createObjectURL(
            new Blob([data.data], { type: "application/vnd.ms-excel" })
        );
        let link = document.createElement("a");
        link.style.display = "none";
        link.href = url;
        let excelExportNameFormat = excelExportName + dayjs().format("YYYY-MM-DD hh:mm");//定义下载导出的文件名称加一些日期格式
        link.setAttribute("download", excelExportNameFormat + ".xlsx");
        document.body.appendChild(link);// 将<a>元素附加到body中
        link.click();
        document.body.removeChild(link); //从文档的 <body> 元素中移除名为 "link" 的子元素。document.body.removeChild(link) 表示删除 <body> 元素下的一个子元素,其中 link 是要删除的子元素。
        window.URL.revokeObjectURL(url); /*window.URL.revokeObjectURL(url) 是用于释放通过 window.URL.createObjectURL() 创建的 URL 对象的方法。
在使用 window.URL.createObjectURL() 方法创建 URL 对象时,通常是为了在浏览器中展示或下载一个 Blob 或 File 对象。一旦完成了对该 URL 的使用,为了释放内存并防止内存泄漏,应该调用 window.URL.revokeObjectURL() 方法来撤销该 URL,使其无效。
在代码中,url 是之前通过 window.URL.createObjectURL() 创建的 URL 对象。通过调用 window.URL.revokeObjectURL(url),就可以释放和撤销该 URL 对象。*/
    });
}

Excel表头

List<List> headList = new ArrayList<>();
ExcelWriter excelWriter= null;
excelWriter= EasyExcel.write(response.getOutputStream()).head(headList).build();

  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java可以使用EasyExcel组件来导出数据Excel表格EasyExcel是阿里巴巴开源的一个优秀的Java解析和生成Excel的框架。相对于其他框架如Apache POI和JXL,EasyExcel具有更低的内存消耗,能够处理大型Excel文件而不会导致内存溢出的问题。EasyExcel提供了简单易用的API,使得导出Excel变得简单方便。你可以通过访问EasyExcel的官方网站(https://easyexcel.opensource.alibaba.com)或者GitHub地址(https://github.com/alibaba/easyexcel)来了解更多关于EasyExcel的详细信息和使用方法。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Java使用easyexcel导出数据Excel表格](https://blog.csdn.net/weixin_45536587/article/details/124751757)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Java导出Excel文件合集(easyExcel)](https://blog.csdn.net/weixin_42555014/article/details/131853805)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值