过滤器和监听器
**web三大组件:**servlet、过滤器和监听器。
过滤器 -->1.我们每次在servlet的实现类中 每次都要进行设置字符编码 文本格式;
2.图片 pc端 手机端 下载下来的时候 图片大小不一致 --);
3.在新闻管理项目中,你的分类基本是不变的,用application作用域进行存储 但是什么时候存呢 (首页一打开就存?) 万一别人进的是添加页面
4.你在浏览网页 提示让你登录以后才能进行别的操作
1. 掌握过滤器的使用
1.1 理解过滤器的特点和执行原理
每次在请求前都要进行一系列的编码问题解决和响应格式问题解决。
每次请求前需要记录请求日志,响应后也需要记录响应日志。
检查当前用户是否有处理目标资源的权限。(查看用户是否登录)
过滤器就可以实现上述的处理。
过滤器用于拦截传入的请求和传出的响应,监视、修改或以某种方式处理正在客户端和服务器之间交换的数据流。
过滤器会过滤两次,一次请求过滤,一次响应过滤。
在目标资源执行请求处理前进行过滤,在目标资源处理后响应前进行过滤。
目标资源如 jsp页面/servlet等
web容器就是 tomcat
1.2 掌握过滤器的创建和配置
接口是一种能力
ctrl+shift+t全局搜索类
ctrl+t查看继承体系
ctrl+o查看方法
filter过滤
**Filter接口:**类似于Servlet接口 用于执行过滤操作的接口 javax.servlet
**FilterConfig接口:**类似于ServletConfig接口 用于获取Filter配置参数信息的接口
-
创建一个类实现过滤器接口
public class HelloFilter1 implements Filter { @Override public void destroy() {} // 执行过滤 @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { System.out.println("----->正在执行请求过滤------>"); filterChain.doFilter(request, response); // 放行 System.out.println("----->正在执行响应过滤------>"); } @Override public void init(FilterConfig filterConfig) throws ServletException {} }
-
在web.xml中配置此过滤器
<!-- 配置过滤器 --> <filter> <filter-name>helloFilter1</filter-name> <filter-class>cn.kgc.demo1.HelloFilter1</filter-class> </filter> <filter-mapping> <filter-name>helloFilter1</filter-name> <!-- http://localhost:8080/newsmgr/xx/xxx?opr=xxx --> <!-- 过滤器能够给哪些请求进行过滤 (过滤规则) --> <!-- 此规则同样适用于servlet --> <!-- 完全匹配: 例如:/hello 它只能匹配到 http://localhost:8080/newsmgr/hello 目录匹配: 例如:/hello/* 它能匹配到:http://localhost:8080/newsmgr/hello/test1 它能匹配到:http://localhost:8080/newsmgr/hello/test2/xxx 扩展名匹配: 例如: *.do *.action *.html 它能匹配到:http://localhost:8080/newsmgr/xxx/xxx/xx.do --> // /hello/* 如果没有前面的/ 就是包含hello就可以 加上表示目录 <url-pattern>/hello/*</url-pattern> </filter-mapping>
你也可以这样创建filter 会自动帮你配置好在web.xml里面的内容
还可以通过注解配置过滤器。
@WebFilter(filterName="helloFilter2",urlPatterns= {"/hello/*"})
public class HelloFilter2 implements Filter {
}
1.3 Filter的生命周期【面试题】
回顾Servlet的生命周期:
当第一次请求过来的时候,服务器会对对应的Servlet进行实例化(构造方法)和初始化(init()方法)。
每一次请求过来的时候,服务器都会执行service方法然后根据请求方式的不同,执行doXx()方法。
当服务器被正常关闭的时候会调用Servlet的destroy方法
Filter的生命周期:
当服务器启动时,过滤器就会进行实例化(构造方法)和初始化(init方法)!
当请求符合过滤器过滤规则时,会执行doFilter方法,如果过滤合格,可以选择放行到下一个过滤器(过滤器链),同理响应时也会再次进行响应过滤。
当服务器正常关闭时,会调用destroy方法进行销毁。
1.4 理解过滤器链
当多个过滤器的匹配规则都处于交集状态,那么会形成过滤器链,执行完对应的过滤器之后,会依次执行后续的,最后才执行目标资源。(它的顺序由web.xml中的filter-mapping标签决定)
1.5 初始化参数设置
类似于Servlet的初始化参数配置。
@WebFilter(filterName = "characterEncodingFilter", urlPatterns = { "/*" }, initParams = {
@WebInitParam(name = "encoding", value = "utf-8") })
public class CharacterEncodingFilter implements Filter {
private String defaultEncoding = "utf-8";
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String encoding = filterConfig.getInitParameter("encoding");
if (encoding != null) {
defaultEncoding = encoding;
}
}
// 解决中文编码问题
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
request.setCharacterEncoding(defaultEncoding);
// 我们在请求中就要用到out对象 所以在请求前开始在执行
response.setContentType("text/html;charset="+defaultEncoding );
response.setCharacterEncoding(defaultEncoding);
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
2. 掌握监听器的使用
你也可以右键去搜索listener 实现一下你要实现的接口,这样创建的时候,以后就不需要在web.xml中进行配置了
2.1 理解监听器的作用
**监听器:**用于监听我们一些特别的作用域对象的活动的一种组件。
ServletContext(application作用域)、HttpSession(session作用域)、ServletRequest(request作用域)三个域对象
2.2 了解监听器的分类
- 监听作用域创建和销毁的监听器
- ServletContextListener
- HttpSessionListener
- ServletRequestListener
- 监听作用域属性列表变化的监听器
(只要有属性在添加移除 我就触发 但是我希望有用户对象的属性再添加的我才触发 需要借助下面的感知性监听器)- ServletContextAttributeListener
- HttpSessionAttributeListener
- ServletRequestAttributeListener
- 感知型监听器
- HttpSessionBindingListener
- HttpSessionActivationListener
2.3 掌握监听器的定义和配置
监听作用域创建和销毁的监听器
-
创建一个监听器实现对应的监听器接口,服务器启动的时候执行初始化,服务器关闭时执行销毁操作。
public class MyListener1 implements ServletContextListener { // 监听销毁 @Override public void contextDestroyed(ServletContextEvent arg0) { System.out.println("正在执行销毁"); } // 监听初始化 @Override public void contextInitialized(ServletContextEvent arg0) { System.out.println("正在执行初始化"); } }
-
在web.xml中配置对应的监听器全类名
<listener> <listener-class>cn.kgc.demo1.MyListener1</listener-class> </listener>
监听作用域属性列表变化的监听器
- 创建一个监听器实现对应的监听器接口
HttpSession session = request.getSession();
User user=new User("heise","123");
属性添加session.setAttribute("loginUser",user);
属性移除session.removeAttribute()
属性修改session.setAttribute("userName", "heiUpdate");
public class MyListener2 implements HttpSessionAttributeListener {
// 属性添加
@Override
public void attributeAdded(HttpSessionBindingEvent sessionBindingEvent) {
String name = sessionBindingEvent.getName();
Object value = sessionBindingEvent.getValue();
System.out.println("有属性在添加!"+name+"-->"+value);
}
// 属性移除
@Override
public void attributeRemoved(HttpSessionBindingEvent sessionBindingEvent) {
String name = sessionBindingEvent.getName();
Object value = sessionBindingEvent.getValue();
System.out.println("有属性在移除!"+name+"-->"+value);
}
// 属性替换
@Override
public void attributeReplaced(HttpSessionBindingEvent sessionBindingEvent) {
String name = sessionBindingEvent.getName();
Object value = sessionBindingEvent.getValue();
System.out.println("有属性在替换!"+name+"-->"+value);
}
}
-
在web.xml中配置
<listener> <listener-class>cn.kgc.demo1.MyListener1</listener-class> </listener>
感知型监听器
-
在需要感知的类型上去实现对应的接口
-
实现对应的感知方法即可
public class User implements Serializable,HttpSessionBindingListener{ private static final long serialVersionUID = 1L; private String username; private String password; // 省略getter/setter和构造 @Override public String toString() { return "User [username=" + username + ", password=" + password + "]"; } // 当用户类型对象被绑定时触发 // session.setAttribute(); @Override public void valueBound(HttpSessionBindingEvent event) { //获取值 Object value = event.getValue(); User loginUser = (User)value; System.out.println("用户:"+loginUser.getUsername()+"上线了!"); } // 当用户类型对象被解绑时触发 @Override public void valueUnbound(HttpSessionBindingEvent event) { Object value = event.getValue(); User loginUser = (User)value; System.out.println("用户:"+loginUser.getUsername()+"下线了!"); } }