一、为什么你的Maven项目总是乱码?

搞Java的朋友应该都遇到过这样的场景:明明在IDE里运行得好好的代码,打包部署后就变成了一堆问号。特别是当项目里混着中文注释、中文日志、甚至中文业务数据时,这种编码问题简直让人抓狂。

问题的根源往往出在编码不统一。Windows系统默认用GBK,Linux默认用UTF-8,而Maven编译时如果没有明确指定编码,就会使用系统默认编码。这就好比一群人说不同的方言开会,不乱才怪。

举个真实案例:某次我在处理用户导入功能时,CSV文件里的中文在测试环境显示正常,上了生产环境全变成"????"。最后发现是Maven打包时没有统一编码配置,导致编译后的class文件编码与运行时环境不匹配。

二、UTF-8为什么是终极解决方案?

UTF-8有三个不可替代的优势:

  1. 它是ASCII的超集,兼容英文环境
  2. 支持全球所有语言的字符
  3. 是互联网事实上的标准编码

在Java技术栈中,从JDK到主流框架都对UTF-8有最完善的支持。比如Spring Boot的默认字符集就是UTF-8,Tomcat9+也默认使用UTF-8处理请求。

来看个对比实验:

// 测试代码:分别用GBK和UTF-8读取中文文件
public class EncodingTest {
    public static void main(String[] args) throws IOException {
        // GBK读取(在UTF-8环境下会乱码)
        String gbkContent = Files.readString(Paths.get("data.txt"), Charset.forName("GBK"));
        System.out.println("GBK读取结果:" + gbkContent);
        
        // UTF-8读取(通用方案)
        String utf8Content = Files.readString(Paths.get("data.txt"), StandardCharsets.UTF_8);
        System.out.println("UTF-8读取结果:" + utf8Content);
    }
}

当文件实际编码是UTF-8时,GBK读取会出现乱码,而UTF-8读取正常。这证明了统一编码的重要性。

三、Maven项目完整UTF-8配置方案

1. 基础POM配置

在项目的pom.xml中添加如下配置:

<project>
    ...
    <properties>
        <!-- 关键配置:设置项目编码为UTF-8 -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>
    
    <build>
        <plugins>
            <!-- 编译器插件配置 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <encoding>UTF-8</encoding> <!-- 指定编译器编码 -->
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </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>
        </plugins>
    </build>
</project>

2. 针对不同场景的增强配置

场景1:处理属性文件

<!-- 专门处理.properties文件的插件配置 -->
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-resources-plugin</artifactId>
    <configuration>
        <nonFilteredFileExtensions>
            <nonFilteredFileExtension>pdf</nonFilteredFileExtension>
        </nonFilteredFileExtensions>
        <encoding>UTF-8</encoding>
    </configuration>
</plugin>

场景2:JSP文件编码

如果是Web项目,还需要确保JSP文件的编码:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>3.3.2</version>
    <configuration>
        <webResources>
            <resource>
                <directory>src/main/webapp</directory>
                <filtering>true</filtering>
                <includes>
                    <include>**/*.jsp</include>
                </includes>
            </resource>
        </webResources>
    </configuration>
</plugin>

四、验证配置是否生效的三种方法

方法1:编译后检查class文件

使用JDK自带的native2ascii工具:

native2ascii -encoding UTF-8 MyClass.class

方法2:Maven命令验证

mvn clean compile -X | grep encoding
# 应该能看到类似输出:
# [DEBUG] Using encoding 'UTF-8' to copy filtered resources.

方法3:单元测试验证

@Test
public void testSystemProperties() {
    // 验证文件编码设置
    assertEquals("UTF-8", System.getProperty("file.encoding"));
    
    // 验证控制台输出编码
    assertEquals("UTF-8", Charset.defaultCharset().name());
}

五、常见问题解决方案

问题1:IntelliJ IDEA中仍显示乱码

在IDEA的配置中添加VM参数:

-Dfile.encoding=UTF-8

并检查:

  1. File -> Settings -> Editor -> File Encodings
  2. 确保Global Encoding、Project Encoding和Default encoding都设置为UTF-8

问题2:Maven打包后资源文件乱码

在resources插件中添加过滤配置:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-resources-plugin</artifactId>
    <configuration>
        <escapeString>\</escapeString>
        <includeEmptyDirs>true</includeEmptyDirs>
        <encoding>UTF-8</encoding>
    </configuration>
</plugin>

六、深入理解编码问题的本质

Java的编码处理流程可以简化为:

  1. 源代码文件(.java) -> 编译器 -> 字节码(.class)
  2. 资源文件 -> 资源处理器 -> 打包文件
  3. 运行时JVM -> 系统默认编码

其中每个环节都可能引入编码转换。我们通过Maven配置实际上是在控制前两个环节的编码行为。

来看个编码转换的典型示例:

// 演示错误的编码转换过程
public class EncodingDemo {
    public static void main(String[] args) throws UnsupportedEncodingException {
        String original = "中文测试";
        
        // 错误示范:混合编码转换
        byte[] gbkBytes = original.getBytes("GBK");
        String wrongString = new String(gbkBytes, "ISO-8859-1");
        System.out.println(wrongString); // 输出乱码
        
        // 正确做法:全程UTF-8
        byte[] utf8Bytes = original.getBytes(StandardCharsets.UTF_8);
        String correctString = new String(utf8Bytes, StandardCharsets.UTF_8);
        System.out.println(correctString); // 输出正常
    }
}

七、现代Java项目的编码最佳实践

  1. 全栈统一:从数据库到前端全部使用UTF-8

    • MySQL配置:character_set_server=utf8mb4
    • HTTP响应头:Content-Type: text/html;charset=UTF-8
  2. 构建工具扩展

    <!-- 确保测试资源也使用UTF-8 -->
    <testResources>
        <testResource>
            <directory>src/test/resources</directory>
            <filtering>true</filtering>
            <encoding>UTF-8</encoding>
        </testResource>
    </testResources>
    
  3. 持续集成环境配置: 在Jenkins等CI工具中设置环境变量:

    export MAVEN_OPTS="-Dfile.encoding=UTF-8"
    

八、总结与建议

经过多年的项目实践,我总结出以下经验:

  1. 新项目必须从一开始就配置UTF-8
  2. 老项目迁移时要逐步改造,先确保构建系统统一编码
  3. 不仅要配置Maven,还要检查IDE、数据库、操作系统等环境的编码设置

最后送大家一个检查清单:

  1. [ ] pom.xml中配置了sourceEncoding
  2. [ ] 编译器插件设置了UTF-8
  3. [ ] 资源插件配置了过滤
  4. [ ] IDE设置同步更新
  5. [ ] 数据库连接字符串指定了编码

记住:编码问题越早解决成本越低。现在就在你的项目中应用这些配置吧!