过滤器(Filter)
它会在一组资源(jsp、servlet、.css、.html等等)的前面执行
它可以让请求得到目标资源,也可以不让请求达到
过滤器有拦截请求的能力
- 用来拦截传入的请求和传出的响应
- 修改或以某种方式处理正在客户端和服务端之间交换的数据流
public class CharacterFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("UTF-8");
filterChain.doFilter(servletRequest,servletResponse);
}
}
<filter>
<filter-name>charcater</filter-name>
<filter-class>my.filter.CharacterFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>charcater</filter-name>
<url-pattern>/login</url-pattern>
<url-pattern>/test</url-pattern>
</filter-mapping>
注意: dofilter方法中处理完业务逻辑之后,必须添加filterChain.doFilter(servletRequest,servletResponse);
否则请求或者响应无法向后传递。一直停留在过滤器中。
过滤器的创建和配置
-
写一个类实现Filter接口
Filter接口
void init(FilterConfig)
-
创建之后,马上执行;Filter会在服务器启动时就创建!
void destory() -
销毁之前执行!在服务器关闭时销毁
void doFilter(ServletRequest,ServletResponse,FilterChain)
-
每次过滤时都会执行
Filter是单例的
FilterChain
- doFilter(ServletRequest, ServletResponse):放行
放行,就相当于调用了目标Servlet的service()方法
public class CharsetFilter implements Filter{ private String charset; @Override public void destroy() { System.out.println("=======destroy=========="); } @Override public void init(FilterConfig conf) throws ServletException { System.out.println("=======init=====CharsetFilter====="); charset = conf.getInitParameter("charset"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //处理的 request.setCharacterEncoding(charset); response.setContentType("text/html;charset=utf-8"); System.out.println("======CharsetFilter======="+charset); //"放行" 调用后续的过滤器或资源 chain.doFilter(request, response); // response.setCharacterEncoding("utf-8"); } }
-
-
在web.xml中进行配置
<filter> <filter-name>timer</filter-name> <filter-class>filter.TimerFilter</filter-class> </filter> <filter> <filter-name>charsetFilter</filter-name> <filter-class>filter.CharsetFilter</filter-class> <init-param> <param-name>charset</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>timer</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>charsetFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
生命周期***:
-
构造方法(加载和实例化) :创建过滤器对象的时候调用。在加载当前项目的时候加载过滤器,只调用1次。单实例的多线程。
-
init方法(初始化) :在创建完过滤器对象之后调用。只调用1次。
-
doFilter方法(过滤): 过滤任务方法。会调用n次。每次访问目标资源的时候,doFilter就会被调用。
-
destory方法:(销毁):在销毁过滤器对象的时候调用。在web项目重新部署或tomcat服务器停止的时候销毁过滤器对象。只调用1次。
加载时间:默认在服务器启动时加载,实例化初始化
问题:Servlet和Filter,谁先启动 ?Filter
同时配置多个Filter,Filter的调用顺序是由web.xml中的配置顺序来决定的,写在上面的配置先调用。
<filter>
<filter-name>charcater</filter-name>
<filter-class>my.filter.CharacterFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>charcater</filter-name>
<url-pattern>/login</url-pattern>
<url-pattern>/test</url-pattern>
</filter-mapping>
注解配置
@WebFilter("/login")
public class MyFilter implements Filter {
}
什么是过滤器链?
chain.doFilter(req,resp); //放行,执行目标资源,或是执行下一个过滤器!如果没有下一个过滤器那么执行的是目标资源,如果有,那么就执行下一个过滤器
过滤器链中过滤器有先后顺序
过滤器在链中的顺序与它在web.xml中配置的顺序有关
初始化配置参数
初始化参数问题:<init-param>
FilterConfig–>与ServletConfig相似
Filter接口中的init()方法的参数类型为FilterConfig类型,与web.xml文件中的配置信息对应
-
ServletContext getServletContext():获取ServletContext的方法;
-
String getFilterName():获取Filter的配置名称;与元素对应;
-
String getInitParameter(String name):获取Filter的初始化配置,与元素对应;
-
Enumeration getInitParameterNames():获取所有初始化参数的名称。
<filter>
<filter-name>charsetFilter</filter-name>
<filter-class>filter.CharsetFilter</filter-class>
<init-param>
<param-name>charset</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
过滤器应用:
登录权限验证、资源访问权限控制、敏感词汇过滤、字符编码转换…
乱码问题:区分请求乱码和响应乱码
request.setCharacterEncoding(charset);
response.setContentType("text/html;charset=utf-8");
请求乱码:
-
get请求:
-
new String(msg.getBytes(“iso-8859-1”),“utf-8”);
-
修改tomcat配置/conf/server.xml
-
post请求:
- 过滤器中request.setCharacterEncoding(charset);
- 过滤器中request.setCharacterEncoding(charset);
路径问题:
//转发 斜杠(工程目录)相对工程的目录
request.getRequestDispatcher("/login.jsp").forward(request, response);
//相对路径 相对当前访问的路径
resp.sendRedirect("login.jsp"); //
//绝对路径(IP目录) /表示ip地址,从ip开始找路径资源
resp.sendRedirect("/login.jsp"); //
// http://127.0.0.1:8080/webfilter/login.jsp
resp.sendRedirect("/webfilter/login.jsp"); //
为什么在过滤器中resp.sendReidrect("login.jsp");死循环
http://ip:8080/webfilter/admin/emp.jsp
resp.sendRedirect("login.jsp");
等价于
resp.sendRedirect("http://ip:8080/webfilter/admin/login.jsp")
转发的绝对路径,是工程目录
重定向的绝对路径,是IP服务器目录
相对路径:不是斜杠开头,相对当前访问的目录
监听器(Listener)
监听器用于监听web应用中某些对象、信息的创建、销毁、增加,修改,删除等动作的发生,然后作出相应
的响应处理。当范围对象的状态发生变化的时候,服务器自动调用监听器对象中的方法。
常用于统计在线人数和在线用户,系统加载时进行信息初始化,统计网站的访问量等等。
JavaWeb中的监听器
在JavaWeb被监听的事件源为:ServletContext、HttpSession、ServletRequest,即三大域对象。
-
监听域对象“创建”与“销毁”的监听器;
-
监听域对象“操作域属性”的监听器;
-
监听HttpSession的监听器。
事件源:三大域
-
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):移除属性时
事件对象:
-
ServletContextEvent:ServletContext getServletContext()
-
HttpSessionEvent:HttpSession getSession()
-
ServletRequest:
ServletContext getServletContext();
ServletReques getServletRequest();
-
ServletContextAttributeEvent:
ServletContext getServletContext();
String getName():获取属性名
Object getValue():获取属性值
-
HttpSessionBindingEvent
-
ServletRequestAttributeEvent
分类:
ServletContext对象监听器
HttpSession对象监听器
ServletRequest对象监听器
public class MyListener implements HttpSessionListener,
HttpSessionAttributeListener {
public void sessionCreated(HttpSessionEvent e) {
System.out.println("session创建");
System.out.println(e.getSession());
}
public void sessionDestroyed(HttpSessionEvent arg0) {
System.out.println("session销毁");
}
public void attributeAdded(HttpSessionBindingEvent arg0) {
System.out.println("向session添加数据");
}
public void attributeRemoved(HttpSessionBindingEvent arg0) {
}
public void attributeReplaced(HttpSessionBindingEvent arg0) {
}
}
<listener>
<listener-class>web.MyListener</listener-class>
</listener>
web.xml配置
<!-- 监听器配置 -->
<listener>
<listener-class>listener.OnlineCountListener</listener-class>
</listener>
注解配置
@WebListener
public class ListenerClass implements ListenerInterface{
}
例子
如何统计session个数? session生命周期,tomcat控制的
需要使用Session监听器
如何创建监听器?
实现监听器接口
如何配置监听器?
web.xml中配置监听器,或 使用注解
/**
* session生命周期监听器
* 在线人数统计
* 把人数放入application上下文
*
*/
@WebListener //注册监听器,告知容器
public class OnlineCountListener implements HttpSessionListener {
/**
* session被创建时执行这里
*/
public void sessionCreated(HttpSessionEvent se) {
HttpSession session = se.getSession();
System.out.println("============session创建了======="+session.getId());
//先获取上下文件对象
ServletContext application = session.getServletContext();
Integer count = (Integer)application.getAttribute("onlineCount");
if(count == null) {
count = 0;
}
// 一定不是null
count++;
application.setAttribute("onlineCount", count);
}
/**
* session被销毁时执行这里
*/
public void sessionDestroyed(HttpSessionEvent se) {
HttpSession session = se.getSession();
System.out.println("*************session销毁了======="+session.getId());
ServletContext application = session.getServletContext();
Integer count = (Integer)application.getAttribute("onlineCount");
if(count != null) {
count--;
}
application.setAttribute("onlineCount", count);
}
}
两小一大
子类返回类型小于等于父类方法返回类型,
子类抛出异常小于等于父类方法抛出异常,
子类访问权限大于等于父类方法访问权限。