过滤器简介

  WEB过滤器是一个服务器端的组件,它可以截取用户端的请求与相应信息,并对这些信息过滤。

过滤器的工作原理和生命周期

  在没有Web过滤器的情况下,用户直接访问服务器上的Web资源。但是如果存在过滤器,用户就不可以直接访问过滤器了。

  Web容器启动的时候过滤器就已经启动了,用户的请求到达过滤器,过滤器判断用户的请求是否符合过滤规则,如果符合规则则将用户的请求发送给Web资源,Web资源将响应信息发送给过滤器,过滤器将Web资源的响应发送给用户。工作原理如下图所示:

  过滤器的生命周期:

  其中实例化方法在Web容器开始装载的时候就执行,初始化方法配置一些初始化参数,Web容器卸载(服务器关闭)的时候执行销毁方法。过滤方法会执行多次,其他方法只会执行一次。

第一个过滤器

    1.创建一个类实现javax.servlet.Filter接口。需要实现该接口中的3个方法。

 package filter;

 import java.io.IOException;

 import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; public class FirstFilter implements Filter { public void destroy() {
System.out.println("*********执行过滤器的销毁方法*******"); } public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
System.out.println("*******开始执行过滤器的doFilter方法*********");
filterChain.doFilter(request, response);
System.out.println("*******结束执行过滤器的doFilter方法**********");
} public void init(FilterConfig arg0) throws ServletException {
System.out.println("*******执行过滤器的初始化方法***********"); } }

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,如下图:

 <?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name></display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list> <!-- 配置过滤器开始 -->
<filter>
<filter-name>FirstFilter</filter-name>
<filter-class>filter.FirstFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>FirstFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 配置过滤器结束 --> </web-app>

web.xml

  在index.jsp中我们在控制台打印一行信息:"**********这是index.jsp*********";   

  将项目部署到服务器,启动服务器:

  在Servlet容器装载的时候,执行过滤器的init方法,当用户请求页面的时候首先执行doFilter()方法,当Servlet容器卸载的时候执行过滤器的销毁方法。【注意:用户的请求先是到达过滤器并不是直接访问的Web资源】

  还有一点需要注意:用户虽然能够改变用户请求的资源(例如:网上购物的时候点击“立即购买”,这个请求先要到达过滤器,如果过滤器检测到用户没有登录,就会将页面重定向到登陆页),但是过滤器不能直接处理用户的请求(过滤器不是Servlet),不能直接返回数据。

过滤器链

  针对同一个用户请求(url-pattern),与之匹配的过滤器有多个,这个时候用户请求就会依次通过各个过滤器到达web资源。

  新建2个过滤器:

 package filter;

 import java.io.IOException;

 import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; public class FirstFilter implements Filter { public void destroy() {
System.out.println("*********过滤器1----->销毁方法*******"); } public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
System.out.println("*******开始执行过滤器1----->doFilter方法*********");
filterChain.doFilter(request, response);
System.out.println("*******结束执行过滤器1----->doFilter方法**********");
} public void init(FilterConfig arg0) throws ServletException {
System.out.println("*******执行过滤器1------>初始化方法***********"); } }

FirstFilter.java

 package filter;

 import java.io.IOException;

 import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; public class SecondFilter implements Filter { public void destroy() {
System.out.println("*********过滤器2----->销毁方法*******");
} public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
System.out.println("*******开始执行过滤器2----->doFilter方法*********");
filterChain.doFilter(request, response);
System.out.println("*******结束执行过滤器2----->doFilter方法**********");
} public void init(FilterConfig arg0) throws ServletException {
System.out.println("*******执行过滤器2------>初始化方法***********");
} }

SecondFilter.java

  在web.xml中配置两个过滤器(第一个过滤器在前面,两个过滤器都匹配index.jsp)

 <?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name></display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list> <!-- 配置过滤器开始 -->
