java字符集编码乱码问题

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介:   博客分类:   web javajspservlet    最近做网页这块时碰到了正文字符乱码问题、别看这小小的一个问题,对我来说却花费了好长一段时间。现在让我慢慢分析它吧(说实话、这些有部分是从网上找的,但都是自己亲自打出来的、这样对自己来说不仅理解了而且还加深了印象)。

 

博客分类:

  最近做网页这块时碰到了正文字符乱码问题、别看这小小的一个问题,对我来说却花费了好长一段时间。现在让我慢慢分析它吧(说实话、这些有部分是从网上找的,但都是自己亲自打出来的、这样对自己来说不仅理解了而且还加深了印象)。 
   

    在java内部运算中、涉及到所有字符串都会被转化UTF-8编码来运算,然而、在被java转化之前,字符串是怎么样的字符集呢?其实java总是根据操作系统的默认编码字符集来决定字符串的初始编码的;而且java系统的输入输出都是采取操作系统的默认编码。所以、我们如果能统一java系统的输入输出以及操作系统三者的编码字符集合,那么就能够正确处理和显示汉字。这也是处理java系统汉字的一个原则。 
   

    然而在实际项目中、能够正确抓住和控制住java系统的输入输出部分是比较难的。在J2EE中、由于涉及到外部浏览器和数据库等,中文乱码问题很明显。J2EE应用程序是运行在J2EE容器中的、在这个系统中,输入途径有多种:一种是通过页面表单打包成请求(request)发往服务器的;第二种是通过数据库读入;而第三种输入比较复杂,jsp在第一次运行时总是被编译成Servlet,jsp中常常包含中文字符、那么编译使用javac时,java将根据默认的操作系统编码作为初始编码;除非自己特别指定了编码。 


  J2EE中的输出途径也有几种:第一种是jsp页面输出、由于jsp页面已经被编译成Servlet,那么在输出时、也将根据操作系统的默认编码来选择输出编码,除非指定输出编码方式;第二种输出途径便是将字符串输出到数据库。所以一个J2EE系统的输入输出是非常复杂、而且还是动态变化的。而java是跨平台运行的、在实际编译和运行中,都可能涉及到不同的操作系统;如果任由java自由地根据操作系统来决定输入输出的编码字符集、那将不可控制的出现乱码了。 


  要处理此种情况、根本办法就是明确指定整个应用系统的统一字符集,指定统一字符集到底是ISO8859_1、GBK、还是UTF—8呢?下面我们来分析下: 

  1、如果统一指定为ISO8859_1,因为目前大多数软件都是西方人编制的、他们默认的字符集就是ISO8859_1,包括Linux和数据库MySQL等。所以我们一般只需要注意在jsp头部声明、运行操作系统默认编码以及开发和编译代码时指定字符集是否为默认为ISO8859_1。 

  2、统一指定为GBK中文字符集、上面提到的三个地方需要同样做到,不同的是只能运行在编码默认为GBK的操作系统上、比如Windows;统一编码为ISO8859_1和GBK虽然能带来编制代码的方便、但是各自只能在相应的操作系统上运行;所以破坏了java跨平台运行的优越性、在一定范围内行得通;比如:为了使得GBK编码在linux上运行,设置Linux编码为GBK。 


  3、将java/j2EE系统的统一 编码定义为UTF-8,那么除应用系统以外就不需要任何附加设置的中文编码了。UTF-8是一种兼容所有语言的编码方式,唯一比较麻烦的就是要找到应用系统的所有出入口;然后用UTF-8来更改它。 

  一个J2EE应用系统需要做下面几项工作: 
  1、开发和编译代码时指定字符集为UTF-8,JBuild(一种可视化java开发工具)和Ecplise都可以在项目属性中设置。 

  2、使用过滤器、如果所有请求都经过一个Servlet控制分配器,那么我们使用Servlet时用filter执行语句,将所有来自浏览器的请求(request)转换为UTF-8;这是因为浏览器发过来的请求包括浏览器所在的操作系统编码可能是各种形式的编码、我们在他们数据流通的必经之地设置过滤:request.setCharacterEncoding(“UTF-8”);在使用filter时我们需要配置web.xml里文件来激活Filter。同时在jsp代码中声明UTF-8、设定数据库连接方式也是UTF-8,比如连接mysql时的配置URL :jdbc:mysql://localhost:3306/test?useUnicode=true&charcaterEncoding=UTF-8; 

  下面看看java中文乱码问题的由来吧: 
      Java的内核和class文件是基于unicode的,这使得java程序具有很好的跨平台性;由此也带来了一些中文乱码问题。原因主要有两方面:java和jsp文件本身编译时产生的乱码问题和java程序于其他媒介交互时产生的乱码问题。 

  首先java(包括jsp)源文件中很可能包含有中文,而java和jsp源文件的保存方式是基于字节流的;如果java和jsp编译成class文件过程中、使用的编码方式与源文件的编码不一致,就会出现乱码。对于处理这种乱码、建议在java文件中尽量不要写中文,如果必须写的话、尽量手动带参数-ecoding GBK 或者-ecoding gb2312编译;对于jsp、在文件头加上<%@ page contentType =”text/html;charset=GBK”%>或者是<%@ page contentType="text/html;charset=gb2312"%> 就能基本解决这类乱码问题。 

  下面就来重点讨论第二类乱码问题吧、即java程序与其他存储媒介交互时产生的乱码;很多存储媒介如数据库、文件、流等等的存储方式都是基于字节流的;java程序与这类媒介交互时就会发生字符(char)与字节(byte)之间的转换;具体情况如下: 
  页面form提交数据---->java程序(byte-->char) 
  java程序---->页面数据显示(char--->byte) 
   
  数据库---->java程序(char----->byte) 
  Java程序---->数据库(byte--->char)  
   
  文件--->java程序(byte-->char) 
  Java程序---->文件(char---->byte) 
   
  流--->java程序(byte---->char) 
  Java程序--->流(char--->byte) 
   
