提示:其实使用EasyExcel根据模板导出一个excel并不难,难点在于指定图片的位置
提示:EasyExcel请使用 3.0 以上版本,我这里使用的是 3.0.2 版本:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.0.2</version>
</dependency>
提示:我的需求是,前端页面有个 echarts 图,需要导出到excel,当然前端也可以直接导出图片;但是我是需要将图片插入到模板指定位置,模板中还有其他内容,所以需要前端先将图片传给我,后台再写入到模板中
@ApiOperation(value = "导出excel")
@PostMapping("/export")
public void exportExcel(@RequestParam("file") MultipartFile file, HttpServletResponse response, @Valid FwFloodForecastResultExportDto dto) {
service.export(file, response, dto);
}
ResourceUtil工具类使用的是开源的java工具包cn.hutool,具体的pom中的maven依赖坐标,自行百度
Map<String, Object> map = new HashMap<>();
map.put("startW", 33);
map.put("avgRain", 35);
map.put("pa", 36);
map.put("forecastTime", "12月10日12时03分");
map.put("maxFlow", 37);
map.put("maxFlowTime", "11月27日20时");
map.put("maxOtq", 38);
map.put("maxOtqTime", "11月29日2时");
map.put("maxW", 39);
map.put("maxWTime", "11月27日20时");
List<Map<String, Object>> list = new ArrayList<>();
Map<String, Object> m1 = new HashMap<>();
m1.put("month", "11");
m1.put("day", "3");
m1.put("hour", "10");
m1.put("rain", 40);
m1.put("inq", 41);
m1.put("otq", 42);
Map<String, Object> m2 = new HashMap<>();
m2.put("month", "12");
m2.put("day", "3");
m2.put("hour", "10");
m2.put("rain", 40);
m2.put("inq", 41);
m2.put("otq", 42);
Map<String, Object> m3 = new HashMap<>();
m3.put("month", "1");
m3.put("day", "3");
m3.put("hour", "10");
m3.put("rain", 40);
m3.put("inq", 41);
m3.put("otq", 42);
Map<String, Object> m4 = new HashMap<>();
m4.put("month", "2");
m4.put("day", "3");
m4.put("hour", "10");
m4.put("rain", 40);
m4.put("inq", 41);
m4.put("otq", 42);
Map<String, Object> m5 = new HashMap<>();
m5.put("month", "3");
m5.put("day", "3");
m5.put("hour", "10");
m5.put("rain", 40);
m5.put("inq", 41);
m5.put("otq", 42);
list.add(m1);
list.add(m2);
list.add(m3);
list.add(m4);
list.add(m5);
InputStream is = null;
// 取出模板
try {
is = ResourceUtil.getStream("classpath:templates/forecastTemp.xlsx");
// 这里定义最终导出的文件名称
String fileName = "xxxx.xlsx";
// 这里的 file 就是 Controller 中传过来的 MultipartFile 文件对象;TemplateExcelUtils.imageCells()里面有图片的一些参数,可以根据自己需要调整图片的起始位置,边框等
WriteCellData<Void> voidWriteCellData = TemplateExcelUtils.imageCells(file.getBytes());
// 这个 img 就是你在模板中文件图片所在位置的占位符 ,需要提前在模板中定义好 => {img}
map.put("img", voidWriteCellData);
ExcelWriter excelWriter = EasyExcel.write(TemplateExcelUtils.getOutputStream(fileName, response)).withTemplate(is).excelType(ExcelTypeEnum.XLSX).build();
WriteSheet writeSheet = EasyExcel.writerSheet().build();
// 这个传进去的 map 就是非表格数据,详见我定义的模板中图片位置上方那部分
excelWriter.fill(map, writeSheet);
// 这个 data 是官方约定就这么写, 传进去的 list 就是要遍历的表格数据,详见我定义的模板中图片位置右侧那部分
excelWriter.fill(new FillWrapper("data", list), writeSheet);
excelWriter.finish();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
代码如下(示例):
package com.jxstjh.xjwpsm.forecastWarning.app.utils;
import com.alibaba.excel.metadata.data.ImageData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.util.FileUtils;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
/**
* @version 1.0
* @date 2022-12-11 18:00
*/
public class TemplateExcelUtils {
/**
* Excel所有图片设置
*
* @param bytes
* @return
* @throws IOException
*/
public static WriteCellData<Void> imageCells(byte[] bytes) throws IOException {
WriteCellData<Void> writeCellData = new WriteCellData<>();
// 这里可以设置为 EMPTY 则代表不需要其他数据了
//writeCellData.setType(CellDataTypeEnum.EMPTY);
// 可以放入多个图片
List<ImageData> imageDataList = new ArrayList<>();
writeCellData.setImageDataList(imageDataList);
ImageData imageData = new ImageData();
imageDataList.add(imageData);
// 设置图片
imageData.setImage(bytes);
// 图片类型
//imageData.setImageType(ImageData.ImageType.PICTURE_TYPE_PNG);
// 上 右 下 左 需要留空,这个类似于 css 的 margin;这里实测 不能设置太大 超过单元格原始大小后 打开会提示修复。暂时未找到很好的解法。
imageData.setTop(10);
imageData.setRight(10);
imageData.setBottom(10);
imageData.setLeft(10);
// * 设置图片的位置。Relative表示相对于当前的单元格index。first是左上点,last是对角线的右下点,这样确定一个图片的位置和大小。
// 目前填充模板的图片变量是images,index:row=7,column=0。所有图片都基于此位置来设置相对位置
// 第1张图片相对位置
imageData.setRelativeFirstRowIndex(0);
imageData.setRelativeFirstColumnIndex(0);
imageData.setRelativeLastRowIndex(20);
imageData.setRelativeLastColumnIndex(5);
return writeCellData;
}
/**
* 导出文件时为Writer生成OutputStream.
*
* @param fileName 文件名
* @param response response
* @return ""
*/
public static OutputStream getOutputStream(String fileName, HttpServletResponse response) throws Exception {
try {
fileName = URLEncoder.encode(fileName, "UTF-8");
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf8");
response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
response.setHeader("Pragma", "public");
response.setHeader("Cache-Control", "no-store");
response.addHeader("Cache-Control", "max-age=0");
return response.getOutputStream();
} catch (IOException e) {
throw new Exception("导出excel表格失败!", e);
}
}
}
提示:对图片操作最重要的类就是 WriteCellData
如果有多张图片需要指定位置的请参考这里:请点击这里