<!-- 过滤器1 -->
<filter>
<filter-name>FirstFilter</filter-name>
<filter-class>filter.FirstFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>FirstFilter</filter-name>
<url-pattern>/index.jsp</url-pattern>
</filter-mapping>
<!-- 过滤器2 -->
<filter>
<filter-name>SecondFilter</filter-name>
<filter-class>filter.SecondFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SecondFilter</filter-name>
<url-pattern>/index.jsp</url-pattern>
</filter-mapping>
<!-- 配置过滤器结束 --> </web-app>

web.xml

  在index.jsp中我们打印如下的一句话: System.out.println("******** 这是index.jsp,处理过程完成 *********");

运行结果:

过滤器的分类:

  Servlet 2.5中将过滤器分为4种,如下图所示:

1.REQUEST过滤器

  新建一个过滤器FirstFilter(在web.xml中配置两个过滤地址index.jsp和main.jsp): 

 <?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name></display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list> <!-- 配置过滤器开始 -->
<filter>
<filter-name>FirstFilter</filter-name>
<filter-class>filter.FirstFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>FirstFilter</filter-name>
<url-pattern>/index.jsp</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>FirstFilter</filter-name>
<url-pattern>/main.jsp</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<!-- 配置过滤器结束 --> </web-app>

web.xml

  在FirstFilter的doFilter方法中将页面重定向到main.jsp

 package filter;

 import java.io.IOException;

 import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; public class FirstFilter implements Filter { public void destroy() {
System.out.println("*********过滤器1----->销毁方法*******"); } public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response; System.out.println("*******开始执行过滤器1----->doFilter方法*********");
res.sendRedirect(req.getContextPath() + "/main.jsp");//重定向
System.out.println("*******结束执行过滤器1----->doFilter方法**********");
} public void init(FilterConfig arg0) throws ServletException {
System.out.println("*******执行过滤器1------>初始化方法***********"); } }

FirstFilter.java

  启动服务器:

  当我们访问index.jsp的时候,过滤器将页面重定向到main.jsp——相当于我们又重新请求了main.jsp,main.jsp又会遇到过滤器,如此页面不停重定向到main.jsp,产生了死循环不会输出任何内容!

  换一种方式,我们在过滤器中使用服务器内部转发的方式将页面转发到main.jsp(main.jsp向页面打印"这是main.jsp")。

 package filter;

 import java.io.IOException;

 import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; public class FirstFilter implements Filter { public void destroy() {
System.out.println("*********过滤器1----->销毁方法*******"); } public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response; System.out.println("*******开始执行过滤器1----->doFilter方法*********");
req.getRequestDispatcher("main.jsp").forward(request, response);//使用服务器内部转发
System.out.println("*******结束执行过滤器1----->doFilter方法**********");
} public void init(FilterConfig arg0) throws ServletException {
System.out.println("*******执行过滤器1------>初始化方法***********"); } }

FirstFilter.java

  运行结果:

2.FORWARD过滤器

  将main.jsp的过滤规则改为FORWARD。

 ……
<filter-mapping>
<filter-name>FirstFilter</filter-name>
<url-pattern>/main.jsp</url-pattern>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
……

  重新访问index.jsp

3.INCLUDE过滤器

  INCLUDE和FORWARD过滤器的使用类似,对应的jsp动作是include。

4.ERROR过滤器

  例如我们访问一个错误的页面时,系统会给出一个错误,用户看不懂这个错误是什么概念——我们需要给出一些人性化的提示。

  以下是没有在web.xml中配置错误页,用户访问一个不存在的页面:

  在web.xml中配置错误页:

 <?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name></display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list> <!-- 配置错误页面 -->
<error-page>
<error-code>404</error-code>
<location>/error.jsp</location>
</error-page> </web-app>

web.xml

  在web.xml中配置404错误的页面为error.jsp则当用户访问一个不存在的页面时将会将error.jsp中的内容输出(以人性化的方式提示用户):

  当页面出现错误或者异常的时候,ERROR过滤器可以将错误或者异常捕捉到,系统会记录下错误的信息,程序员就可以查找错误的来源。

  新建一个ErrorFilter,并在web.xml中进行如下配置:

 <!-- 配置错误页面 -->
