2. 什么是字符编码?为什么需要关注?

世界上存在多种语言,每种语言使用不同的字符。Unicode系统包含超过10万个字符、符号甚至表情符号。为了节省内存,我们使用编码系统在二进制数据与屏幕上可读字符之间进行转换。目前存在多种编码系统,读取文件时必须知道使用的是哪种编码。

2.1. 不在Maven中声明编码会发生什么?

Maven非常重视编码问题,如果未声明编码,会输出警告信息。这个警告在Apache Maven官方FAQ中排名第一。让我们通过添加两个插件来复现这个问题:

首先添加maven-resources-plugin(用于复制资源文件):

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-resources-plugin</artifactId>
    <version>3.2.0</version>
</plugin>

再添加maven-compiler-plugin(用于编译代码):

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
</plugin>

在多模块项目中,父POM可能已设置编码。为演示效果,我们清空编码属性:

<properties>
    <project.build.sourceEncoding></project.build.sourceEncoding>
</properties>

执行构建命令:

mvn clean install

构建会失败并输出警告:

[INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ maven-properties ---
  [WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!

警告表明:未指定编码时,Maven会使用平台默认编码(Windows上通常是Cp1252)。这种默认值可能因环境而异,导致构建结果不一致。

2.2. 声明错误编码会发生什么?

Maven作为构建工具,必须使用与源文件相同的编码来读取文件。同时,Maven生成的输出文件也需要使用预期编码,否则在其他系统上可能无法读取。

创建包含非ASCII字符的Java类:

public class NonAsciiString {

    public static String getNonAsciiString() {

        String nonAsciiŞŧř = "ÜÝÞßàæç";
        return nonAsciiŞŧř;
    }
}

在POM中设置ASCII编码:

<properties>
    <project.build.sourceEncoding>US-ASCII</project.build.sourceEncoding>
</properties>

执行mvn clean install会报错:

[ERROR] /Baeldung/tutorials/maven-modules/maven-properties/src/main/java/
com/baeldung/maven/properties/NonAsciiString.java:[15,31] unmappable character (0xC3) for encoding US-ASCII

原因:文件包含非ASCII字符,无法用ASCII编码读取。建议尽量避免使用非ASCII字符,并统一使用UTF-8编码。

3. 如何在Maven配置中设置编码?

3.1. 如何在插件中设置encoding参数?

大多数插件都提供encoding参数。在maven-resources-pluginmaven-compiler-plugin中添加:

<configuration>
    <encoding>UTF-8</encoding>
</configuration>

执行构建后日志显示:

[INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ maven-properties ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.

警告消失,插件已使用UTF-8编码。

3.2. 如何设置项目级编码参数?

为每个插件单独设置编码很繁琐。大多数插件默认使用全局属性project.build.sourceEncoding。移除插件中的encoding配置,改为在POM中设置:

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

效果与插件级设置相同。在多模块项目中,通常在父POM设置此属性。注意:插件级配置会覆盖项目级配置。部分旧版插件(如maven-war-plugin <2.2)可能忽略此属性。

3.3. 如何为报告插件设置项目级编码?

需要同时设置两个属性才能覆盖所有场景。以properties-maven-plugin为例:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>properties-maven-plugin</artifactId>
    <version>1.1.0</version>
</plugin>

清空报告输出编码属性:

<project.reporting.outputEncoding></project.reporting.outputEncoding>

执行构建会失败:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-pmd-plugin:3.13.0:pmd (pmd) on project maven-properties: Execution pmd of goal 
  org.apache.maven.plugins:maven-pmd-plugin:3.13.0:pmd failed: org.apache.maven.reporting.MavenReportException: : UnsupportedEncodingException -> [Help 1]

原因:构建过程和报告过程使用不同的属性键。仅设置project.build.sourceEncoding不够,还需添加:

<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

建议:在项目级同时设置这两个属性。

3.4. 如何通过命令行设置编码?

可通过命令行参数设置编码,适用于无POM修改权限的场景:

mvn clean install -Dproject.build.sourceEncoding=UTF-8 -Dproject.reporting.outputEncoding=UTF-8

命令行参数优先级最高,会覆盖POM中的配置。即使删除POM中的编码属性,也能成功构建。

4. 在同一Maven项目中使用多种编码

建议整个项目使用统一编码,但有时不得不处理多种编码(如资源文件编码不受控)。解决方案取决于具体情况:

  • 插件级设置:可为不同插件设置不同编码(如代码用CP-1252,测试报告用UTF-8)
  • 多执行配置:同一插件的不同执行可使用不同编码

maven-resources-plugin支持特殊配置:

<configuration>
    <encoding>UTF-8</encoding>
    <propertiesEncoding>ISO-8859-1</propertiesEncoding>
</configuration>

执行构建日志:

[INFO] --- maven-resources-plugin:3.2.0:resources (default-resources) @ maven-properties ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Using 'ISO-8859-1' encoding to copy filtered properties files.

提示:查阅maven.apache.org的插件文档了解编码支持细节。

5. 总结

本文探讨了Maven中字符编码的关键问题:

  • 声明编码可确保:在任何环境中都能获得一致的构建结果
  • 两种项目级属性project.build.sourceEncoding(构建过程)和project.reporting.outputEncoding(报告过程)
  • 命令行设置:通过-D参数临时覆盖编码配置
  • 多编码场景:可通过插件级配置或特殊参数(如propertiesEncoding)处理

最佳实践:在父POM中统一设置UTF-8编码,避免踩坑。示例代码可在GitHub获取。


原始标题:A Guide to Maven Encoding