java-listener&filter(监听和过滤)

01_Filter的概述
Filter也称之为过滤器,Filter是Servlet技术中最激动人心的技术,
Filter可以管理WEB服务器中所有的WEB资源,
Filter可以对JSP,Servlet,HTML,以及图片文件等进行拦截和过滤,
Filter常用于实现一些特殊的功能,比如访问权限的控制,敏感词汇的过滤,乱码的处理等等,
Filter其实就是一个特殊的Servlet,
Servlet API提供了Filter接口,在WEB项目中,一个Java类实现了Filter接口,那这个Java类他就是Filter过滤器,
Filter其实就是在用户访问目标资源之前,对请求和响应进行拦截过滤和处理。

Filter,Listener 是Servlet规范中的两个高级的特性.他是不同于Servlet,他们不用于处理客户端请求
只用于对request,response进行修改或者对Context,session,request事件进行监听
可以为我们的Servlet提供一些额外的辅助性的功能,帮助我们简化开发

Filter过滤器 2层含义
第一个是让不让你过(检验用户是否登录)
第二个是改变你中间的内容(统一全站字符编码,替换敏感词汇)

Filter作用
在HTTPServletRequest到达Servlet之前,拦截用户的HTTPServletRequest
根据需要检查HTTPServletRequest,也可以修改HTTPServletRequest头和数据
在HTTPServletResponse到达Servlet之前,拦截用户的HTTPServletResponse
根据需要检查HTTPServletResponse,也可以修改HTTPServletResponse头和数据


02_Filter的入门案例 
在WEB项目中创建一个Java类,
让该类实现javax.servlet.Filter接口,
在该类中实现Filter接口的所有方法,
在web.xml文件中进行相关的配置。

Filter是一个特殊的Servlet,他的配置和Servlet是一样的
他和Servlet的本质区别 他不能产生一个请求或者响应,他只能拦截或者是修改某一资源的请求和响应

注意:
必须要实现javax.Servlet.Filter接口,需要在web.xml中进行配置才能生效
Filter和特定的url关联,当用户访问此url的时候,才会触发Filter调用doFilter这个方法





03_Filter的生命周期
创建
Filter对象在WEB服务器启动的时候,由WEB服务器帮我们创建
init()
销毁
Filter对象在WEB服务器关闭的时候会被销毁
destory()
Filter生命周期和Servlet生命周期是一样的,他们都提供了 init()和destroy()方法来控制
当web服务器启动的时候,就会自动调用init()方法对Filter进行初始化
当关闭服务器,关机,或者reload整个应用的时候,都会调用destroy()方法来销毁filter

总结:
当web服务器启动的时候,filter就会被加载到内存,并且在destroy()方法调用之前都常驻内存



04_Filter链
在同一个WEB应用中,可以开发编写多个Filter,那这多个Filter组成了一个链子,这个链子我们就称之为Filter链,
WEB服务器在执行Filter链的时候,会根据Filter在web.xml文件中的配置顺序来执行。

注意:
1,多个filter对同一个资源进行过滤的时候,他其实是按照他在web.xml里面的配置顺序,从上到下进行执行的
2,要访问到最后的web资源,需要所有的filter都放行,如果有一个没有放行,用户是无法访问最后的web资源


05_获取Filter的初始化参数
在web.xml文件中,可以通过<init-param>标签来为Filter配置初始化参数,
WEB服务器在创建Filter对象的时候,会调用Filter对象的init方法,并且将封装了Filter初始化参数的FilterConfig对象传递进去,
在Filter的init方法中,就可以通过FilterConfig对象来获取Filter的初始化参数。


06_统一全站字符编码01
制造乱码
服务器端响应数据的乱码
获取客户端请求数据的乱码




07_统一全站字符编码02
EncodingFilter
拦截post请求的乱码问题
对于请求的乱码问题(表单提交的数据乱码问题)         request.setCharacterEncoding("UTF-8");
对于响应的乱码问题(服务器向浏览器发送数据乱码问题) response.setContentType("text/html;charset=UTF-8");