<error-page>
<error-code>404</error-code>
<location>/error.jsp</location>
</error-page>
……
<filter>
<filter-name>ErrorFilter</filter-name>
<filter-class>filter.ErrorFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ErrorFilter</filter-name>
<url-pattern>/error.jsp</url-pattern>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
……

web.xml

  错误过滤器ErrorFilter

 package filter;

 import java.io.IOException;

 import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; public class ErrorFilter implements Filter { public void destroy() { } public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
System.out.println("检测到错误信息!");
filterChain.doFilter(request, response);//注意打印错误后要放行,不然页面不会显示
} public void init(FilterConfig filterConfig) throws ServletException { } }

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中注册该过滤器):

 package filter;

 import java.io.IOException;

 import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter; @WebFilter(filterName = "AsyncFilter", value = { "/servlet/AsyncServlet" }, asyncSupported = true, dispatcherTypes = {
DispatcherType.ASYNC, DispatcherType.REQUEST })
public class AsyncFilter implements Filter { @Override
public void destroy() {
System.out.println("***** 销毁AsyncFilter *****");
} @Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
System.out.println("***** 开始AsyncFilter *****");
filterChain.doFilter(request, response);//放行
System.out.println("***** 结束AsyncFilter *****");
} @Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("***** 初始化AsyncFilter *****");
} }

AsyncFilter.java

  创建一个处理业务的Servlet(该Servlet在doGet方法中使用了线程的休眠方法休眠了10s模拟业务的花费时间)

 package servlet;

 import java.io.IOException;
import java.util.Date; import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; public class AsyncServlet extends HttpServlet { public class Excutor implements Runnable{
private AsyncContext context;
public Excutor(AsyncContext context) {
this.context = context;
} @Override
public void run() {
// 执行相关的复杂业务
try {
Thread.sleep(1000*10);//休眠10s
// context.getRequest();
// context.getResponse();
System.out.println("业务完成执行时间:"+new Date());
} catch (InterruptedException e) {
e.printStackTrace();
}
} } public AsyncServlet() {
super();
} public void destroy() {
super.destroy(); // Just puts "destroy" string in log
} public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { AsyncContext context = request.startAsync(); //HttpServletRequest对象开始异步方法
// context.getRequest();
// context.getResponse(); System.out.println("Servlet执行开始时间:"+new Date());
new Thread(new Excutor(context)).start();
request.getRequestDispatcher("/index.jsp").forward(request, response);
System.out.println("Servlet执行结束时间:"+new Date());
} public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { doGet(request, response);
} public void init() throws ServletException { } }

AsyncServlet.java

  编写好异步处理业务的Servlet类之后一定要在web.xml中配置该Servlet启用异步,如下图所示:

  在index.jsp中有一个链接指向AsyncServlet:

<a href="<%=request.getContextPath() %>/servlet/AsyncServlet">点击跳转到AsyncServlet处理业务</a>

  运行结果:

过滤器在实际项目中的应用场景

用户身份的验证

  例如现在有一个web项目,登陆页login.jsp将用户名和密码提交给LoginServlet处理,Servlet使用request.getParameter方法获得表单中的用户名和密码,将用户名和密码进行验证,验证成功则页面重定向到success.jsp,显示登陆成功和登录的用户名【保存在session中再从session中取出】;如果登录失败则重定向到failure.jsp。

  在不使用过滤器的情况下,即使用户不进行登录也可以访问到success.jsp——任何人都可以访问到success.jsp,这显然来说不安全。

  验证用户身份的Servlet(验证用户名和密码都是admin):

 package servlet;

 import java.io.IOException;

 import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; public class LoginServlet extends HttpServlet { public LoginServlet() {
super();
} public void destroy() {
super.destroy(); // Just puts "destroy" string in log
} public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password"); if ("admin".equals(username)&&"admin".equals(password)) {
// 验证通过
HttpSession session = request.getSession();
session.setAttribute("username", username);//把用户名放入session中
response.sendRedirect(request.getContextPath()+"/success.jsp");
}else {
// 验证失败
response.sendRedirect(request.getContextPath()+"/failure.jsp");
}
} public void init() throws ServletException { } }

