You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

部署Tomcat WAR包后Java文本归一化行为异常求助

这种本地跑正常、部署就炸的编码问题我太熟了!核心原因几乎都是全链路编码不一致——本地IDE、Maven构建、Tomcat运行这三个环节里,肯定有某个地方没统一用UTF-8,导致重音字符在打包或部署过程中被悄悄转码了。下面给你一步步排查和解决的思路:

1. 先把Maven构建的编码锁死

本地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
2. 检查Tomcat的编码配置

Tomcat默认的URI和请求编码可能不是UTF-8,你可以对照自己的server.xml配置,补全以下参数:

Connector配置补全编码

确保HTTP Connector添加URIEncodinguseBodyEncodingForURI

<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是处理系统文件名/资源的编码,很容易被忽略,却是导致字符乱码的常见坑。

3. 确认代码里的编码处理细节

检查你的归一化代码,确保输入字符串没有被提前转码:

  • 如果是从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)));
    

如果本地和服务器的字节数组不一样,说明字符串在传输/打包过程中被转码了。

4. 快速验证定位问题
  • 先在本地用Maven命令行打包(mvn clean package),然后把WAR包放到本地Tomcat运行,如果本地Tomcat也出问题,那就是Maven打包的问题;如果本地Tomcat正常,那就是服务器上的Tomcat配置或环境变量的问题。
  • 检查打包后的WAR包,解压后看包含重音字符的文件(比如配置文件、class文件里的字符串)是否已经乱码,这能快速定位是打包阶段还是部署阶段出的问题。

核心原则就是:从代码编写、Maven构建到Tomcat运行,全链路必须统一用UTF-8编码,任何一个环节掉链子,都会导致重音字符的归一化结果不符合预期。

内容的提问来源于stack exchange,提问作者user52715

火山引擎 最新活动