文章目录▼CloseOpen
- 先搞懂JSP中文乱码的“病根”,才不会瞎试
- 三步解决JSP中文乱码,简单到不用记代码
- 第一步:把JSP页面的编码“锁死”成UTF-8
- 第二步:处理请求和响应的编码,让数据“不走样”
- 第三步:给服务器“换”个支持中文的编码(以Tomcat为例)
- 附:常见JSP乱码场景&解决方法对照表
- Page指令里的pageEncoding和contentType有什么区别?
- POST和GET请求乱码的解决方法为什么不一样?
- 改了Tomcat的URIEncoding后,GET请求还是乱码怎么办?
- JSP页面设了UTF-8,为什么打开还是乱码?
- 用了编码过滤器,为什么还有部分请求乱码?
先搞懂JSP中文乱码的“病根”,才不会瞎试
要解决乱码,得先明白“为什么会乱”——其实就是“编码”和“解码”用了不一样的规则,就像你用英文写了封信,对方用日文翻译,肯定看不懂。JSP中文乱码的常见“病根”就三个,我一个个给你掰明白:
第一个病根是“JSP页面本身的编码没设对”。你写JSP页面的时候,是不是有时候忘在开头加那个page指令?我刚学JSP的时候也常忘,结果页面打开全是乱码。其实JSP文件本身是文本文件,得告诉服务器“我用的是UTF-8编码写的”(pageEncoding属性),同时还要告诉浏览器“你用UTF-8解码看我”(contentType里的charset)。要是这俩不一致,比如页面文件是UTF-8,却让浏览器用ISO-8859-1解析,浏览器“读不懂”,自然显示乱码。小杨之前就是漏了pageEncoding,只设了contentType,结果页面乱码,改了之后立刻正常。
第二个病根是“请求和响应的编码‘不同步’”。比如你用表单的POST方法提交中文用户名,服务器默认用ISO-8859-1编码接收数据——这玩意儿是英文编码,压根不认识中文,把“张三”编成一堆乱码字符,等你再用UTF-8解码,肯定变“å¼ ä¸‰”。还有响应的时候,要是你没告诉浏览器“我返回的是UTF-8编码的数据”,浏览器可能用默认的GBK解析,也会乱。我之前做一个用户注册功能,POST提交的用户名乱码,查了半小时才发现没加request.setCharacterEncoding(“UTF-8”),加了之后立刻好了。
第三个病根是“服务器的默认编码不兼容”。比如最常用的Tomcat服务器,默认的URI编码是ISO-8859-1,要是你用GET方法传中文参数(比如URL里写?name=张三),Tomcat会用ISO-8859-1解码这个参数,结果自然乱码。我去年做一个商品列表页,用GET传商品名称的中文参数,结果页面显示乱码,改了Tomcat的URIEncoding之后才好。
Oracle的JSP官方文档里也提到,“UTF-8是JSP页面的推荐编码,因为它支持所有 Unicode 字符,能避免大多数字符编码问题”(链接:https://docs.oracle.com/javaee/5/tutorial/doc/bnaou.htmlnofollow)。所以解决乱码的核心思路,就是把“页面编码、请求编码、响应编码、服务器编码”全统一成UTF-8,让所有环节都用同一个“语言”交流。
三步解决JSP中文乱码,简单到不用记代码
明白了“病根”,解决起来就简单了,我把常用的解决方法整成了三步,每一步都有具体操作,甚至不用记代码,复制粘贴就行。
第一步:把JSP页面的编码“锁死”成UTF-8
不管你写什么JSP页面,先在开头加这么一行代码:
我解释下这行代码的作用:
这俩charset和pageEncoding都设成UTF-8,基本能解决90%的“页面显示乱码”问题。小杨之前就是漏了pageEncoding,只写了contentType,结果页面乱码,加上之后立刻好了。我自己写JSP页面的时候,这行代码是“必写项”,比记密码还牢。
你可能会问:“要是我有几十个JSP页面,一个个加太麻烦怎么办?”别急,Tomcat有个“全局配置”的方法——在web.xml里加一个JSP servlet的初始化参数,让所有JSP页面默认用UTF-8编码。具体操作是找到Tomcat的conf/web.xml
文件,找到标签下的
jsp
,然后加个:
jsp
org.apache.jasper.servlet.JspServlet
pageEncoding
UTF-8
contentType
text/html; charset=UTF-8
3
这样所有JSP页面不用加page指令,默认就是UTF-8编码了。我之前给一个老项目改编码,几十页JSP,用这个方法十分钟就搞定了,比一个个改省事儿多了。
第二步:处理请求和响应的编码,让数据“不走样”
页面编码解决了,接下来处理“数据传输”的乱码——也就是请求(比如表单提交)和响应(比如服务器返回数据)的编码。
要是你用POST方法提交数据(比如),只需要在接收请求的Servlet或者JSP里,先调用
request.setCharacterEncoding("UTF-8")
,再获取参数。比如:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 必须放在所有getParameter之前调用!
request.setCharacterEncoding("UTF-8");
String username = request.getParameter("username"); // 这时候username就是正常的中文了
}
我强调一下:这行代码必须放在所有request.getParameter()
之前,要是你先获取了参数再设置编码,等于没设,还是会乱码。小杨之前就犯过这个错,先getParameter再setCharacterEncoding,结果还是乱,改了顺序就好了。
要是你用GET方法传中文参数(比如URL里的?name=张三
),处理起来稍微麻烦点,因为Tomcat默认用ISO-8859-1解码GET参数。解决方法有两个:
conf/server.xml
文件,找到
标签,加一个URIEncoding="UTF-8"
属性:
connectionTimeout="20000"
redirectPort="8443"
URIEncoding="UTF-8" />
这样Tomcat会用UTF-8解码所有GET请求的URL参数,彻底解决GET乱码问题。我去年做的商品列表页就是用这个方法解决的,改了之后再也没乱过。
方法二:手动转码(应急用):要是你没法改Tomcat配置(比如用的是虚拟主机),可以把乱码的参数手动转成UTF-8。比如:
java
String username = request.getParameter("username");
// 先把乱码的字符串转成字节数组(用ISO-8859-1解码),再转成UTF-8字符串
username = new String(username.getBytes("ISO-8859-1"), "UTF-8");
response.getWriter()
这个方法能应急,但不如改Tomcat配置彻底,而且每个GET参数都要转,麻烦。我一般只在没法改服务器配置的时候用。
解决响应的乱码 有时候服务器返回给浏览器的数据会乱码,比如你用
输出中文,这时候要告诉浏览器“我返回的是UTF-8编码”。方法很简单,在输出之前加两行:
java
response.setContentType(“text/html; charset=UTF-8”);
response.setCharacterEncoding(“UTF-8”);
其实
setContentType已经包含了charset,所以加一行
response.setContentType(“text/html; charset=UTF-8”)也能解决,但我习惯加两行,更保险。
第三步:给服务器“换”个支持中文的编码(以Tomcat为例)
除了前面的步骤,还有两个Tomcat的配置要注意,能解决一些“隐藏”的乱码问题:
bin/catalina.bat(Windows)或
catalina.sh(Linux)文件,加一行环境变量:
set JAVA_OPTS=-Dfile.encoding=UTF-8
export JAVA_OPTS=”-Dfile.encoding=UTF-8″
这是告诉Tomcat用UTF-8作为默认的文件编码,避免Tomcat读取配置文件时的乱码。
request.setCharacterEncoding太麻烦,可以用过滤器统一处理所有请求。比如写一个
EncodingFilter:
java
import javax.servlet.;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
// 设置请求编码
req.setCharacterEncoding("UTF-8");
// 设置响应编码
resp.setContentType("text/html; charset=UTF-8");
resp.setCharacterEncoding("UTF-8");
// 继续执行后续过滤链
chain.doFilter(req, resp);
}
@Override
public void destroy() {}
}
然后在
web.xml里配置这个过滤器,让它拦截所有请求:
xml
EncodingFilter
com.yourpackage.EncodingFilter
EncodingFilter
/ <!-
这个过滤器会帮你处理所有请求和响应的编码,不用再在每个Servlet里写重复的代码。我现在做项目都用这个方法,省了好多时间。
附:常见JSP乱码场景&解决方法对照表
为了让你更清楚,我把常见的乱码场景、原因和解决方法做成了表格,对照着查更方便:
乱码场景 | 背后的原因 | 具体解决方法 |
---|---|---|
JSP页面显示乱码 | 页面编码未设为UTF-8 | 加page指令: |
POST请求参数乱码 | 服务器用ISO-8859-1接收请求 | 在Servlet/JSP里先调用request.setCharacterEncoding(“UTF-8”) |
GET请求URL参数乱码 | Tomcat默认URI编码是ISO-8859-1 | 修改server.xml的Connector标签,加URIEncoding=”UTF-8″ |
服务器返回数据乱码 | 响应编码未设为UTF-8 | 调用response.setContentType(“text/html; charset=UTF-8”) |
最后再提醒你一句:所有编码都统一成UTF-8,别一会儿用UTF-8一会儿用GBK,不然肯定乱。我之前帮一个朋友改项目,他页面用UTF-8,Servlet用GBK,结果数据传过去全是乱码,统一成UTF-8之后立刻好了。
这些方法我用了五六年,解决过至少十几个项目的乱码问题,小杨试了之后说“早知道这么简单,之前不用熬通宵查资料了”。你要是碰到JSP中文乱码,赶紧按这三步试,要是还有问题,评论区告诉我具体情况,比如是页面显示乱码还是表单提交乱码,我帮你看看。
很多刚学JSP的朋友都问过我,page指令里的pageEncoding和contentType到底有啥不一样?其实你把它俩想象成“翻译接力”的两步就懂了——第一步是服务器“读”你写的JSP文件,第二步是浏览器“看”服务器生成的页面,这俩步骤得用对同一套“翻译规则”,不然中间哪一步错了,页面都会乱。
先说说pageEncoding哈,它其实是给服务器的“小纸条”:“我这个JSP文件是用UTF-8写的,你读我的时候得用UTF-8解码!”我刚学JSP那会就犯过傻,写页面忘加这个,结果服务器默认用ISO-8859-1读我的文件——那玩意儿是英文编码,压根不认识中文,我文件里的“你好”全被当成乱码字符读进去,生成的页面能不乱吗?就像你用中文写了封信,对方拿英文字典翻,肯定越翻越糊涂。后来我把pageEncoding加上“UTF-8”,服务器才“看懂”我写的内容,生成的页面内容先对了第一步。
再来说contentType里的charset,这是给浏览器的“提示牌”:“这个页面的内容是UTF-8编码的,你得用UTF-8打开哦!”举个真实例子,之前帮小吴调页面,他pageEncoding设对了UTF-8,但contentType只写了“text/html”,漏了后面的“charset=UTF-8”——结果服务器虽然正确读了文件,却没告诉浏览器该用啥编码解析,浏览器默认用ISO-8859-1打开,页面上的中文又变成了问号。我让他把contentType改成“text/html; charset=UTF-8”,刷新一下立刻就正常了。你看,这俩就像“前后门的钥匙”,pageEncoding是开服务器的“前门”,charset是开浏览器的“后门”,俩钥匙都得是“UTF-8”,才能让页面从服务器到浏览器的全流程都“通顺”。
还有人问过我,“能不能只设一个?”我试过,比如只设pageEncoding不设charset,浏览器可能用默认编码解析,结果还是乱;只设charset不设pageEncoding,服务器读文件的时候就错了,后面再对也没用。就像你做饭,米洗干净了(pageEncoding对),但火没开对(charset错),饭还是夹生;火开对了,但米没洗(pageEncoding错),饭还是没法吃。所以呀,这俩必须都设成UTF-8,一个都不能少。
Page指令里的pageEncoding和contentType有什么区别?
pageEncoding是告诉服务器“这个JSP文件本身用什么编码写的”,比如你用UTF-8编辑JSP文件,必须设pageEncoding=”UTF-8″,否则服务器读取文件时会用默认的ISO-8859-1编码,导致文件内容被错误解析;而contentType里的charset是告诉浏览器“要用什么编码解析这个页面”,两者都设为UTF-8才能保证页面从“服务器读取”到“浏览器显示”的全流程编码一致。
POST和GET请求乱码的解决方法为什么不一样?
因为POST请求的中文参数是放在“请求体”里的,服务器默认用ISO-8859-1编码接收,所以只要在Servlet/JSP里先调用request.setCharacterEncoding("UTF-8")
(必须在获取参数前调用),就能让服务器用UTF-8解码请求体;而GET请求的参数是拼在URL里的,Tomcat默认用ISO-8859-1解码URL中的参数,所以需要修改Tomcat的server.xml
里的Connector标签,加URIEncoding="UTF-8"
,让Tomcat用UTF-8解码URL参数。
改了Tomcat的URIEncoding后,GET请求还是乱码怎么办?
首先确认“Tomcat是否重启”——修改server.xml
后必须重启Tomcat,否则配置不生效;其次检查“URL参数是否在修改后传递”——如果修改前已经传过乱码参数,浏览器可能缓存了旧的URL,需要清空缓存或重新输入URL;如果还是不行,可能是你的Tomcat版本过旧(比如Tomcat 6及以下),或者参数被前端“二次编码”(比如用encodeURIComponent
转码后,服务器需要对应解码),这种情况可以用new String(参数.getBytes("ISO-8859-1"), "UTF-8")
手动转码应急。
JSP页面设了UTF-8,为什么打开还是乱码?
除了漏设pageEncoding或contentType,最常见的原因是“JSP文件本身的保存编码不对”——比如你的IDE(如Eclipse、IDEA)默认用GBK保存文件,即使你在页面里写了UTF-8的page指令,服务器读取的文件内容其实是GBK编码的,自然显示乱码。解决方法是在IDE里把JSP文件的“保存编码”改成UTF-8:比如IDEA可以通过“File -> Settings -> Editor -> File Encodings”,把“Project Encoding”和“Default encoding for properties files”都设为UTF-8,同时确保JSP文件的右下角编码显示为UTF-8。
用了编码过滤器,为什么还有部分请求乱码?
首先检查过滤器的“拦截范围”——url-pattern
是不是设为/*
(要拦截所有请求,包括JSP和Servlet);其次检查“过滤器顺序”——编码过滤器要放在所有其他过滤器的最前面,否则后面的过滤器可能会覆盖编码设置;最后确认过滤器里有没有“同时设置请求和响应编码”:不仅要调用request.setCharacterEncoding("UTF-8")
,还要调用response.setContentType("text/html; charset=UTF-8")
,否则响应数据可能还是会用默认编码。