使用alibaba的easyexcel填充复杂模板,导出Excel,返回文件流

 做个记录,试了很多方法都不行(本来想使用对象单独写一个table,但是没找到属性),又不想更换依赖,后面才看到的模板填充,能用............

//依赖
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>easyexcel</artifactId>
	<version>${easypoi.version}</version>
</dependency>

 控制层

//Controller层
    @ApiOperation(value = "导出", notes = "导出")
	@GetMapping("/export/{projectId}")
	public void exportByProjectId(@PathVariable String projectId,HttpServletResponse response) {
		projectOrderService.exportByProjectId(projectId,response);
	}

 添加一个模板

代码(  projectOrderExcelVO 是一个对象,他里面带了一个list  )

service层

//​​​​​​​service层
    public void exportByProjectId(String projectId, HttpServletResponse response) {
        //查询出来的对象
		ProjectOrderExcelVO projectOrderExcelVO = getProjectOrderExcelVO(projectId);

        //使用模板
		//获取模板
		ClassPathResource classPathResource = new ClassPathResource("/templates/专案执行单.xlsx");
		//输入流
		InputStream inputStream = null;
		//输出流
		ServletOutputStream outputStream = null;
		//Excel对象
		ExcelWriter excelWriter = null;
		try {
			//输入流
			inputStream = classPathResource.getInputStream();
			// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
			response.setContentType("application/vnd.ms-excel");
			response.setCharacterEncoding("utf-8");
			// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
			String fileName = URLEncoder.encode("专案执行单", "UTF-8");
			response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
			outputStream = response.getOutputStream();

			//设置输出流和模板信息
			excelWriter = EasyExcel.write(outputStream).withTemplate(inputStream).build();
			WriteSheet writeSheet = EasyExcel.writerSheet().build();
			//开启自动换行,自动换行表示每次写入一条list数据是都会重新生成一行空行,此选项默认是关闭的,需要提前设置为true
			FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
            //列表
			excelWriter.fill(projectOrderExcelVO.getProjectOrderContentExcelList(), fillConfig, writeSheet);
            //对象
			excelWriter.fill(projectOrderExcelVO, writeSheet);
			excelWriter.finish();
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			// 千万别忘记finish 会帮忙关闭流
			if (excelWriter != null) {
				excelWriter.finish();
			}
			//关闭流
			if (outputStream != null) {
				try {
					outputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (inputStream != null) {
				try {
					inputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

在模板上添加   单个对象 {属性名}  或  多条数据 {.属性名}     (可以使用map)

 中途遇到的bug

excelgenerateexception create workbook failure    //没有图片了,就这一句话或是往下滑

Unexpected record signature: 0X9   //这一句

可以先看下target的classes文件下有没有把模板编译进去,没有的话就重新编译(pom.xml文件下得有这个配置)

    <build>
        <resources>
			<resource>
				<directory>src/main/resources</directory>
				<filtering>true</filtering>
				<excludes>
					<exclude>**/*.xlsx</exclude>
					<exclude>**/*.xls</exclude>
				</excludes>
			</resource>
			<resource>
				<directory>src/main/resources</directory>
				<filtering>false</filtering>
				<includes>
					<include>**/*.xlsx</include>
					<include>**/*.xls</include>
				</includes>
			</resource>
		</resources>
	</build>

 成功的效果图 

写的初版

//​​​​​​​service层
    public void exportByProjectId(String projectId, HttpServletResponse response) {
        //查询出来的对象
		ProjectOrderExcelVO projectOrderExcelVO = getProjectOrderExcelVO(projectId);

        
		List<ProjectOrderExcelVO> projectOrderExcelList = new ArrayList<>();
		projectOrderExcelList.add(projectOrderExcelVO);

		//初版
		try {
			// 方法1 如果写到同一个sheet
			String fileName = "tableWrite" + System.currentTimeMillis() + ".xlsx";
			// 这里直接写多个table的案例了,如果只有一个 也可以直一行代码搞定,参照其他案例
			ExcelWriter excelWriter = null;

			// 头的策略
			WriteCellStyle headWriteCellStyle = new WriteCellStyle();
			// 背景色
			headWriteCellStyle.setFillForegroundColor(IndexedColors.PALE_BLUE.getIndex());
			//内容的策略
			WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
			// 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定
			contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
			//设置 自动换行
			//contentWriteCellStyle.setWrapped(true);
			//设置 垂直居中
			contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
			//设置 水平居中
			contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
			//设置边框样式
			contentWriteCellStyle.setBorderLeft(THIN);
			contentWriteCellStyle.setBorderTop(THIN);
			contentWriteCellStyle.setBorderRight(THIN);
			contentWriteCellStyle.setBorderBottom(THIN);

			HorizontalCellStyleStrategy horizontalCellStyleStrategy =
					new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);

			try {
				// 这里不指定class
				excelWriter = EasyExcel.write(fileName).build();

				// 把sheet设置为不需要头 不然会输出sheet的头 这样看起来第一个table 就有2个头了
				WriteSheet writeSheet = EasyExcel.writerSheet("专案执行单").needHead(Boolean.FALSE)
						.registerWriteHandler(horizontalCellStyleStrategy)
						.build();
				// 这里必须指定需要头,table 会继承sheet的配置,sheet配置了不需要,table 默认也是不需要
				WriteTable writeTable0 = EasyExcel.writerTable(0).head(ProjectOrderExcelVO.class).needHead(Boolean.TRUE).build();
				// 第二个对象 读取对象的excel实体类中的标题
				WriteTable writeTable1 = EasyExcel.writerTable(1).head(ProjectOrderContentExcelVO.class).needHead(Boolean.TRUE).relativeHeadRowIndex(1).build();
				// 第一次写入会创建头
				excelWriter.write(projectOrderExcelList, writeSheet, writeTable0);
				// 第二次写如也会创建头,然后在第一次的后面写入数据
				excelWriter.write(projectOrderExcelVO.getProjectOrderContentExcelList(), writeSheet, writeTable1);

			} finally {
				// 千万别忘记finish 会帮忙关闭流
				if (excelWriter != null) {
					excelWriter.finish();
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

 半成品    实现两个列表(table)

//​​​​​​​service层
    public void exportByProjectId(String projectId, HttpServletResponse response) {
        //查询出来的对象
		ProjectOrderExcelVO projectOrderExcelVO = getProjectOrderExcelVO(projectId);

        
		List<ProjectOrderExcelVO> projectOrderExcelList = new ArrayList<>();
		projectOrderExcelList.add(projectOrderExcelVO);


		//半成品   没有实现单个列折叠
		// 头的策略
		WriteCellStyle headWriteCellStyle = new WriteCellStyle();
		// 背景色
		headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
		//内容的策略
		WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
		// 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定
		contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
		//设置 自动换行
		contentWriteCellStyle.setWrapped(true);
		//设置 垂直居中
		contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
		//设置 水平居中
		contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
		//设置边框样式
		contentWriteCellStyle.setBorderLeft(THIN);
		contentWriteCellStyle.setBorderTop(THIN);
		contentWriteCellStyle.setBorderRight(THIN);
		contentWriteCellStyle.setBorderBottom(THIN);

		HorizontalCellStyleStrategy horizontalCellStyleStrategy =
				new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
		ServletOutputStream outputStream = null;
		// 这里直接写多个table的案例了,如果只有一个 也可以直一行代码搞定,参照其他案例
		ExcelWriter excelWriter = null;
		try {
			// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
			response.setContentType("application/vnd.ms-excel");
			response.setCharacterEncoding("utf-8");
			// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
			String fileName = URLEncoder.encode("专案执行单", "UTF-8");
			response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
			outputStream = response.getOutputStream();

			// 这里不指定class
			excelWriter = EasyExcel.write(outputStream).build();

			// 把sheet设置为不需要头 不然会输出sheet的头 这样看起来第一个table 就有2个头了
			WriteSheet writeSheet = EasyExcel.writerSheet("专案执行单").needHead(Boolean.FALSE)
					.registerWriteHandler(horizontalCellStyleStrategy)
					.build();
			// 这里必须指定需要头,table 会继承sheet的配置,sheet配置了不需要,table 默认也是不需要
			WriteTable writeTable0 = EasyExcel.writerTable(0).head(ProjectOrderExcelVO.class).needHead(Boolean.TRUE).build();
			// 第二个对象 读取对象的excel实体类中的标题
			WriteTable writeTable1 = EasyExcel.writerTable(1).head(ProjectOrderContentExcelVO.class).needHead(Boolean.TRUE).relativeHeadRowIndex(1).build();
			// 第一次写入会创建头
			excelWriter.write(projectOrderExcelList, writeSheet, writeTable0);
			// 第二次写如也会创建头,然后在第一次的后面写入数据
			excelWriter.write(projectOrderExcelVO.getProjectOrderContentExcelList(), writeSheet, writeTable1);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 千万别忘记finish 会帮忙关闭流
			if (excelWriter != null) {
				excelWriter.finish();
			}
			//关闭流
			if (outputStream != null) {
				try {
					outputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

 //成品

 

### 使用阿里巴巴 EasyExcel 实现模板导出 Excel 文件 要通过阿里巴巴的 EasyExcel 库实现模板导出功能,可以按照以下方式操作。EasyExcel 提供了一种灵活的方式来读取和写入 Excel 数据,并支持基于模板的方式生成复杂Excel 文档。 以下是具体的代码示例以及说明: #### Maven 依赖配置 首先,在项目的 `pom.xml` 中引入 EasyExcel 的依赖项[^1]: ```xml <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3.3.2</version> </dependency> ``` #### 创建模板类 为了使用模板导出功能,需要定义一个 Java 类作为数据模型。假设我们要导出员工信息表,则可以创建如下实体类: ```java public class EmployeeData { private String name; private Integer age; private String department; // Getters and Setters } ``` #### 编写模板导出逻辑 下面是一个完整的代码片段,展示如何利用 EasyExcel 进行模板填充导出 Excel 文件: ```java import com.alibaba.excel.EasyExcel; import java.util.ArrayList; import java.util.List; public class TemplateExportExample { public static void main(String[] args) { // 设置模板路径 (确保该路径下存在对应的 Excel 模板文件) String templateFilePath = "path/to/your/template.xlsx"; // 导出的目标文件路径 String exportFilePath = "path/to/exported/file.xlsx"; // 准备数据列表 List<EmployeeData> data = new ArrayList<>(); data.add(new EmployeeData("Alice", 28, "HR")); data.add(new EmployeeData("Bob", 30, "Engineering")); // 调用 EasyExcel 方法完成模板填充导出 EasyExcel.write(exportFilePath).withTemplate(templateFilePath).sheet().doFill(data); } } // 定义数据对象 class EmployeeData { private String name; private Integer age; private String department; // 构造函数、Getters 和 Setters public EmployeeData() {} public EmployeeData(String name, Integer age, String department) { this.name = name; this.age = age; this.department = department; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getDepartment() { return department; } public void setDepartment(String department) { this.department = department; } } ``` 上述代码实现了以下几个核心步骤: 1. **指定模板文件路径**:提供一个预设好的 Excel 模板文件。 2. **准备数据源**:构建待填入的数据集合。 3. **调用 API 填充模板**:借助 `EasyExcel.write(...).withTemplate(...)...doFill()` 方法完成模板替换与保存。 此方法充分利用了 EasyExcel 的强大特性——即无需手动解析单元格位置即可快速完成复杂文档的自动化生成功能[^2]。 ---
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值