LoginServlet.java

如下图所示:

  现在我们要做这样一件事:只有用户登录成功才可以访问到success.jsp,反之跳转到登录界面。即:不允许未登录用户访问success.jsp。

  创建一个登录校验的过滤器LoginFilter并在web.xml中配置该过滤器的url为success.jsp

 package servlet;

 import java.io.IOException;

 import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; public class LoginServlet extends HttpServlet { public LoginServlet() {
super();
} public void destroy() {
super.destroy(); // Just puts "destroy" string in log
} public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password"); if ("admin".equals(username)&&"admin".equals(password)) {
// 验证通过
HttpSession session = request.getSession();
session.setAttribute("username", username);//把用户名放入session中
response.sendRedirect(request.getContextPath()+"/success.jsp");
}else {
// 验证失败
response.sendRedirect(request.getContextPath()+"/failure.jsp");
}
} public void init() throws ServletException { } }

LoginFilter.java

 <?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name></display-name>
<servlet>
<description>This is the description of my J2EE component</description>
<display-name>This is the display name of my J2EE component</display-name>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>servlet.LoginServlet</servlet-class>
</servlet> <servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/servlet/LoginServlet</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<filter>
<filter-name>LoginFilter</filter-name>
<filter-class>filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LoginFilter</filter-name>
<url-pattern>/success.jsp</url-pattern>
</filter-mapping>
</web-app>

web.xml

  加入过滤器之后(只有成功登录的用户【session中保存了该用户的用户名】才可以访问index.jsp):

 在实际的开发中一个网站的页面成百上千,这时我们可以使用通配符"/*"来匹配所有的url。但是这样带来一个问题:

 当我们新建立一个session的时候,访问任何页面都会被重定向到login.jsp,login.jsp自己也重定向到login.jsp,这样就形成了重定向循环

  这时就需要在过滤器中判断页面是否是login.jsp,如果是login.jsp或者请求的是LoginServlet就直接放行。在LoginFilter的doFilter方法中添加这样几行代码:

 if (req.getRequestURI().indexOf("login.jsp")!=-1||req.getRequestURI().indexOf("LoginServlet")!=-1) {
filterChain.doFilter(request, response); // 如果用户请求的是login.jsp直接放行
return; // 这一行代码一定要加上啊!
}

  运行结果:

  上述程序看似已经没有问题,但是还存在一个小bug,当我们在登陆页输入一个错误的用户名和密码页面并不会重定向到failure.jsp而是重定向到了login.jsp。如下图所示:

  这是因为虽然我们在Servlet验证失败的时候将页面重定向到了failure.jsp,failure.jsp又被过滤器重定向到了login.jsp【因为过滤规则为所有的页面,并且session中没有用户名】

  这时我们就会发现我们在doFilter中需要例外的页面越来越多(登陆页面、成功页面、失败页面、错误页面……)。为了减轻工作的复杂度,我们可以使用过滤器的init方法中的FilterConfig对象。

 1. 在web.xml中配置不过滤页面的初始化参数:

  2.  在过滤方法中使用以上初始化参数。

 public class LoginFilter implements Filter{

     private FilterConfig filterConfig;// 声明一个FilterConfig对象

     public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig; // 初始化方法的时候给filterConfig赋值
} public void destroy() { } public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
// 代码省略
} }

  3. 在doFilter方法中使用FilterConfig对象获得初始化参数。

 public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
