目录
Filter过滤器
1.什么是过滤器?
2.过滤器的使用场景
3.如何编写过滤器?
4.Filter接口的生命周期
5.Filter接口中的相关类介绍
6.多个过滤器的执行顺序
7.过滤器的四种拦截方式
Listener监听器
是什么
分什么
1.application监听器
2.Session监听器
3.request监听器
Filter过滤器
1.什么是过滤器?
Filter过滤器它是JavaWEB三大组件之一(Servlet应用程序、Listener监听器、Filter过滤器)
Filter过滤器它是JavaEE的规范,也就是接口。
Filter过滤器它的作用:拦截请求,过滤响应
它会在一组资源(jsp,servlet,.css,.html等)的前面执行
2.过滤器的使用场景
a.防止未登录就进入界面
b.控制应用编码
c.过滤敏感词汇等场景
3.如何编写过滤器?
a.自定义类实现Filter接口,重写接口中的抽象方法(3个)
b.在web.xml中进行配置<filter> <filter-name>DemoFilter</filter-name> <filter-class>com.zking.filter.DemoFilter</filter-class> </filter> <filter-mapping> <filter-name>DemoFilter</filter-name> <url-pattern>/as.do</url-pattern> </filter-mapping>
<url-pattern>/a.jsp</url-pattern>:你要拦截的内容是什么? <url-pattern>/*.jsp</url-pattern> <url-pattern>/*.do</url-pattern> <url-pattern>/*</url-pattern>
4.Filter接口的生命周期
void init(FilterConfig)
* 创建之后,马上执行:Filter会在服务器启动时就创建
void destory()
* 销毁之前执行!在服务器关闭时销毁
void doFilter(ServletRequest,ServletResponse,FilterChain)
* 每次过滤器时都会执行
5.Filter接口中的相关类介绍
FilterConfig---->与ServletConfig相似
* 获取初始化参数:getInitParameter
* 获取过滤器名称:getFilterName
* 获取application:getServletContextFilterChain
* doFilter(ServletRequest,ServletResponse):放行请求
6.多个过滤器的执行顺序
过滤器的执行顺序和url-pattern标签匹配的精确程度无关,只和他们的filter-mapping标签在web.xml文件中的顺序有关,靠上的配置的先执行。
7.过滤器的四种拦截方式(了解)
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>
这个配置中,b.jsp为目标资源。
当直接请求b.jsp时,会执行过滤器。
当转发到b.jsp页面时,会执行过滤器。
8.案例
1.自动登录package com.zking.servlet; 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; import com.zking.utils.CookieUtil; public class LoginFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; if(req.getRequestURI().contains("login.jsp")) {//如果访问login,直接放行 chain.doFilter(req, resp); return; }else { String username = (String) req.getSession().getAttribute("username"); if(username==null) {//sesion中没有,去Cookie中找 String val = CookieUtil.getCookieValByKey("auto", req); if(val!= null&& !val.equals("")) { String name = val.split("_")[0]; String pass = val.split("_")[1]; if("admin".equals(name) && "123".equals(pass)) {//重新验证登录 req.getSession().setAttribute("username", name);//登录成功,放入Session,并放行 chain.doFilter(req, resp); return; }else {//验证失败,重新登录 resp.sendRedirect("login.jsp"); } }else {//Cookie中也没有,第一次访问,跳转登录页面 resp.sendRedirect("login.jsp"); } }else {//session中有,放行 chain.doFilter(req, resp); return; } } } @Override public void destroy() { // TODO Auto-generated method stub } @Override public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub } }
package com.zking.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class LoginServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); String username = request.getParameter("username"); String password = request.getParameter("password"); String auto = request.getParameter("auto"); // 是否自动登录 if ("admin".equals(username) && "123".equals(password)) {// 如果登录成功 request.getSession().setAttribute("username", username); if (auto == null) {// 未勾选自动登录 Cookie cookie = new Cookie("auto", null); cookie.setMaxAge(60 * 60 * 24);// cookie有效时间 response.addCookie(cookie); } else {// 勾选自动登录 Cookie cookie = new Cookie("auto", username + "_" + password); cookie.setMaxAge(60 * 60 * 24);// cookie有效时间 response.addCookie(cookie); } // 登录成功,跳转 response.sendRedirect("index.jsp"); } else { // 未登录成功,重新登录 response.sendRedirect("login.jsp"); } } }
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> 欢迎你:${sessionScope.username } </body> </html>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html> <head> <meta charset = "utf-8" /> <title>Title</title> </head> <body> <form method="post" action="login.do"> 用户名:<input type="text" name="username"><br> 密码:<input type="text" name="password"><br> 自动登录:<input type="checkbox" name="auto" value="auto"><br> <input type="submit" value="登录"> </form> </body> </html>
2.解决全站字符乱码(POST和GET中文编码问题)
Filter传给后面Servlet的Request对象肯定不能是原先的,不然request.getParameter()还是会乱码
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; // 拦截所有的请求,解决全站中文乱码 // 指定request和response的编码 request.setCharacterEncoding("utf-8");//只对消息体有效 response.setContentType("text/html;charset=utf-8"); // 对request进行包装 CharacterRequest characterRequest = new CharacterRequest(request); // 放行 chain.doFilter(characterRequest, response); } public void init(FilterConfig fConfig) throws ServletException { } }
//继承,默认包装类HttpServletRequestWrapper
class CharacterRequest extends HttpServletRequestWrapper{ private HttpServletRequest request; public CharacterRequest(HttpServletRequest request) { super(request); this.request=request; }
// 子类继承父类一定会重写一些方法,此处用于重写
public String getParameter(String name) { // 调用包装对象的getParameter()方法,获得请求参数 String value = super.getParameter(name); if(value==null) { return null; } // 判断请求方式 String method = super.getMethod(); if("get".equalsIgnoreCase(method)) { try { value = new String(value.getBytes("iso-8859-1"),"utf-8"); } catch(UnsupportedEncodingException e){ throw new RuntimeException(e); } } // 解决乱码后返回结果 return value; }
Listener监听器
是什么???
主要功能是负责监听Web的各种操作,当相关的事件触发后将产生事件,并对事件进行处理。
分什么???
监听器分为3种:
application监听器
session监听器
request监听器事件:点击、移动、键盘、触摸
1.application监听器 servlet---ServletContext
实现:ServletContextListener (常用)
重写://容器启动时调用 public void contextInitialized(ServletContextEvent event){ } //容器消毁时调用 public void contextDestroyed(ServletContextEvent event){ } ServletContextEvent事件方法: .getServletContext() //取得ServletContext对象,即上下文
例示:
event.getServletContext().getContextPath();
2.Session监听器
实现:HttpSessionListener (偶尔用)
重写:
//session创建时调用 public void sessionCreated(HttpSessionEvent event){ } //session销毁时调用 public void sessionDestroyed(HttpSessionEvent event){ } HttpSessionEvent事件方法: .getSession() //取得当前的session 例示: event.getSession().getId(); //得到session的ID 实现:HttpSessionAttributeListener (不用,性能差) 重写: //增加属性时触发 public void attributeAdded(HttpSessionBindingEvent event){ } //删除属性时触发 public void attributeRemoved(HttpSessionBindingEvent event){ } //替换属性时触发 public void attributeReplaced(HttpSessionBindingEvent event){ }
HttpSessionBindingEvent事件方法:
.getSession() //取得session
.getName() //取得属性的名称
.getValue() //取得属性的内容
例示:
event.getSession() //取得session
event.getName() //取得属性的名称
event.getValue() //取得属性的内容
3.request监听器
实现:ServletRequestListener (不用,性能差)
重写://请求开始时调用 public requestInitialized(ServletRequestEvent event){ } //请求结束时调用 public requestDestroyed(ServletRequestEvent event){ }
ServletRequestEvent事件方法:
.getServletRequest() //取得ServletRequest对象
.getServletContext() //取得ServletContext对象
例示:
event.getServletRequest().getRemoteAddr(); //得到IP地址
event.getServletContext().getContextPath(); //得到当前路径
=======================================================================
为什么说session监听器和request监听器一般都不用?
答:以request监听器为例,如果采用request监听,那就意味着每次请求都要触发一次监听,这大大降低了程率的效率,因此很少用。
=======================================================================
web.xml
<listener>
<listener-class>com.listener.Application</listener-class>
</listener>
实例:监听在线人数
分析:创建一个会话就+1,销毁了会话则-1
(在会话被创建时,往全局变量中+1;会话被关闭时,全局变量-1)
服务器停止则移除 count
public class AppListrener implements ServletContextListener,HttpSessionListener { ServletContext app=null; //容器销毁时调用 public void contextDestroyed(ServletContextEvent sce) { // TODO Auto-generated method stub System.out.println("容器销毁了"); } //容器初始化时调用 public void contextInitialized(ServletContextEvent sce) { // TODO Auto-generated method stub System.out.println("容器初始化了"); app=sce.getServletContext(); Integer count=0; app.setAttribute("cut", count); System.out.println(count+"___"); } //session创建时调用 public void sessionCreated(HttpSessionEvent arg0) { // TODO Auto-generated method stub System.out.println("session创建时调用"); Integer count=(Integer)app.getAttribute("cut"); if(count==null){ count=0; } count++; System.out.println("创建时:"+count); app.setAttribute("cut", count); } //session销毁时调用 public void sessionDestroyed(HttpSessionEvent arg0) { // TODO Auto-generated method stub System.out.println("session销毁时调用"); Integer count=(Integer)app.getAttribute("cut"); if(count==null){ count=0; } count--; System.out.println("注销时:"+count); app.setAttribute("cut", count); } web.xml <listener> <listener-class>com.servlet.AppListrener</listener-class> </listener> http://193.168.2.224:8080/listenerDemo/index.jsp