• 使用阿里的EasyExcel实现表格导出功能


    在项目B端中,经常会有Excel表格导入导出功能,java中的Apache POI 是一个针对Excel功能非常好的操作库。关于POI网上也有很多的文章,这里主要说一下阿里的EasyExcel实现导表功能;

    之前我们项目中的Excel导出功能使用的是poi userModel模式,相信在过去的一段时间中,应该也有不少的项目采用的是这种模式,此种模式的解析速度很快,但是弊端也很大,如果表数据量一旦很大内存就很容易爆掉了。因为userModel的数据解析类似于Dom方式解析,将数据全部加载到内存,然后生成Dom树的过程。

    注意:userModel是将所有数据全部加载到内存中进行解析,所以他的解析速度快,内存消耗非常大!但是这也是可能导致OOM(内存溢出)的原因。

    导表OOM的解决方案:

    1.将数据量减小,比如分批次导出(原来你导的一周的数据分成按天导出,数据量就能小很多)

    2.前端js导表

    3.阿里EasyExcel

    这里着重谈一下阿里EasyExcel工具类:

    导表的效果如图:

    这里说明一下:上面表格样式最终的呈现需要在实体类上使用部分注解配合,可以通过下面的注解来设置行高列宽,设置标题名和主标题名。

    下面是我在项目中针对导表使用到的工具类(因为项目中只用到导出暂时没有表格导入,所以这里我就没写导入了)

    
    /**
     * @Author: LQ
     * @Date: 2019/9/25 16:17
     */
    public class EasyExcelUtils {
    
    	/**
    	 * 导出Excel(一个sheet)
    	 *
    	 * @param response  HttpServletResponse
    	 * @param list      数据list
    	 * @param fileName  导出的文件名
    	 * @param sheetName 导入文件的sheet名
    	 * @param clazz     实体类
    	 */
    	public static <T> void writeExcel(HttpServletResponse response, List<T> list, String fileName, String sheetName, Class<T> clazz) {
    
    		OutputStream outputStream = getOutputStream(response, fileName);
    
    		ExcelWriter excelWriter = EasyExcel.write(outputStream, clazz).build();
    		WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build();
    
    		excelWriter.write(list, writeSheet);
    
    		excelWriter.finish();
    	}
    
    	public static <T> void writeStyleExcel(List<T> list, String fileName, String sheetName, Class<T> clazz) {
    		// 头的策略
    		WriteCellStyle headWriteCellStyle = new WriteCellStyle();
    		// 背景设置为红色
    		headWriteCellStyle.setFillForegroundColor(IndexedColors.YELLOW.getIndex());
    		headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
    		WriteFont headWriteFont = new WriteFont();
    		headWriteFont.setFontHeightInPoints((short) 10);
    		headWriteFont.setFontName("宋体");
    		headWriteCellStyle.setWriteFont(headWriteFont);
    
    		// 内容的策略
    		WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
    		contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
    		contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
    		contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
    		contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
    		contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
    		// 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定
    		contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
    		// 背景绿色
    		contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
    		WriteFont contentWriteFont = new WriteFont();
    		// 字体大小
    		contentWriteFont.setFontHeightInPoints((short) 10);
    		contentWriteFont.setFontName("宋体");
    		contentWriteCellStyle.setWriteFont(contentWriteFont);
    		// 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
    		HorizontalCellStyleStrategy horizontalCellStyleStrategy =
    				new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
    
    		// 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
    		EasyExcel.write(fileName, clazz).registerWriteHandler(horizontalCellStyleStrategy).sheet(sheetName)
    				.doWrite(list);
    	}
    
    
    	/**
    	 * 导出Excel(带样式)
    	 *
    	 * @return
    	 */
    	public static <T> void writeStyleExcel(HttpServletResponse response, List<T> list, String fileName, String sheetName, Class<T> clazz) {
    		// 头的策略
    		WriteCellStyle headWriteCellStyle = new WriteCellStyle();
    		// 背景设置为红色
    		headWriteCellStyle.setFillForegroundColor(IndexedColors.YELLOW.getIndex());
    		headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
    		WriteFont headWriteFont = new WriteFont();
    		headWriteFont.setFontHeightInPoints((short) 10);
    		headWriteFont.setFontName("宋体");
    		headWriteCellStyle.setWriteFont(headWriteFont);
    
    		// 内容的策略
    		WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
    		contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
    		contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
    		contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
    		contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
    		contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
    		// 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定
    		contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
    
    		// 背景绿色
    		contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
    		WriteFont contentWriteFont = new WriteFont();
    		// 字体大小
    		contentWriteFont.setFontHeightInPoints((short) 10);
    		contentWriteFont.setFontName("宋体");
    		contentWriteCellStyle.setWriteFont(contentWriteFont);
    		// 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
    
    		HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
    
    		OutputStream outputStream = getOutputStream(response, fileName);
    		EasyExcel.write(outputStream, clazz).registerWriteHandler(horizontalCellStyleStrategy).sheet(sheetName).doWrite(list);
    
    	}
    
    
    	/**
    	 * 导出时生成OutputStream
    	 */
    	private static OutputStream getOutputStream(HttpServletResponse response, String fileName) {
    		//创建本地文件
    		String filePath = fileName + ".xlsx";
    		File file = new File(filePath);
    		try {
    			if (!file.exists() || file.isDirectory()) {
    				file.createNewFile();
    			}
    			fileName = new String(filePath.getBytes(), "ISO-8859-1");
    			response.addHeader("Content-Disposition", "filename=" + fileName);
    			return response.getOutputStream();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		return null;
    	}
    }
    

    除了阿里的easyexcel,在我另一篇文章:https://blog.csdn.net/qq_43655835/article/details/102371136 中也有对excel导入导出的工具类封装,两种封装最终都能实现表格导出,封装方式有差别,可以根据自己的需要来使用。

  • 相关阅读:
    ThinkPHP实现定时任务
    VUE 父子组件之间通信传值 props和 $emit,事件触发传值ref,以及兄弟组件之间的通信传值 eventBus
    JS链接转换为二维码
    VUE 动态切换列表active样式
    微信内置浏览器video标签自动全屏的问题
    JS监听video视频播放时间
    JS数据统计表 highcharts.js的运用
    JS 自动返回每个月的天数
    JS 一键复制插件应用 和 原生实现
    JS enter键一键登录
  • 原文地址:https://www.cnblogs.com/wgty/p/12810498.html
Copyright © 2020-2023  润新知