过滤器简介
WEB过滤器是一个服务器端的组件,它可以截取用户端的请求与相应信息,并对这些信息过滤。
过滤器的工作原理和生命周期
在没有Web过滤器的情况下,用户直接访问服务器上的Web资源。但是如果存在过滤器,用户就不可以直接访问过滤器了。
Web容器启动的时候过滤器就已经启动了,用户的请求到达过滤器,过滤器判断用户的请求是否符合过滤规则,如果符合规则则将用户的请求发送给Web资源,Web资源将响应信息发送给过滤器,过滤器将Web资源的响应发送给用户。工作原理如下图所示:
过滤器的生命周期:
其中实例化方法在Web容器开始装载的时候就执行,初始化方法配置一些初始化参数,Web容器卸载(服务器关闭)的时候执行销毁方法。过滤方法会执行多次,其他方法只会执行一次。
第一个过滤器
1.创建一个类实现javax.servlet.Filter接口。需要实现该接口中的3个方法。
1 packagefilter;2
3 importjava.io.IOException;4
5 importjavax.servlet.Filter;6 importjavax.servlet.FilterChain;7 importjavax.servlet.FilterConfig;8 importjavax.servlet.ServletException;9 importjavax.servlet.ServletRequest;10 importjavax.servlet.ServletResponse;11
12 public class FirstFilter implementsFilter {13
14 public voiddestroy() {15 System.out.println("*********执行过滤器的销毁方法*******");16
17 }18
19 public voiddoFilter(ServletRequest request, ServletResponse response,20 FilterChain filterChain) throwsIOException, ServletException {21 System.out.println("*******开始执行过滤器的doFilter方法*********");22 filterChain.doFilter(request, response);23 System.out.println("*******结束执行过滤器的doFilter方法**********");24 }25
26 public void init(FilterConfig arg0) throwsServletException {27 System.out.println("*******执行过滤器的初始化方法***********");28
29 }30
31 }
FirstFilter.java
init(FilterConfig ):过滤器的初始化方法,Web容器创建过滤器之后将调用这个方法,在这个方法中可以读取web.xml中的过滤器参数。
doFilter(ServletRequest,ServletResponse,FilterChain):完成实际的过滤操作,是过滤器的核心方法。当用户请求访问与过滤器相关联的URL的时候,Web容器将先调用过滤器的doFilter方法。FilterChain参数可以调用chain.doFilter方法【放行方法】,将请求传送给下一个过滤器(或者目标资源),或利用转发、重定向将请求转发给其他资源。
destroy():Web容器在销毁过滤器实例前调用该方法,在这个方法中可以释放过滤器占用的资源。【大多数情况下用不到】
2.在web.xml中配置过滤器(和再web.xml中注册servlet类似)
在MyEclipse中提供了可视化的配置web.xml,如下图:
1 <?xml version="1.0" encoding="UTF-8"?>
2
3 xmlns="http://java.sun.com/xml/ns/javaee"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee6 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
7
8
9 index.jsp
10
11
12
13
14 FirstFilter
15 filter.FirstFilter
16
17
18 FirstFilter
19 /*
20
21
22
23
web.xml
在index.jsp中我们在控制台打印一行信息:"**********这是index.jsp*********";
将项目部署到服务器,启动服务器:
在Servlet容器装载的时候,执行过滤器的init方法,当用户请求页面的时候首先执行doFilter()方法,当Servlet容器卸载的时候执行过滤器的销毁方法。【注意:用户的请求先是到达过滤器并不是直接访问的Web资源】
还有一点需要注意:用户虽然能够改变用户请求的资源(例如:网上购物的时候点击“立即购买”,这个请求先要到达过滤器,如果过滤器检测到用户没有登录,就会将页面重定向到登陆页),但是过滤器不能直接处理用户的请求(过滤器不是Servlet),不能直接返回数据。
过滤器链
针对同一个用户请求(url-pattern),与之匹配的过滤器有多个,这个时候用户请求就会依次通过各个过滤器到达web资源。
新建2个过滤器:
1 packagefilter;2
3 importjava.io.IOException;4
5 importjavax.servlet.Filter;6 importjavax.servlet.FilterChain;7 importjavax.servlet.FilterConfig;8 importjavax.servlet.ServletException;9 importjavax.servlet.ServletRequest;10 importjavax.servlet.ServletResponse;11
12 public class FirstFilter implementsFilter {13
14 public voiddestroy() {15 System.out.println("*********过滤器1----->销毁方法*******");16
17 }18
19 public voiddoFilter(ServletRequest request, ServletResponse response,20 FilterChain filterChain) throwsIOException, ServletException {21 System.out.println("*******开始执行过滤器1----->doFilter方法*********");22 filterChain.doFilter(request, response);23 System.out.println("*******结束执行过滤器1----->doFilter方法**********");24 }25
26 public void init(FilterConfig arg0) throwsServletException {27 System.out.println("*******执行过滤器1------>初始化方法***********");28
29 }30
31 }
FirstFilter.java
1 packagefilter;2
3 importjava.io.IOException;4
5 importjavax.servlet.Filter;6 importjavax.servlet.FilterChain;7 importjavax.servlet.FilterConfig;8 importjavax.servlet.ServletException;9 importjavax.servlet.ServletRequest;10 importjavax.servlet.ServletResponse;11
12 public class SecondFilter implementsFilter {13
14 public voiddestroy() {15 System.out.println("*********过滤器2----->销毁方法*******");16 }17
18 public voiddoFilter(ServletRequest request, ServletResponse response,19 FilterChain filterChain) throwsIOException, ServletException {20 System.out.println("*******开始执行过滤器2----->doFilter方法*********");21 filterChain.doFilter(request, response);22 System.out.println("*******结束执行过滤器2----->doFilter方法**********");23 }24
25 public void init(FilterConfig arg0) throwsServletException {26 System.out.println("*******执行过滤器2------>初始化方法***********");27 }28
29 }
SecondFilter.java
在web.xml中配置两个过滤器(第一个过滤器在前面,两个过滤器都匹配index.jsp)
1 <?xml version="1.0" encoding="UTF-8"?>
2
3 xmlns="http://java.sun.com/xml/ns/javaee"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee6 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
7
8
9 index.jsp
10
11
12
13
14
15 FirstFilter
16 filter.FirstFilter
17
18
19 FirstFilter
20 /index.jsp
21
22
23
24 SecondFilter
25 filter.SecondFilter
26
27
28 SecondFilter
29 /index.jsp
30
31
32
33
web.xml
在index.jsp中我们打印如下的一句话: System.out.println("******** 这是index.jsp,处理过程完成 *********");
运行结果:
过滤器的分类:
Servlet 2.5中将过滤器分为4种,如下图所示:
1.REQUEST过滤器
新建一个过滤器FirstFilter(在web.xml中配置两个过滤地址index.jsp和main.jsp):
1 <?xml version="1.0" encoding="UTF-8"?>
2
3 xmlns="http://java.sun.com/xml/ns/javaee"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee6 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
7
8
9 index.jsp
10
11
12
13
14 FirstFilter
15 filter.FirstFilter
16
17
18 FirstFilter
19 /index.jsp
20 REQUEST
21
22
23 FirstFilter
24 /main.jsp
25 REQUEST
26
27
28
29
web.xml
在FirstFilter的doFilter方法中将页面重定向到main.jsp
1 packagefilter;2
3 importjava.io.IOException;4
5 importjavax.servlet.Filter;6 importjavax.servlet.FilterChain;7 importjavax.servlet.FilterConfig;8 importjavax.servlet.ServletException;9 importjavax.servlet.ServletRequest;10 importjavax.servlet.ServletResponse;11 importjavax.servlet.http.HttpServletRequest;12 importjavax.servlet.http.HttpServletResponse;13
14 public class FirstFilter implementsFilter {15
16 public voiddestroy() {17 System.out.println("*********过滤器1----->销毁方法*******");18
19 }20
21 public voiddoFilter(ServletRequest request, ServletResponse response,22 FilterChain filterChain) throwsIOException, ServletException {23
24 HttpServletRequest req =(HttpServletRequest) request;25 HttpServletResponse res =(HttpServletResponse) response;26
27 System.out.println("*******开始执行过滤器1----->doFilter方法*********");28 res.sendRedirect(req.getContextPath() + "/main.jsp");//重定向
29 System.out.println("*******结束执行过滤器1----->doFilter方法**********");30 }31
32 public void init(FilterConfig arg0) throwsServletException {33 System.out.println("*******执行过滤器1------>初始化方法***********");34
35 }36
37 }
FirstFilter.java
启动服务器:
当我们访问index.jsp的时候,过滤器将页面重定向到main.jsp——相当于我们又重新请求了main.jsp,main.jsp又会遇到过滤器,如此页面不停重定向到main.jsp,产生了死循环不会输出任何内容!
换一种方式,我们在过滤器中使用服务器内部转发的方式将页面转发到main.jsp(main.jsp向页面打印"这是main.jsp")。
1 packagefilter;2
3 importjava.io.IOException;4
5 importjavax.servlet.Filter;6 importjavax.servlet.FilterChain;7 importjavax.servlet.FilterConfig;8 importjavax.servlet.ServletException;9 importjavax.servlet.ServletRequest;10 importjavax.servlet.ServletResponse;11 importjavax.servlet.http.HttpServletRequest;12 importjavax.servlet.http.HttpServletResponse;13
14 public class FirstFilter implementsFilter {15
16 public voiddestroy() {17 System.out.println("*********过滤器1----->销毁方法*******");18
19 }20
21 public voiddoFilter(ServletRequest request, ServletResponse response,22 FilterChain filterChain) throwsIOException, ServletException {23
24 HttpServletRequest req =(HttpServletRequest) request;25 HttpServletResponse res =(HttpServletResponse) response;26
27 System.out.println("*******开始执行过滤器1----->doFilter方法*********");28 req.getRequestDispatcher("main.jsp").forward(request, response);//使用服务器内部转发
29 System.out.println("*******结束执行过滤器1----->doFilter方法**********");30 }31
32 public void init(FilterConfig arg0) throwsServletException {33 System.out.println("*******执行过滤器1------>初始化方法***********");34
35 }36
37 }
FirstFilter.java
运行结果:
2.FORWARD过滤器
将main.jsp的过滤规则改为FORWARD。
1 ……2
3 FirstFilter
4 /main.jsp
5 FORWARD
6
7 ……
重新访问index.jsp
3.INCLUDE过滤器
INCLUDE和FORWARD过滤器的使用类似,对应的jsp动作是include。
4.ERROR过滤器
例如我们访问一个错误的页面时,系统会给出一个错误,用户看不懂这个错误是什么概念——我们需要给出一些人性化的提示。
以下是没有在web.xml中配置错误页,用户访问一个不存在的页面:
在web.xml中配置错误页:
1 <?xml version="1.0" encoding="UTF-8"?>
2
3 xmlns="http://java.sun.com/xml/ns/javaee"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee6 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
7
8
9 index.jsp
10
11
12
13
14 404
15 /error.jsp
16
17
18
web.xml
在web.xml中配置404错误的页面为error.jsp则当用户访问一个不存在的页面时将会将error.jsp中的内容输出(以人性化的方式提示用户):
当页面出现错误或者异常的时候,ERROR过滤器可以将错误或者异常捕捉到,系统会记录下错误的信息,程序员就可以查找错误的来源。
新建一个ErrorFilter,并在web.xml中进行如下配置:
1
2
3 404
4 /error.jsp
5
6 ……7
8 ErrorFilter
9 filter.ErrorFilter
10
11
12 ErrorFilter
13 /error.jsp
14 ERROR
15
16 ……
web.xml
错误过滤器ErrorFilter
1 packagefilter;2
3 importjava.io.IOException;4
5 importjavax.servlet.Filter;6 importjavax.servlet.FilterChain;7 importjavax.servlet.FilterConfig;8 importjavax.servlet.ServletException;9 importjavax.servlet.ServletRequest;10 importjavax.servlet.ServletResponse;11
12 public class ErrorFilter implementsFilter {13
14 public voiddestroy() {15
16 }17
18 public voiddoFilter(ServletRequest request, ServletResponse response,19 FilterChain filterChain) throwsIOException, ServletException {20 System.out.println("检测到错误信息!");21 filterChain.doFilter(request, response);//注意打印错误后要放行,不然页面不会显示
22 }23
24 public void init(FilterConfig filterConfig) throwsServletException {25
26 }27
28 }
ErrorFilter.java
J2EE5默认的web.xml是Servlet 2.5,J2EE6默认的web.xml是Servlet 3.0【支持异步处理】。
异步处理:如果在过滤器的doFilter()方法中页面跳转到了一个Servlet用于业务的处理,加入Servlet处理的业务时间花费很多,这时过滤器就会一直等待Servlet执行完成。这样用户体验就会非常差。Servlet 3.0支持异步处理。
在Servlet中新加入了@WebFilter Annotation。该Annotation用于将一个类声明为过滤器,该注解将会在部署时被容器处理,容器将根据具体的属性配置相应的类,将响应的类部署为过滤器。——因此我们不需要在web.xml中配置过滤器,只需要用注解的方式。@WebFilter的常用属性如下:
下面使用J2EE6.0创建一个Web项目,创建一个过滤器名称为AsyncFilter,使用@WebFilter Annotation配置该过滤器(PS:可以不再web.xml中注册该过滤器):
1 packagefilter;2
3 importjava.io.IOException;4
5 importjavax.servlet.DispatcherType;6 importjavax.servlet.Filter;7 importjavax.servlet.FilterChain;8 importjavax.servlet.FilterConfig;9 importjavax.servlet.ServletException;10 importjavax.servlet.ServletRequest;11 importjavax.servlet.ServletResponse;12 importjavax.servlet.annotation.WebFilter;13
14 @WebFilter(filterName = "AsyncFilter", value = { "/servlet/AsyncServlet" }, asyncSupported = true, dispatcherTypes ={15 DispatcherType.ASYNC, DispatcherType.REQUEST })16 public class AsyncFilter implementsFilter {17
18 @Override19 public voiddestroy() {20 System.out.println("***** 销毁AsyncFilter *****");21 }22
23 @Override24 public voiddoFilter(ServletRequest request, ServletResponse response,25 FilterChain filterChain) throwsIOException, ServletException {26 System.out.println("***** 开始AsyncFilter *****");27 filterChain.doFilter(request, response);//放行
28 System.out.println("***** 结束AsyncFilter *****");29 }30
31 @Override32 public void init(FilterConfig filterConfig) throwsServletException {33 System.out.println("***** 初始化AsyncFilter *****");34 }35
36 }
AsyncFilter.java
创建一个处理业务的Servlet(该Servlet在doGet方法中使用了线程的休眠方法休眠了10s模拟业务的花费时间)
1 packageservlet;2
3 importjava.io.IOException;4 importjava.util.Date;5
6 importjavax.servlet.AsyncContext;7 importjavax.servlet.ServletException;8 importjavax.servlet.http.HttpServlet;9 importjavax.servlet.http.HttpServletRequest;10 importjavax.servlet.http.HttpServletResponse;11
12 public class AsyncServlet extendsHttpServlet {13
14 public class Excutor implementsRunnable{15 privateAsyncContext context;16 publicExcutor(AsyncContext context) {17 this.context =context;18 }19
20 @Override21 public voidrun() {22 //执行相关的复杂业务
23 try{24 Thread.sleep(1000*10);//休眠10s25 //context.getRequest();26 //context.getResponse();
27 System.out.println("业务完成执行时间:"+newDate());28 } catch(InterruptedException e) {29 e.printStackTrace();30 }31 }32
33 }34
35 publicAsyncServlet() {36 super();37 }38
39 public voiddestroy() {40 super.destroy(); //Just puts "destroy" string in log
41 }42
43 public voiddoGet(HttpServletRequest request, HttpServletResponse response)44 throwsServletException, IOException {45
46 AsyncContext context = request.startAsync(); //HttpServletRequest对象开始异步方法47 //context.getRequest();48 //context.getResponse();
49
50 System.out.println("Servlet执行开始时间:"+newDate());51 new Thread(newExcutor(context)).start();52 request.getRequestDispatcher("/index.jsp").forward(request, response);53 System.out.println("Servlet执行结束时间:"+newDate());54 }55
56 public voiddoPost(HttpServletRequest request, HttpServletResponse response)57 throwsServletException, IOException {58
59 doGet(request, response);60 }61
62 public void init() throwsServletException {63
64 }65
66 }
AsyncServlet.java
编写好异步处理业务的Servlet类之后一定要在web.xml中配置该Servlet启用异步,如下图所示:
在index.jsp中有一个链接指向AsyncServlet:
/servlet/AsyncServlet">点击跳转到AsyncServlet处理业务
运行结果:
过滤器在实际项目中的应用场景
用户身份的验证
例如现在有一个web项目,登陆页login.jsp将用户名和密码提交给LoginServlet处理,Servlet使用request.getParameter方法获得表单中的用户名和密码,将用户名和密码进行验证,验证成功则页面重定向到success.jsp,显示登陆成功和登录的用户名【保存在session中再从session中取出】;如果登录失败则重定向到failure.jsp。
在不使用过滤器的情况下,即使用户不进行登录也可以访问到success.jsp——任何人都可以访问到success.jsp,这显然来说不安全。
验证用户身份的Servlet(验证用户名和密码都是admin):
1 packageservlet;2
3 importjava.io.IOException;4
5 importjavax.servlet.ServletException;6 importjavax.servlet.http.HttpServlet;7 importjavax.servlet.http.HttpServletRequest;8 importjavax.servlet.http.HttpServletResponse;9 importjavax.servlet.http.HttpSession;10
11 public class LoginServlet extendsHttpServlet {12
13 publicLoginServlet() {14 super();15 }16
17 public voiddestroy() {18 super.destroy(); //Just puts "destroy" string in log
19 }20
21 public voiddoPost(HttpServletRequest request, HttpServletResponse response)22 throwsServletException, IOException {23 String username = request.getParameter("username");24 String password = request.getParameter("password");25
26 if ("admin".equals(username)&&"admin".equals(password)) {27 //验证通过
28 HttpSession session =request.getSession();29 session.setAttribute("username", username);//把用户名放入session中
30 response.sendRedirect(request.getContextPath()+"/success.jsp");31 }else{32 //验证失败
33 response.sendRedirect(request.getContextPath()+"/failure.jsp");34 }35 }36
37 public void init() throwsServletException {38
39 }40
41 }
LoginServlet.java
如下图所示:
现在我们要做这样一件事:只有用户登录成功才可以访问到success.jsp,反之跳转到登录界面。即:不允许未登录用户访问success.jsp。
创建一个登录校验的过滤器LoginFilter并在web.xml中配置该过滤器的url为success.jsp
1 packageservlet;2
3 importjava.io.IOException;4
5 importjavax.servlet.ServletException;6 importjavax.servlet.http.HttpServlet;7 importjavax.servlet.http.HttpServletRequest;8 importjavax.servlet.http.HttpServletResponse;9 importjavax.servlet.http.HttpSession;10
11 public class LoginServlet extendsHttpServlet {12
13 publicLoginServlet() {14 super();15 }16
17 public voiddestroy() {18 super.destroy(); //Just puts "destroy" string in log
19 }20
21 public voiddoPost(HttpServletRequest request, HttpServletResponse response)22 throwsServletException, IOException {23 String username = request.getParameter("username");24 String password = request.getParameter("password");25
26 if ("admin".equals(username)&&"admin".equals(password)) {27 //验证通过
28 HttpSession session =request.getSession();29 session.setAttribute("username", username);//把用户名放入session中
30 response.sendRedirect(request.getContextPath()+"/success.jsp");31 }else{32 //验证失败
33 response.sendRedirect(request.getContextPath()+"/failure.jsp");34 }35 }36
37 public void init() throwsServletException {38
39 }40
41 }
LoginFilter.java
1 <?xml version="1.0" encoding="UTF-8"?>
2
3 xmlns="http://java.sun.com/xml/ns/javaee"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee6 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
7
8
9 This is the description of my J2EE component
10 This is the display name of my J2EE component
11 LoginServlet
12 servlet.LoginServlet
13
14
15
16 LoginServlet
17 /servlet/LoginServlet
18
19
20 index.jsp
21
22
23 LoginFilter
24 filter.LoginFilter
25
26
27 LoginFilter
28 /success.jsp
29
30
web.xml
加入过滤器之后(只有成功登录的用户【session中保存了该用户的用户名】才可以访问index.jsp):
在实际的开发中一个网站的页面成百上千,这时我们可以使用通配符"/*"来匹配所有的url。但是这样带来一个问题:
当我们新建立一个session的时候,访问任何页面都会被重定向到login.jsp,login.jsp自己也重定向到login.jsp,这样就形成了重定向循环
这时就需要在过滤器中判断页面是否是login.jsp,如果是login.jsp或者请求的是LoginServlet就直接放行。在LoginFilter的doFilter方法中添加这样几行代码:
1 if (req.getRequestURI().indexOf("login.jsp")!=-1||req.getRequestURI().indexOf("LoginServlet")!=-1) {2 filterChain.doFilter(request, response); //如果用户请求的是login.jsp直接放行
3 return; //这一行代码一定要加上啊!
4 }
运行结果:
上述程序看似已经没有问题,但是还存在一个小bug,当我们在登陆页输入一个错误的用户名和密码页面并不会重定向到failure.jsp而是重定向到了login.jsp。如下图所示:
这是因为虽然我们在Servlet验证失败的时候将页面重定向到了failure.jsp,failure.jsp又被过滤器重定向到了login.jsp【因为过滤规则为所有的页面,并且session中没有用户名】
这时我们就会发现我们在doFilter中需要例外的页面越来越多(登陆页面、成功页面、失败页面、错误页面……)。为了减轻工作的复杂度,我们可以使用过滤器的init方法中的FilterConfig对象。
1.在web.xml中配置不过滤页面的初始化参数:
2. 在过滤方法中使用以上初始化参数。
1 public class LoginFilter implementsFilter{2
3 private FilterConfig filterConfig;//声明一个FilterConfig对象
4
5 public void init(FilterConfig filterConfig) throwsServletException {6 this.filterConfig = filterConfig; //初始化方法的时候给filterConfig赋值
7 }8
9 public voiddestroy() {10
11 }12
13 public voiddoFilter(ServletRequest request, ServletResponse response,14 FilterChain filterChain) throwsIOException, ServletException {15 //代码省略
16 }17
18 }
3. 在doFilter方法中使用FilterConfig对象获得初始化参数。
1 public voiddoFilter(ServletRequest request, ServletResponse response,2 FilterChain filterChain) throwsIOException, ServletException {3 HttpServletRequest req =(HttpServletRequest) request;4 HttpServletResponse res =(HttpServletResponse) response;5 HttpSession session =req.getSession();6
7 String noLoginPaths = filterConfig.getInitParameter("noLoginPaths");8 if (noLoginPaths!=null&&noLoginPaths.length()>0) {9 String[]temp = noLoginPaths.split(";");10 for(String string : temp) {11 if (string==null||"".equals(string)) {12 continue;13 }14 //例外的URL,如果符合这些URL就直接放行
15 if (req.getRequestURI().indexOf(string)!=-1) {16 filterChain.doFilter(request, response); //如果用户请求的是login.jsp直接放行
17 return; //这一行代码一定要加上啊!
18 }19 }20 }21
22 if (session.getAttribute("username")!=null) {23 filterChain.doFilter(request, response); //如果用户已经登录则放行
24 }else{25 res.sendRedirect("login.jsp");26 }27 }
这样就完成了一个比较完整的登录验证。
编码转换
以上面的登录页面为例,在处理登录页的LoginServlet中我们将用户提交的用户名打印出来:
1 public voiddoPost(HttpServletRequest request, HttpServletResponse response)2 throwsServletException, IOException {3 String username = request.getParameter("username");4 System.out.println("用户提交的用户名是:" +username);5
6 }
后台的输出出现了乱码!
已知的2种处理乱码的方式:
1 String username = request.getParameter("username");2
3 request.setCharacterEncoding("utf-8"); //【方式1】修改请求的编码方式
4 new String(username.getBytes("iso-8859-1"),"utf-8") //【方式2】使用特定编码重新构建字符串
除此之外,还可以使用过滤器解决以上问题。
在过滤器的doFilter方法的第一行代码加上以下代码:
request.setCharacterEncoding("utf-8");
这样一次设置就可以让该网站的所有页面都不会乱码(因为请求总是先到达过滤器)。但是为了更好地完成服务器的配置,我们一般在过滤器的初始化参数里配置字符集:
然后在doFilter方法中这样调用:
1 public class LoginFilter implementsFilter{2
3 private FilterConfig filterConfig;//声明一个FilterConfig对象
4
5 public voiddestroy() {6
7 }8
9 public voiddoFilter(ServletRequest request, ServletResponse response,10 FilterChain filterChain) throwsIOException, ServletException {11
12 String charset = filterConfig.getInitParameter("charset");13 if (charset == null) {14 charset = "utf-8"; //如果没有指定字符集,默认是utf-8
15 }16 request.setCharacterEncoding(charset); //从初始化参数里面获得字符集17
18 //代码省略
19
20 }21
22 public void init(FilterConfig filterConfig) throwsServletException {23 this.filterConfig = filterConfig; //初始化方法的时候给filterConfig赋值
24 }25
26 }