HttpSession session = req.getSession(); String noLoginPaths = filterConfig.getInitParameter("noLoginPaths");
if (noLoginPaths!=null&&noLoginPaths.length()>0) {
String[]temp = noLoginPaths.split(";");
for (String string : temp) {
if (string==null||"".equals(string)) {
continue;
}
// 例外的URL,如果符合这些URL就直接放行
if (req.getRequestURI().indexOf(string)!=-1) {
filterChain.doFilter(request, response); // 如果用户请求的是login.jsp直接放行
return; // 这一行代码一定要加上啊!
}
}
} if (session.getAttribute("username")!=null) {
filterChain.doFilter(request, response); // 如果用户已经登录则放行
}else {
res.sendRedirect("login.jsp");
}
}

  这样就完成了一个比较完整的登录验证。

编码转换

  以上面的登录页面为例,在处理登录页的LoginServlet中我们将用户提交的用户名打印出来:

 public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
System.out.println("用户提交的用户名是:" + username); }

  

 后台的输出出现了乱码!

  已知的2种处理乱码的方式:

 String username = request.getParameter("username");

 request.setCharacterEncoding("utf-8");                // 【方式1】修改请求的编码方式
new String(username.getBytes("iso-8859-1"),"utf-8") // 【方式2】使用特定编码重新构建字符串

  除此之外,还可以使用过滤器解决以上问题。

  在过滤器的doFilter方法的第一行代码加上以下代码:

request.setCharacterEncoding("utf-8");

  这样一次设置就可以让该网站的所有页面都不会乱码(因为请求总是先到达过滤器)。但是为了更好地完成服务器的配置,我们一般在过滤器的初始化参数里配置字符集:

  然后在doFilter方法中这样调用:

 public class LoginFilter implements Filter{

     private FilterConfig filterConfig;// 声明一个FilterConfig对象

     public void destroy() {

     }

     public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException { String charset = filterConfig.getInitParameter("charset");
if (charset == null) {
charset = "utf-8"; // 如果没有指定字符集,默认是utf-8
}
request.setCharacterEncoding(charset); // 从初始化参数里面获得字符集 // 代码省略 } public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig; // 初始化方法的时候给filterConfig赋值
} }

