
网罗开发 (小红书、快手、视频号同名)
大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等方向。在移动端开发、鸿蒙开发、物联网、嵌入式、云原生、开源等领域有深厚造诣。
图书作者:《ESP32-C3 物联网工程开发实战》
图书作者:《SwiftUI 入门,进阶与实战》
超级个体:COC上海社区主理人
特约讲师:大学讲师,谷歌亚马逊分享嘉宾
科技博主:华为HDE/HDG
我的博客内容涵盖广泛,主要分享技术教程、Bug解决方案、开发工具使用、前沿科技资讯、产品评测与使用体验 。我特别关注云服务产品评测、AI 产品对比、开发板性能测试以及技术报告,同时也会提供产品优缺点分析、横向对比,并分享技术沙龙与行业大会的参会体验。我的目标是为读者提供有深度、有实用价值的技术洞察与分析。
展菲:您的前沿技术领航员
👋 大家好,我是展菲!
📱 全网搜索"展菲",即可纵览我在各大平台的知识足迹。
📣 公众号"Swift社区",每周定时推送干货满满的技术长文,从新兴框架的剖析到运维实战的复盘,助您技术进阶之路畅通无阻。
💬 微信端添加好友"fzhanfei",与我直接交流,不管是项目瓶颈的求助,还是行业趋势的探讨,随时畅所欲言。
📅 最新动态:2025 年 3 月 17 日
快来加入技术社区,一起挖掘技术的无限潜能,携手迈向数字化新征程!
文章目录
-
- 前言
- 问题背景
- [解决方案一:统一使用 UTF-8](#解决方案一:统一使用 UTF-8)
-
- [为什么选择 UTF-8](#为什么选择 UTF-8)
- [如何在项目中统一使用 UTF-8](#如何在项目中统一使用 UTF-8)
- [解决方案二:设置 JVM 参数](#解决方案二:设置 JVM 参数)
- 解决方案三:数据库字符集设置
-
- [MySQL 字符集设置](#MySQL 字符集设置)
- 连接数据库时设置字符集
- 其他数据库的字符集设置
- 实际应用场景
- 最佳实践建议
- 总结
前言
最近在做一个 Java 项目的时候,遇到了一个让人头疼的问题:在 Windows 上开发的时候,中文字符显示正常,但部署到 Linux 服务器上就变成乱码了。刚开始以为是数据库的问题,检查了数据库字符集也没问题。后来才发现,原来是不同系统的默认编码不一致导致的。
相信很多开发者都遇到过类似的问题:代码里写的中文,在不同环境下显示不一样;从数据库读取的数据,有时候是乱码;日志文件里的中文显示不正常。这些问题虽然看起来简单,但如果不了解字符编码的原理,可能会折腾很久。今天我们就来聊聊字符编码问题的原因和解决方案。
问题背景
字符编码问题是一个很常见但又容易被忽视的问题。不同的系统、不同的环境,默认的字符编码可能不一样,这就导致了各种乱码问题。
为什么会出现编码问题
现在的计算机系统,底层都是使用二进制来存储数据的。但我们在屏幕上看到的文字,比如中文、英文、日文等,都是字符。要把字符转换成二进制存储,就需要用到字符编码。
常见的字符编码:
- ASCII:最早的字符编码,只能表示 128 个字符,主要是英文字母、数字和一些符号
- GBK/GB2312:中文编码,Windows 系统默认使用
- UTF-8:现在最流行的编码,可以表示世界上所有的字符,跨平台兼容性好
问题根源:
不同系统默认的字符编码不一样:
- Windows 系统默认使用 GBK 或 GB2312
- Linux 系统默认使用 UTF-8
- Mac 系统默认使用 UTF-8
如果你的代码在 Windows 上开发(默认 GBK),但部署到 Linux 服务器上(默认 UTF-8),就可能出现乱码问题。
常见的乱码场景
在实际开发中,我们经常会遇到这些乱码场景:
场景一:文件读取乱码
从文件读取数据时,如果文件的编码和读取时使用的编码不一致,就会出现乱码。比如文件是 UTF-8 编码的,但用 GBK 编码去读取,中文就会变成乱码。
场景二:数据库存储乱码
数据库的字符集设置不对,或者连接数据库时没有指定正确的字符集,存储和读取的数据就可能出现乱码。
场景三:日志输出乱码
程序输出的日志,如果控制台的编码设置不对,或者日志文件的编码不对,中文日志就会显示成乱码。
场景四:网络传输乱码
不同系统之间通过网络传输数据时,如果编码不一致,接收到的数据可能就是乱码。
解决方案一:统一使用 UTF-8
解决字符编码问题最根本的方法,就是统一使用 UTF-8 编码。UTF-8 是目前最流行的字符编码,几乎所有的现代系统都支持,而且可以表示世界上所有的字符。
为什么选择 UTF-8
UTF-8 有很多优点:
- 兼容性好:几乎所有的系统、浏览器、数据库都支持 UTF-8
- 国际化支持:可以表示世界上所有的字符,包括中文、日文、韩文、阿拉伯文等
- 向后兼容:对于 ASCII 字符,UTF-8 编码和 ASCII 编码完全一样
- 变长编码:英文字符只占 1 个字节,中文字符占 3 个字节,比较节省空间
如何在项目中统一使用 UTF-8
代码文件编码:
确保所有的源代码文件都使用 UTF-8 编码保存。在 IDE 中,可以设置默认的文件编码:
- IntelliJ IDEA:File → Settings → Editor → File Encodings,将 Project Encoding 和 Default encoding for properties files 都设置为 UTF-8
- Eclipse:Window → Preferences → General → Workspace,将 Text file encoding 设置为 UTF-8
- VS Code:在设置中搜索 "files.encoding",设置为 UTF-8
配置文件编码:
配置文件(如 properties、xml、json 等)也要使用 UTF-8 编码。特别是 properties 文件,如果包含中文,必须使用 UTF-8 编码,否则会出现乱码。
资源文件编码:
资源文件(如国际化文件、模板文件等)也要使用 UTF-8 编码。
解决方案二:设置 JVM 参数
在 Java 项目中,JVM 的默认字符编码可能会影响程序的运行。如果 JVM 的默认编码不是 UTF-8,可能会导致文件读写、网络传输等操作出现乱码。
设置 JVM 参数
在启动 Java 程序时,可以通过 JVM 参数来设置字符编码:
bash
java -Dfile.encoding=UTF-8 -jar your-app.jar
这个参数会告诉 JVM,文件系统的默认编码是 UTF-8。
在 IDE 中设置
如果你在 IDE 中运行程序,也需要设置 JVM 参数:
IntelliJ IDEA:
- 点击 Run → Edit Configurations
- 选择你的运行配置
- 在 VM options 中输入:
-Dfile.encoding=UTF-8 - 点击 Apply 和 OK
Eclipse:
- 右键项目 → Run As → Run Configurations
- 选择你的运行配置
- 在 Arguments 标签页的 VM arguments 中输入:
-Dfile.encoding=UTF-8 - 点击 Apply 和 Run
在代码中设置
除了 JVM 参数,也可以在代码中设置系统属性:
java
System.setProperty("file.encoding", "UTF-8");
但这种方式不推荐,因为有些代码可能在设置之前就已经读取了系统属性。
验证编码设置
可以通过代码来验证当前的编码设置:
java
System.out.println("默认字符编码: " + System.getProperty("file.encoding"));
System.out.println("控制台编码: " + System.getProperty("console.encoding"));
如果输出不是 UTF-8,说明设置没有生效。
解决方案三:数据库字符集设置
数据库的字符集设置也很重要,如果数据库的字符集不对,存储和读取的数据就可能出现乱码。
MySQL 字符集设置
创建数据库时设置字符集:
sql
CREATE DATABASE mydb
DEFAULT CHARACTER SET utf8mb4
DEFAULT COLLATE utf8mb4_unicode_ci;
utf8mb4 是 MySQL 中真正的 UTF-8 编码,可以存储所有的 Unicode 字符,包括 emoji 表情。而 MySQL 的 utf8 实际上只支持最多 3 字节的字符,不支持 emoji。
创建表时设置字符集:
sql
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
修改现有数据库字符集:
如果数据库已经创建,可以修改字符集:
sql
ALTER DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
连接数据库时设置字符集
在连接数据库时,也要指定字符集:
JDBC 连接字符串:
java
String url = "jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8&useSSL=false";
或者使用更完整的参数:
java
String url = "jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8mb4&useSSL=false&serverTimezone=UTC";
Spring Boot 配置:
在 application.properties 或 application.yml 中配置:
properties
spring.datasource.url=jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8mb4&useSSL=false
spring.datasource.username=root
spring.datasource.password=password
或者:
yaml
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8mb4&useSSL=false
username: root
password: password
其他数据库的字符集设置
PostgreSQL:
PostgreSQL 默认使用 UTF-8 编码,创建数据库时:
sql
CREATE DATABASE mydb WITH ENCODING 'UTF8';
Oracle:
Oracle 数据库的字符集在创建数据库时设置,之后很难修改。建议在创建数据库时就选择 UTF-8 相关的字符集,如 AL32UTF8。
实际应用场景
让我们看看几个实际应用场景,了解如何在实际项目中应用这些解决方案:
场景一:Web 应用开发
在 Web 应用中,需要处理前端的请求和响应:
设置请求和响应编码:
在 Spring MVC 中,可以配置字符编码过滤器:
java
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Bean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
filter.setForceEncoding(true);
return filter;
}
}
或者在 web.xml 中配置:
xml
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
场景二:文件读写
在读写文件时,要明确指定编码:
读取文件:
java
// 使用 UTF-8 编码读取文件
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream("file.txt"), StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
写入文件:
java
// 使用 UTF-8 编码写入文件
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream("file.txt"), StandardCharsets.UTF_8))) {
writer.write("中文内容");
}
场景三:日志输出
在输出日志时,要确保日志文件的编码正确:
Logback 配置:
xml
<configuration>
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>app.log</file>
<encoder>
<charset>UTF-8</charset>
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
</configuration>
Log4j2 配置:
xml
<Configuration>
<Appenders>
<File name="File" fileName="app.log">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n" charset="UTF-8"/>
</File>
</Appenders>
</Configuration>
最佳实践建议
在实际项目中,为了避免字符编码问题,建议遵循以下最佳实践:
统一编码规范
- 所有代码文件使用 UTF-8 编码:包括 Java 源文件、配置文件、资源文件等
- 所有数据库使用 UTF-8 字符集:MySQL 使用 utf8mb4,PostgreSQL 使用 UTF8
- 所有网络传输使用 UTF-8 编码:HTTP 请求和响应、消息队列等
- 所有日志文件使用 UTF-8 编码:确保日志中的中文能正常显示
明确指定编码
在代码中,凡是涉及字符编码的地方,都要明确指定 UTF-8,不要依赖系统默认编码:
java
// 好的做法:明确指定编码
String content = new String(bytes, StandardCharsets.UTF_8);
// 不好的做法:依赖默认编码
String content = new String(bytes); // 可能在不同环境下表现不一致
验证编码设置
在项目启动时,可以输出当前的编码设置,方便排查问题:
java
@PostConstruct
public void checkEncoding() {
System.out.println("file.encoding: " + System.getProperty("file.encoding"));
System.out.println("Default Charset: " + Charset.defaultCharset());
}
测试不同环境
在部署到不同环境之前,要测试字符编码是否正常:
- 在 Windows 开发环境测试
- 在 Linux 测试环境测试
- 在 Linux 生产环境测试
确保在所有环境下,中文字符都能正常显示。
总结
字符编码问题虽然看起来简单,但在实际项目中却经常遇到。解决这类问题的关键是统一使用 UTF-8 编码,并在所有可能涉及编码的地方明确指定。
关键点总结:
- 统一使用 UTF-8:所有文件、数据库、网络传输都使用 UTF-8 编码
- 设置 JVM 参数 :通过
-Dfile.encoding=UTF-8设置 JVM 默认编码 - 数据库字符集:数据库和表都使用 UTF-8 字符集,连接时也要指定字符集
- 明确指定编码:在代码中,凡是涉及编码的地方都要明确指定,不要依赖默认值
- 验证和测试:在不同环境下测试,确保编码设置正确
最佳实践:
- 项目开始时就统一编码规范
- 在 IDE 中设置默认编码为 UTF-8
- 在构建脚本中设置 JVM 参数
- 数据库创建时就使用 UTF-8 字符集
- 代码中明确指定编码,不要依赖默认值