RTF模板VelocityContext替换俄文字符乱码问题求助(Java+SpringBoot3+Apache POI)
解决RTF模板替换俄文占位符乱码问题
问题根源
模板原有俄文正常,但动态插入的俄文乱码,本质是Apache POI处理RTF时,未将UTF-8字符串转换为RTF兼容的编码格式:
- 模板本身的俄文已被RTF正确编码(如CP1251或UTF-8转义)
- 动态替换的文本直接以UTF-8写入RTF,而Word/LibreOffice解析RTF时默认使用ANSI编码(如CP1252),导致俄文被错误解析
解决方案
1. 对替换文本进行RTF编码转义
将俄文字符转换为RTF标准的十六进制转义序列,确保Office软件能正确识别:
public static String escapeRtf(String text) { StringBuilder rtfText = new StringBuilder(); for (char c : text.toCharArray()) { // 非ASCII字符转成RTF的\u转义格式 if (c > 127) { rtfText.append("\\uc0\\u").append((int) c).append("?"); } else { rtfText.append(c); } } return rtfText.toString(); }
使用时,先转义待替换的俄文文本,再执行占位符替换。
2. 使用HWPF API进行原生替换(避免直接操作RTF字符串)
不要直接读取RTF为字符串替换,而是用Apache POI的HWPFDocument API遍历文档内容,确保编码处理正确:
try (InputStream templateStream = new FileInputStream("template.rtf")) { HWPFDocument rtfDoc = new HWPFDocument(templateStream); Range docRange = rtfDoc.getRange(); // 转义俄文文本后替换占位符 String russianText = escapeRtf("русские слова."); docRange.replaceText("{RUSSIAN_PLACEHOLDER}", russianText); try (OutputStream outputStream = new FileOutputStream("output.rtf")) { rtfDoc.write(outputStream); } } catch (IOException e) { e.printStackTrace(); }
3. 修正RTF文档的编码声明
检查RTF模板开头的编码标记,将\ansi替换为\utf8,确保Office软件以UTF-8解析整个文档:
- 打开RTF模板(用文本编辑器),找到开头的
{\rtf1\ansi,改为{\rtf1\utf8 - 若使用代码修改,可在读取RTF前先替换头部的编码声明
4. 升级Apache POI版本
确保使用5.2.5及以上版本的Apache POI,旧版本存在RTF编码处理的已知bug,升级后可解决部分编码兼容问题。
验证
替换后生成的RTF文件:
- 在Postman中仍能正常显示俄文
- 用Word/LibreOffice打开时,动态插入的俄文与模板原有俄文一致
内容的提问来源于stack exchange,提问作者newbor
相关产品推荐
相关产品推荐

