我们在写项目的时候常常会传递一些中文參数,可是j2e默认使用ISO-8859-1来编码和解码,所以非常easy出现中文乱码问题。

这里我做一个统一的整理,事实上这里的中文乱码问题和上一篇的路径问题都是j2e常常遇见的非常普遍的问题。无论你使用不使用框架都是非常easy发生的。所以好好的整理一下还是非常有必要的。

  • 详细有可能发生乱码的地方有:

1. 从数据库到Java程序 byte——〉char
2. 从Java程序到数据库 char——〉byte
3. 从文件到Java程序 byte——〉char
4. 从Java程序到文件 char——〉byte
5. 从流到Java程序byte——〉char
6. 从Java程序到流char——〉byte
7. 从Java程序到页面显示 char——〉byte
8. 从页面form提交数据到Java程序byte——〉char

其它的临时先无论,如今我们先来处理Servlet中的中文乱码,也就是上面最后2点。

  • 首先必需要明确的,Tomcat的參数问题不管是GET或是POST方式都是用8859_1编码的。

1,GET方式要看tomcat下源代码。
protected static Locale defaultLocale = Locale.getDefault();貌似这里的编码使用的本地的编码,可是我们细致看下
org.apache.tomcat.service.http. HttpRequestAdapter类
---- line=new String(buf, 0, count, Constants.CharacterEncoding.Default);
----  Constants.CharacterEncoding.Default=8859_1  
这段代码不好跟踪。千万不要被一些假象迷惑住,HttpRequestAdapter是从RequestImpl中派生的。

可是。实际上用8080port的Server并没有直接用到RequestImpl。而是用了HttpRequestAdapter来获得queryString。

2,POST方式我们看下javax.servlet.http.HttpUtils的parsePostData方法。以下贴出源代码。

public static Hashtable parsePostData(int len, ServletInputStream in){if (len <= 0){return new Hashtable();}if (in == null){throw new IllegalArgumentException();}byte[] postedBytes = new byte[len];try{int offset = 0;do{int inputLen = in.read(postedBytes, offset, len - offset);if (inputLen <= 0){String msg = lStrings.getString("err.io.short_read");throw new IllegalArgumentException(msg);}offset += inputLen;}while (len - offset > 0);}catch (IOException e){throw new IllegalArgumentException(e.getMessage());}try{String postedBody = new String(postedBytes, 0, len, "8859_1");return parseQueryString(postedBody);}catch (UnsupportedEncodingException e){}throw new IllegalArgumentException(e.getMessage());}

事实上研究这个tomcat的编码源代码没啥意义,也就不用管了,记住就好,无论是GET还是POST,tomcat都是用8859_1来编码的。

  • OK,如今開始整理中文乱码的处理,解决Servlet中的乱码问题。

1。表单提交
POST方式。在代码第一行设置request的编码格式就OK。

jsp页面中一般都是设置过编码格式的,一般都是UTF-8。所以我们在这里request也设置用UTF-8解码就OK。

req.setCharacterEncoding("UTF-8");

GET方式,上面的操作不生效,由于get方式提交參数丫的不是在header里面是在url后面跟着的,仅仅能自己用String来转换了。

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

2,超链接和重定向
比方:

<a href="/linkin/LinkinServlet?userName=林肯公园">GET方式传參</a>

这2种情况和上面的用GET方式提交表单一样,处理方式也一样,这里不做赘述了。

3,上面的情况都是属于编码级别的,一般的我们的项目上了生产上无论是GET方式还是POST方式,编码格式这些都设置好了。最多是ajxa异步请求的时候添加过滤器编码设置。

这里针对tomcat本地开发说下:
假设是GET方式。在改动tomcat配置的地方加入一个属性:URIEncoding,将该属性值设置为UTF-8,就可以让Tomcat(默认ISO-8859-1编码)以UTF-8的编码处理get请求。

<Connector port="8080"   protocol="HTTP/1.1"      connectionTimeout="20000"    redirectPort="8443" URIEncoding="UTF-8" />

