背景:
接了新需求,前端提供一个大概的word模板,包含通用信息,用户在前端填写可修改内容至模板完善,然后将整个数据传递给后端进行保存,后端提供导出word的功能。
数据中包含这种类型,由于前端输出框不是富文本编辑框所以无法填写。最终传递到后端的数据格式是1.37m-1,如此一来在导出word的时候格式就变得不符合预期。
现在代码中导出word使用的库是easypoi,easypoi仅仅提供了,指定项目路径下的word文档模板,然后在其中添加占位符,再通过代码设置key-value的方式给其赋值。没有提供特殊文本的处理方法,所以只能设置数据,无法添加上标。但是easypoi本质是通过继承对poi实现了封装,其对象仍然具备poi对象的方法。所以可以使用poi的接口设置这种文本。
解决过程:
1.在接口导出数据到word的时候,硬编码识别m-1这个特殊字符,然后在其前后添加自定义语法,后续可通过该自定义语法针对性的对一些特殊的格式进行处理。这里的m代表的普通字符,后面的{[和]}框起来的内容代表需要解析的内容,:前的SUPERSCRIPT代表上标的意思,:后的-1代表上标的值
"m{[SUPERSCRIPT:-1]}"
String[] split = fifthRecord.split("m-1");
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < split.length; i++) {
if (i != split.length - 1){
stringBuilder.append(split[i]).append("m{[SUPERSCRIPT:-1]}");
} else {
stringBuilder.append(split[i]);
}
}
例如:
fifthRecord="光吸收系数为1.37m-1"
stringBuilder="光吸收系数为1.37m{[SUPERSCRIPT:-1]}"
2.
判断文本是否包含需要解析的文本,如果包含的话,进行特殊处理,
XWPFParagraph对象是对应poi每个段落的对象,包含一段文字,表格的格式和内容。
private static final String START_STR = "{[";
public static void parseParagraph(XWPFParagraph paragraph) {
List<XWPFRun> runs = paragraph.getRuns();
List<XWPFRun> copyRuns = new ArrayList<>(runs);
for (int i = 0; i < copyRuns.size(); i++) {
XWPFRun v = copyRuns.get(i);
String text = v.getText(0);
if (text.contains(START_STR)) {
ArrayList<String> strings = parseContent(text);
paragraph.removeRun(i);
strings.forEach(s -> {
if (s.contains(START_STR)) {
XWPFRun run = paragraph.createRun();
parseSubscript(s, run, 16);
} else {
XWPFRun paragraphOneRunTwo = paragraph.createRun();
paragraphOneRunTwo.setFontSize(16);
paragraphOneRunTwo.setBold(false);
paragraphOneRunTwo.setText(s);
paragraphOneRunTwo.setUnderline(UnderlinePatterns.SINGLE);
paragraphOneRunTwo.setFontFamily("仿宋");
}
});
}
}
}
3.识别{[符号,并切分,例如
content="光吸收系数为1.37m{[SUPERSCRIPT:-1]}"
return=["光吸收系数为1.37m","{[SUPERSCRIPT:-1]}"]
这样我们就可以单独处理这个上标-1
public static ArrayList<String> parseContent(String content) {
int length = content.length();
ArrayList<String> strings = new ArrayList<>();
int startIndex = 0;
for (int i = 0; i < length - 1; i++) {
char c1 = content.charAt(i);
char c2 = content.charAt(i + 1);
if (c1 == '{' && c2 == '[') {
if (i != 0) {
strings.add(content.substring(startIndex, i));
startIndex = i;
}
}
if (c1 == ']' && c2 == '}') {
strings.add(content.substring(startIndex, i + 2));
startIndex = i + 2;
}
if (i == length - 2 && startIndex != i + 2) {
strings.add(content.substring(startIndex, i + 1));
}
}
return strings;
}
例如
content="光吸收系数为1.37m{[SUPERSCRIPT:-1]}"
return=["光吸收系数为1.37m","{[SUPERSCRIPT:-1]}"]
4.最终解析自定义的语法并通过poi的方法添加一个上标或者下标的文本,当然这里只是用到了上标和下标,可以使用类似的方式,去做更多的自定义格式的处理。
public static XWPFRun parseSubscript(String msg, XWPFRun xwpfRun, Integer fontSize) {
String substring = msg.substring(2, msg.length() - 2);
String[] split = substring.split(":");
if (split[0].equals(VerticalAlign.SUPERSCRIPT.toString())) {
xwpfRun.setFontSize(fontSize);
xwpfRun.setBold(false);
xwpfRun.setSubscript(VerticalAlign.SUPERSCRIPT);
xwpfRun.setText(split[1]);
xwpfRun.setUnderline(UnderlinePatterns.SINGLE);
xwpfRun.setFontFamily("仿宋");
return xwpfRun;
}
if (split[0].equals(VerticalAlign.SUBSCRIPT.toString())) {
xwpfRun.setFontSize(fontSize);
xwpfRun.setBold(false);
xwpfRun.setSubscript(VerticalAlign.SUBSCRIPT);
xwpfRun.setText(split[1]);
xwpfRun.setUnderline(UnderlinePatterns.SINGLE);
xwpfRun.setFontFamily("仿宋");
return xwpfRun;
}
return null;
}