admin 管理员组文章数量: 887017
需求:生成一份领料单,其中包括文本、表格、图片二维码,为了表格内容好看,表格内容每页最多30行。每页都需要基本信息表头。
效果如下:
maven依赖:
<!-- excel工具 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>${poi-ooxml-schemas.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>${poi-tl.version}</version>
</dependency>
注意点:poi-tl 1.12.x 要求 POI 版本在 5.2.2+.
模板制作:
说明:
1、为什么要用区块?由于需求是每页30行,每页都要有基本信息表头,所以用区块标签,将表头和表格作为一个区块。区块可循环N次,一个区块就是一页。
2、为什么要分页标记?通过分页标记来插入分页符。
3、为什么底部签名要用整个标签?表格内容动态,会将底部内容挤到下一页,所以通过代码在最后一行插入签名文本。
4、为什么不用excel模板?excel单元格插入图片展示不美观,且不好分页打印。其实也可以用excel操作,参考这篇文章:使用poi操作excel模板记录
完整代码,仅供参考:
public SysFile materialUseGenWord(MachineMaterialUseResult useResult) {
try {
// 从resources下获取模板
ClassPathResource resource = new ClassPathResource("template/lldmb.docx");
InputStream inputStream = resource.getInputStream();
// 添加二维码图片
BufferedImage qrCodeImage = QrCodeUtil.generate(useResult.getSerialNo(), QrConfig.create().setMargin(1));
// 计算页数:每页30行,新页都要有表头
double page = 1;
if (useResult.getParts().size() > 30) {
page = Math.ceil((double) useResult.getParts().size() / 30);
}
List<Map<String, Object>> foreachList = new ArrayList<>();
// 区块标签
Map<String, Object> resMap = new HashMap<>();
resMap.put("list", foreachList);
for (int i = 0; i < page; i++) {
log.info("第{}页表格数据", i + 1);
List<MachineMaterialUseDetail> parts = new ArrayList<>();
for (int j = 0; j < 30; j++) {
if (i * 30 + j < useResult.getParts().size()) {
parts.add(useResult.getParts().get(i * 30 + j));
} else {
break;
}
}
Map<String, Object> materialMap = new HashMap<>();
// 表格行数据循环标签:置于循环行的上一行
materialMap.put("tables", parts);
// 其他标签
materialMap.put("serialNo", useResult.getSerialNo());
materialMap.put("useDate", useResult.getUseTime());
materialMap.put("deptName", "测试部门");
materialMap.put("warehouse", "DJ0001");
materialMap.put("projectCode", "XM123121");
materialMap.put("projectName", "项目0001");
materialMap.put("startTime", "2024-05-06");
// 插入分页标记,最后一页不用分页
if (i != page - 1) {
materialMap.put("isPageBreak", "分页标记");
}
// 底部文字(签名)
String bottomWord = "\n制单人:" +
useResult.getSponsor() +
" 发料人:" +
useResult.getOperator() +
" 领料人:领料人";
materialMap.put("bottomWord", Texts.of(bottomWord).create());
materialMap.put("qrCode", Pictures.ofBufferedImage(qrCodeImage, PictureType.PNG).size(120, 120).create());
foreachList.add(materialMap);
}
//渲染表格:将插件应用到表格标签
LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
Configure config = Configure.builder().bind("tables", policy).build();
XWPFTemplate template = XWPFTemplatepile(inputStream, config).render(resMap);
// 替换分页标记为分页符
List<XWPFParagraph> paragraphs = template.getXWPFDocument().getParagraphs();
for (XWPFParagraph p : paragraphs) {
List<XWPFRun> runs = p.getRuns();
if (runs != null) {
for (XWPFRun r : runs) {
String text = r.getText(0);
if (text != null && text.contains("分页标记")) {
text = text.replace("分页标记", "");
r.setText(text, 0);
r.addBreak(BreakType.PAGE);
}
}
}
}
// 1将文档写入到输出流
// FileOutputStream outStream = new FileOutputStream("D:\\opt\\mes\\领料单.docx");
// template.write(outStream);
// 2将文档作为响应返回
// response.setHeader("Content-Disposition", "attachment; filename=exported-word.docx");
// response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
// OutputStream outStream = new BufferedOutputStream(response.getOutputStream());
// template.write(outStream);
// 将word转为输出流
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
template.write(outStream);
template.close();
// 3将输出流转为 multipartFile 并上传
MockMultipartFile multipartFile = new MockMultipartFile("file", useResult.getSerialNo() + "领料单" + System.currentTimeMillis() + ".docx", null, outStream.toByteArray());
outStream.close();
R<SysFile> upload = fileService.upload(multipartFile, 1);
return upload.getData();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
遇到的问题:
将模板放入resource目录下,无法读取,maven打包时,报错MalformedInputException。
解决方法:解决 `MalformedInputException: Input length = 1` 错误
版权声明:本文标题:使用poi-tl操作word模板记录 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.freenas.com.cn/jishu/1726312455h934681.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论