共计 3816 个字符,预计需要花费 10 分钟才能阅读完成。
1、解决全站字符乱码(POST 和 GET 中文编码问题)
servlet:
-
POST:request.setCharacterEncoding(“utf-8”);
-
GET:
String username = request.getParameter(“username”);
username = new String(username.getBytes(“ISO-8859-1”),“utf-8”);
2、说明
乱码问题:
获取请求参数中的乱码问题;
POST 请求:request.setCharacterEncoding(“utf-8”);
GET 请求:new String(request.getParameter(“xxx”).getBytes(“iso-8859-1”),“utf-8”);
响应的乱码问题:response.setContextType(“text/html;charset=utf-8”)。
基本上在每个 Servlet 中都要处理乱码问题,所以应该把这个工作放到过滤器中来完成。
3、分析
其实全站乱码问题的难点就是处理 GET 请求参数的问题。
如果只是处理 POST 请求的编码问题,以及响应编码问题,那么这个过滤器就太!太!太简单的。
public class EncodingFilter extends HttpFilter {public void doFilter(HttpServletRequest request,
HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {String charset = this.getInitParameter("charset");
if(charset == null || charset.isEmpty()) {charset = "UTF-8";
}
request.setCharacterEncoding(charset);
response.setContentType("text/html;charset=" + charset);
chain.doFilter(request, response);
}
}
如果是 POST 请求,当执行目标 Servlet 时,Servlet 中调用 request.getParameter() 方法时,就会根据 request.setCharacterEncoding() 设置的编码来转码!这说明在过滤器中调用 request.setCharacterEncoding() 方法会影响在目标 Servlet 中的 request.getParameter() 方法的行为!
但是如果是 GET 请求,我们又如何能影响 request.getParameter() 方法的行为呢?这是不好做到的!我们不可能先调用 request.getParameter() 方法获取参数,然后手动转码后,再施加在到 request 中!因为 request 只有 getParameter(),而没有 setParameter() 方法。
处理 GET 请求参数编码问题,需要在 Filter 中放行时,把 request 对象给“调包”了,也就是让目标 Servlet 使用我们“调包”之后的 request 对象。这说明我们需要保证“调包”之后的 request 对象中所有方法都要与“调包”之前一样可以使用,并且 getParameter() 方法还要有能力返回转码之后的参数。
这可能让你想起了“继承”,但是这里不能用继承,而是“装饰者模式(Decorator Pattern)”!
下面是三种对 a 对象进行增强的手段:
l 继承:AA 类继承 a 对象的类型:A 类,然后重写 fun1() 方法,其中重写的 fun1() 方法就是被增强的方法。但是,继承必须要知道 a 对象的真实类型,然后才能去继承。如果我们不知道 a 对象的确切类型,而只知道 a 对象是 IA 接口的实现类对象,那么就无法使用继承来增强 a 对象了;
l 装饰者模式:AA 类去实现 a 对象相同的接口:IA 接口,还需要给 AA 类传递 a 对象,然后在 AA 类中所有的方法实现都是通过代理 a 对象的相同方法完成的,只有 fun1() 方法在代理 a 对象相同方法的前后添加了一些内容,这就是对 fun1() 方法进行了增强;
l 动态代理:动态代理与装饰者模式比较相似,而且是通过反射来完成的。动态代理会在最后一天的基础加强中讲解,这里就不再废话了。
对 request 对象进行增强的条件,刚好符合装饰者模式的特点!因为我们不知道 request 对象的具体类型,但我们知道 request 是 HttpServletRequest 接口的实现类。这说明我们写一个类 EncodingRequest,去实现 HttpServletRequest 接口,然后再把原来的 request 传递给 EncodingRequest 类!在 EncodingRequest 中对 HttpServletRequest 接口中的所有方法的实现都是通过代理原来的 request 对象来完成的,只有对 getParameter() 方法添加了增强代码!
JavaEE 已经给我们提供了一个 HttpServletRequestWrapper 类,它就是 HttpServletRequest 的包装类,但它做任何的增强!你可能会说,写一个装饰类,但不做增强,其目的是什么呢?使用这个装饰类的对象,和使用原有的 request 有什么分别呢?
HttpServletRequestWrapper 类虽然是 HttpServletRequest 的装饰类,但它不是用来直接使用的,而是用来让我们去继承的!当我们想写一个装饰类时,还要对所有不需要增强的方法做一次实现是很心烦的事情,但如果你去继承 HttpServletRequestWrapper 类,那么就只需要重写需要增强的方法即可了。
4、代码
EncodingRequest
public class EncodingRequest extends HttpServletRequestWrapper {private String charset;
public EncodingRequest (HttpServletRequest request, String charset) {super(request);
this.charset = charset;
}
public String getParameter (String name) {HttpServletRequest request = (HttpServletRequest) getRequest();
String method = request.getMethod() ;
if(method.equalsIgnoreCase("post")) {try {request.setCharacterEncoding(charset);
} catch (UnsupportedEncodingException e) {}} else if(method.equalsIgnoreCase("get")) {String value = request.getParameter(name);
try {value = new String(name.getBytes("ISO-8859-1"), charset);
} catch (UnsupportedEncodingException e) { }
return value ;
}
return request.getParameter(name);
}
}
EncodingFilter
public class EncodingFilter extends HttpFilter {
public void doFilter(HttpServletRequest request,
HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {String charset = this.getInitParameter("charset");
if(charset == null || charset.isEmpty()) {charset = "UTF-8";}
response.setCharacterEncoding(charset);
response.setContentType("text/html;charset=" + charset);
EncodingRequest res = new EncodingRequest(request, charset);
chain.doFilter(res, response);
}
}
web.xml
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>cn.itcast.filter.EncodingFilter</filter-class>
<init-param>
<param-name>charset</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>