假设是POST方式,就仅仅能添加编码过滤器。没使用框架的话用自己写一个过滤器,建议将过滤的编码写成配置的,比方写在<init-param>标签中。假设使用了spring,则直接配置就OK。

<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><!-- 控制是否强制设置编码,假设是true,无论request中有没有指定编码,这个过滤器设置编码都会被触发,假设是false,仅仅是在request中没有设置编码的时候被触发设置上这里的编码 --><init-param><param-name>forceEncoding</param-name><param-value>true</param-value></init-param></filter><!-- 这里是jsp中的编码格式 都被设置为统一的了 --><filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping> 

以下贴出这个类的源代码:核心就是doFilterInternal()方法。

package org.springframework.web.filter;import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public class CharacterEncodingFilter extends OncePerRequestFilter
{/*** @param request* @param response* @param filterChain* @throws ServletException* @throws IOException* 个人不喜欢forceEncoding这样的控制和别的控制一起写的写法,单独拎出来写成旗标多好* 普通情况下。为了不冲掉自己的request中原有的编码。建议forceEncoding配置成false*/@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException{//1,假设配置的encoding为空。不设置编码//2,假设配置的encoding不为空,forceEncoding为true,无论request中有没有自己的编码都会设置编码//3,假设配置的encoding不为空,forceEncoding为false,仅仅有在request没有自己的编码的时候才会设置编码if (this.encoding != null && (this.forceEncoding || request.getCharacterEncoding() == null)){request.setCharacterEncoding(this.encoding);if (this.forceEncoding){response.setCharacterEncoding(this.encoding);}}filterChain.doFilter(request, response);}}

另外这里也略微花点时间来说明一下,OncePerRequestFilter这个抽象过滤器非常好的实现了对每一个request仅仅运行一次过滤操作。假设有类似的需求能够继承该类并实现doFilterInternal方法来完毕。上面的CharacterEncodingFilter就是继承这个抽象类的,以下贴出这个抽象类的源代码,后面整理框架的时候我会做具体的整理的。


package org.springframework.web.filter;import java.io.IOException;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;public abstract class OncePerRequestFilter extends GenericFilterBean {public static final String ALREADY_FILTERED_SUFFIX = ".FILTERED";//開始过滤,有点小技巧。实现了仅仅过滤一次的功能public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)throws ServletException, IOException {if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {throw new ServletException("OncePerRequestFilter just supports HTTP requests");}HttpServletRequest httpRequest = (HttpServletRequest) request;HttpServletResponse httpResponse = (HttpServletResponse) response;String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();if (request.getAttribute(alreadyFilteredAttributeName) != null || shouldNotFilter(httpRequest)) {//第2次进来// Proceed without invoking this filter...filterChain.doFilter(request, response);}else {//第一次进来// Do invoke this filter...request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE);try {doFilterInternal(httpRequest, httpResponse, filterChain);}finally {//最后清空alreadyFilteredAttributeName属性// Remove the "already filtered" request attribute for this request.request.removeAttribute(alreadyFilteredAttributeName);}}}protected String getAlreadyFilteredAttributeName() {String name = getFilterName();if (name == null) {name = getClass().getName();}return name + ALREADY_FILTERED_SUFFIX;}protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {return false;}//推迟到子类实现,真正的过滤的方法protected abstract void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException;}


4,向页面传參
后台处理完逻辑后,跳转到页面上,假设页面上中文出现乱码,比方

resp.getWriter().write(req.getParameter("userName"));

在返回响应之前加入

response.setCharacterEncoding("UTF-8");

其有用上面那个设置编码格式的方式不怎么好,最好用以下这样的的。

response.setContentType("text/html;charset=UTF-8");
response.setContentType("application/json;charset=gbk");

5,最后2点补充。


第一点,经常使用中文字符用utf-8编码占用3个字节。用GBK、GB2312编码的汉字占2个字节,严格地用iso8859-1无法表示汉字,仅仅能转为问号。所以当我们传递的中文假设是基数的时候。即使我们正常编码和转码了也会出现乱码。在IE6版本号一下就会出现这样的情况。解决的办法就是在前台页面就编码下中文。

java.net.URLEncoder.encode("林肯公园","UTF-8");

在后台不须要转码,Servlet引擎已经帮我做好了。

某些情况下比方搜索引擎的搜索时。假设发送请求的是GET方式。浏览器上面的中文就会变成application/x-www-form-urlencoded MIME字符串。比方“%E6%E6”这样的。Servlet引擎来解析这段字符串的时候自己主动会给我们转会成汉字的。

转码的代码例如以下:

URLDecoder.decode(req.getParameter("userName"), "UTF-8");

第二点。BASE64Encoder,BASE64Decoder编码和解码,这样的编码和解码还会涉及算法的。了解下好了。

这2个类在API中查不到,由于JDK已经不推荐使用了。只是我个人认为还是挺好使的。

String name = new sun.misc.BASE64Encoder().encode("林肯公园".getBytes());// name:wda/z7mr1LA=System.out.println(new String((new sun.misc.BASE64Decoder()).decodeBuffer(name)));//林肯公园

OK。最后贴出自己写的Servlet和jsp:

package linkin;import java.io.IOException;
import java.net.URLDecoder;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;/*** @author LinkinPark* @author 2015-7-10* @Descri 解决j2e中文乱码问题*/
public class LinkinServlet extends HttpServlet
{private static final long serialVersionUID = 1L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{//req.setCharacterEncoding("UTF-8");//解决POST方式//String userName = new String(req.getParameter("userName").getBytes("ISO-8859-1"),"UTF-8");//解决GET方式System.out.println(req.getParameter("userName"));System.out.println(URLDecoder.decode(req.getParameter("userName"), "UTF-8"));req.setAttribute("userName", "林肯公园");//resp.setCharacterEncoding("UTF-8");//解决向页面传參乱码问题。建议使用以下这样的resp.setContentType("text/html;charset=UTF-8");//解决向页面传參乱码问题。建议使用这样的resp.getWriter().write(req.getParameter("userName"));//req.getRequestDispatcher("/jsp/Linkin1.jsp").forward(req, resp);//resp.sendRedirect("/linkin/jsp/Linkin1.jsp");//以下使用base64来编码和解码String name = new sun.misc.BASE64Encoder().encode("林肯公园".getBytes());// name:wda/z7mr1LA=System.out.println(new String((new sun.misc.BASE64Decoder()).decodeBuffer(name)));//林肯公园}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{this.doGet(req, resp);}public static void main(String[] args) throws Exception{}}
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%String path = request.getContextPath();String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>"><title>Servlet中文乱码</title>
<script type="text/javascript" src="/linkin/jsp/jquery-1.8.0.js"></script>
<script type="text/javascript">
var huhu = function(){var userName = $("#userName").val();$.ajax({url : "/linkin/LinkinServlet",type : "GET",async : true,data:{userName:userName},dataType : "json",success : function(a) {}});
}</script></head><body><form action="/linkin/LinkinServlet" method="GET">姓名:<input type="text" name="userName" id="userName" /><input type="button" value="提交" name="tijiao" οnclick="huhu();"/><a href="/linkin/LinkinServlet?userName=<%=java.net.URLEncoder.encode("林肯公园","UTF-8") %>林肯公园">GET方式传參</a></form>
</body>
</html>

转载于:https://www.cnblogs.com/mfmdaoyou/p/7161664.html

Servlet--j2e中文乱码解决相关推荐

  1. Servlet 传输中文乱码解决方法

    就一句话,而且要用于讲所要转换的变量之下: name = new String(name.getBytes("iso-8859-1"),"utf-8"); 整体 ...

  2. Java中文jsp页面_java中文乱码解决之道(七)—–JSP页面编码过程

    我们知道JSP页面是需要转换为servlet的,在转换过程中肯定是要进行编码的.在JSP转换为servlet过程中下面一段代码起到至关重要的作用. 在上面代码中有两个地方存在编码:pageEncodi ...

  3. java 页面编码_java中文乱码解决之道(七)-----JSP页面编码过程

    我们知道JSP页面是需要转换为servlet的,在转换过程中肯定是要进行编码的.在JSP转换为servlet过程中下面一段代码起到至关重要的作用. 在上面代码中有两个地方存在编码:pageEncodi ...

  4. struts中文乱码解决方法详解

    在学习struts中,遇到了中文乱码问题,解决方法整理如下: 使用get方法时:需要修改 $TOMCAT/conf/server.xml部署文件,改变web容器请求数据的编码格式(对post请求方式无 ...

  5. java中文乱码解决之道(二)—–字符编码详解:基础知识 + ASCII + GB**

    原文出处:http://cmsblogs.com/?p=1412 在上篇博文(java中文乱码解决之道(一)-–认识字符集)中,LZ简单介绍了主流的字符编码,对各种编码都是点到为止,以下LZ将详细阐述 ...

  6. pycharm 运行控制台中文乱码解决办法

    pycharm 运行控制台中文乱码解决办法

  7. vs code中文乱码解决方法

    修改 1.(安装方法) 2.显示终端输入数据输出结果(完美解决) 3.修改部分:中文乱码解决方法 第一步: 第二步: 1.(安装方法) 转载于: https:blog.csdn.net/qq_4304 ...

  8. Zabbix 中文乱码解决

    Zabbix 中文乱码解决 1.在本地的C:\Windows\Fonts下选择自己喜欢的字体,此处选择黑体(我只测试过宋体,楷体,黑体,幼圆其他中文字体应该都支持) 在C:\Windows\Fonts ...

  9. Ubuntu10.04下gFtp2.0.19 远程客户端中文乱码解决方法

    Ubuntu10.04下gFtp2.0.19 远程客户端中文乱码解决方法如下: 1.打开"gFTP-FTP-属性-常规-远程字符集": 2.将远程字符集设置为:gb2312,gbk ...

最新文章

  1. 环回测试能够提供什么信息_以太网测试仪
  2. 页面样式乱了,但是又感觉各种js,css都引入了
  3. cadence原理图封装pin名称重复_原理图设计篇|单片机设计项目实例分享
  4. MySql 踩坑小记
  5. 高性能MySQL(第3版)
  6. suid shell
  7. 怎样判断网页是静态还是伪静态呢
  8. Oracle 10g新特性——正则表达式(转)
  9. CSS3:nth-child()伪类选择器,Table表格奇偶数行定义样式
  10. [转载] python win32api 使用小技巧
  11. excel自动调整列宽_Excel双击鼠标的9种用法
  12. 装饰模式案列(OutputStream)
  13. 微信小程序 首页弹出用户协议
  14. torch.nn.Module.parameters(recurse=True)
  15. 【游戏开发实战】Unity实现水果忍者切水果的刀痕效果教程(两种实现方式:TrailRenderer、LineRenderer)
  16. 如何解决安装或者卸载时 临时文件夹已满或不能访问
  17. 产品经理小技术:图片素材随手找,原型设计快又好
  18. Web安全-网页开发者工具
  19. 东北大学专业 计算机专业英语教材,东北大学非英语专业硕士生用的哪套英语教材。求赐教!...
  20. 10-3 查找王姓同学不学的课程的课程号

热门文章

  1. 从头细说统计机器翻译(1)
  2. miRNA数据库篇——miRWalk:综合型的miRNA靶基因数据库
  3. 计算机信息安全技术第一章小知识点
  4. Cadence OrCAD Capture 原理图中创建差分对约束的两种常用方法
  5. 设计模式 | 外观模式
  6. CTF Crypton系列————6、滴滴滴
  7. 【Redis】——滴滴滴滴滴滴滴
  8. iPhone12和Pro的有什么区别?哪种颜色更好看?
  9. vue折叠面板的实现
  10. React-native中实现折叠效果实现