java web中的中文乱码问题——浏览器与服务器之间的中文乱码

一. 乱码产生原因

浏览器在向服务器发送请求时会对携带的请求参数进行编码(UTF-8格式),服务器在接收到请求参数时会对其进行解码,由于浏览器与服务器编码格式不同产生乱码。不同服务器默认编码格式不同,Tomcat默认ISO-8859-1。

二. get、post请求方式乱码解决方案——简单版

1. get请求

get请求有三种解决方案。

a. 通过先编码再解码方式。服务器以不同编码格式解码后导致乱码,此时可以通过先以与服务器相同的编码格式将字符串编码成原始的字节流,再通过String类的构造方法解码生成正确的字符串。代码如下:

String newJoo = new String(joo.getBytes("ISO-8859-1"), "UTF-8");  //joo为字符串

b. 修改tomcat服务器配置文件,设置url编码格式。tomcat安装目录下conf文件夹内server.xml配置文件,在<Connector connectionTimeout="20000" port="8090" protocol="HTTP/1.1" redirectPort="8443" />中添加 URIEncoding="UTF-8"属性。该方法对post乱码无作用,因为它只能设置url中携带的请求参数,而post请求参数存放在请求体中。

c. 在页面中用js函数如:encoding(),进行编码,后台用java代码解码。这种方法麻烦,就不多说了。

三种方法各有各的缺陷,使用a方法需要在每个servlet类中都添加那段代码,造成代码冗余,可维护性差;使用b方法可以达到一劳永逸的效果,但是如果服务器中有其他项目需要用不同的url编码格式怎么办?所以这样不灵活,不友好,而且对post请求乱码无效;c方法的缺陷同a方法。

2. post请求

post请求乱码解决方式很简单,只需要一行代码。request对象中有个设置编码格式的方法:

request.setCharacterEncoding("utf-8")

同样的,这种方法也有缺陷。首先,它造成代码冗余,使可维护性变差,其次,它只对请求体中的参数有作用,对get请求方式乱码无效。

三. post get乱码解决方案——Filter版

1. 如何做

在Servlet中获取请求参数有三种方法:getParameter(),getParameterValues(),getParameterMap(),getParameter()返回String类型,用于获取单个请求参数,getParameterValues()返回String[]类型,也用于获取单个请求参数,只不过这个请求参数包含多个值,如复选框,getParameterMap()返回值为Map<String, String[]>,用于获取所有请求参数。

ServletRequest接口中定义了这三个方法,tomcat实现这三个方法,但实现源码并没有做编码相关的处理,如果我们自己定义一个类实现ServletRequest接口然后重写这三个方法,并在其中解决post和get乱码不就既可以一劳永逸解决问题,避免代码冗余,同时还保证了灵活性,确保不会影响同服务器中的其它项目。但是实现ServletRequest接口就必须实现其中的所有方法,工作量太大!

sun公司早已考虑到这个问题,很体贴的设计了一个包装类实现ServletRequest接口,我们只需要定义一个类继承HttpServletRequestWrapper类,并重写三个方法就能达到目的。先来看看HttpServletRequestWrapper类的继承关系:

public class HttpServletRequestWrapper extends ServletRequestWrapper implements HttpServletRequest  可以看到它继承了ServletRequestWrapper类,ServletRequestWrapper类实现了HttpServletRequest接口,而HttpServletRequest接口是ServletRequest接口的子接口,所以HttpServletRequestWrapper实现了ServletRequest接口的所有方法。

我们的目的是要让所有Servlet都使用重写的方法,上面我们解决了怎么重写三个获取请求参数的方法,但是还有一个问题——如何才能让所有Servlet都使用我们重写的方法,即在哪里重写这三个方法。解决这个问题首先要明白Servlet的生命周期,这里简单的介绍下,tomcat启动时实例化Servlet对象并执行其中的init()方法进行初始化操作,当tomcat接收到请求时会创建HttpServletRequest和HttpServletResponse对象,然后执行Servlet对象中的Service()方法判断请求方式并调用doGet()或者doPost()方法,这里会将两对象当作参数传递给doGet()和doPost()方法,当tomcat正常stop时执行Servlet类中的destory()方法进行销毁操作。知道了Servlet的生命周期我们知道,如果要让所有Servlet类都使用重写的方法我们可以修改tomcat的源代码,使它在创建HttpServletRequest和HttpServletResponse对象的过程中创建的是我们自定义对象,但这样工作量很大,而且还会影响其他项目,不灵活也不友好。到这里java web三大组件之一Filter就浮出水面了。

