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-plugin
和maven-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获取。