filter应用案例三:解决全站编码问题
1 说明
乱码问题:
获取请求参数中的乱码问题;
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中都要处理乱码问题,所以应该把这个工作放到过滤器中来完成。
2 分析
其实全站乱码问题的难点就是处理GET请求参数的问题。
如果是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对象进行增强的手段:
继承:AA类继承a对象的类型:A类,然后重写fun1()方法,其中重写的fun1()方法就是被增强的方法。但是,继承必须要知道a对象的真实类型,然后才能去继承。如果我们不知道a对象的确切类型,而只知道a对象是IA接口的实现类对象,那么就无法使用继承来增强a对象了;
装饰者模式:AA类去实现a对象相同的接口:IA接口,还需要给AA类传递a对象,然后在AA类中所有的方法实现都是通过代理a对象的相同方法完成的,只有fun1()方法在代理a对象相同方法的前后添加了一些内容,这就是对fun1()方法进行了增强;
动态代理:动态代理与装饰者模式比较相似,而且是通过反射来完成的。
对request对象进行增强的条件,刚好符合装饰者模式的特点!因为我们不知道request对象的具体类型,但我们知道request是HttpServletRequest接口的实现类。这说明我们写一个类EncodingRequest,去实现HttpServletRequest接口,然后再把原来的request传递给EncodingRequest类!在EncodingRequest中对HttpServletRequest接口中的所有方法的实现都是通过代理原来的request对象来完成的,只有对getParameter()方法添加了增强代码!
JavaEE已经给我们提供了一个HttpServletRequestWrapper类,它就是HttpServletRequest的包装类,但它做任何的增强!你可能会说,写一个装饰类,但不做增强,其目的是什么呢?使用这个装饰类的对象,和使用原有的request有什么分别呢?HttpServletRequestWrapper类虽然是HttpServletRequest的装饰类,但它不是用来直接使用的,而是用来让我们去继承的!当我们想写一个装饰类时,还要对所有不需要增强的方法做一次实现是很心烦的事情,但如果你去继承HttpServletRequestWrapper类,那么就只需要重写需要增强的方法即可了。
代码示例:
1 import java.io.UnsupportedEncodingException; 2 import javax.servlet.http.HttpServletRequest; 3 import javax.servlet.http.HttpServletRequestWrapper; 4 5 /** 6 * 装饰reqeust 7 */ 8 public class EncodingRequest extends HttpServletRequestWrapper { 9 private HttpServletRequest req; 10 public EncodingRequest(HttpServletRequest request) { 11 super(request); 12 this.req = request; 13 } 14 15 public String getParameter(String name) { 16 String value = req.getParameter(name); 17 // 处理编码问题 18 try { 19 value = new String(value.getBytes("iso-8859-1"), "utf-8"); 20 } catch (UnsupportedEncodingException e) { 21 throw new RuntimeException(e); 22 } 23 return value; 24 } 25 }
1 import java.io.IOException; 2 3 import javax.servlet.Filter; 4 import javax.servlet.FilterChain; 5 import javax.servlet.FilterConfig; 6 import javax.servlet.ServletException; 7 import javax.servlet.ServletRequest; 8 import javax.servlet.ServletResponse; 9 import javax.servlet.http.HttpServletRequest; 10 11 public class EncodingFilter implements Filter { 12 public void destroy() {} 13 14 public void doFilter(ServletRequest request, ServletResponse response, 15 FilterChain chain) throws IOException, ServletException { 16 // 处理post请求编码问题 17 request.setCharacterEncoding("utf-8"); 18 HttpServletRequest req = (HttpServletRequest) request; 19 /* 20 * 处理GET请求的编码问题 21 * 调包request 22 * 1. 写一个request的装饰类 23 * 2. 在放行时,使用我们自己的request 24 */ 25 if(req.getMethod().equals("GET")) { 26 EncodingRequest er = new EncodingRequest(req); 27 chain.doFilter(er, response); 28 } else if(req.getMethod().equals("POST")) { 29 chain.doFilter(request, response); 30 } 31 } 32 33 public void init(FilterConfig fConfig) throws ServletException {} 34 }
1 import java.io.IOException; 2 3 import javax.servlet.ServletException; 4 import javax.servlet.http.HttpServlet; 5 import javax.servlet.http.HttpServletRequest; 6 import javax.servlet.http.HttpServletResponse; 7 8 public class AServlet extends HttpServlet { 9 public void doGet(HttpServletRequest request, HttpServletResponse response) 10 throws ServletException, IOException { 11 response.setContentType("text/html;charset=utf-8"); 12 String username = request.getParameter("username"); 13 response.getWriter().println(username); 14 } 15 16 public void doPost(HttpServletRequest request, HttpServletResponse response) 17 throws ServletException, IOException { 18 response.setContentType("text/html;charset=utf-8"); 19 String username = request.getParameter("username"); 20 response.getWriter().println(username); 21 } 22 }
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 3 <% 4 String path = request.getContextPath(); 5 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; 6 %> 7 8 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 9 <html> 10 <head> 11 <base href="<%=basePath%>"> 12 13 <title>My JSP 'index.jsp' starting page</title> 14 <meta http-equiv="pragma" content="no-cache"> 15 <meta http-equiv="cache-control" content="no-cache"> 16 <meta http-equiv="expires" content="0"> 17 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 18 <meta http-equiv="description" content="This is my page"> 19 <!-- 20 <link rel="stylesheet" type="text/css" href="styles.css"> 21 --> 22 </head> 23 24 <body> 25 <a href="<c:url value='/AServlet?username=张三'/>">点击这里</a><br/> 26 <form action="<c:url value='/AServlet'/>" method="post"> 27 用户名:<input type="text" name="username" value="李四"/> 28 <input type="submit" value="提交"/> 29 </form> 30 </body> 31 </html>
1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> 3 <display-name></display-name> 4 <servlet> 5 <servlet-name>AServlet</servlet-name> 6 <servlet-class>AServlet</servlet-class> 7 </servlet> 8 <servlet-mapping> 9 <servlet-name>AServlet</servlet-name> 10 <url-pattern>/AServlet</url-pattern> 11 </servlet-mapping> 12 <welcome-file-list> 13 <welcome-file>index.jsp</welcome-file> 14 </welcome-file-list> 15 <filter> 16 <display-name>EncodingFilter</display-name> 17 <filter-name>EncodingFilter</filter-name> 18 <filter-class>EncodingFilter</filter-class> 19 </filter> 20 <filter-mapping> 21 <filter-name>EncodingFilter</filter-name> 22 <url-pattern>/*</url-pattern> 23 </filter-mapping> 24 </web-app>