使用easypoi根据Excel模板导出复杂Excel表 教程
前提:需要使用easypoi根据Excel模板导出复杂Excel表,表中有合并单元格,图片等内容。
前提:需要使用easypoi根据Excel模板导出复杂Excel表,表中有合并单元格,图片等内容。
效果图
maven依赖
建议就用我这个版本的,因为这个版本解决图片不显示的bug。
参考:
使用esaypoi模板导出图片不显示问题解决
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>4.2.0</version>
</dependency>
Excel模版图片
模板内的标签,参考
3.1 模板 指令介绍
模板是处理复杂Excel的简单方法,复杂的Excel样式,可以用Excel直接编辑,完美的避开了代码编写样式的雷区,同时指令的支持,也提了模板的有效性 下面列举下EasyPoi支持的指令以及作用,最主要的就是各种fe的用法
空格分割
三目运算 {{test ? obj:obj2}}
n: 表示 这个cell是数值类型 {{n:}}
le: 代表长度{{le:()}} 在if/else 运用{{le:() > 8 ? obj1 : obj2}}
fd: 格式化时间 {{fd:(obj;yyyy-MM-dd)}}
fn: 格式化数字 {{fn:(obj;###.00)}}
fe: 遍历数据,创建row
!fe: 遍历数据不创建row
$fe: 下移插入,把当前行,下面的行全部下移.size()行,然后插入
#fe: 横向遍历
v_fe: 横向遍历值
!if: 删除当前列 {{!if:(test)}}
单引号表示常量值 ‘’ 比如’1’ 那么输出的就是 1
&NULL& 空格
]] 换行符 多行遍历导出
sum: 统计数据
整体风格和el表达式类似,大家应该也比较熟悉 采用的写法是{{}}代表表达式,然后根据表达式里面的数据取值
关于样式问题 easypoi不会改变excel原有的样式,如果是遍历,easypoi会根据模板的那一行样式进行复制
模板放在resouce下
src/main/resources/template/report.xlsx
Java代码
//报表导出
@Override
public void exportReport(Integer taskRunId, HttpServletResponse response) throws IOException {
if (null == taskRunId) {
throw new BusinessException("任务id不能为空");
}
TaskRun taskRun = getById(taskRunId);
List<PointResult> pointResultList = pointResultService.listByTaskRunId(taskRunId);
// 创建导出参数
POICacheManager.setFileLoaderOnce(new FileLoaderImpl());//自己的实现类,解决读取模板文件报错问题
TemplateExportParams exportParams = new TemplateExportParams("template/report.xlsx");
Map<String, Object> map = new HashMap<>();
map.put("taskCode", taskRun.getTaskCode());
map.put("taskName", taskRun.getTaskName());
map.put("startTime", DateUtil.getDateStr(taskRun.getStartTime()));
map.put("endTime", DateUtil.getDateStr(taskRun.getEndTime()));
map.put("pointCount", taskRun.getPointCount());
map.put("normalCount", taskRun.getNormalCount());
map.put("failCount", taskRun.getFailCount());
map.put("beatOffCount", taskRun.getBeatOffCount());
map.put("beatOffSuccessCount", taskRun.getBeatOffSuccessCount());
map.put("beatOffFailCount", taskRun.getBeatOffFailCount());
map.put("virtualFocalCount", taskRun.getVirtualFocalCount());
map.put("virtualFocalSuccessCount", taskRun.getVirtualFocalSuccessCount());
map.put("virtualFocalFailCount", taskRun.getVirtualFocalFailCount());
//封装点位结果数据
List<Map<String, Object>> listMap = getMaps(pointResultList);
map.put("maplist", listMap);
Workbook workbook = ExcelExportUtil.exportExcel(exportParams, map);
// 设置响应头
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment; filename=报告信息模板.xlsx");
// 写入响应流
workbook.write(response.getOutputStream());
response.getOutputStream().flush();
response.getOutputStream().close();
}
private List<Map<String, Object>> getMaps(List<PointResult> pointResultList) {
List<Map<String, Object>> listMap = new ArrayList<>();
for (int i = 0; i < pointResultList.size(); i++) {
PointResult pointResult = pointResultList.get(i);
Map<String, Object> lm = new HashMap<>();
lm.put("id", i + 1 + "");
lm.put("pointName", pointResult.getPointName());
lm.put("meterType", pointResult.getPointType());
lm.put("beatOff", pointResult.getBeatOff());
lm.put("virtualFocal", pointResult.getVirtualFocal());
String presetOnePicture = pointResult.getPresetOnePicture();
String presetTwoPicture = pointResult.getPresetTwoPicture();
String url1 = getImageUrl(presetOnePicture);
String url2 = getImageUrl(presetTwoPicture);
ImageEntity image1 = fixImageEntity(url1);
ImageEntity image2 = fixImageEntity(url2);
lm.put("presetOnePicture", image1);
lm.put("presetTwoPicture", image2);
listMap.add(lm);
}
return listMap;
}
private static ImageEntity fixImageEntity(String url) {
ImageEntity image = new ImageEntity();
image.setHeight(200);
image.setWidth(200);
image.setType(ImageEntity.Data);
byte[] bytes = new byte[]{};
File file = new File(url);
try (FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
baos.write(buffer, 0, bytesRead);
}
bytes = baos.toByteArray();
} catch (Exception e) {
log.error(e.getMessage());
}
image.setData(bytes);
return image;
}
/**
* 原始图片地址
* @param originalUrl 原始图片地址
* @return
*/
private String getImageUrl( String originalUrl) {
String pathPre = "BoxImages/";
String substring = originalUrl.substring(originalUrl.lastIndexOf(pathPre) + pathPre.length());
String url = fileSavePath + substring;
url = url.replace('/', File.separatorChar);
return url;
}
自己实现IFileLoader 接口,解决读取文件失败报错问题
参考文章Easypoi教程
import cn.afterturn.easypoi.cache.manager.IFileLoader;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.util.IOUtils;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* 自己实现IFileLoader接口,解决easypoi读取文件报错问题,
* 使用时手动设置POICacheManager.setFileLoaderOnce(new FileLoaderImpl());
* @author : lpx
* @since : 2024/9/26 星期四 19:31
* @Description :
*/
@Slf4j
public class FileLoaderImpl implements IFileLoader {
@Override
public byte[] getFile(String url) {
InputStream fileis = null;
ByteArrayOutputStream baos = null;
try {
//判断是否是网络地址
if (url.startsWith("http")) {
URL urlObj = new URL(url);
URLConnection urlConnection = urlObj.openConnection();
urlConnection.setConnectTimeout(30);
urlConnection.setReadTimeout(60);
urlConnection.setDoInput(true);
fileis = urlConnection.getInputStream();
} else {
// //先用绝对路径查询,再查询相对路径
Path path = Paths.get(url);
if (Files.exists(path)) {
fileis = new FileInputStream(path.toFile());
} else {
// 再查询相对路径
fileis = getClass().getClassLoader().getResourceAsStream(url);
if (fileis == null) {
throw new FileNotFoundException("File not found: " + url);
}
}
}
baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = fileis.read(buffer)) > -1) {
baos.write(buffer, 0, len);
}
baos.flush();
return baos.toByteArray();
} catch (IOException e) {
log.error(e.getMessage(), e);
} finally {
IOUtils.closeQuietly(fileis);
IOUtils.closeQuietly(baos);
}
log.error(fileis + "这个路径文件没有找到,请查询");
return null;
}
}
ps:easypoi官方文档已经不开放了,好像没人维护和更新代码了!!!
看到这里,点个关注吧。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)