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来编码的。
req.setCharacterEncoding("UTF-8");GET方式,上面的操作不生效,因为get方式提交参数丫的不是在header里面是在url后面跟着的,只能自己用String来转换了。
String userName = new String(req.getParameter("userName").getBytes("ISO-8859-1"),"UTF-8");
<a href="/linkin/LinkinServlet?userName=林肯公园">GET方式传参</a>这2种情况和上面的用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 */ @Override protected 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; }
resp.getWriter().write(req.getParameter("userName"));在返回响应之前添加
response.setCharacterEncoding("UTF-8");其实用上面那个设置编码格式的方式不怎么好,最好用下面这种的。
response.setContentType("text/html;charset=UTF-8"); response.setContentType("application/json;charset=gbk");
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; @Override protected 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)));//林肯公园 } @Override protected 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" onclick="huhu();"/> <a href="/linkin/LinkinServlet?userName=<%=java.net.URLEncoder.encode("林肯公园","UTF-8") %>林肯公园">GET方式传参</a> </form> </body> </html>
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/u011794238/article/details/46831009