JavaWeb——过滤器的更多相关文章

  1. 第16 天 JavaWEB过滤器和监听器技术

    Day16 JavaWEB过滤器和监听器技术 复习: 1.大结果集分页mysql的实现,是使用那个关键字,从user表中取第一页的数据,长度为10,sql语句怎么写? 2.分页查询的起始位置(star ...

  2. JAVAWEB过滤器、监听器的作用及使用>从零开始学JAVA系列

    目录 JAVAWEB过滤器.拦截器的作用及使用 过滤器Filter 什么是过滤器 为什么要使用过滤器(过滤器所能解决的问题) 配置一个过滤器完成编码的过滤 编写一个EncodingFilter(名称自 ...

  3. JavaWeb—过滤器Filter

    1.Filter简介 Filter称之为过滤器,是用来做一些拦截的任务.比如客户端请求服务器的某个资源时(可以是Servlet.JSP.HTML等等),我们可以拦截.当服务器返回资源给客户端的时候,我 ...

  4. JavaWEB过滤器和监听器技术

    过滤器介绍 什么是过滤器 生活中的例子: 滤水器,口罩,杯子上滤网,渔网 生活中的过滤器:留下我们想要的,排除,我们不想要的. 高考: 只有分数够高的同学才能进入理想的大学.有一部分同学被拦截在大学之 ...

  5. JavaWeb——过滤器及监听器

    什么是过滤器? 过滤器示意图 Filter是如何实现拦截的? Filter的生命周期 Filter的创建 Filter的销毁 FilterConfig接口 Servlet过滤器有关接口 过滤器配置 F ...

  6. Javaweb——过滤器映射

    什么是过滤器? 过滤器:从字面上看,可以理解为将具有杂质的水过滤,留下干净的水.那么从IT的角度上理解.过滤器:是处在源数据(数据库之类的)和目标数据(显示页面)的中间组件.对于Web应用来说,过滤器 ...

  7. struts2 javaweb 过滤器、监听器 拦截器 原理

    转: 过滤器.监听器 拦截器 过滤器 创建一个 Filter 只需两个步骤: (1)创建 Filter 处理类: (2)在 web.xml 文件中配置 Filter . 创建 Filter 必须实现 ...

  8. JavaWeb过滤器.监听器.拦截器-原理&区别-个人总结

    对比项 拦截器 过滤器 机制 反射机制 函数回调 是否依赖servlet容器 是 否 请求处理 只能对action请求起作用 几乎所有的请求起作用 对action处理 可以访问action上下文.值栈 ...

  9. JavaWeb 过滤器——验证登录 防止未登录进入界面

    昨天刚刚完成老师布置的一个Web小项目,项目中用到了两个过滤器(编码过滤.登录过滤) 比如电商网页中有些不需要登录也能访问(首页.商品详细信息...),其他都需要过滤在会话作用域(session)中是 ...

  10. JavaWeb过滤器.监听器.拦截器-原理&区别(转)

    1.拦截器是基于java的反射机制的,而过滤器是基于函数回调 2.过滤器依赖与servlet容器,而拦截器不依赖与servlet容器 3.拦截器只能对action请求起作用,而过滤器则可以对几乎所有的 ...

随机推荐

  1. C#字符串来袭——因为爱,所以爱

    一直以来都喜欢谢霆锋,喜欢他身上的那股劲,也一直喜欢唱他的歌,比如这首最广为人知的<因为爱,所以爱>:因为爱所以爱,温柔经不起安排,愉快那么快,不要等到互相伤害...是的,没到互相伤害,他 ...

  2. iframe中,页面转换后回到页面的顶部

    看到网上有这样描述的: 现在A页面内分为上下两个部分,上部分是top,下部分分左右,左是treeview右边是iframe,iframe内嵌一个B页面,B页面的内容实质上是个月刊,可以理解为杂志,里面 ...

  3. 如何设置outlook实现自动秘密抄送邮件的功能?

    很多朋友会发现虽然在家里同步了公司的邮箱可以正常收发邮件,可是每当使用家里的outlook发送相关邮件的时候,在公司的邮箱里找不到相关的发件记录,只能同步收件箱,而不能同步发件箱应该是比较让人困扰的问 ...

  4. 禁止chrome自动更新

    删除C:\Program Files (x86)\Google文件夹下面的updata文件夹

  5. easyui 动态加载语言包

    解决办法是:把语言包中的语言类型写到cookie,动态修改cookie中的语言名称,修改完后重新渲染一下页面. 在页面加载完成后,先判断cookie存不存在,如果不存在就写入默认语言,存在就给easy ...

  6. 区别原生chrome 和以chrome为内核的360浏览器

    function isChrome360() { if( navigator.userAgent.toLowerCase().indexOf('chrome') > -1 ) { var des ...

  7. andorid手机电脑操作

    之前一直使用androidscreencast在pc上对手机进行操作,好久都没用了,前些天再次用的时候,提演示样例如以下: 决定还是自己写一个吧,由于7月份要做一个小分享,打算讲一些android的东 ...

  8. C#事件-自定义事件的使用方法(转载)

    1.声明一个委托类 public delegate SomethingChangedHandler(object sender,EventArgs e); 2.在你的类中声明一个事件绑定到该委托 pu ...

  9. 红茶一杯话Binder (ServiceManager篇)

    1.先说一个大概 Android平台的一个基本设计理念是构造一个相对平坦的功能集合,这些功能可能会身处于不同的进程中,然而却可以高效地整合到一起,实现不同的用户需求.这就必须打破过去各个孤立App所形 ...

  10. AES_CBC_PKCS5Padding 加密

    在项目中需要对一些关键信息进行传输,但又不能是明文,所以采用此种方式进行加密,另一端再进行解密. AES: 算法 CBC: 模式 ​ 使用CBC模式,需要一个向量iv,可增加加密算法的强度 PKCS5 ...