监听器,监听某一个事件的发生或者某一个状态的改变,不论什么监听器的实现都是基于接口回调,监听器的内部机制就是接口回调。
没考虑回调的做法:
TestA.java
package com.nikehu.demo; public class TestA { public void print(){ for (int i = 0; i < 10; i++) { System.out.println("循环到了--"+i); if(i==5){ System.out.println("循环到了5了,该通知TestB"); TestB tb = new TestB(); tb.printFive(); } } } }TestB.java
package com.nikehu.demo; public class TestB { public void printFive(){ System.out.println("A已经循环到了5,所以TestB的这个方法将被调用"); } }需求:A在执行循环,当A触发某一事件时或,某一状态改变时通知B;
实现先把某一个对象传递给A,当A触发某一条件时,通过这个对象来调用B中的方法。不是直接传递B的实例,而是床底一个接口的实例过去。不能直接new B(),也不能传一个B的实例,A和B之间借助接口去联系上
TestA.java
package com.nikehu.demo; import com.nikehu.demo01.PrintListener; public class TestA { public void print(PrintListener p){ for (int i = 0; i < 10; i++) { System.out.println("循环到了--"+i); if(i==5){ System.out.println("循环到了5了,该通知监听器了"); p.print(); } } } }PrintListener.java
package com.nikehu.demo01; /** * 打印监视器 * @author 猪猪 * 1988 */ public interface PrintListener { /** * 一旦触发某一条件就调用这个方法 */ void print(); }TestB.java
package com.nikehu.demo; import com.nikehu.demo01.PrintListener; public class TestB implements PrintListener{ public void printFive(){ System.out.println("A已经循环到了5,所以TestB的这个方法将被调用"); } @Override public void print() { System.out.println("A已经循环到了5,所以TestB的这个方法将被调用"); } }Test01.java
package com.nikehu.demo; import org.junit.Test; import com.nikehu.demo01.PrintListener; public class Test01 { @Test public void test01(){ TestA ta = new TestA(); ta.print(new TestB()); } @Test public void test02(){ TestA ta = new TestA(); ta.print(new PrintListener(){ @Override public void print() { System.out.println("匿名内部类实现了Printlistener这个接口"); } }); } }Web监听器总共有8个,可以划分成三种各类型:
第一种:监听三个作用域创建和销毁
第二种:监听三个作用域属性状态变更
第三种:监听HttpSession里面存值的状态变更
作用域:pageContext,request,session,application
监听的是:
request,—HttpServletRequest—ServletRequestListener
session,—HttpSession—HttpSessionListener
application —ServletContext—ServletContextListener
ServletContext:
1.启动服务器的时候创建
2.关闭服务器或项目从服务器移除的时候销毁
如何注册监听器:
1.定义一个类实现接口
package com.nike.listener; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; public class MyServletContextListener implements ServletContextListener{ public void contextInitialized(ServletContextEvent sce) { System.out.println("ServletContextListener初始化了"); } public void contextDestroyed(ServletContextEvent sce) { System.out.println("ServletContextListener销毁了"); } }2.注册|配置监听器
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>listener01</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <listener> <listener-class>com.nike.listener.MyServletContextListener</listener-class> </listener> </web-app>HttpServletRequest
request创建:访问任何一个项目上的资源都会创建
访问html:会创建
访问jsp:会创建
访问servlet:会创建
request销毁:服务器已经对这次请求做出了响应,即销毁
package com.nike.listener; import javax.servlet.ServletRequestEvent; import javax.servlet.ServletRequestListener; public class MyRequestListener implements ServletRequestListener{ public void requestDestroyed(ServletRequestEvent sre) { System.out.println("HttpServletRequest创建了"); } public void requestInitialized(ServletRequestEvent sre) { System.out.println("HttpServletRequest销毁了"); } }HttpSession
session创建:request.getSession();
session销毁:超时,非正常关闭服务器
package com.nike.listener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; public class MySessionListener implements HttpSessionListener{ public void sessionCreated(HttpSessionEvent se) { System.out.println("HttpSession创建了"); } public void sessionDestroyed(HttpSessionEvent se) { System.out.println("HttpSession销毁了"); } }作用:ServletContextListener可以监听去我们的ServletContext在初始化的时候的状态,利用它来,在ServletContext创建的时候加载资源,初始引擎等初始化动作,执行自定义的任务调度。
HttpSessionListener可以统计在线人数
可以监听在作用域中值 添加 | 替换 | 移除的动作
request—ServletResquestAttributeListener
session—HttpSessionAttributeListener
servletContent— ServletContextAttributeListener
package com.nike.listener02; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; public class MySessionChangeListener implements HttpSessionAttributeListener{ public void attributeAdded(HttpSessionBindingEvent se) { System.out.println("session中添加属性"); System.out.println(se.getName()+","+se.getValue()); } public void attributeRemoved(HttpSessionBindingEvent se) { System.out.println("session中移除属性"); System.out.println(se.getName()+","+se.getValue()); } public void attributeReplaced(HttpSessionBindingEvent se) { System.out.println("session中替换属性"); System.out.println(se.getName()+","+se.getValue()); } }HttpSessionBindingListener :让JavaBean实现该接口
package com.nike.domain; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; public class Bean01 implements HttpSessionBindingListener{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public void valueBound(HttpSessionBindingEvent event) { System.out.println("值被绑定劲来了"); } public void valueUnbound(HttpSessionBindingEvent event) { System.out.println("解除绑定"); } }HttpSessionActivationListener :监听现在session的值是钝化和活化
钝化:序列化,把内存中的数据存储到硬盘上。
活化:反序列化,把硬盘中的数据读取到内存中。
package com.nike.domain; import java.io.Serializable; import javax.servlet.http.HttpSessionActivationListener; import javax.servlet.http.HttpSessionEvent; public class Bean02 implements HttpSessionActivationListener,Serializable { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public void sessionWillPassivate(HttpSessionEvent se) { System.out.println("session中的值被钝化了"); } public void sessionDidActivate(HttpSessionEvent se) { System.out.println("session中的值被活化了"); } }session钝化活化的用意何在:
session中的值可能会很多,并且我们有很长一段时间不使用这个值,因此可以考虑把session中的值存储到硬盘上,等下一次再用的时候,在从硬盘上提取出来。
如何设置session中的值在固定时间内钝化:
配置session钝化活化:
3种手法:
1.在tomcat服务器里面的 conf/context.xml 配置 ,对所有运行在该服务器上的项目生效
2.在tomcat服务器里面的 conf/Catalina/localhost中新建context.xml,对localhost域名生效
3.在自己的web项目中的META-INF中配置context.xml,只对当前项目生效
maxIdleSwap=“1”:1分钟不用即被钝化
directory=“it315”:钝化后文件存放的目录
<Context> <Manager className="org.apache.Catalina.session.PersistentManager" maxIdleSwap="1"> <Store className="org.apache.catalina.session.FileStore" directory="it315"/> </Manager> </Context>过滤器,就是对客户端发出的请求进行过滤,其实过滤器起到的是拦截的作用。
1.对一些敏感词汇进行过滤;
2.统一设置编码
3.自动登录
1.定义一个类实现Filter接口;
package com.nike.filter; 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; /** * Servlet Filter implementation class FilterDemo */ public class FilterDemo implements Filter { public void destroy() { // TODO Auto-generated method stub } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("来到了过滤器"); chain.doFilter(request, response); } public void init(FilterConfig fConfig) throws ServletException { // TODO Auto-generated method stub } }2.注册过滤器。在web.xml中注册,注册手段与Servlet一致。
<filter> <display-name>FilterDemo</display-name> <filter-name>FilterDemo</filter-name> <filter-class>com.nike.filter.FilterDemo</filter-class> </filter> <filter-mapping> <filter-name>FilterDemo</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>何时创建:在服务器启动时创建。
何时销毁:在服务器停止时销毁。
只要有一个filter不放行,请求就不能到达servlet。
chain.doFilter(request, response);//放行Filter的执行顺序与Filter注册时<filter-mapping>映射的注册先后顺序有关。
<filter-mapping> <filter-name>FilterDemo04</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>FilterDemo03</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>FilterDemo02</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>服务器响应的时候依旧会经过过滤器,顺序与请求的顺序相反。
1.init方法的参数FilterConfig,可以用于Filter在注册的名字,以及初始化参数。其实这里的设计初衷与ServletConfig一致
2.如果想放行,那么在doFilter方法里面操作,使用参数chain。
chain.doFilter(request, response);//放行,让请求到达下一个目标3.<url-pattern>/*</url-pattern> 写法格式与url-pattern一样。
(1).全路径匹配,以/匹配,如/LoginServlet;
(2).以目录匹配,以/开始,以*结束,如/demo01/*
(3).以后缀名匹配,以*开始,以后缀名结束,如*.jsp,*.do
(4).针对请求设置<dispatcher>:
REQUEST:只要是请求过来都拦截,默认设置
ERROR:页面出错发生跳转时拦截
FORWARD:只要是转发都拦截。
INCLUDE:包含页面就拦截
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> <form action="LoginServlet" method="post"> 账号:<input type="text" name="uname"><br/> 密码:<input type="password" name="upwd"><br/> <input type="checkbox" name="auto">自动登录<br/> <input type="submit" value="登录"> </form> </body> </html>LoginServlet.java
package com.nike.servlet; import java.io.IOException; import java.sql.SQLException; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import com.nike.dao.UserDao; import com.nike.dao.impl.UserDaoImpl; import com.nike.domain.User; /** * Servlet implementation class LoginServlet */ public class LoginServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); try { String uname = request.getParameter("uname"); String upwd = request.getParameter("upwd"); String auto = request.getParameter("auto"); UserDao userDao = new UserDaoImpl(); User u = new User(); u.setUname(uname); u.setUpwd(upwd); User user = userDao.login(u); if(user==null){ request.getRequestDispatcher("login.jsp").forward(request, response); }else{ if(auto!=null&&auto.equals("on")){ Cookie cookie = new Cookie("auto_login",user.getUname()+"#nike#"+user.getUpwd()); cookie.setMaxAge(7*24*60*60); //request.getContextPath() 获取当前应用的名字 cookie.setPath(request.getContextPath()); response.addCookie(cookie); } HttpSession session = request.getSession(); session.setAttribute("user", user); //request.getRequestDispatcher("index.jsp").forward(request, response);; response.sendRedirect("index.jsp"); } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }BeanUtils不支持日期类型,但他提供了一个方法注册转换器,用来将String转换成Date类型
自定义一个转化器实现Converter
package com.nike.utils; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import org.apache.commons.beanutils.Converter; /** * 自定义 java.util.Date日期转换器 * * */ public class MyDateConverter implements Converter { public Object convert(Class arg0, Object value) { String strVal = (String) value; // 将String转换为Date --- 需要使用日期格式化 DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); try { Date date = dateFormat.parse(strVal); return date; } catch (ParseException e) { e.printStackTrace(); } return null; } } package com.nike.servlet; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.Date; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.beanutils.ConvertUtils; import com.nike.bean.User; import com.nike.utils.MyDateConverter; /** * Servlet implementation class RegisterServlet */ public class RegisterServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); User user = new User(); try { //注册自己的转化器 ConvertUtils.register(new MyDateConverter(), Date.class); BeanUtils.populate(user, request.getParameterMap()); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(user); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!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> <h2>这是首页, <c:if test="${ not empty user }">欢迎你,${ user.uname }</c:if> <c:if test="${ empty user }"> <a href="login.jsp">欢迎您,请登录!</a> </c:if> </h2> </body> </html>过滤器实现自动登录
package com.nike.filter; import java.io.IOException; import java.sql.SQLException; 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.Cookie; import javax.servlet.http.HttpServletRequest; import com.nike.dao.UserDao; import com.nike.dao.impl.UserDaoImpl; import com.nike.domain.User; import com.nike.util.CookieUtils; /** * Servlet Filter implementation class AutoLoginFilter */ public class AutoLoginFilter implements Filter { /** * @see Filter#destroy() */ public void destroy() { // TODO Auto-generated method stub } /** * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain) */ public void doFilter(ServletRequest req, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("自动登录"); HttpServletRequest request = (HttpServletRequest)req; try { //先判断session中有没有user User user = (User) request.getSession().getAttribute("user"); System.out.println("自动登录1"); System.out.println(user+"----1"); if(user==null){ //session失效,关闭浏览器或session过了保存时长 //先从请求中获取cookie System.out.println("自动登录2"); Cookie[] cookies = request.getCookies(); Cookie cookie = CookieUtils.findCookie(cookies, "auto_login"); if(cookie!=null){ String value = cookie.getValue(); String uname = value.split("#nike#")[0]; String upwd = value.split("#nike#")[1]; System.out.println(value); User user1 = new User(); user1.setUname(uname); user1.setUpwd(upwd); UserDao dao = new UserDaoImpl(); user = dao.login(user1); //把用户信息存储到session中 request.getSession().setAttribute("user", user); } } } catch (SQLException e) { e.printStackTrace(); }finally{ chain.doFilter(request, response); } } /** * @see Filter#init(FilterConfig) */ public void init(FilterConfig fConfig) throws ServletException { // TODO Auto-generated method stub } }查找指定的cookie
package com.nike.util; import javax.servlet.http.Cookie; public class CookieUtils { /** * 获取指定内容的cookie * @param cookies * @param name * @return */ public static Cookie findCookie(Cookie[] cookies,String name){ if(cookies!=null){ for (Cookie cookie : cookies) { if(cookie.getName().equals(name)){ return cookie; } } } return null; } }