模板设计模式:
并不是重新创建一个对象,而是在原有对象基础上给他做一个增强
所以在方法中必须拿到原有对象的引用,你才能对他进行一个增强,做一个包装

步骤:
声明一个包装类 实现 和被包装类 同样的接口
在包装类中,声明有参的构造,去拿到被包装类的引用
在方法中,对被包装类做一个增强

例如: IO 基本流 缓冲区流(基本流)

  


08_统一全站字符编码03
MyHttpServletRequest 
对传入的请求做一个增强(包装的方法),解决get请求的乱码问题

注意:
setCharacterEncoding方法处理不了get请求的乱码问题
get请求需要把获取到的数据打回原形,再用正确的编码拼接.关键是在什么时候打回原形
也就在获取到请求过来的参数之后,也就是调用request.getParamter()方法的时候
这个时候先获取到一个错误的字符串,在把这个错误的字符串打回原形,在用正确的编码拼接成一个新的字符串
思考: 可以把打回原形,并且重新拼接这个功能放到getParamter()方法这个方法里面去做.其实也就是对这个方法做一个增强



09_统一全站字符编码04
使用filter的初始化参数来设置编码



10_校验用户是否登录1
先实现登录和注销的功能
准备用户数据
LoginServlet
LogoutServlet



11_校验用户是否登录2
登录页面
首页 
重要的web资源



12_校验用户是否登录3
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = null;
HttpServletResponse resp = null;

req = (HttpServletRequest) request;
resp = (HttpServletResponse) response;

//获取session对象
HttpSession session = req.getSession();
Object obj = session.getAttribute("user");

//判断用户是否登陆
if(obj != null) {
//用户登陆,放行
chain.doFilter(req, resp);
}
else {
//用户没有登陆,给出提示并且跳转到登陆页
PrintWriter out = resp.getWriter();
out.println("请先登陆!3秒后跳转到登陆页面");
resp.setHeader("Refresh", "3;URL=/myFilter/login.jsp");
}

}



01_监听器的概述
概述
是一个实现了特定接口的普通Java类,用于监听其他对象的创建和销毁,监听其他对象的方法执行和属性改变,
被监听的对象如果发生了上述的事件,监听器的某个方法就会立刻的执行。
作用
监听(监视,观察)其他对象所发生的变化,主要用于图形化界面的程序员,比如Java的GUI,Android,IOS。

三个要素
事件源:被监听的对象
监听器:用来监听事件源,简单理解为事件处理程序. 3个域对象要创建或者销毁的时候,都会执行事件监听程序进行相应的处理
ServletContext 创建的时候,我们就可以初始化一些整个应用都用到的参数 等ServletContext被销毁的时候 
我们可以执行整个应用的保存工作,收尾工作
事件:就是发生的那件事,创建和销毁的这件事 当这件事发生的时候,我们的监听程序就应该被执行

三个步骤
1.要有事件源
2,搞一个监听器(写事件的处理处理程序)
3,把事件和监听器绑定到一起
今天3类 8 种监听器
第一类: 3个 监听域对象的创建和销毁
第二类: 3个 监听3个域对象存数据,取数据,删除数据这种状态
第三类: 2个 监听javaBean自己的状态 

02_监听器入门案例
public static void main(String[] args) {   //GUI 
//创建窗口对象
Frame f = new Frame();
//设置窗口可见
f.setVisible(true);
//设置窗口的宽和高
f.setSize(500, 500);
//为窗口对象绑定监听器
//f.addWindowListener(new MyWindowListener());
//f.addWindowListener(new MyInnerWindowListener());
f.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
e.getWindow().dispose();
}
});


}

new 类名/接口名(){} 创建了一个继承该类或者实现了该接口的子类对象
事件源:窗口
事件 点击 X 这件事
事件处理程序: 监听器


03_自定义监听器
Student (事件源)
eat();
sleep();
addStudentListener(StudentListener listener);

StudentListener (监听器)
preEat();
preSleep();

事件源:Student
监听器:StudentListener接口的实现类
事件:学生调用了吃饭和睡觉的方法

04_Servlet中的监听器


Servlet规范为我们提供了8个监听器。

