官网文档地址: https://www.bookstack.cn/read/poi-tl/258f4c53f5d376be.md
吐槽一句: 文档用例太少了,找了很久的资料。
简单说一下我在项目中踩的坑吧
我在word模板中定义了一个值为:
{{;#JsonStrToStr(#JsonArrGetKeyToStr(LCYY_LCXX_HQLCMX_fw_prison_detail,“ouname”,“1”).zbldame,“\n”)}}
注: JsonStrToStr 和 JsonArrGetKeyToStr是我自定义的有参函数
由于 poi-tl 默认使用 springEl表达式, 而该表达式是使用 # 的符号使用自定义函数。
目前到这里都没有什么问题,springEL 表达式大家都会用。
由于 # 刚好又是 poi-tl 的表格插件用法, 导致 poi-tl 框架识别有问题 然后转换不了想要的数据。
那么如何解决呢?
表格插件默认以 # 定义,改为别的符号定义就行了。
关键代码如下:
// =========================
ConfigureBuilder builder = Configure.builder();
// 方式一 注册自定义插件:
// 建议用法:
// 1.如果涉及到数据结构的调整用自定义函数去处理。否则有局限性,以后扩展没有这么多特殊字符。
// 2.处理涉及到样式调整,展示方式等才使用插件的方式
builder.addPlugin('%', new ParagraphStringRenderPolicy())
.addPlugin(';', new ParagraphWrapRenderPolicy()) // 自定义换行插件
// 注释原因: 只做数据转换或逻辑判断,不建议这样使用,参考下面自定义函数用法
//.addPlugin(':', new JSONArrayToStringRenderPolicy())
.addPlugin('^', new TableRenderPolicy()); // 表格默认以 # 定义,现在改为以 ^ 定义。
// 移除以 # 定义的表格插件
builder.build().getDefaultPolicys().remove('#');
// 方式二 注册自定义函数
Map<String, Method> spELFunction = new HashMap<>();
try{
spELFunction.put("JsonStrToStr", ELFunction.class.getMethod("JsonStrToStr", String.class, String.class));
spELFunction.put("JsonArrGetKeyToStr", ELFunction.class.getMethod("JsonArrGetKeyToStr", JSONArray.class, String.class, String.class));
}catch (Exception e){
log.error("获取方法失败", e);
}
builder.useSpringEL(spELFunction);
// =========================
输出模板相关代码:
// 输出word
try {
String fileName = System.getProperty("java.io.tmpdir") + IdUtil.fastSimpleUUID() + ".docx";
long l = HttpUtil.downloadFile(reportTemplateEntity.getFile(), fileName);
String doFileName = URLEncoder.encode(reportTemplateEntity.getName() + "-" + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_MS_PATTERN) , "UTF-8");
if (l > 0L) {
XWPFTemplate template = XWPFTemplate.compile(FileUtil.file(fileName), builder.build());
template.render(wordParamMap);
if ("word".equals(filetype)) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
template.write(bos);
InputStream inputStream = new ByteArrayInputStream(bos.toByteArray());
HttpHeaders headers = new HttpHeaders();
headers.add("charset", "utf-8");
headers.add("Content-Disposition", "inline;filename=\"" + doFileName + ".docx\"");
Resource resource = new InputStreamResource(inputStream);
return ResponseEntity.ok().headers(headers).contentType(MediaType.valueOf(Utils.getContentType(Utils.getFileType(fileName)))).body(resource);
} else if ("pdf".equals(filetype)) {
String wordFileName = System.getProperty("java.io.tmpdir") + IdUtil.fastSimpleUUID() + ".docx";
String pdfFileName = System.getProperty("java.io.tmpdir") + IdUtil.fastSimpleUUID() + ".pdf";
template.writeToFile(wordFileName);
File wordFile = FileUtil.file(wordFileName);
File pdfFile = FileUtil.touch(pdfFileName);
PdfUtil.word2pdf(wordFileName, pdfFileName);
// WPSUtil.doc2pdf(wordFileName, pdfFileName);
InputStream inputStream = new ByteArrayInputStream(FileUtil.readBytes(pdfFile));
HttpHeaders headers = new HttpHeaders();
headers.add("charset", "utf-8");
headers.add("Content-Disposition", "inline;filename=\"" + doFileName + ".pdf\"");
Resource resource = new InputStreamResource(inputStream);
response.setContentType("application/pdf");
return ResponseEntity.ok().headers(headers).contentType(MediaType.valueOf(Utils.getContentType(Utils.getFileType(pdfFileName)))).body(resource);
}
throw new ServiceException("文件类型错误");
}
throw new ServiceException("下载模板失败");
} catch (Exception e) {
log.error("输出模板失败," + e.getMessage(), e);
throw new ServiceException("输出模板失败," + e.getMessage());
}
换行插件:
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.policy.RenderPolicy;
import com.deepoove.poi.template.ElementTemplate;
import com.deepoove.poi.template.run.RunTemplate;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
/**
* @Author : lyy
* @create 2024/07/19
*/
@Slf4j
public class ParagraphWrapRenderPolicy implements RenderPolicy {
@Override
public void render(ElementTemplate eleTemplate, Object data, XWPFTemplate template) {
try {
XWPFRun run = ((RunTemplate) eleTemplate).getRun();
if (run == null) {
return;
}
if (data != null){
String value = String.valueOf(data);
XWPFParagraph paragraph = ((RunTemplate) eleTemplate).getRun().getParagraph();
if(value.indexOf("\\n") > 0){
//设置换行
String[] text = value.split("\\\\n");
paragraph.removeRun(0);
run = paragraph.insertNewRun(0);
for(int f = 0;f < text.length; f++) {
if(f == 0){
//此处不缩进因为word模板已经缩进了。
run.setText(text[f].trim());
}else{
run.addBreak();
//注意:wps换行首行缩进是三个空格符,office要的话可以用 run.addTab();缩进或者四个空格符
run.setText(text[f].trim());
}
}
}
} else {
run.setText("");
}
} catch (Exception e){
log.error("变量的内容转换Word段落处理出错!内容:{}", data, e);
}
}
}
变量的内容 转 Word段落 插件:
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.policy.RenderPolicy;
import com.deepoove.poi.template.ElementTemplate;
import com.deepoove.poi.template.run.RunTemplate;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.xmlbeans.XmlCursor;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Slf4j
public class ParagraphStringRenderPolicy implements RenderPolicy {
@Override
public void render(ElementTemplate eleTemplate, Object data, XWPFTemplate template) {
try {
XWPFRun run = ((RunTemplate) eleTemplate).getRun();
if (run == null) {
return;
}
if (data != null){
String thing = String.valueOf(data);
thing = thing.replace("\\\\", "\\");
List<String> splitList = new ArrayList<>();
String[] split1 = thing.split("\\r\\n");
for (String s : split1) {
String[] splits = s.split("\\n");
if(splits.length>0) {
splitList.addAll(Arrays.asList(splits));
} else {
splitList.add("");
}
}
createParagraphs(run.getDocument(), ((RunTemplate) eleTemplate).getRun().getParagraph(), run, splitList);
if (!CollectionUtils.isEmpty(splitList)) {
run.setText(splitList.get(splitList.size() - 1), 0);
} else {
run.setText("");
}
} else {
run.setText("");
}
} catch (Exception e){
log.error("变量的内容转换Word段落处理出错!内容:{}", data, e);
}
}
private void createParagraphs(XWPFDocument document, XWPFParagraph xwpfParagraph, XWPFRun run, List<String> paragraphs) {
if (xwpfParagraph != null) {
for (int i = 0; i < paragraphs.size(); i++) {
if (i == paragraphs.size() - 1) {
continue;
}
XmlCursor cursor = xwpfParagraph.getCTP().newCursor();
XWPFParagraph newParagraph = document.insertNewParagraph(cursor);
newParagraph.setAlignment(xwpfParagraph.getAlignment());
newParagraph.setIndentationFirstLine(xwpfParagraph.getIndentationFirstLine());
// newParagraph.getCTP().insertNewR(0).insertNewT(0).setStringValue(paragraphs[i]);
newParagraph.setNumID(xwpfParagraph.getNumID());
newParagraph.getCTP().setPPr(xwpfParagraph.getCTP().getPPr());
XWPFRun newParaRun = newParagraph.createRun();
newParaRun.getCTR().setRPr(run.getCTR().getRPr());
newParaRun.setText(paragraphs.get(i));
// newParaRun.setFontFamily(run.getFontFamily());
// newParaRun.setFontSize(run.getFontSize());
// newParaRun.setBold(false);
}
}
}
}
导出结果: