• 关于Servlet,JSP,HTML中文乱码的问题(转载自https://blog.csdn.net/qq_27368993/article/details/83616090)


    首先说明一点,以下的测试方法只有一个HttpServletRequest.forward,但是基于原理上的讲解,其他乱码问题应该也可以从中得到一些启示。不敢保证百分百正确,但能提供一个大致的方向。

    下面为测试入口servlet的代码,其中的getWriter被注释掉,后面讲其作用。

        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
            resp.setContentType("text/html;charset=utf-8");
    
            //PrintWriter out=resp.getWriter();
    
            resp.setHeader("Expires","0");
            resp.setHeader("Cache-Control","no-cache,no-store");
            resp.setHeader("Pragma","no-cache");
    
            req.getRequestDispatcher("/WEB-INF/jsp/in2.jsp").forward(req,resp);
        }

    测试流程就是很简单的从一个servlet转到另一个jsp或者html上。

    一.从servlet转到jsp页面

    <1>直接转到一个jsp

    首先我们应该知道,jsp页面实际上会转换成一个servlet,至于存在那个地方,可以自行百度,不同的系统以及集成开发环境会使之存在不同的地方。下面为测试的第一个jsp文件in2.jsp,很简单,直接输出一段话。

    <%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8"%>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    <%
        out.print("我是in2.jsp文件的内容");
        //out.print("参数为:"+request.getParameter("param"));
    %>
    </body>
    </html>

    其中的page里面设置的几个UTF-8编码有必要讲下它的作用范围:

    • charset="UTF-8":它是设置的response的输出编码,其实设置的就是Content-type头字段里面的编码,是告诉浏览器以什么方式解码的。
    • pageEncoding="UTF-8":这个是指用什么编码格式打开这个文件,而不是以什么格式保存这个文件,虽然想要得到正确的内容,打开文件的格式和文件编码的格式必须一致,但这个逻辑关系必须理清楚。
    • 其实还有另外一个属性可以设置,那就是<head>标签下的<meta>标签可以设置文档的编码格式,它作用的是html文档的内容,告诉浏览器以什么编码格式来解析文档。对于jsp而言,它会被content-type的charset给覆盖掉。如果没有设置content-type,指的是<%@ page%>里设置的,生成的servlet会默认使用"text/html;charset=ISO-8859-1",<meta>标签里设置的无效,在jsp里设置和不设置影响不到浏览器以什么格式解码。但在HTML里就不一样,因为HTML不生成servlet,所以可以指定浏览器以什么格式解码。但有一点及其重要,即便HTML以UTF-8格式保存,标签告诉浏览器以UTF-8格式解码,但也可能产生乱码,那是因为,服务器在写入HTML时,是以默认的格式写入的,它没有pageEncoding指定打开写入的格式,而默认格式为ANSI,不一定为UTF-8,所以就产生了乱码!!!

    下面的jsp转换成一个servlet的流程必须清楚:

    • 将指定的jsp文件以pageEncoding指定的编码格式打开,转换成一个.java文件
    • 类装载器以utf-8的格式读取.java文件,转换成一个.class文件,在将这个.class文件以Unicode编码格式载入虚拟机,现在就相当于一个servlet

    上述in2.jsp文件是UTF-8格式保存的,接下来打开它转换成的servlet,片段代码如下,可以看到没有乱码

        out.write("
    ");
          out.write("
    ");
          out.write("<html>
    ");
          out.write("<head>
    ");
          out.write("    <title>Title</title>
    ");
          out.write("</head>
    ");
          out.write("<body>
    ");
    
        out.print("我是in2.jsp文件的内容");
        //out.print("参数为:"+request.getParameter("param"));
    
          out.write("
    ");
          out.write("</body>
    ");
          out.write("</html>
    ");

    浏览器端的输出也是正常的

    现在我们改动pageEncoding=ISO-8859-1

    再次查看jsp转换成的servlet

        out.write("
    ");
          out.write("
    ");
          out.write("<html>
    ");
          out.write("<head>
    ");
          out.write("    <title>Title</title>
    ");
          out.write("</head>
    ");
          out.write("<body>
    ");
    
        out.print("ææ¯in2.jspæ件çå容");
        //out.print("åæ°ä¸º:"+request.getParameter("param"));
    
          out.write("
    ");
          out.write("</body>
    ");
          out.write("</html>
    ");

    可以看到已经乱码了,这就是以ISO-8859-1编码打开UTF-8编码文件时产生的乱码,网页输出端也是如此

    因此,可以总结出,如果要保证不乱码,必须以文件编码的格式打开文件,而且还得指定浏览器以同样的编码格式解码。这儿并未测试response设置编码格式,但得注意这点!

    <2>现在改变一下测试方式,从一个servlet转到test.jsp,然后test.jsp转到in2.jsp

    test.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>测试jsp</title>
    </head>
    <body>
    <jsp:forward page="in2.jsp">
        <jsp:param name="param" value="data数据"/>
    </jsp:forward>
    </body>
    </html>

    in2.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="ISO-8859-1"%>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    <%
        out.print("我是in2.jsp文件的内容");
        out.print("参数为:"+request.getParameter("param"));
    %>
    </body>
    </html>
    

    入口servlet

        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    //        resp.setContentType("text/html;charset=utf-8");
    //        PrintWriter out=resp.getWriter();
    
            resp.setHeader("Expires","0");
            resp.setHeader("Cache-Control","no-cache,no-store");
            resp.setHeader("Pragma","no-cache");
    
            req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,resp);
        }

    网页端得输出为以下情况:

    in2.jsp文件的内容没问题,test.jsp中设置的参数汉字乱码,这个也可以从test_jsp.java里面看到原因,是因为这个"data数据"是更据request的编码格式来写入的,默认为ISO-8859-1,将其改变为utf-8则正常显示。在设置参数之前改变编码,不要在乱码之后改变编码,那时没用了,可以在jsp里面改变,也可以在入口servlet改变,如req.setCharacterEncoding("utf-8");。

    二.从一个servlet转到一个静态HTML

    静态HTML文件如下in1.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta http-equiv="content-type" content="text/html" charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    这是in1.html里面的内容
    </body>
    </html>

    入口servlet的代码如下:

        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
            resp.setContentType("text/html;charset=utf-8");
            PrintWriter out=resp.getWriter();
    
            resp.setHeader("Expires","0");
            resp.setHeader("Cache-Control","no-cache,no-store");
            resp.setHeader("Pragma","no-cache");
            req.setCharacterEncoding("utf-8");
            req.getRequestDispatcher("/WEB-INF/jsp/in1.html").forward(req,resp);
        }

    结果为如下,乱码了,归根揭底其实也是pageEncoding的原因

    因为HTML文件无法设置pageEncoding,也不会生成servlet,所以我也不能确定是不是pageEncoding的原因,因此作出假设,转发到HTML后,HTML的打开方式为以下2种情况。

    1. 是以UTF-8的格式打开
    2. 不是以UTF-8的格式打开,这个格式我等下说明

    以notepad++打开这个in1.html,并且将编码格式设置为ANSI,则结果如下,刚好和浏览器输出一致

    因此我猜测是以ANSI的格式打开HTML,这个格式会因操作系统和地区而已,中国WINDOWS为GBK格式

    下面我另存为一个in2.html格式保存为ANSI

    并将servlet的转发到in2.html,输出正常

    因此,我认为一个HTML文件在集成开发创建时是UTF-8的格式,这个格式在IDE上应该可以设置,但在打开时是更具默认编码格式打开的(即ANSI),因此会产生乱码,当然,这只是找到了原因。而解决的办法就是将这个HTML以我们想要的格式打开,即UTF-8,但又不能设置pageEncoding,因此我们可以将HTML当作JSP处理,静态HTML是可以转成JSP的。

    这种途径可以配置XML文件,添加如下XML语句

        <jsp-config>
            <jsp-property-group>
                <url-pattern>*.html</url-pattern>
                <page-encoding>UTF-8</page-encoding>
            </jsp-property-group>
        </jsp-config>

    意思是,任何以html结尾的URL请求的资源,都已UTF-8格式打开,因此在次转到in1.html则正常了。如果配置了XML就不能在访问in2.html,会乱码,因为in2.html的编码格式为ANSI,以UTF-8的格式打开会乱码。

    关于最开始说的PrintWriter out=resp.getWriter的作用关于另一个知识点,对于一切没有在XML中配置的servlet,都是采用缺省servlet访问,关于缺省servlet,可以百度查看更多。如上面测试时,如果在转发之前没有使用getWriter,则缺省servlet使用的是字节流输出,如果使用了getwriter则使用字符流输出,字节流同理。关于content-type头字段的charset编码格式和字节流字符流之间又会产生多种情况,如使用字符流,但不指定charset,则默认的格式为ISO-8859-1,用来输出中文则会乱码;使用字节流时,不论是否设置为utf-8,都不会产生乱码,按理字节流使用utf-8输出中文会乱码,我没有去看这个缺省servlet的源码,只能猜测使用字节流时都采用ISO-8859-1来输出。

  • 相关阅读:
    九,WPF资源
    八,WPF 命令
    七,WPF的元素绑定
    六,WPF的Application类
    五,控件
    四,路由事件
    三,依赖项属性
    二,WPF的布局
    一,XAML基础
    压缩解压缩字符串
  • 原文地址:https://www.cnblogs.com/KeepZ/p/12912618.html
Copyright © 2020-2023  润新知