监听域对象的创建和销毁
ServletContextListener
HttpSessionListener
ServletReqestListener
监听域对象中属性的变化
ServletContextAttributeListener
HttpSessionAttributeListener    -----------站在session的立场上,绑定是session
ServletRequestAttributeListener
编写步骤
创建一个普通的Java类
让该类实现监听器的接口
在该类中实现监听器接口的所有方法
在web.xml文件中通过<listener>标签来配置(注册)监听器----绑定

帮助JavaBean对象感知自己在session域对象中的状态  ----------站在javaBean的立场,绑定是javaBean
HttpSessionBindingListener
帮助javaBean对象感知自己在session对象中的绑定和解绑 ,也就是感知javabean对象被添加到session对象中和被删除2种状态
HttpSessionActivationListener
帮助javaBean对象感知自己在session对象中被钝化或者恢复

注意:这两个特殊的监听器不需要在web.xml文件中配置,让JavaBean实现这两个接口就可以了


05_监听域对象的创建和销毁
ServletContextListener
HttpSessionListener
ServletReqestListener

ServletContext生命周期:应用被加载或者服务器启动的时候被创建,服务器关闭的时候才销毁
HttpSession生命周期:会话开始的时候创建,超时30分钟,非正常关闭,或者调用invalidate方法才销毁
ServletReqest生命周期:一次请求开始的时候创建,响应结束之后就销毁了
 
一个对象有没有用跟他所处的位置有很大关系的
对于ServletContext 他可以做一些应用级别的数据保存,或者是定时发送东西这些功能
每年过生日,生日邮件 (定时的任务) 这个调度任务,我们就可以在ServletContext中配置,然后每天执行
每天晚上,我们的运营数据需要备份, 也可以在里面进行配置
对于HttpSession 可以用在购物车 可以在session销毁的时候,保存购物车中的数据到数据库 
对于ServletReqest 因为他的创建太频繁了,所欲这个监听器没什么用
 



06_监听域对象中属性的变化
ServletContextAttributeListener
HttpSessionAttributeListener
ServletRequestAttributeListener


    注意:
1,点击红色按钮是关闭 不正常操作  session对象不会被钝化到硬盘里面,
2,重启Tomcat是一个正常的操作,session对象以及他里面的数据会被钝化到硬盘上,重启之后,,session对象以及他里面的数据会被恢复
不会创建新的session对象


07_JavaBean的感知监听器
绑定:添加到session域对象中
解绑:从session域对象中删除

注意:
直接让User类实现HttpSessionBindingListener,HttpSessionActivationListener接口,相当于进行了一个绑定
不需要在web.xml中进行配置



08_统计在线用户数分析 统计某个页面访问量
计数器
可以把计数器保存在ServletContext域对象当中
计数器的默认值是0
如果session域对象创建了,那我们认为用户在线了,计数器就需要+1
如果session域对象销毁了,那我们认为用户离线了,计数器就需要-1

在线
一个用户有了自己的session对象,我们就认为这个用户在线了
离线
一个用户手动销毁自己的session对象,获取超时了,那我们就认为这个用户离线了

区别:
 统计某个页面访问量   count +1 
 用户在线数    访问一个页面很多次,只算1次




09_统计在线用户数
//监听ServletContext域对象的创建
    public void contextInitialized(ServletContextEvent sce)  { 
        //获取ServletContext域对象
    ServletContext context = sce.getServletContext();
    //初始化计数器
    context.setAttribute("count", 0);
    }

//监听session域对象的创建
public void sessionCreated(HttpSessionEvent se)  { 
         //获取ServletContext对象
    ServletContext context = se.getSession().getServletContext();
    //获取计数器
    Object obj = context.getAttribute("count");
    int count = Integer.parseInt(obj.toString());
    //使用计数器进行加一的操作
    count++;
    //覆盖替换计数器的值
    context.setAttribute("count", count);
    }

//监听session域对象的销毁
public void sessionDestroyed(HttpSessionEvent se)  { 
       ServletContext context = se.getSession().getServletContext();
       Object obj = context.getAttribute("count");
       int count = Integer.parseInt(obj.toString());
       count--;
       context.setAttribute("count", count);
    }
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值