字符编码在项目中的应用(二)

    在第一篇文章(字符编码在项目中的应用(一) )中对各个字符编码进行了讲解,下面做个总结:

      可以显示中文的编码有UTF-8 UTF-16 unicode GBK GB2312等 在项目中常用的就是UTF-8

      UTF-8编码则是用以解决国际上字符的一种多字节编码,它对英文使用8位(即一个字节),中文使用24位(三个字节)来编码。对于英文字符较多的论坛则用UTF-8节省空间。

       GBK包含全部中文字符;UTF-8则包含全世界所有国家需要用到的字符。

       GBK是在国家标准GB2312基础上扩容后兼容GB2312的标准

       UTF-8编码的文字可以在各国各种支持UTF8字符集的浏览器上显示。

   比如,如果是UTF8编码,则在外国人的英文IE上也能显示中文,而无需他们下载IE的中文语言支持包。 所以,对于英文比较多的论坛 ,使用GBK则每个字符占用2个字节,而使用UTF-8英文却只占一个字节。

      UTF8是国际编码,它的通用性比较好,外国人也可以浏览论坛,GBK是国家编码,通用性比UTF8差,不过UTF8占用的数据库比GBK大。

       建议使用UTF-8。

Java项目中的编码问题

一.中文字符作为参数在页面/服务器之间的传递

1.对于在页面之间的跳转

汉字会以16进制的形式传输,只需要将接收的16进制用

Js代码:rname=window.decodeURIComponent(rname);

 

2.对于前端页面传递到服务器的中文字符

对于在网络上传输 的字符Tomcat默认为ISO-8859-1Tomcat8以后会自动转码,不会出现乱码的情况,但是Tomcat7以前需要手动设置编码,汉字通过网络传输过来是ISO-8859-1编码,不兼容汉字,所以手动转换成utf-8

rname=new String(rname.getBytes("iso-8859-1"),"utf-8");

3.前端页面向后端传递参数时有Get/post两种方式对比

Get是URL解码方式。默认解码格式是Tomcat8编码格式。所以URL解码是UTF-8,覆盖掉了request容器解码格式
Post是实体内容解码方式。默认解码格式是request编码格式(reuqest默认编码格式是iso8859-1),与Tomcat8编码格式无关,所以在很多时候,在doPost方法的第一句,就是这句代码 request.setCharacterEncoding(“utf-8”),防止获取请求参数时乱码。

tomcat8以后的版本对于字符的默认编码格式是UTF-8;

tomcat7之前的都是iso-8859-1。如果默认情况下,tomcat8之前使用的的编码方式:iso-8859-1

则需要设置在Servlet中设置: request.setCharacterEncoding(“utf-8”);

post得到前台数据:request容器默认是iso8859-1格式
request.setCharacterEncoding(“utf-8”); //该方法只对post请求有效,对get请求无效
System.out.println(request.getParameter(“name”));

GET得到前台数据:(不需要设置编码格式,默认是按照tomcat服务器的编码格式)
System.out.println(request.getParameter(“name”));

注意:

request.setCharacterEncoding(“utf-8”);是设置从request中取得的值或从数据库中取出的值。

指定后可以通过getParameter()则直接获得正确的字符串,如果不指定,则默认使用iso8859-1编码。值得注意的是在执行setCharacterEncoding()之前,不能执行任何getParameter()。因为在执行第一个getParameter()的时候,java将会按照编码分析所有的提交内容,而后续的getParameter()不再进行分析,所以setCharacterEncoding()无效。而且,该指定只对POST方法有效,对GET方法无效。而对于GET方法提交表单是,提交的内容在URL中,一开始就已经按照编码分析提交内容,setCharacterEncoding()自然就无效。


Get请求:

get请求的参数是在url后面提交过来的,也就是在请求行中,在使用HTTP网络协议进行传输的时候,请求行中的信息都是按照ISO-8859-1编码方式进行编码的,浏览器默认的也是按照ISO-8859-1来解码

如果浏览器使用的是UTF-8码表,通过http协议传输,http协议只支持IS0-8859-1,到了服务器,默认也是使用的是IS0-8859-1的码表

不同浏览器可以有不同的编码方式,但是通过http传输时使用的是ISO-8859-1,tomcat生成的request的默认编码方式也是ISO-8859-1

Post请求:

 post请求方式的参数是在请求体中,相对于get请求简单很多,没有经过http协议这一步的编码过程,所以只需要在服务器端,设置服务器解码的码表跟浏览器编码的码表是一样的就行了,在这里浏览器使用的是UTF-8码表编码,那么服务器端就设置解码所用码表也为UTF-8就OK了,请求体中的编码默认为Content-Type里指定的编码格式 Content-Type默认为ISO-8859-1

