1. 先别慌,Tomcat控制台乱码到底是怎么一回事
很多刚接触Java Web开发的朋友,第一次启动Tomcat的时候,估计都被cmd窗口里那一大片“锟斤拷”、“浣犲ソ”之类的乱码吓了一跳。我第一次遇到这个问题的时候,还以为是下载的Tomcat安装包损坏了,甚至重装了好几次,后来才发现根本不是那么回事。
这个问题的出现范围非常广,不管是Windows 10还是Windows 11,不管是Tomcat 8、Tomcat 9还是Tomcat 10,只要你用的是Windows系统,在cmd窗口(控制台)里启动Tomcat,几乎都有概率碰到中文乱码。乱码的内容主要集中在启动日志、初始化信息、部署报错信息这几块,英文日志显示完全正常,偏偏就是中文部分变成了“天书”。
这个问题的本质,用一句话说就是:Tomcat的日志输出使用的编码格式,和Windows控制台默认使用的编码格式对不上。说得再直白一点,就是Tomcat在“说话”的时候用了一种语言,而cmd窗口在“听”的时候用了另一种语言去解读,两边没对齐,听到的自然就是乱码了。
这篇内容适合谁看?我觉得只要满足下面任一条件,你都值得花十分钟把它读完:
- 刚下载好Tomcat,启动后发现控制台乱码,不知道怎么处理;
- 用IntelliJ IDEA、Eclipse等IDE集成了Tomcat,运行项目时控制台同样乱码;
- 已经尝试过一些网上的办法,但要么操作不完整,要么改完之后出现了新的问题;
- 想彻底搞清楚乱码的底层逻辑,下次遇到类似问题可以直接举一反三。
这篇文章我会从乱码的产生原理讲起,再给出三级递进的解决方案,最后附上常见的排查方法。保证你看完不仅能解决当前问题,还能明白为什么这么改就能好,以后给别人解释的时候也底气十足。
2. 为什么Tomcat在cmd窗口里会变成乱码
2.1 编码不一致才是罪魁祸首
乱码这件事,追根溯源永远只有一个原因:编码和解码的方式不一致。
我给你打个比方。假设有个人用汉语拼音写了一封信,信上写的是“ni hao”,结果收信的人不懂拼音,非要拿英语的读音规则去读,读出来的就成了“你嚎”,意思全变了。Tomcat和cmd窗口之间就是这种关系。
Tomcat的日志输出默认使用的是UTF-8编码,这是Tomcat 8.5版本之后的一个默认调整。而在中文版的Windows操作系统上,cmd窗口和控制台默认使用的却是GBK编码(也叫做CP936,是简体中文字符集的标准编码)。UTF-8的“锟斤拷”和GBK的“浣犲ソ”互不认账,于是你看到的就是一堆莫名其妙的字符。
在Windows的cmd窗口里,你可以输入下面这个命令来查看当前窗口使用的编码:
chcp如果输出结果是936,那就代表当前活动代码页是936,也就是GBK编码。如果你在cmd里看到的是65001,则是UTF-8编码。绝大多数情况下,中文Windows系统的cmd都默认是936。
2.2 编码转换的具体流程
Tomcat的日志体系是基于Java的java.util.logging组件实现的,它的配置文件是conf/logging.properties。Tomcat在启动的时候,会按照这个配置文件中的设置,把日志内容以指定的字符编码写入到控制台输出流中。
关键配置项是下面这行:
java.util.logging.ConsoleHandler.encoding = UTF-8这行配置的作用,是告诉Tomcat的ConsoleHandler(控制台处理器),往控制台写日志的时候用UTF-8编码。问题就出在这里:Tomcat用UTF-8往cmd窗口里扔字符,而cmd窗口却固执地用GBK去理解和渲染,于是UTF-8编码的中文字符(每个汉字3个字节),被GBK按两个字节一组去解析,结果自然就全乱了。
还有一个跟编码相关的经典梗:“锟斤拷”。这三个字实际上是UTF-8字节序列被错误地用GBK解码后产出的典型乱码字符,很多老程序员一看到这三个字,就能立刻判断出“哦,这是UTF-8被GBK解码了”。你这次看到的乱码,大概率就是这个“锟斤拷”家族的一员。
2.3 为什么英文不乱码,偏偏中文乱码
这个问题的答案其实很朴素:因为ASCII编码、UTF-8编码和GBK编码,对英文字母和数字的表示方式是完全一致的。英文字母和数字在所有这些编码里都是单字节存储,并且值完全一样,所以不管用哪种规则去解读,结果都是正确的。
而中文字符在UTF-8里占3个字节,在GBK里占2个字节,底层存储的字节序列完全不同。甲用UTF-8写出来的字节流,乙用GBK去读,读出来的字符数量不对、内容也不对,自然就乱套了。
明白了这个原理,你其实就知道解决方案的大方向了:要么让Tomcat输出GBK编码,要么让cmd窗口用UTF-8编码来接收。接下来我给的几个方案,本质上都是围绕这两条路展开的。
3. 最快最省事的解法:修改Tomcat的logging.properties
3.1 操作步骤
这个方法可以说是全网公认的入门级解法,也是我每一次帮别人处理Tomcat乱码问题时最先推荐的方法。它不需要修改系统的任何设置,只动Tomcat自己的配置文件,风险最小。
找到Tomcat安装目录下的conf文件夹,里面有一个名为logging.properties的文件。用记事本、Notepad++或者VS Code打开它,定位到下面这一行:
java.util.logging.ConsoleHandler.encoding = UTF-8把它改成:
java.util.logging.ConsoleHandler.encoding = GBK保存文件,然后重新启动Tomcat。到这一步,绝大多数情况下的乱码问题就已经解决了。
这里我要啰嗦一句:修改配置文件前,建议先备份一下原文件。你别小看这个习惯,我在实际工作中见过太多次改完配置出了问题想回退、结果原文件内容已经被改得面目全非的局面。
3.2 为什么改编码就行
把这个值从UTF-8改成GBK,本质上是让Tomcat“说”cmd窗口能听懂的语言。前面说了,中文Windows的cmd窗口默认按GBK解码,Tomcat也改用GBK输出,两边就对齐了,中文自然就恢复正常了。
这个方案不仅适用于Tomcat 9,Tomcat 8.5和Tomcat 10同样适用。因为这三个大版本的日志配置文件结构基本一致,ConsoleHandler.encoding这个配置项都还存在。
3.3 修改后依然乱码怎么办
如果你改完GBK之后,重启Tomcat发现乱码反而变得更离谱了,比如出现了“锟斤拷”的变体,或者原本还能看懂一部分的英文提示也出了问题,那说明你的情况可能不在这个方案覆盖范围内。
有两种可能:
- 第一种,你的Windows系统或者cmd窗口已经被手动改成了UTF-8代码页(也就是
chcp显示的是65001),这时候你应该把logging.properties改成UTF-8,或者干脆把cmd窗口的编码改回GBK; - 第二种,你使用的Tomcat发行版在启动脚本
catalina.bat里额外指定了JAVA_OPTS,强制覆盖了日志编码设置。这种情况比较少见,但我也确实碰到过,后面第4节会详细讲。
所以在动手之前,我建议你先花10秒钟执行一下chcp命令,确认当前cmd窗口的代码页,再决定把配置文件改成GBK还是保持UTF-8。这一步看似多余,实际上能帮你少绕很多弯路。
4. 备选方案:从cmd窗口侧下手,改用UTF-8编码
4.1 临时修改cmd窗口的代码页
如果你不想动Tomcat的任何配置文件,或者因为某些原因不能修改生产环境的Tomcat配置,那么从cmd窗口这一侧解决就是更好的选择。
在启动Tomcat之前,先在cmd窗口里执行下面的命令:
chcp 65001这条命令的作用,是把当前cmd窗口的活动代码页临时切换成UTF-8。切换之后,你再执行startup.bat启动Tomcat,原本乱码的中文日志就会恢复正常显示。
不过要提醒一句:这种修改是临时的,只对当前这个cmd窗口有效。窗口一关,下次重新打开一个新的cmd窗口,代码页又会还原成默认的936。所以如果你每次启动Tomcat都想要正常显示,就需要每次先执行一次chcp 65001,比较繁琐。
4.2 永久修改cmd窗口的默认代码页
如果你觉得每次手动输入命令太麻烦,也可以通过修改注册表的方式,让cmd窗口永久默认使用UTF-8代码页。
按下Win + R组合键,输入regedit并回车打开注册表编辑器。定位到下面这个路径:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor在右侧窗口中找到或新建一个名为Autorun的字符串值,双击它,把数值数据设置为:
chcp 65001 >nul点击确定关闭注册表编辑器。此后每当你打开一个新的cmd窗口,系统都会自动执行chcp 65001,把代码页切换成UTF-8。
但我要特别提醒一下:修改注册表的方式我其实不太推荐给新手用户,也不推荐在重要的开发机上随便改。原因有两点:
- 第一,
Autorun这个配置项对所有cmd窗口都会生效,如果你的其他脚本、批处理文件对GBK有依赖,改了之后可能引发连带问题; - 第二,有些第三方软件在调用cmd执行命令时,并不会读取这个注册表的
Autorun,所以这个方案的实际生效范围是有限的,并不像网上某些教程说的那么“万能”。
4.3 两个方案之间的本质区别
简单总结一下:改logging.properties的方案,是“Tomcat迁就cmd窗口”;改cmd代码页的方案,是“cmd窗口迁就Tomcat”。两条路都能抵达终点,但适用场景不同。
- 如果你只在本机开发,Tomcat是你自己启动的,我建议优先采用改
logging.properties的方案,一劳永逸; - 如果你在管理服务器,或者Tomcat是作为Windows服务安装的,不方便频繁改配置,那么用
chcp 65001临时切换的方式往往更合适。
在下面的表格里,我把两个方案的关键差异整理了出来,方便你做选择:
| 方案 | 修改对象 | 是否需重启 | 影响范围 | 推荐指数 |
|---|---|---|---|---|
| 修改logging.properties | Tomcat配置 | 是 | 仅Tomcat自身 | 五星 |
| chcp 65001临时切换 | cmd窗口 | 仅当前窗口 | 本窗口 | 三星 |
| 注册表Autorun | 系统级 | 新窗口生效 | 全部cmd窗口 | 两星 |
表格里的推荐指数是我个人的看法,不代表绝对标准。但如果你问我,我会坚定地站在“修改Tomcat配置文件”这一边。
5. 深入源码与实践:从启动脚本层面根治乱码
5.1 catalina.bat里藏着的猫腻
讲完最基础的两种解法,我们再深入一层,看看Tomcat的启动脚本里还有没有影响编码的“隐藏开关”。
Tomcat的启动脚本bin/catalina.bat是整个Tomcat生命周期里最重要的一段批处理脚本。它负责设置环境变量、拼装JAVA_OPTS、调用org.apache.catalina.startup.Bootstrap类来真正拉起Tomcat进程。
在这个脚本里,有一项配置值得你特别注意:
set "JAVA_OPTS=%JAVA_OPTS% -Dfile.encoding=UTF-8"如果你在catalina.bat里看到类似这样的一行,说明启动脚本在JVM层面强行指定了file.encoding为UTF-8。这个参数会作用于JVM进程中所有涉及文件读写和流输出的编码行为,包括System.out的输出、日志文件的写入等。
问题来了:如果file.encoding=UTF-8被写死在了启动脚本里,那么即使你把logging.properties里的ConsoleHandler.encoding改成了GBK,也有可能因为JVM级别的编码设置与ConsoleHandler的配置产生冲突,最终输出还是一团乱麻。
5.2 如何在catalina.bat层面做调整
我给你的建议是,打开bin/catalina.bat,用文本编辑器的搜索功能查找file.encoding相关的字符串。如果真的找到了,你可以尝试把UTF-8改成GBK,然后重启Tomcat看效果。
如果你在脚本里没有找到任何file.encoding相关的配置,那就说明这个“隐藏开关”并不存在,你不需要额外添加。很多网上教程会让用户手动往catalina.bat里添加-Dfile.encoding=UTF-8,这其实是一个典型的“画蛇添足”行为。
原因很简单:Tomcat在启动时,JVM会默认读取操作系统的字符集设置来确定file.encoding。在中文Windows上,这个默认值通常就是GBK。如果你手动再强制指定为UTF-8,反而人为制造了编码冲突。这不是在解决问题,而是在制造问题。
5.3 代码层面的System.out.println乱码问题
还有一种情况需要单独拎出来讲:有时候Tomcat本身的启动日志已经完全正常了,但你自己写的Web应用在控制台输出的System.out.println语句,依然显示乱码。
这是因为Java应用默认的file.encoding编码可能是平台的默认编码,也可能被容器环境覆盖了。如果你的Web应用是在IDEA里通过Tomcat启动的,那么你还需要去检查IDEA的编码设置。
在IntelliJ IDEA里,打开Settings -> Editor -> File Encodings,你可以看到三个下拉框:Global Encoding、Project Encoding和Properties Files。建议都统一设置成UTF-8。同时,在Help -> Edit Custom VM Options里,可以打开IDEA自己的配置文件,加上一行:
-Dfile.encoding=UTF-8然后重启IDEA,让这个配置生效。这一步做完,IDEA传递给Tomcat的JVM参数里就会包含UTF-8编码设置,System.out.println的中文输出基本上就能恢复正常了。
我在实际项目里遇到过一种很典型的情况:Tomcat的启动日志已经正常了,但项目里一个System.out.println("登录成功")的语句,在IDEA的控制台里就是显示乱码。我检查了上面说的所有配置,最后发现问题出在IDEA的Run/Debug Configurations里,Tomcat Server的VM options一栏被手动填了一个-Dfile.encoding=GBK。删掉之后,一切都正常了。
所以我要在这里给你一个非常实用的经验:排查乱码问题时,不要只看Tomcat自身,还要检查你的开发工具和运行环境给JVM塞了什么额外的参数。
# 在cmd里启动Tomcat前,先查看当前JVM默认编码(适用于已经配置好JAVA_HOME的环境) java -XshowSettings:properties -version 2>&1 | findstr file.encoding这条命令输出的结果,会明确告诉你当前JVM默认的file.encoding是什么。如果你发现这里显示GBK,而Tomcat日志输出UTF-8,冲突的根源就找到了。
6. 高频问题排查手册:五分钟定位乱码根源
6.1 常见问题与解决对照表
我把这些年遇到的Tomcat控制台乱码问题,按表现特征归了一下类,整理成下面这张速查表。你对号入座,找到自己属于哪一类,然后照着对应的方法处理即可。
| 故障现象 | 可能原因 | 解决动作 |
|---|---|---|
| 启动日志全是“锟斤拷” | Tomcat输出UTF-8,cmd按GBK解码 | 改logging.properties为GBK |
| 修改GBK后乱码更严重 | cmd代码页本身就是65001 | 先确认chcp结果再调整 |
| 日志中英文正常,只有中文乱 | 编码冲突只波及多字节字符 | 统一ConsoleHandler编码即可 |
| 中文前半段正常,后半段乱 | 启动脚本或IDE覆盖了file.encoding | 检查catalina.bat和IDEA VM options |
| 在cmd里正常,在IDE里乱 | IDEA自带控制台编码设置不一致 | 检查IDEA的File Encodings设置 |
| 修改配置后重启又还原 | Tomcat被安装为Windows服务,走了服务配置 | 检查服务安装时的JVM参数 |
这张表覆盖了我能想到的绝大多数场景。如果你遇到的问题正好被列在表里,那就照着对应的方法去改;如果不在表里,别急,下一节我再讲一个更系统的排查思路。
6.2 事无巨细的排查四步法
我平时在帮别人排查乱码问题时,不是东试一个方法西试一个方法,而是按照固定的顺序一层层往深处挖。这套方法我称之为“排查四步法”,分享给你。
第一步:确认当前cmd窗口的代码页。
打开一个新的cmd窗口,输入chcp回车,看输出是936还是65001还是其他数值。这个结果直接决定你改Tomcat配置时该用GBK还是UTF-8。这一步是整个排查过程的地基,地基不稳,后面全白搭。
第二步:确认Tomcat的ConsoleHandler编码。
打开conf/logging.properties,找到java.util.logging.ConsoleHandler.encoding这一行,看它的值是多少。如果这一步的编码和第一步的代码页对不上,那这就是乱码的直接原因,改对齐即可。
第三步:确认JVM级file.encoding是否被覆盖。
在启动Tomcat的同一环境下执行java -XshowSettings:properties -version 2>&1 | findstr file.encoding,看输出的值。如果这里显示的编码与前面两步的值都不一致,就说明有第三方配置强插了一脚,你需要检查catalina.bat和IDE的VM options。
第四步:排除应用自身的输出乱码。
如果以上三步全部检查完毕,Tomcat启动日志完全正常,但只有某个特定Web应用的信息输出乱码,那问题就出在应用层面。你需要检查项目的编码设置、web.xml里字符编码过滤器的配置,以及数据库连接URL是否指定了正确的编码。
这个流程走下来,90%以上的乱码问题都能找到根源并解决。剩下的10%则可能是极端情况,比如操作系统区域语言设置被改成了非中文但代码页没正确更新,或者杀毒软件拦截了配置文件写入导致修改未生效。遇到这类特殊环境,就需要具体问题具体分析了。
6.3 一个容易被忽视的细节:Windows服务模式启动
最后再讲一个特别容易踩坑的细节。如果你是通过如下命令把Tomcat注册成Windows服务的:
service install Tomcat9那么Tomcat就会以Windows服务的形式在后台运行,它的标准输出会重定向到系统日志,而不是显示在cmd窗口里。有些人在排查乱码时,对着logging.properties改了半天,结果打开服务管理器一看,发现Tomcat压根不是从cmd启动的,日志输出走的完全是另一条通道。
这种情况下,你需要在“服务管理器”里找到Tomcat服务,右键选择“属性”,查看“登录”选项卡下的设置。如果服务的登录身份是Local System Account,那么它执行时使用的代码页会和当前登录用户的默认设置不同,UTF-8与GBK的冲突也可能因此被放大。
解决办法是在catalina.bat里通过JAVA_OPTS显式指定编码,或者直接把服务删除,回到用startup.bat启动的方式。如果你对Windows服务没刚需,我更建议直接用startup.bat开发调试,操作简单、日志直观,排查问题也方便。
7. 一些个人经验与彩蛋技巧
写到这里,关于乱码的原理、解法、排查方法都已经讲得比较完整了。最后再分享几点我自己在实际操作中的心得,这些经验不是从文档里抄来的,都是踩坑踩出来的。
第一个心得是:遇到乱码别忙着搜“最有效的解决办法”,先花一分钟搞明白你的环境到底是什么情况。“锟斤拷”和“浣犲ソ”虽然都是乱码,但它们的产生机制不同,盲目套用网上教程反而可能把问题搞得更复杂。先执行chcp,再打开logging.properties看一眼,两分钟就能定位到问题。
第二个心得是:改配置文件一定要养成备份的习惯。不只是Tomcat,任何项目的配置文件都一样。我见过太多人改完配置发现问题想回退,结果发现原文件早被覆盖了,只能重新安装。备份一个文件用不了一秒钟,却能省下几个小时的重装时间。
第三个心得是:尽量保持编码体系的统一。如果你的整个开发链路——从代码文件、到IDE、到Tomcat、到数据库——全部统一使用UTF-8,那么理论上你根本不会遇到编码问题。乱码的根源永远是“不一致”,从这个角度看,最根本的解法不是某个配置项的调整,而是建立一套统一的编码规范。当然,Windows的cmd默认GBK是系统级行为,你改变不了它,那就学会让Tomcat去适配它。
最后再送大家一个小技巧。修改完logging.properties之后,不用每次重启电脑才能生效——只需要关掉当前cmd窗口,重新打开一个新的窗口再启动Tomcat就可以了。这个操作虽然简单,但真的有人不知道,以为改了配置就得重启系统,白白浪费时间。
好了,关于Tomcat启动时cmd窗口中文乱码的问题,核心的内容就到这里。希望这篇文章能帮你一次性解决问题,而不是像当年的我一样,被这个看似小的问题折腾了一整天才弄清楚。如果你按照上面的方案操作后,问题依然存在,欢迎把具体的乱码截图和Tomcat版本信息发出来一起讨论。技术问题不怕复杂,怕的是没有清晰的排查思路。