Filter实现统一全站编码
在Web开发中,经常会遇到中文乱码问题,按照前面所学的知识,解决乱码的通常做法都是在Servlet程序中设置编码方式,但是,如果多个Servlet程序都需要设置编码方式,势必会书写大量重复的代码。
为了解决上面的问题,我们可以在Filter中对获取到的请求和响应消息进行编码,从而统一全站的编码方式。接下来,分步骤讲解如何使用Filter实现统一全站的编码,具体如下:
(1)编写form.jsp页面
在chapter04工程的WebContent根目录中,编写一个form.jsp页面,用于提交用户登录的表单信息,如例1所示。
例1 form.jsp
1 <%@ page language="java" contentType="text/html; charset=utf-8"
2 pageEncoding="utf-8" import="java.util.*"
3 %>
4 <html>
5 <head></head>
6 <center>
7 <h3>用户登录</h3>
8 </center>
9 <body style="text-align: center;">
10 <a href="<%=request.getContextPath()%>/CharacterServlet?name=
11 传智播客&password=123456">点击超链接登录</a>
12 <form action="<%=request.getContextPath()%>/CharacterServlet"
13 method="post">
14 <table border="1" width="600px" cellpadding="0" cellspacing="0"
15 align="center">
16 <tr>
17 <td height="30" align="center">用户名:</td>
18 <td> <input type="text" name="name" /></td>
19 </tr>
20 <tr>
21 <td height="30" align="center">密 码:</td>
22 <td> <input type="password" name="password" /></td>
23 </tr>
24 <tr>
25 <td height="30" colspan="2" align="center">
26 <input type="submit"value="登录" />
27 <input type="reset"value="重置" /></td>
28 </tr>
29 </table>
30 </form>
31 </body>
32 <html>
(2)编写CharacterServlet.java程序
在chapter04工程的cn.itcast.chapter04.servlet包中,编写一个CharacterServlet.java程序,该程序用于获取用户输入的请求参数,并将参数输出到控制台,如例2所示。
例2 CharacterServlet.java
1 package cn.itcast.chapter04.servlet;
2 import java.io.IOException;
3 import javax.servlet.*;
4 import javax.servlet.http.*;
5 public class CharacterServlet extends HttpServlet {
6 public void doGet(HttpServletRequest request, HttpServletResponse
7 response)throws ServletException, IOException {
8 System.out.println(request.getParameter("name"));
9 System.out.println(request.getParameter("password"));
10 }
11 public void doPost(HttpServletRequest request, HttpServletResponse
12 response)throws ServletException, IOException {
13 doGet(request, response);
14 }
15 }
(3)编写CharacterFilter.java过滤器
CharacterFilter类用于拦截用户的请求访问,实现统一全站编码的功能。但是,由于请求方式post和get解决乱码方式的不同,post方式的请求参数存放在消息体中,可以通过setCharacterEncoding()方法进行设置,而get方式的请求参数存放在消息头中,必须得通过获取URI参数才能进行设置。如果每次单独对get请求方式进行处理,势必会很麻烦,为此,可以通过HttpServletRequestWrapper类对HttpServletRequest进行包装,通过重写getParameter()的方式来设置get方式提交参数的编码,CharacterFilter类的实现代码如例3所示。
例3 CharacterFilter.java
1 package cn.itcast.chapter04.filter;
2 import java.io.*;
3 import javax.servlet.*;
4 import javax.servlet.http.*;
5 public class CharacterFilter implements Filter {
6 public void init(FilterConfig filterConfig) throws ServletException {
7 }
8 public void doFilter(ServletRequest req, ServletResponse resp,
9 FilterChain chain) throws IOException, ServletException {
10 HttpServletRequest request = (HttpServletRequest) req;
11 HttpServletResponse response = (HttpServletResponse) resp;
12 // 拦截所有的请求 解决全站中文乱码
13 // 指定 request 和 response 的编码
14 request.setCharacterEncoding("utf-8"); // 只对消息体有效
15 response.setContentType("text/html;charset=utf-8");
16 // 在放行时 应该给目标资源一个request对象 让目标资源调用
17 // getParameter时调到我们写的getParameter
18 // 对request进行包装
19 CharacterRequest characterRequest = new CharacterRequest(request);
20 chain.doFilter(characterRequest, response);
21 }
22 public void destroy() {
23 }
24 }
25 // 针对 request 对象进行包装
26 // 继承 默认包装类HttpServletRequestWrapper
27 class CharacterRequest extends HttpServletRequestWrapper {
28 public CharacterRequest(HttpServletRequest request) {
29 super(request);
30 }
31 // 子类继承父类一定会覆写一些方法,此处用于重写getParamter()方法
32 public String getParameter(String name) {
33 // 调用 被包装对象的getParameter()方法 获得请求参数
34 String value = super.getParameter(name);
35 if (value == null)
36 return null;
37 // 判断请求方式
38 String method = super.getMethod();
39 if ("get".equalsIgnoreCase(method)) {
40 try {
41 value = new String(value.getBytes("iso-8859-1"), "utf-8");
42 } catch (UnsupportedEncodingException e) {
43 throw new RuntimeException(e);
44 }
45 }
46 // 解决乱码后返回结果
47 return value;
48 }
49 }
在web.xml文件中,配置CharacterFilter过滤器,由于要拦截用户访问资源的所有请求,因此将<filter-mapping>元素拦截的路径设置为“/*”,具体代码如下:
<filter>
<filter-name>CharacterFilter</filter-name>
<filter-class>
cn.itcast.chapter04.filter.CharacterFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
(4)访问form.jsp页面
重新启动Web服务器,打开IE浏览器,在地址栏中输入http://localhost:8080/chapter04/form.jsp
,此时,浏览器窗口中会显示一个用户登录的表单,在这个表单中输入用户名传智播客、密码123456,如图1所示。
图1 运行结果
点击图1界面中的登录按钮来提交表单,此时,控制台窗口显示的结果如图2所示。
图2 控制台窗口
从图2可以看出,在form.jsp表单中输入的用户名和密码都正确的显示在控制台窗口,而且中文的用户名也没有出现乱码问题。需要注意的是,form.jsp表单的提交方式是post,因此可以说明使用post提交表单可以解决中文乱码问题,表单的提交方式还有一种是get,接下来就验证get方式提交表单的乱码问题能否解决。
(5)使用超连接访问form.jsp页面
点击图1界面中的“点击超链接登录”提交表单,这种提交方式相当于get方式提交表单,此时,控制台窗口显示的结果如图3所示。
图3 控制台窗口
从图3可以看出,get方式提交表单与post方式提交表单的效果是一样的,同样不会出现乱码问题。因此,可以说明使用Filter过滤器可以方便的完成统一全站编码的功能。
需要注意的是,针对response对象,Servlet API也提供了对应的包装类HttpServletResponseWrapper,它的用法与HttpServletRequestWrapper类似,在此不再进行举例介绍了。