javaEE包括13门规范 在课程中主要学习 servlet技术 和 jsp技术
其中 servlet规范包括三个技术点:servlet listener filter
【监听器 Listener】
1.什么是监听器?
监听器就是监听某个对象的的状态变化的组件
监听器的相关概念:
事件源:被监听的对象 ----- 三个域对象 request session servletContext
监听器:监听事件源对象 事件源对象的状态的变化都会触发监听器 ---- 6+2
注册监听器:将监听器与事件源进行绑定
响应行为:监听器监听到事件源的状态变化时 所涉及的功能代码 ---- 程序员编写代码
2.监听器(接口)有哪些?
3.监听三大域对象的创建与销毁的监听器编写步骤(重点):
a、编写一个监听器类去实现监听器接口
b、覆盖(重写)监听器的方法
c、需要在web.xml中进行配置---注册
例子:银行每隔24小时就要计算利息一次
package com.bwf.listener;
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import com.sun.beans.util.Cache;
public class MyServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("ServletContext创建了");
// 获得触发事件的域对象
// sce.getServletContext();
// 银行系统, 每天的24点计息一次
// 想获得明天的0点的date
Calendar time = Calendar.getInstance();
time.add(Calendar.DATE, 1);
time.set(Calendar.HOUR, 0);
time.set(Calendar.MINUTE, 0);
time.set(Calendar.SECOND, 0);
time.set(Calendar.MILLISECOND, 0);
// void scheduleAtFixedRate(TimerTask task, Date firstTime, long period)
// 安排指定的任务在指定的时间开始进行重复的固定速率执行。
new Timer().scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
System.out.println("银行计息拉");
}
}, time.getTime(), 24 * 60 * 60 * 1000);
}
// 获得24小时以后的时间,不能这么写,这样的话主线程休眠24小时了
// public static Date get24(){
// try {
// Thread.sleep(24 * 60 * 1000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// return new Date();
// }
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("ServletContext销毁了");
}
}
配置文件(注册监听器):
<listener>
<listener-class>com.bwf.listener.MyServletContextListener</listener-class>
</listener>
4.监听三大域对象的属性变化的
(1)域对象的通用的方法:
setAttribute(name,value)
--- 触发添加属性的监听器的方法
--- 触发修改属性的监听器的方法
removeAttribute(name)
--- 触发删除属性的监听器的方法
getAttribute(name)
(2)ServletContextAttibuteListener监听器
attributeAdded
attributeRemoved
attributeReplaced
这里以ServletContextAttributeListener为例:
写一个监听类实现ServletContextAttributeListener接口,重写attributeAdded,attributeRemoved,attributeReplaced三个方法
package com.bwf.listener;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
public class MyServletContextAttrListener implements ServletContextAttributeListener {
@Override
public void attributeAdded(ServletContextAttributeEvent scae) {
System.out.println("添加了一个属性");
// 获得域对象
ServletContext context = scae.getServletContext();
// 添加的属性名
String name = scae.getName();
// 添加的值
Object value = scae.getValue();
System.out.println("name = " + name + " value = " + value);
}
@Override
public void attributeRemoved(ServletContextAttributeEvent scae) {
//这个方法传入的k-v是原来的
System.out.println("删除了一个属性");
// 移除的属性名
String name = scae.getName();
// 移除的属性值
Object value = scae.getValue();
System.out.println("name = " + name + " value = " + value);
}
@Override
public void attributeReplaced(ServletContextAttributeEvent scae) {
System.out.println("修改了一个属性");
// 添加的属性名
String name = scae.getName();
// 原来的值
Object value = scae.getValue();
// 新的值
Object value2 = scae.getServletContext().getAttribute(name);
System.out.println("name = " + name + " value = " + value);
System.out.println("value2 = " + value2);
}
}
并在web.xml文件中注册监听器
<listener>
<listener-class>com.bwf.listener.MyServletContextAttrListener</listener-class>
</listener>
监听器买好了,接下来就是创建一个被监视者(这个监视者要对servletcontext域对象的内容产生过改变)
package com.bwf.servlet;
import java.io.IOException;
import java.util.Random;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/t1")
public class Test1Servlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 往ServletContext中放入一个数据(随机数)
getServletContext().setAttribute("num", new Random().nextInt(100));
}
}
可以看到,如果多次访问了t1这个servlet的doGet方法,那么监听器第一次会调用attributeAdded方法,后面都是调用attributeReplaced方法
添加了一个属性
name = num value = 81
修改了一个属性
name = num value = 81
value2 = 84
修改了一个属性
name = num value = 84
value2 = 84
修改了一个属性
name = num value = 84
value2 = 45
修改了一个属性
name = num value = 45
value2 = 93
修改了一个属性
name = num value = 93
如果servletContext调用removeAttribute方法,那么监视器会调用attributeRemoved方法
// 从ServletContext中移除一个数据
getServletContext().removeAttribute("num");
(3) HttpSessionAttributeListener监听器(同上)
(4) ServletRequestAriibuteListenr监听器(同上)
5.与session中的绑定的对象相关的监听器(对象感知监听器)
(1)即将要被绑定到session中的对象有几种状态
绑定状态:就一个对象被放到session域中
解绑状态:就是这个对象从session域中移除了
钝化状态:是将session内存中的对象持久化(序列化)到磁盘
活化状态:就是将磁盘上的对象再次恢复到session内存中
(2)绑定与解绑的监听器HttpSessionBindingListener
(3)钝化与活化的监听器HttpSessionActivationListener
实例:user类实现了序列化接口,绑定解绑接口,钝化活化接口,并重写相关方法
package com.bwf.bean;
import java.io.Serializable;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
import javax.servlet.http.HttpSessionEvent;
public class User implements HttpSessionBindingListener, HttpSessionActivationListener, Serializable{
private String name;
private int age;
public User() {
super();
}
public User(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User [name=" + name + ", age=" + age + "]";
}
// 绑定 - 被放到session去了
@Override
public void valueBound(HttpSessionBindingEvent event) {
System.out.println("我叫" + name + ", 我被 " + event.getSession().getId() + " session绑定了");
System.out.println(hashCode());
}
// 解绑 - 从session中被移除
@Override
public void valueUnbound(HttpSessionBindingEvent event) {
System.out.println("我叫" + name + ", 我被 " + event.getSession().getId() + " session解绑了");
}
// 钝化
@Override
public void sessionWillPassivate(HttpSessionEvent se) {
System.out.println("我叫" + name + ", 我会回来的!");
}
// 活化
@Override
public void sessionDidActivate(HttpSessionEvent se) {
System.out.println("我叫" + name + ", 我又活了!");
}
}
t3的servlet往session中放入数据
// 往Session中放入一个User对象
User u1 = new User("张三", 18);
User u2 = new User("李四", 19);
request.getSession().setAttribute("user", u2);
可以看到,u2放入session(u1并没有放入)时调用了绑定方法
过了1分钟后,调用了钝化方法,把对象从内存放入了硬盘(持久化)
session里移除该对象
// 往Session中解绑user
request.getSession().removeAttribute("user");
会先调用活化方法,把它从硬盘恢复到内存,再调用解绑方法
面试题:当用户很多时,怎样对服务器进行优化?
# 可以通过配置文件 指定对象钝化时间 --- 对象多长时间不用被钝化
在META-INF下创建一个context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<!-- maxIdleSwap:session中的对象多长时间不使用就钝化 -->
<!-- directory:钝化后的对象的文件写到磁盘的哪个目录下 配置钝化的对象文件在 work/catalina/localhost/钝化文件 -->
<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
<Store className="org.apache.catalina.session.FileStore" directory="bwf" />
</Manager>
</Context>
【过滤器 Filter】
1.filter的简介
filter是对客户端访问资源的过滤,
符合条件放行,
不符合条件不放行,
并且可以对目标资源访问前后进行逻辑处理
2. 快速入门
步骤:
- 编写一个过滤器的类实现Filter接口
- 实现接口中尚未实现的方法(着重实现doFilter方法)
- 在web.xml中进行配置(主要是配置要对哪些资源进行过滤)
3.Filter的API
(1)filter生命周期及其与生命周期相关的方法
Filter接口有三个方法,并且这个三个都是与Filter的生命相关的方法
init(Filterconfig):代表filter对象初始化方法 filter对象创建时执行
doFilter(ServletRequest,ServletResponse,FilterCha):
代表filter执行过滤的核心方法,如果某资源在已经被配置到这个filter进行过滤的话
那么每次访问这个资源都会执行doFilter方法
destory():代表是filter销毁方法 当filter对象销毁时执行该方法
Filter对象的生命周期:
Filter何时创建:服务器启动时就创建该filter对象
Filter何时销毁:服务器关闭时filter销毁
(2)Filter的AP详解
1)init(FilterConfig)
其中参数config代表 该Filter对象的配置信息的对象,内部封装是该filter的配置信息。
2)destory()方法
filter对象销毁时执行
3)doFilter方法
doFilter(ServletRequest,ServletResponse,FilterChain)
其中的参数:
ServletRequest/ServletResponse:每次在执行doFilter方法时web容器负责创建一个request和一个response对象作为doFilter的参数传递进来.该request和该response就是在访问目标资源的service方法时的request和response。
FilterChain:过滤器链对象,通过该对象的doFilter方法可以放行该请求
package com.bwf.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;
public class Filter1 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("创建了过滤器");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("过滤方法");
// 放行
chain.doFilter(request, response);
}
@Override
public void destroy() {
System.out.println("销毁了过滤器");
}
}
4.Filter的配置(2.5下用xml文件进行配置,3.0用@WebFilter注解进行配置)
url-pattern配置时
1)完全匹配 /sertvle1
2)目录匹配 /aaa/bbb/* ----最多的
/user/*:访问前台的资源进入此过滤器
/admin/*:访问后台的资源时执行此过滤器
3)扩展名匹配 *.abc *.jsp
注意:url-pattern可以使用servlet-name替代,也可以混用
例1:2.5servlet下,配置xml文件,对/s1路径的访问进行过滤
<filter>
<filter-name>filter1</filter-name>
<filter-class>com.bwf.filter.Filter1</filter-class>
</filter>
<filter-mapping>
<filter-name>filter1</filter-name>
<url-pattern>/s1</url-pattern>
</filter-mapping>
例2:3.0servlet下,注解方式
@WebFilter(dispatcherTypes = {DispatcherType.REQUEST }
, urlPatterns = { "/login" })
# dispatcher:访问的方式
REQUEST:默认值,代表直接访问某个资源时执行filter
FORWARD:转发时才执行filter
INCLUDE: 包含资源时执行filter
ERROR:发生错误时 进行跳转是执行filter
实战:写一个过滤器,实现:解决全局下doGet方法获得参数的中文乱码
带过滤器的访问流程
思路:
写一个装饰模式,servlet有专门用于继承的类,用来写装饰模式,这里用到HttpServletRequestWrapper类
继承该类,并重写里面的getParameter方法
package com.bwf.filter;
import java.io.UnsupportedEncodingException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public class Utf8Request extends HttpServletRequestWrapper {
public Utf8Request(HttpServletRequest request) {
super(request);
}
@Override
public String getParameter(String name) {
// 先拿出原来的数据 -> 乱码
String parameter = super.getParameter(name);
String res = parameter;
try {
res = new String(parameter.getBytes("ISO-8859-1"), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return res;
}
}
写一个过滤器,利用装饰模式强化的getParameter方法,对request参数进行过滤,这个过滤器用@WebFilter注解建立映射关系
package com.bwf.filter;
import java.io.IOException;
import javax.servlet.DispatcherType;
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.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
@WebFilter(dispatcherTypes = {DispatcherType.REQUEST }
, urlPatterns = { "/login" })
public class EncodingFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// request 参数就是后面Servlet会拿到的request
// 希望增强
// 把request包装一下
Utf8Request nRequest = new Utf8Request((HttpServletRequest) request);
//放行
chain.doFilter(nRequest, response);
}
public void init(FilterConfig fConfig) throws ServletException {
}
public void destroy() {
}
}