如果以上转换过程中使用编码方式与字节原有编码不一致,很可能会出现乱码。 

解决方法:关键在于确保转换时使用的编码方式与字节原有的编码方式保持一致。 

1、jsp与页面参数之间的乱码 
  Jsp获取页面参数时一般采用系统默认的方式,如果页面参数的编码类型与系统默认的 编码类型不一致、很可能就会出现乱码。所以解决它的办法是在页面获取参数之前,强制指定request获取参数的编码方式:request.setCharacterEncoding(“GBK”);如果在jsp将变量输出到页面时出现了乱码、可以通过设置request.setContentType(“text/html;charset=GBK”).如果不想在每个文件里都写这样两句话,更简洁的办法是使用Servlet规范中的过虑器指定编码,过滤器的在web.xml中的典型配置和主要代码如下: 

Java代码   收藏代码
  1. //web.xml:  
  2. <filter>  
  3. <filter-name>CharacterEncodingFilter</filter-name>  
  4. <filter-class>travel.web.CharacterEncodingFilter</filter-class>  
  5. <init-param>  
  6. <param-name>encoding</param-name>  
  7. <param-value>GBK</param-value>  
  8. </init-param>  
  9. </filter>  
  10. <filter-mapping>  
  11. <filter-name>CharacterEncodingFilter</filter-name>  
  12. <url-pattern>/*</url-pattern>  
  13. </filter-mapping>  
  14.   过滤器中的代码:  
  15. //CharacterEncodingFilter.java:  
  16. public class CharacterEncodingFilter implements Filter {  
  17.   
  18.       protected String encoding = null;  
  19.   
  20. public void init(FilterConfig filterConfig) throws ServletException {  
  21.      
  22.      this.encoding = filterConfig.getInitParameter("encoding");  
  23. }  
  24.   
  25. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {  
  26.   
  27. request.setCharacterEncoding(encoding);response.setContentType("text/html;charset="+encoding);chain.doFilter(request, response);  
  28.   
  29. }  
  30. }  


2、java与数据库之间的乱码 
  大部分数据库都支持以unicode编码方式,所以解决Java与数据库之间的乱码问题比较明智的方式是直接使用unicode编码与数据库交互。很多数据库驱动自动支持unicode,如Microsoft的SQLServer驱动。其他大部分数据库驱动,可以在驱动的url参数中指定,如mysql驱动:jdbc:mysql://localhost/WEBCLDB?useUnicode=true&characterEncoding=GBK。 
   
3、java与文件/流之间的乱码 
  Java读写文件最常用的类是FileInputStream/FileOutputStream和FileReader/FileWriter。其中FileInputStream和FileOutputStream是基于字节流的,常用于读写二进制文件。读写字符文件建议使用基于字符的FileReader和FileWriter,省去了字节与字符之间的转换。但这两个类的构造函数默认使用系统的编码方式,如果文件内容与系统编码方式不一致,可能会出现乱码。 在这种情况下,建议使用FileReader和FileWriter的父类:InputStreamReader/OutputStreamWriter,它们也是基于字符的,但在构造函数中可以指定编码类型: InputStreamReader(InputStream in, Charset cs) 和OutputStreamWriter(OutputStream out, Charset cs)。 

4、其他 上面提到的方法应该能解决大部分乱码问题,如果在其他地方还出现乱码,可能需要手动修改代码。解决Java乱码问题的关键在于在字节与字符的转换过程中,你必须知道原来字节或转换后的字节的编码方式,转换时采用的编码必须与这个编码方式保持一致。
相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
2月前
|
Java
Java开发实现图片URL地址检验,如何编码?
【10月更文挑战第14天】Java开发实现图片URL地址检验,如何编码?
85 4
|
2月前
|
Java
Java实现随机生成某个省某个市的身份证号?如何编码?
【10月更文挑战第18天】Java实现随机生成某个省某个市的身份证号?如何编码?
136 5
|
2月前
|
Java
Java开发实现图片地址检验,如果无法找到资源则使用默认图片,如何编码?
【10月更文挑战第14天】Java开发实现图片地址检验,如果无法找到资源则使用默认图片,如何编码?
65 2
|
4月前
|
安全 Java API
告别繁琐编码,拥抱Java 8新特性:Stream API与Optional类助你高效编程,成就卓越开发者!
【8月更文挑战第29天】Java 8为开发者引入了多项新特性,其中Stream API和Optional类尤其值得关注。Stream API对集合操作进行了高级抽象,支持声明式的数据处理,避免了显式循环代码的编写;而Optional类则作为非空值的容器,有效减少了空指针异常的风险。通过几个实战示例,我们展示了如何利用Stream API进行过滤与转换操作,以及如何借助Optional类安全地处理可能为null的数据,从而使代码更加简洁和健壮。
123 0
|
2月前
|
存储 缓存 Java
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
这篇文章详细介绍了Java中的IO流,包括字符与字节的概念、编码格式、File类的使用、IO流的分类和原理,以及通过代码示例展示了各种流的应用,如节点流、处理流、缓存流、转换流、对象流和随机访问文件流。同时,还探讨了IDEA中设置项目编码格式的方法,以及如何处理序列化和反序列化问题。
86 1
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
|
3月前
|
存储 移动开发 Java
java核心之字符串与编码
java核心之字符串与编码
25 2
|
4月前
|
Java PHP 开发者
PHP中的异常处理:Java常见的编码方式
在PHP开发中,掌握异常处理至关重要,它有助于预见并管理运行时错误,避免用户体验受损或数据丢失。本文介绍PHP异常处理的基本概念与实践,包括try-catch语句的使用,以及如何通过抛出和捕获异常来增强代码的健壮性和可靠性。通过示例展示如何避免常见错误,如除数为零的情况,并探讨多catch块和finally语句的高级用法,帮助开发者提升程序稳定性与可维护性。[总字符数:238]
31 0
|
20天前
|
Java 开发者
Java多线程编程中的常见误区与最佳实践####
本文深入剖析了Java多线程编程中开发者常遇到的几个典型误区,如对`start()`与`run()`方法的混淆使用、忽视线程安全问题、错误处理未同步的共享变量等,并针对这些问题提出了具体的解决方案和最佳实践。通过实例代码对比,直观展示了正确与错误的实现方式,旨在帮助读者构建更加健壮、高效的多线程应用程序。 ####
|
11天前
|
缓存 Java 开发者
Java多线程编程的陷阱与最佳实践####
本文深入探讨了Java多线程编程中常见的陷阱,如竞态条件、死锁和内存一致性错误,并提供了实用的避免策略。通过分析典型错误案例,本文旨在帮助开发者更好地理解和掌握多线程环境下的编程技巧,从而提升并发程序的稳定性和性能。 ####