1 结论
l req.setCharacterEncoding( "gbk" );
n 含义是取上一个页面的参数,按照 gbk 进行解码
n tomcat 取参数默认按照 iso-8859-1 进行解码
l resp.setContentType( "text/html;charset=gbk" );
n 含义是发送内容到客户端浏览器,按照 gbk 进行编码
n tomcat 发送内容到客户端浏览器,默认按照 iso-8859-1 进行编码
| 场景 1 | 场景 2 | 场景 3 |
|
|
|
form 表单存为什么格式 | ansi | ansi | utf-8 |
|
|
|
form 表单提交方式 | post | post | post |
|
|
|
Servlet 端 resp.setContentType | - | charset=gbk | charset=gbk |
|
|
|
Servlet 端 req.setCharacterEncoding | - | gbk | gbk |
|
|
|
是否有乱码 | 没有乱码 | 没有乱码 | 鎴戜滑 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 场景 1
form.html
<form action="/my/servlet/TestServlet" method="post" > <input name="username"> <input type="submit" value=" 提交 "> </form> |
TestServlet.java
import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
public class TestServlet extends HttpServlet {
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { PrintWriter out = resp.getWriter(); String username = req.getParameter( "username" ); System. out .println(username); out .println(username); out .close(); }
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
|
web.xml
<servlet> <servlet-name>TestServlet</servlet-name> <servlet-class>TestServlet</servlet-class> </servlet>
<servlet-mapping> <servlet-name>TestServlet</servlet-name> <url-pattern>/servlet/TestServlet</url-pattern> </servlet-mapping> |
访问这个地址 http://127.0.0.1/my/form.html
输入“我们”然后提交。我们看到的是正确的中文,没有乱码
2.1 分析
下面通过例子详细说明为什么没有乱码。
虽然场景 1 没有乱码。但不是最终的解决办法。
因为页面本身的中文会有乱码。
// 重要结论 //jvm 只能表示 unicode 收录的字符们 //jvm 在内存里用 utf-16 编码表示一个字符 //System.out.println 先按照操作系统默认的编码来编码,得到的字节们传到 console , console 再按系统默认的编码解码 //zhongwen.getBytes("GBK")--> 编码 //new String(zhongwen.getBytes("GBK"), "iso8859-1");--> 解码 //tomcat 取参数默认按照 iso-8859-1 进行解码 //tomcat 发送内容到客户端浏览器,默认按照 iso-8859-1 进行编码
// 字符 " 我 " 的 gbk 编码: ced2 // 字符 " 我 " 的 utf-16 编码: 6211 // 字符 " 我 " 的 utf-8 编码: e6 88 91 public class TestBB {
public static void main(String args[]) throws Exception { //jvm 在内存里用 utf-16 编码表示一个字符 , // 所以在内存中, zhongwen 这个引用指向的字符串对象包括 2 个字节 62 11 String zhongwen = " 我 " ; //println 方法不会把内存中的 utf-16 编码输出到 console 。 // 而是按照系统默认编码( gbk )编码,然后才将 gbk 编码( ced2 )输出到 console 。 //cosole 接收 gbk 编码( ced2 ),再按照系统默认编码来解码,显示出正确的中文 System . out .println(zhongwen); //getBytes 方法是编码的意思。 // 下面验证 " 我 " 这个字符的 gbk 编码是 ced2 byte [] bytes = zhongwen.getBytes( "gbk" ); System . out .println( "--------GBK----------" ); for ( byte b:bytes){ System . out .format( "%x " ,b); } System . out .println(); // 浏览器默认按照 gbk 编码,然后将参数传到服务器 // 浏览器将以什么编码来提交参数,和 form 表单这个 html 页面的存储方式有关。 // 如果 form 表单存为 ansi ,即 jbk ,那么提交参数也用 gbk.
// 服务器端接收 gbk 编码 2 个字节( ced2 ),默认按照 iso8859-1 解码 // 所以解码出错误的 2 个字符 System . out .println( "-------iso8859-1--------" ); // 这 2 个 iso8859-1 字符在内存里表示为 4 个字节: 00 ce 00 d2 zhongwen = new String(zhongwen.getBytes( "GBK" ), "iso8859-1" ); //println 方法不会把内存中的 utf-16 编码输出到 console 。 // 而是按照系统默认编码( gbk )来编码,得到 2 个字节: 3f 3f , (为什么是 3f 下面会解释) // 然后才将这些 gbk 编码输出到 console 。 //cosole 再按照系统默认编码来解码,得到 2 个 ? // (因为 ascii 中, ? 就是 3f ,并且 gbk 和 ascii 兼容,所以在 gbk 中, 3f 也是 ? )
System . out .println(zhongwen);
// 内存中的 00 ce 表示的那个 iso8859-1 字符在 gbk 中没有收录,所以按照 gbk 编码就会出错。 // 如果出错,一律编码为 3f ,所以得到 2 个 3f bytes = zhongwen.getBytes( "gbk" ); for ( byte b:bytes){ System . out .format( "%x " ,b); } System . out .println();
// 服务器再按照 iso8859-1 编码,传到客户端浏览器 bytes = zhongwen.getBytes( "iso8859-1" );
// 最初的 gbk 编码 cede 是不是没有丢? // 可见有些编码解码的过程是可逆的。 // 当然有些编码解码的过程就不可逆。 for ( byte b:bytes){ System . out .format( "%x " ,b); } System . out .println();
// 浏览器得到传过来的字节们,再按照 gbk 解码。得到正确的中文。 System . out .println( "-------GBK--------" ); System . out .println( new String(bytes, "GBK" )); } }
|
3 场景 2
form.html
<form action="/my/servlet/TestServlet" method="post" > <input name="username"> <input type="submit" value=" 提交 "> </form> |
TestServlet.java
import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
public class TestServlet extends HttpServlet {
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType( "text/html;charset=gbk" ); PrintWriter out = resp.getWriter(); req.setCharacterEncoding( "gbk" ); String username = req.getParameter( "username" ); System. out .println(username); out .println(username); out .close(); }
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
|
web.xml
<servlet> <servlet-name>TestServlet</servlet-name> <servlet-class>TestServlet</servlet-class> </servlet>
<servlet-mapping> <servlet-name>TestServlet</servlet-name> <url-pattern>/servlet/TestServlet</url-pattern> </servlet-mapping> |
访问这个地址 http://127.0.0.1/my/form.html
输入“我们”然后提交。我们看到的是正确的中文,没有乱码
3.1 分析
浏览器发送 form 表单内容到服务器
服务器接收内容,进行解码
服务器将解码后得到的内容进行编码,再传到浏览器
浏览器接收内容,进行解码
详细内容略。。。。。。
4 场景 3
略。。。。。。