request.setCharacterEncoding(),记住该编码方式只对请求体(个人理解)并且该设置对Get方式无效,只对Post方式有效,而Post方式的携带的数据就在请求体中

4.服务器向前端页面发数据:

服务器发给浏览器的数据默认是按照ISO-8859-1编码,浏览器接收到数据后按照默认的字符集进行解码后显示,如果浏览器的默认解码字符集不是ISO-8859-1,就出现乱码。

    对于response乱码,只需要在服务器端指定一个编码字符集,然后通知浏览器按照这个字符集进行解码就可以了,就是设置Content-type的编码。有三种方式:

    方式一:

         A、设置服务器端的编码

   response.setCharacterEncoding("utf-8”);

   默认是ISO-8859-1;该方法必须在response.getWriter()之前进行设置

   B、通知浏览器服务器发送的数据格式

         response.setHeader("Content-type", "text/html; charset=utf-8”);

    方式二:

          A、通知浏览器服务器发送的数据格式

     response.setContentType("text/html;charset=utf-8”);

   等同于response.setHeader("contentType", "text/html; charset=utf-8”);它其实会覆盖response.setCharacterEncoding("utf-8”) ,在开发中只需要设 response.setContentType("text/html;charset=utf-8”) 即可

       方式三:

           A、设置服务器端的编码

   response.setCharacterEncoding("utf-8”);

   B、浏览器使用utf-8进行解码 (现在主流浏览器基本上都使用utf-8,所以方式二三都比较简便,哪个都行)

小结:

1.对于使用Tomcat8以后的版本就无需设置编码,至于向客户端发送数据时设置编码格式  response.setCharacterEncoding(“utf-8”)

2.对于8版本以前的tomcat,最好的办法就是无论get还是Post,Servlet的第一行直接写上 request.setCharacterEncoding(“utf-8”);

 

二.对于JSP页面解析的编码问题(JSP页面编码的原理 注意上面讲的是传参问题,这里讲的是解析JSP页面)

不要觉得现在开发中基本用不到JSP就无需关注了,其实各个框架以及JSP的本质都是通过Servlet进行前后端交互,只是封装后看不到罢了

1.从JSP页面请求的生命周期来看,一般的都需要经历下面几个阶段:

  1。应用服务器根据JSP页面生成一个Java文件 

  2。应用服务器调用javac将Java文件编译成一个Servlet对应的class文件 

  3。用户的浏览器请求JSP对应的Servlet,Web容器起一个线程执行Servlet,将数据返回给客户端浏览器。

  4。用户的浏览器根据返回的数据,将结果显示给用户。

2.JSP要经过两次的“编码”

第一阶段会用pageEncoding,第二阶段会用utf-8至utf-8(固定的),第三阶段就是由Tomcat出来的网页,用的是contentType。

第一阶段  

jsp编译成.java,它会根据pageEncoding的设定读取jsp,结果是由指定的编码方案翻译成统一的UTF-8 JAVA源码(即.java)(一定会转换为UTF-8,就是这样设计的),如果pageEncoding设定错了,或没有设定,出来的就是中文乱码。

举例:

1>JSP页面设定的编码格式pageEncoding是 ISO8859-1,可以转换为UTF-8,不会出错

2>如果JSP设定pageEncoding为Big5,他和UTF-8无法相互转换,这时解析就会出错

第二阶段 

是由JAVAC的JAVA源码至java byteCode的编译,不论JSP编写时候用的是什么编码方案,经过这个阶段的结果全部是UTF-8的encoding的java源码。

JAVAC用UTF-8的encoding读取java源码,编译成UTF-8 encoding的二进制码(即.class),这是JVM对常数字串在二进制码(java encoding)内表达的规范。

第三阶段

是Tomcat(或其的application container)载入和执行阶段二的来的JAVA二进制码,输出的结果,也就是在客户端见到的,这时隐藏在阶段一和阶段二的参数contentType就发挥了功效

contentType的設定.

pageEncoding 和contentType的预设都是 ISO8859-1. 而随便设定了其中一个, 另一个就跟着一样了(TOMCAT4.1.27是如此). 但这不是绝对的, 这要看各自JSPC的处理方式. 而pageEncoding不等于contentType, 更有利亚洲区的文字 CJKV系JSP网页的开发和展示, (例pageEncoding=GB2312 不等于 contentType=utf-8)。

jsp文件不像.java,.java在被编译器读入的时候默认采用的是操作系统所设定的locale所对应的编码。一般我们不管是在记事本还是在ue中写代码,如果没有经过特别转码的话,写出来的都是本地编码格式的内容。所以编译器采用的方法刚好可以让虚拟机得到正确的资料。

但是jsp文件不是这样,它没有这个默认转码过程,但是指定了pageEncoding就可以实现正确转码了。
 

三.Spring中的编码问题

SpringMvc中一般使用CharacterEncodingFilter来对前段页面传递的字符串进行统一设定编码

1.使用方式:

在web.xml中配置

<filter>
  <filter-name>encodingFilter</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>

 其中encoding用来设置编码格式,forceEncoding用来设置是否理会 request.getCharacterEncoding()方法,设置为true则强制覆盖之前的编码格式。  request.getCharacterEncoding()就是获取前段页面设定的encoding

2.源码赏析

详解Spring中的CharacterEncodingFilter【原】

当Servlet容器启动的时候,会读取web.xml中对于过滤器的配置信息, 读取到<init-param>中的子标签<param-name>encoding和forceEncoding所对应的<param-value>的值,再通过调用该类setEncoding(String encoding)和setForceEncoding(boolean forceEncoding) 将值注入到这连个字段中。
详解Spring中的CharacterEncodingFilter【原】

如果不调用request.setCharacterEncoding来设置的话,request.getCharacterEncoding()返回就永远是null

所以设置foreEncoding为true的会覆盖掉response.getCharacterEncoding()中的方法

这个filter有两个属性,encoding和forceEncoding,我们可以在web.xml文件中来设定这两个属性值。每次request请求到来执行方法doFilterInternal,总是调用request.setCharacterEncoding(this.encoding)将该filter的我们配置的encoding值设置为请求体的编码方式,记住该编码方式只对请求体,不针对请求参数。当forceEncoding=true时,不管请求header content-type有没有编码方式,始终将该filter的encoding值设置到request和response中,同样只针对request的请求体。

      这个过滤器的设置,没有request.setCharacterEncoding时,request.getCharacterEncoding()返回就永远是null,所以只要encoding!=null,始终会设置request.setCharacterEncoding(),而response.getCharacterEncoding()获取的是contentType里设置的编码格式,setForceEncoding设置为true时,会覆盖掉response.getCharacterEncoding()中的编码

以上过滤器类只能保证post提交方式能正确解码。get方式依然会出问题。这个过滤器类实际用的还是跟servlet里设置编码方式一样request.setCharacterEncoding

 

通过上面的编码设置,再来加深对编码的理解

System.out.println(request.getCharacterEncoding());//输出null
System.out.println(response.getCharacterEncoding());//输出ISO-8859-1

1>发送方要发送一串字符,首先必须用字符集给它编码(encode)变成2进制传输,接收方需要用同一个字符集进行解码(decode)方才能知道发送方发送的内容。如果双方所用的字符集不一致就会产生乱码。(对于Get方式比如页面设置为ISO-8859-1编码,转换为2进制后,到服务器端,直接将二进制转换为UTF-8就会出错,所以对于Get方式String str = new String(getParameter("message").getBytes("ISO-8859-1"),"UTF-8"); 而对于Post方式request.setCharacterEncoding应该会自动编码,因为默认request为ISO-8859-1,个人理解,不一定对)

web交互中的request中的发送方是客户端,接收方是服务端。发送方默认使用ISO-8859-1来编码发送的内容(前面说过)。所以这里我们就明白了,发送内容的字符编码服务端是不知道的,因为这是客户端指定的。
所以我们在服务端就只能获取null。

但是,服务端可以request.setCharacterEncoding("UTF-8");来告诉服务器发送端用的是什么编码,以便于服务端用相同的字符集来解码。没有设置会默认使用ISO-8859-1来解码。

以上过滤器类只能保证post提交方式能正确解码。get方式依然会出问题。

所以对于Get方式就通过下面方式设置:

String str = new String(getParameter("message").getBytes("ISO-8859-1"),"UTF-8");

2>在jsp页面中可以用contentType中的charset来指定服务器返回页面用何种字符集来编码。如下就是指定用utf-8编码,如果没有设置则默认为ISO-8859-1,这是一个单字节字符集,处理不了中文。

所以就有System.out.println(response.getCharacterEncoding());//输出ISO-8859-1     

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

参考:

https://blog.csdn.net/yrk0556/article/details/104034601

http://blog.sina.com.cn/s/blog_92b93d6f0100ypp9.html

https://www.jianshu.com/p/3c461ef12bfa

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值