Filter——过滤器,可以先于所有Servlet执行,我们在自定义的Filter中定义个类继承HttpServletRequestWrapper,重写三个获取请求参数方法,再将它传递给Servlet就可以达到我们的目的。

2. 代码实现

web.xml配置

 <filter>
  <filter-name>encodingFilter</filter-name>
  <filter-class>ff.charset.EncodingFilter</filter-class>
  <init-param>
   <param-name>encoding</param-name>
   <param-value>utf-8</param-value>
  </init-param>
 </filter>
 <filter-mapping>
  <filter-name>encodingFilter</filter-name>
  <url-pattern>/*</url-pattern>
 </filter-mapping>

自定义Filter类

public class EncodingFilter implements Filter{
 
 private String encoding;  // 编码格式
 
 @Override
 public void init(FilterConfig filterConfig) throws ServletException {
  
  // 从web.xml中获取编码格式
  this.encoding = filterConfig.getInitParameter("encoding");
 }

 @Override
 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
   throws IOException, ServletException {
  
  // 向下转型成HttpServletRequest
  HttpServletRequest req = (HttpServletRequest) request;
  HttpServletResponse res = (HttpServletResponse) response;
  
  // 设置数据响应编码格式
  response.setContentType("text/html;charset=" + encoding);
  
  // 创建装饰类
  MyHttpRequest myhr = new MyHttpRequest(req, encoding);
  
  // 放行
  chain.doFilter(myhr, res);
 }

 @Override
 public void destroy() {
  // TODO Auto-generated method stub
  
 }
}

自定义类继承HttpServletRequestWrapper

上面提到了getParameterMap()用于获取所有请求参数,那它也可以获取单个请求参数,所有我们只需要重写这个方法,然后其他两方法调用此方法就可以。

public class MyHttpRequest extends HttpServletRequestWrapper {

 private HttpServletRequest req;  // 原始请求对象
 private String encoding;  // 编码格式
 private boolean flag = true;  // 开关

 public MyHttpRequest(HttpServletRequest request, String encoding) {

  super(request);
  this.req = request;
  this.encoding = encoding;
 }
 
 @Override
 public String getParameter(String name) {

  Map<String, String[]> map = getParameterMap();
  String[] values = map.get(name);
  if (null == values) {
   return null;
  }
  return values[0];
 }

 @Override
 public String[] getParameterValues(String name) {

  Map<String, String[]> map = getParameterMap();
  return map.get(name);
 }

 @Override
 public Map<String, String[]> getParameterMap() {

  String method = req.getMethod();

  if (method.equalsIgnoreCase("post")) {
   
   try {
    req.setCharacterEncoding(encoding);
    return req.getParameterMap();
   } catch (UnsupportedEncodingException e) {
    e.printStackTrace();
   }
  } else if (method.equalsIgnoreCase("get") && true == flag) {
   
   // 通过flag使这段代码一次请求只执行一次,因为执行多次相当于解码再编码多次,造成乱码
   Map<String, String[]> map = req.getParameterMap();  // 对象赋值传递的是地址,map指向req地址,修改map值相当于修改req中属性值
   Set<String> set = map.keySet();
   // 迭代遍历map中所有值,通过解码再编码解决get乱码
   Iterator<String> iterator = set.iterator();
   while (iterator.hasNext()) {
    String[] values = map.get(iterator.next());
    if (null != values) {
     for (int i = 0; i < values.length; i++) {
      try {
       values[i] = new String(values[i].getBytes("ISO-8859-1"), encoding);
       
      } catch (UnsupportedEncodingException e) {
       e.printStackTrace();
      }
     }
     
    }
   }
   
   flag = false;
   return map;
  } 
  
  // 其它请求执行原始获取参数方法,除了get post外还有其他请求方式
  return super.getParameterMap();
 }
}
时间: 2024-09-29 02:14:54

java web中的中文乱码问题——浏览器与服务器之间的中文乱码的相关文章

浏览器和服务器之间传输数据

由于web系统采用http协议在浏览器和服务器之间传输数据,而http协议是一种无状态的协议,如何在不 同页面之间传递数据,可以有一下几种方式:   方式一:表单方式传递   表单传递参数是一种最简单,也是最基本的参数传递方式.注意:表单元素隐藏按钮的使用   方式二:带参数的url方式传递   带参数的url写法: url?参数名1=值1&参数名2=值2.   方式三:请求request对象   可以将数据绑定到request对象上,通过request对象getAttribute和setAtt

Java web中常见编码乱码问题(二)

根据上篇记录Java web中常见编码乱码问题(一), 接着记录乱码案例: 案例分析:   2.输出流写入内容或者输入流读取内容时乱码(内容中有中文) 原因分析: a. 如果是按字节写入或读取时乱码,应该先检测系统编码是什么样的,看看是否支持中文编码的字符集. System.out.println(System.getProperty("file.encoding")); a1.如果是不支持中文的就要设置jvm编码了,设置方法: Windows环境就在catalina.bat配置: s

Java Web中涉及的编解码

用户从浏览器发起一个HTTP请求,存在编码的地方是URL.Cookie.Paramiter.服务器端接收到HTTP请求后要解析HTTP协议,其中URL.Cookie和POST表单参数要解码,服务器端可能还需要读取硬盘数据(数据库.文件),这些数据都可能存在编码问题.当Servlet处理完所有请求的数据后,需要将这些数据再编码通过Socket发送到用户请求的浏览器里,再经过浏览器解码成为文本.这些过程用图表示如下: 1.URL的编解码 为了验证浏览器是怎么编码URL的,我们选择FireFox浏览器

java web中servlet、jsp、html 互相访问的路径问题。

在java web种经常出现 404找不到网页的错误,究其原因,一般是访问的路径不对. java web中的路径使用按我的分法可以分两种情况,当然啦两者使用相对路径是一致,本文只说绝对路径. 情况一.指向外部的web组件和本身关系不大的,这一类的有:html中使用路径的标签,比如<a>标签中的href;servlet和jsp中的重定向sendRedirect(path); 情况二.指向内部的web组件和本身有关系的,这一类我暂时看到的有:servlet或者jsp的转发 假设在myapp项目下有

java web中路径问题。

转自:http://blog.csdn.net/liang5630/article/details/38474543 如有侵权,请及时联系本人及时删除 在java web种经常出现 404找不到网页的错误,究其原因,一般是访问的路径不对. java web中的路径使用按我的分法可以分两种情况,当然啦两者使用相对路径是一致,本文只说绝对路径. 情况一.指向外部的web组件和本身关系不大的,这一类的有:html中使用路径的标签,比如<a>标签中的href;servlet和jsp中的重定向sendR

CKEditor4 在java web中的应用说明(详细可行)

按照官方的说明书就可,这里主要注意一点!! 就是<script src="../ckeditor.js"></script>中js文件的路径问题,我的ckeditor文件夹是在WebContent文件夹下,jsp文件是同一层目录的,所以最后的代码应该是 <script type="text/javascript"src="./ckeditor/ckeditor.js"></script> 注意斜杆号

java web 中的转发和重定向

假设应用程序的 contextPath 为 /ctx,在 http://localhost:8080/ctx/a/b 资源中,我们转发和重定向到 http://localhost:8080/ctx/x/y 资源,分别应该怎么写? 转发,是在同一个应用程序中,请求从由资源 A 处理,到由资源 B 处理.资源 A 和资源 B 属于同一个应用程序的资源,它们总是相对于该应用程序的 contextPath 而言的.转发的资源可以使用相对路径(不以 "/" 开头)和绝对路径(以 "/&

jQuery框架+DWR框架实现的Java Web中的Ajax效果(异步请求,局部刷新)

一 简介和实现效果 这里用一个小例子来简单举例说明,做一个搜索引擎搜索提示效果,通过不断输入字符,然后在下方给出搜索提示.效果图如下: 通过上图可以看到,当输入一个"a"时,提示了很多内容,然后继续输入一个"e"后,提示的范围明显就变小了. 注:在文末我会给出完整源代码的下载链接,以供大家参考 二 具体实现 1 在eclipse for java ee中创建一个Java Web工程,然后导入相应的jar包,特别说明的是:这里要导入一个额外的dwr.jar.也就是说,

java web中请求和响应中包含中文出现乱码解析

说明:在计算机中保存的一切文本信息是以一定的编码表(0,1,0,1)来保存我们所认识的字符(汉字或英文字符),由字符到计算机存储的二进制过程是编码,由读取二进制到文本的过程称为解码.而字符编码有多种不同的编码表,所以,如果编码格式和解码格式不是同一个码表就会出现乱码.想要避免出现乱码,需要使保存和读取时使用相同的码表. 在java web编程中经常会出现乱码,现在详细讲解一下如何进行设置,避免乱码 1 网页编码 在编写网页的时候,需要指定网页的编码格式,使用<meta http-equiv=&quo