poi-tl 使用springEl 表达式实现自定义函数

官网文档地址: 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);
			}
		}
	}

}

导出结果:
在这里插入图片描述

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值