监听器和拦截器复习
监听器(Listener)
监听器是一个接口,具体内容由我们来实现,监听器的实现用了观察者模式,我们实现的具体监听器就是观察者
JavaWeb中的监听器
事件源(被监听的对象):三大域!
- ServletContext
生命周期监听:ServletContextListener,它有两个方法,一个在出生时调用,一个在死亡时调用;
- void contextInitialized(ServletContextEvent sce):创建SErvletcontext时
- void contextDestroyed(ServletContextEvent sce):销毁Servletcontext时
属性监听:ServletContextAttributeListener,它有三个方法,一个在添加属性时调用,一个在替换属性时调用,最后一个是在移除属性时调用。
- void attributeAdded(ServletContextAttributeEvent event):添加属性时;
- void attributeReplaced(ServletContextAttributeEvent event):替换属性时;
- void attributeRemoved(ServletContextAttributeEvent event):移除属性时;
- HttpSession
生命周期监听:HttpSessionListener,它有两个方法,一个在出生时调用,一个在死亡时调用;
- void sessionCreated(HttpSessionEvent se):创建session时
- void sessionDestroyed(HttpSessionEvent se):销毁session时
属性监听:HttpSessioniAttributeListener,它有三个方法,一个在添加属性时调用,一个在替换属性时调用,最后一个是在移除属性时调用。
- void attributeAdded(HttpSessionBindingEvent event):添加属性时;
- void attributeReplaced(HttpSessionBindingEvent event):替换属性时
- void attributeRemoved(HttpSessionBindingEvent event):移除属性时
- ServletRequest
生命周期监听:ServletRequestListener,它有两个方法,一个在出生时调用,一个在死亡时调用;
- void requestInitialized(ServletRequestEvent sre):创建request时
- void requestDestroyed(ServletRequestEvent sre):销毁request时
属性监听:ServletRequestAttributeListener,它有三个方法,一个在添加属性时调用,一个在替换属性时调用,最后一个是在移除属性时调用。
- void attributeAdded(ServletRequestAttributeEvent srae):添加属性时
- void attributeReplaced(ServletRequestAttributeEvent srae):替换属性时
- void attributeRemoved(ServletRequestAttributeEvent srae):移除属性时
javaWeb中完成编写监听器:
- 写一个监听器类:要求必须去实现某个监听器接口;
- 注册,是在web.xml中配置来完成注册!(可以使用注解的方式,在后面的笔记中我再记录)
在web.xml文件注册形式为 :
<listener> <listener-class>你编写的具体监听器类</listener-class> </listener>
在三大域中都存在一个生命周期监听和一个属性监听,实际上还有几个监听类,是与HttpSession相关,但它们是用来添加到JavaBean上,而不是添加到三大域上!这两个监听器都不需要在web.xml中注册!它们可以感知session域中对象的创建和销毁
监听器在SSH中的应用
在SSH整合的过程中,我们在项目的web.xml文件中配置的spring监听类,其内部就是实现了一个监听器接口,使服务器在启动的时候可以加载spring的配置文件进行初始化
<!--指定spring文件的位置 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!--配置spring监听器,这样在服务器启动的时候来加载spring--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
拦截器(Filter)
过滤器JavaWeb三大组件之一,它与Servlet很相似!不它过滤器是用来拦截请求的,而不是处理请求的
当用户请求某个Servlet时,会先执行部署在这个请求上的Filter,如果Filter“放行”,那么会继承执行用户请求的Servlet;如果Filter不“放行”,那么就不会执行用户请求的Servlet。
其实可以这样理解,当用户请求某个Servlet时,Tomcat会去执行注册在这个请求上的Filter,然后是否“放行”由Filter来决定。可以理解为,Filter来决定是否调用Servlet!当执行完成Servlet的代码后,还会执行Filter后面的代码
所谓的放行就是使用:
chain.doFilter(request, response);
chain是javax.servlet.FilterChain的参数
javaWeb中完成编写拦截器:
- 写过滤器就是写一个类,实现Filter(javax.servlet.Filter)接口
- 注册,是在web.xml中配置来完成注册!(可以使用注解的方式,在后面的笔记中我再记录)
在web.xml文件注册形式为 :
<filter> <filter-name>取个名字</filter-name> <filter-class>类的全路径名</filter-class> </filter> <filter-mapping> <filter-name>使用上边的名字</filter-name> <url-pattern>要拦截的范围(可以使/*,表示拦截所有请求,还可以是拦截某个Servlet)</url-pattern> </filter-mapping>
和Servlet在web.xml中的配置很相似吧
注意:Filter在web.xml中配置是有顺序的,先配置的先拦截
还有一个值得注意的地方是:不要认为一个请求在给浏览器输出就完成了,实际上很多事情都需要在给客户端响应之后才能完成,可以在放行语句的前后各输出一句话,可以看到,在Filter放行之后,浏览器就可以输出一个页面(如果Servlet中不做过多操作,只起一个转跳的作用),但是放行之后的语句还是会在控制台输出
过滤器的生命周期
Filter的生命周期(和Servlet的生命周期类似)
- init(FilterConfig):在服务器启动时会创建Filter实例,并且每个类型的Filter只创建一个实例,从此不再创建!在创建完Filter实例后,会马上调用init()方法完成初始化工作,这个方法只会被执行一次;
- doFilter(ServletRequest req,ServletResponse res,FilterChain chain):这个方法会在用户每次访问“目标资源(<url->pattern>index.jsp</url-pattern>)”时执行,如果需要“放行”,那么需要调用FilterChain的doFilter(ServletRequest,ServletResponse)方法,如果不调用FilterChain的doFilter()方法,那么目标资源将无法执行;
- destroy():服务器会在创建Filter对象之后,把Filter放到缓存中一直使用,通常不会销毁它。一般会在服务器关闭时销毁Filter对象,在销毁Filter对象之前,服务器会调用Filter对象的destory()方法
四种拦截方式
我们来做个测试,写一个过滤器,指定过滤的资源为b.jsp,然后我们在浏览器中直接访问b.jsp,你会发现过滤器执行了!
但是,当我们在a.jsp中request.getRequestDispathcer(“/b.jsp”).forward(request,response)时,就不会再执行过滤器了!也就是说,默认情况下,只能直接访问目标资源才会执行过滤器,而forward执行目标资源,不会执行过滤器
其实过滤器有四种拦截方式!分别是:REQUEST、FORWARD、INCLUDE、ERROR。
- REQUEST:直接访问目标资源时执行过滤器。包括:在地址栏中直接访问、表单提交、超链接、重定向,只要在地址栏中可以看到目标资源的路径,就是REQUEST;
- FORWARD:转发访问执行过滤器。包括RequestDispatcher#forward()方法、<jsp:forward>标签都是转发访问;
- INCLUDE:包含访问执行过滤器。包括RequestDispatcher#include()方法、<jsp:include>标签都是包含访问;
- ERROR:当目标资源在web.xml中配置为<error-page>中时,并且真的出现了异常,转发到目标资源时,会执行过滤器
可以在<filter-mapping>中添加0~n个<dispatcher>子元素,来说明当前访问的拦截方式:
<filter-mapping> <filter-name>myfilter</filter-name> <url-pattern>/b.jsp</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> </filter-mapping>
当没有给出拦截方式时,那么默认为REQUEST,其实最为常用的就是REQUEST和FORWARD两种拦截方式,而INCLUDE和ERROR都比较少用
我们可以使用拦截器实现一个错误转跳的功能,但发生错误就转跳到一个错误页面:
<filter-mapping> <filter-name>myfilter</filter-name> <url-pattern>/b.jsp</url-pattern> <dispatcher>ERROR</dispatcher> </filter-mapping> <error-page> <error-code>500</error-code> <location>/b.jsp</location> </error-page>
我们就可以在b.jsp中编写一个错误提示页面,或者是做一些其他操作
过滤器的应用场景
- 执行目标资源之前做预处理工作,例如设置编码,这种处理通常都会放行,只是在目标资源执行之前做一些准备工作
- 通过条件判断是否放行,例如校验当前用户是否已经登录,或者用户IP是否已经被禁用;
- 进行权限控制
最后我们再来看看Filter在SSH整合中的使用:
当然是Struts2的使用啦:
<filter> <filter-name>struts2</filter-name> <filter-class> org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter </filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
StrutPrepareAndExecuteFilter这个拦截器的作用就是拦截所有请求