部署Tomcat WAR包后Java文本归一化行为异常求助
这种本地跑正常、部署就炸的编码问题我太熟了!核心原因几乎都是全链路编码不一致——本地IDE、Maven构建、Tomcat运行这三个环节里,肯定有某个地方没统一用UTF-8,导致重音字符在打包或部署过程中被悄悄转码了。下面给你一步步排查和解决的思路:
本地IDE默认一般会用UTF-8,但Maven默认的编译/资源处理编码可能是ISO-8859-1,这会导致打包时字符被转码。你可以对照自己的Maven配置,检查是否添加了以下编码指定:
编译插件指定编码
确保maven-compiler-plugin明确设置UTF-8:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>你的JDK版本</source> <target>你的JDK版本</target> <encoding>UTF-8</encoding> <!-- 关键配置 --> </configuration> </plugin>
资源插件指定编码
如果你的项目里有包含重音字符的配置文件/资源,还要给maven-resources-plugin加编码:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>3.2.0</version> <configuration> <encoding>UTF-8</encoding> </configuration> </plugin>
命令行Maven的环境变量
如果是在服务器上用命令行打包,还要确保Maven的环境变量里指定编码:
- Linux:在终端执行
export MAVEN_OPTS="-Dfile.encoding=UTF-8" - Windows:执行
set MAVEN_OPTS=%MAVEN_OPTS% -Dfile.encoding=UTF-8
Tomcat默认的URI和请求编码可能不是UTF-8,你可以对照自己的server.xml配置,补全以下参数:
Connector配置补全编码
确保HTTP Connector添加URIEncoding和useBodyEncodingForURI:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8" <!-- 解析URI参数用UTF-8 --> useBodyEncodingForURI="true"/> <!-- 让请求体编码和URI编码一致 -->
Tomcat启动脚本添加全局编码
还要修改Tomcat的启动脚本,强制JVM用UTF-8处理字符:
- Linux:在
catalina.sh开头添加:JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8" - Windows:在
catalina.bat开头添加:set JAVA_OPTS=%JAVA_OPTS% -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8
这里的sun.jnu.encoding是处理系统文件名/资源的编码,很容易被忽略,却是导致字符乱码的常见坑。
检查你的归一化代码,确保输入字符串没有被提前转码:
- 如果是从HTTP请求获取的参数,要先调用
request.setCharacterEncoding("UTF-8")再取值,否则Tomcat会用默认的ISO-8859-1解析。 - 确保归一化时用的是正确的字符集,比如:
import java.text.Normalizer; import java.util.regex.Pattern; public String normalizeAccent(String input) { // 先归一化分解重音字符 String normalized = Normalizer.normalize(input, Normalizer.Form.NFD); // 移除重音标记 return Pattern.compile("\\p{InCombiningDiacriticalMarks}+") .matcher(normalized) .replaceAll(""); } - 可以在代码里加日志,输出字符串的字节数组,对比本地和服务器的差异:
import java.nio.charset.StandardCharsets; import java.util.Arrays; // 日志输出示例 logger.info("原始字符串: {}", input); logger.info("UTF-8字节数组: {}", Arrays.toString(input.getBytes(StandardCharsets.UTF_8))); logger.info("ISO-8859-1字节数组: {}", Arrays.toString(input.getBytes(StandardCharsets.ISO_8859_1)));
如果本地和服务器的字节数组不一样,说明字符串在传输/打包过程中被转码了。
- 先在本地用Maven命令行打包(
mvn clean package),然后把WAR包放到本地Tomcat运行,如果本地Tomcat也出问题,那就是Maven打包的问题;如果本地Tomcat正常,那就是服务器上的Tomcat配置或环境变量的问题。 - 检查打包后的WAR包,解压后看包含重音字符的文件(比如配置文件、class文件里的字符串)是否已经乱码,这能快速定位是打包阶段还是部署阶段出的问题。
核心原则就是:从代码编写、Maven构建到Tomcat运行,全链路必须统一用UTF-8编码,任何一个环节掉链子,都会导致重音字符的归一化结果不符合预期。
内容的提问来源于stack exchange,提问作者user52715




