通过Filter可以对web服务器管理的所有web资源,如JSP, Servlet, 静态图片文件或静态html 文件等进行拦截,从而实现一些特殊的功能。
Filter不能通过url直接访问
过滤器本身并不产生请求和响应对象,它只能提供过滤作用。
过滤器能够在web资源被调用之前检查request对象,修改request Header和request内容;在Servlet被调用之后检查response对象,修改response Header和response内容。
访问资源时,针对不同的资源可能会执行很多相同的逻辑操作,如编码的设置,登录权限的判断等,借助Filter中的代码复用,可以提高开发效率
注意:过滤器并不是必须要将请求传递到下一个过滤器或目标资源,它可以自行对请求进行处理,并发送响应给客户端,也可以将请求转发或重定向到其他的 Web 资源。
1)创建和初始化阶段
Tomcat服务器启动时,如果应用中存在filter,会创建filter对象,并调用其初始化方法。filter对象只会创建一次,init方法也只会执行一次。通过init方法的参数,可获得代表当前filter配置信息的FilterConfig对象
2)拦截和过滤阶段
通过chain.doFilter()进行实际的过滤操作,可以访问后续的资源,访问资源后,会回到doFilter方法中
3)销毁阶段
当应用重新加载,或者关闭tomcat服务器时,会销毁filter对象
创建Filter对象
public class FirstFilter implements Filter {
/**
* Default constructor.
*/
public FirstFilter() {
// TODO Auto-generated constructor stub
System.out.println("first filter constructor");
}
/**
* @see Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
System.out.println("first filter destroy");
}
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
// 核心方法,针对filter逻辑,写到该方法中
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// TODO Auto-generated method stub
// place your code here
System.out.println("first filter before");
// 放行请求,如果有其他的filter,继续访问filter,如果没有,访问目标资源
// 多个filter的访问顺序,由filter在web.xml中的注册顺序决定
chain.doFilter(request, response);
System.out.println("first filter after");
}
/**
* @see Filter#init(FilterConfig)
*/
// 一个filter对应一个FilterConfig对象
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
System.out.println("first filter init");
// 获取filter的初始化参数
String value = fConfig.getInitParameter("aaa");
System.out.println(value);
}
}
注册Filter
<filter>
<display-name>FirstFilterdisplay-name>
<filter-name>FirstFilterfilter-name>
<filter-class>com.qianfeng.filter.FirstFilterfilter-class>
<init-param>
<param-name>encodingparam-name>
<param-value>utf8param-value>
init-param>
filter>
<filter-mapping>
<filter-name>FirstFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
在web.xml中对Filter进行注册,设置拦截的资源,一般设置为”/*”,对任意资源都进行过滤
<filter>
<display-name>FirstFilterdisplay-name>
<filter-name>FirstFilterfilter-name>
<filter-class>com.qianfeng.filter.FirstFilterfilter-class>
filter>
<filter-mapping>
<filter-name>FirstFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
用于注册过滤器
用于指定过滤器的注册名,该元素的内容不能为空。
用于指定过滤器的完整限定名(包名+类名)。
元素用于设置 Filter 负责拦截的资源。
用于设置 Filter 的注册名,该值必须在 元素的子元素 中声明过。
用于设置 Filter 拦截的请求路径。
属性名 | 描述 |
---|---|
filterName | 指定过滤器的 name 属性,等价于 。 |
urlPatterns | 指定过滤器的 URL 匹配模式。等价于 标签。 |
value | 该属性等价于 urlPatterns 属性,但是两者不能同时使用。 |
servletNames | 指定过滤器将应用于哪些 Servlet。取值是 @WebServlet 中 filterName 属性的取值,或者 web.xml 中 的取值。 |
dispatcherTypes | 指定过滤器拦截的资源被 Servlet 容器调用的方式。具体取值包括: ASYNC、ERROR、FORWARD、INCLUDE、REQUEST。 |
initParams | 指定一组过滤器初始化参数,等价于 标签。 |
@WebFilter(filterName = "LoginFilter", value = "/*")
public class LoginFilter implements Filter {
}
方法 | 功能描述 |
---|---|
String getInitParameter(String name) | 根据初始化参数名 name,返回对应的初始化参数值。 |
Enumeration getInitParameterNames() | 返回 Servlet 所有的初始化参数名的枚举集合,如果该 Servlet 没有初始化参数,则返回一个空的集合。 |
ServletContext getServletContext() | 返回一个代表当前 Web 应用的 ServletContext 对象。 |
String getFilterName() | 返回 Filter 的名字 |
在一个web应用中,可以开发编写多个Filter,这些Filter组合起来称之为一个Filter链
在doFilter方法中,开发人员如果调用了chain.doFilter方法,web服务器会检查FilterChain对象中是否还有其他的filter,如果有,则调用依次调用其余的filter,如果没有,则调用访问的目标资源。
注意:
访问filter的先后顺序,由filter在web.xml中的注册顺序决定
通过 @WebFilter 注解配置的 Filter 过滤器,没有提供排序的属性,但是,多个过滤器默认按照过滤器类名升序的顺序执行。若需要对 Filter 过滤器进行排序,建议使用 web.xml 进行配置
1) 统一编码
public class EncodingFilter implements Filter {
/**
* Default constructor.
*/
public EncodingFilter() {
// TODO Auto-generated constructor stub
}
/**
* @see Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// TODO Auto-generated method stub
// place your code here
// 针对post方式的中文乱码
request.setCharacterEncoding("utf-8");
// 响应
response.setContentType("text/html;charset=utf-8");
// pass the request along the filter chain
chain.doFilter(request, response);
}
/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
}
}
2) 访问权限控制
有些资源需要登录后访问
public class LoginFilter implements Filter {
private String[] passArr = null;
/**
* Default constructor.
*/
public LoginFilter() {
// TODO Auto-generated constructor stub
}
/**
* @see Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// TODO Auto-generated method stub
// place your code here
// 因为类型原因,某些方法不能正常调用,需要强制转换
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse res = (HttpServletResponse)response;
// 获取请求的资源的路径
String uri = req.getRequestURI();
// 如果是和登录相关的资源,直接放行
// 是否放行的状态
boolean flag = false;
if(passArr != null){
for(String info : passArr){
if(uri.contains(info)){
flag = true;
break;
}
}
}
if(flag){
chain.doFilter(request, response);
}else{
HttpSession session = req.getSession();
String name = (String)session.getAttribute("loginName");
// 已经登陆过
if(name != null){
chain.doFilter(request, response);
}else{
// 跳转到登录页面
res.sendRedirect(req.getContextPath() + "/login.jsp");
}
}
// 获取session对象,判断是否有登录状态,如果有,继续访问,如果没有,跳转到登录页面
}
/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
String initParameter = fConfig.getInitParameter("passInfo");
if(initParameter != null){
passArr = initParameter.split(",");
}
}
}
监听器就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行。
在Servlet规范中定义了多种类型的监听器,它们用于监听的事件源分别为ServletContext, HttpSession 和ServletRequest 这三个域对象,主要用来监听对象的创建、销毁、属性的变化
监听器的相关概念:
事件:方法调用、属性改变、状态改变等。
事件源:被监听的对象( 例如:request、session、servletContext)。
监听器:用于监听事件源对象 ,事件源对象状态的变化都会触发监听器。
注册监听器:将监听器与事件源进行绑定。
Servlet 规范中定义了 8 个监听器接口,可以用于监听 ServletContext、HttpSession 和 ServletRequest 对象的生命周期和属性变化事件。开发 Servlet 监听器需要实现相应的监听器接口并重写接口中的方法。
(1)监听对象创建/销毁的监听器接口
ServlectContxtListener
ServletRequestListener
HttpSessionListener
(2)监听对象属性变化的接口
监听属性的增删改
ServletContextAttributeListener
ServletRequestAttributeListener
HttpSessionAttributeListener
(3)其他session相关监听器接口
HttpSessionBindingListener 监听对象绑定到session的事件
HttpSessionActivationListener 监听HttpSession中对象的活化和钝化过程
// 加载web应用时,创建对象
public class ContextListener implements ServletContextListener {
/**
* Default constructor.
*/
public ContextListener() {
// TODO Auto-generated constructor stub
System.out.println("constructor");
}
/**
* @see ServletContextListener#contextDestroyed(ServletContextEvent)
*/
// 销毁ServletContext对象,调用该方法
public void contextDestroyed(ServletContextEvent arg0) {
// TODO Auto-generated method stub
System.out.println("servletcontext destroy");
}
/**
* @see ServletContextListener#contextInitialized(ServletContextEvent)
*/
// 创建ServletContext对象,调用该方法
public void contextInitialized(ServletContextEvent arg0) {
// TODO Auto-generated method stub
System.out.println("servletcontext init");
}
}
<listener>
<listener-class>com.qfedu.listener.ContextListenerlistener-class>
listener>
public class SessionAttrListener implements HttpSessionAttributeListener {
/**
* Default constructor.
*/
public SessionAttrListener() {
// TODO Auto-generated constructor stub
}
/**
* @see HttpSessionAttributeListener#attributeAdded(HttpSessionBindingEvent)
*/
public void attributeAdded(HttpSessionBindingEvent event) {
// TODO Auto-generated method stub
// 监测到添加的数据的信息
// 获取添加的属性的key值
System.out.println(event.getName());
// 获取添加的属性的value值
System.out.println(event.getValue());
}
/**
* @see HttpSessionAttributeListener#attributeRemoved(HttpSessionBindingEvent)
*/
public void attributeRemoved(HttpSessionBindingEvent event) {
// TODO Auto-generated method stub
System.out.println("delete:" +event.getName());
System.out.println("delete:" +event.getValue());
}
/**
* @see HttpSessionAttributeListener#attributeReplaced(HttpSessionBindingEvent)
*/
// 修改数据时
public void attributeReplaced(HttpSessionBindingEvent event) {
// TODO Auto-generated method stub
// 修改前的数据
System.out.println("update:" + event.getName());
System.out.println("update:" + event.getValue());
HttpSession session = event.getSession();
System.out.println("after update:" + session.getAttribute(event.getName()));
}
}
<listener>
<listener-class>com.rr.listener.MyServletContextListenerlistener-class>
listener>
@WebListener
public class MyListener implements ServletContextListener {
}
通过listener,实现获取所有登录用户信息的功能
package com.qfedu.listener;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import java.util.ArrayList;
import java.util.List;
@WebListener
public class MyListener implements ServletContextListener, HttpSessionAttributeListener {
public MyListener() {
}
// 监听到ServletContext创建后,新建一个用户列表,将列表放入ServletContext对象
@Override
public void contextInitialized(ServletContextEvent sce) {
/* This method is called when the servlet context is initialized(when the Web application is deployed). */
// 用来存储登录的用户名
List<String> userList = new ArrayList<>();
// 将列表存入ServletContext对象中
sce.getServletContext().setAttribute("userList", userList);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
/* This method is called when the servlet Context is undeployed or Application Server shuts down. */
}
// 当用户登录,将用户信息添加到用户列表中
@Override
public void attributeAdded(HttpSessionBindingEvent sbe) {
/* This method is called when an attribute is added to a session. */
String name = sbe.getName();
// 说明是登录时添加的数据
if (name.equals("loginInfo")) {
ServletContext servletContext = sbe.getSession().getServletContext();
List<String> userList = (List<String>) servletContext.getAttribute("userList");
userList.add(sbe.getValue().toString());
}
}
@Override
public void attributeRemoved(HttpSessionBindingEvent sbe) {
/* This method is called when an attribute is removed from a session. */
}
@Override
public void attributeReplaced(HttpSessionBindingEvent sbe) {
/* This method is called when an attribute is replaced in a session. */
}
}