Listener && Filter
来源:互联网 发布:修改默认ssh端口 编辑:程序博客网 时间:2024/06/06 00:07
一、Listener监听器
1、javaweb开发中的监听器,是用于监听web常见对象
2、HttpServletRequest HttpSession ServletContext
3、监听它们的创建与销毁,属性变化,session绑定javaBean
4、监听机制
事件 就是一个事情
事件源 产生这个事情的源头
监听器 用于监听指定的事件的对象
注册监听 要想让监听器可以监听到事件产生,必须对其进行注册
5、javaweb开发中常见监听器
- 监听域对象的创建与销毁
- 监听ServletContext创建与销毁 ServletContextListener
- 监听HttpSession创建与销毁 HttpSessionListener
- 监听HttpServletRequest创建与销毁 ServletRequestListener
- 监听域对象的属性变化
- 监听ServletContext属性变化 ServletContextAttributeListener
- 监听HttpSession属性变化 HttpSessionAttributeListener
- 监听HttpServletRequest属性变化 ServletRequestAttributeListener
- 监听Session绑定javaBean
- 它是用于监听javaBean对象是否绑定到了session域 HttpSessionBindingListener
- 它是用于监听javaBean对象的活化与钝化 HttpSessionActivationListener (服务器停止后Session数据内否恢复)
6、监听器的快速入门
- 关于创建一个监听器的步骤
- 创建一个类,实现指定的监听器接口
- 重写接口中的方法
- 在web.xml文件中对监听器进行注册
7、关于域对象创建与销毁的演示
1、ServletContext对象的创建与销毁
这个对象是在服务器启动时创建的,在服务器关闭时销毁的
<listener>
<listener-class>com.itheima.listener.MyServletContextListener</listener-class>
</listener>
publicclassMyServletContextListenerimplementsServletContextListener{
publicvoidcontextInitialized(ServletContextEventsce) {
System.out.println("ServletContext对象创建了");
}
publicvoidcontextDestroyed(ServletContextEventsce) {
System.out.println("ServletContext对象销毁了");
}
}
2、HttpSession对象的创建与销毁
HttpSession session = request.getSession();
Session 销毁:
1、默认超时 30分钟
2、关闭服务器
3、invalidate()方法
4、setMaxInactiveInterval(int interval) 可以设置超时时间
问题:直接访问一个jsp页面时,是否会创建session?
会创建,因为我们默认情况下时可以在jsp页面中直接使用session内置对象的
<listener>
<listener-class>com.itheima.listener.MyHttpSessionListener</listener-class>
</listener>
publicclassMyHttpSessionListenerimplementsHttpSessionListener {
publicvoidsessionCreated(HttpSessionEventse) {
System.out.println("HttpSession对象创建了");
}
publicvoidsessionDestroyed(HttpSessionEventse) {
System.out.println("HttpSession对象销毁了");
}
}
3、HttpServletRequest创建与销毁
Request对象是发送请求服务器就会创建它,当响应产生时,request对象就会销毁
<listener>
<listener-class>com.itheima.listener.MyServletRequestListener</listener-class>
</listener>
publicclassMyServletRequestListenerimplementsServletRequestListener {
publicvoidrequestDestroyed(ServletRequestEventsre) {
System.out.println("ServletRequest销毁了");
}
publicvoidrequestInitialized(ServletRequestEventsre) {
System.out.println("ServletRequest创建 了");
}
}
8、演示Request域对象中属性变化
在java的监听机制中,它的监听器中的方法都是有参数的,参数就是事件对象,而我们可以通过事件对象直接获取事件源。
publicclassMyServletRequestListenerimplements
ServletRequestAttributeListener {
publicvoidattributeAdded(ServletRequestAttributeEventsrae) {
System.out.println("ServletRequest添加属性了");
}
publicvoidattributeRemoved(ServletRequestAttributeEventsrae) {
System.out.println("ServletRequest移除属性了");
}
publicvoidattributeReplaced(ServletRequestAttributeEventsrae) {//参数代表事件源对象
System.out.println("ServletRequest替换属性了");
System.out.println(srae.getName()+"\t"+srae.getValue());
}
}
9、演示session绑定javaBean
1、javaBean对象自动感知被绑定到session中
HttpSessionBindingListener 这个接口是由javaBean实现的,并且不需要在web.xml文件中注册
publicclassUserimplementsSerializable, HttpSessionBindingListener{
privateStringname;
privateintage;
publicvoidvalueBound(HttpSessionBindingEventevent) {
System.out.println("user对象被绑定了");
}
publicvoidvalueUnbound(HttpSessionBindingEventevent) {
System.out.println("user对象解除被绑定了");
}
}
2、javabean对象可以活化或钝化到session中
HttpSessionActivationListener 如果javaBean实现了这个接口,那么当我们正常关闭服务器时,session中javaBean对象就回被钝化到我们指定的文件中。当下一次再启动服务器,因为我们已经将对象写入到文件中,这是就会自动将javaBean对象活化到session中
<%
//session.invalidate();//使session销毁
/*request.setAttribute("name", "tom");
request.setAttribute("name", "jerry");
request.removeAttribute("name"); */
session.setAttribute("u",newUser());
session.removeAttribute("u");
%>
我们还需要个context.xml文件来配置钝化时存储的文件
在meta-inf目录下创建一个context.xml文件
<Context>
<Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
<Store className="org.apache.catalina.session.FileStore" directory="it315"/>
</Manager>
</Context>
10、定时销毁session
1、怎样可以将每一个创建的session全都保存起来?
我们可以做一个HttpSessionListener,当session对象创建时,就将这个session对象装入到一个集合中
将集合List<HttpSession>保存到ServletContext域中
2、怎么样可以判断session过期了?
在HttpSession中有一个方法public long getLastAccessedTime()
它可以得到session对象最后使用的时间
可以使用invalidate方法销毁
我们上面的操作需要使用任务调度功能
在java中有一个Timer定时器类
publicclassTestTimer {
publicstaticvoidmain(String[]args) {
//创建一个计时器对象
Timert= new Timer();
//调度任务
t.schedule(newTimerTask() {//要执行的任务
@Override
publicvoidrun() {
System.out.println(newDate().toLocaleString());
}
}, 2000, 1000); //2000 执行任务前的延迟时间 1000 执行各后续任务之间的时间间隔
}
}
程序在使用时,需要考虑并发问题,因为我们在web中,它一定是一个多线程的,那么我们的程序对集合进行了添加,还有移除操作。
publicclassMyServletContextListenerimplementsServletContextListener {
publicvoidcontextInitialized(ServletContextEventsce) {
//通过事件源对象得到事件源(ServletContext)
ServletContextapplication= sce.getServletContext();
//创建一个集合用于存储所有session对象
finalList<HttpSession>list= Collections.synchronizedList(newArrayList<HttpSession>());
//把集合放到application域中
application.setAttribute("sessions",list);
//创建一个计时器对象
Timert= new Timer();
t.schedule(newTimerTask() {
@Override
publicvoidrun() {
System.out.println("开始扫描了。。。");
for(Iteratoriterator= list.iterator();iterator.hasNext();) {
HttpSessionsession= (HttpSession)iterator.next();
longl= System.currentTimeMillis()-session.getLastAccessedTime();
if(l>5000){//如果时间大于5秒,把session销毁
System.out.println("session移除了"+session.getId());
session.invalidate();//把session销毁
//list.remove(session);//从集合中移除
iterator.remove();
}
}
/*for (HttpSession session : list) {
long l = System.currentTimeMillis()-session.getLastAccessedTime();
if(l>5000){//如果时间大于5秒,把session销毁
session.invalidate();//把session销毁
list.remove(session);//从集合中移除
}
}*/
}
}, 2000, 5000);//延迟2秒后执行,每间隔5秒执行一次
}
publicvoidcontextDestroyed(ServletContextEventsce) {
}
}
publicclassMySessionListenerimplementsHttpSessionListener {
publicvoidsessionCreated(HttpSessionEventse) {
HttpSessionsession= se.getSession();
//得到application对象中的list集合
ServletContextapplication= session.getServletContext();
//得到session对象,并放入到list集合中
List<HttpSession>list= (List<HttpSession>) application.getAttribute("sessions");
list.add(session);
System.out.println("添加了"+session.getId());
}
publicvoidsessionDestroyed(HttpSessionEventse) {
//TODOAuto-generated method stub
}
}
二、Filter过滤器(重要)
1、javaweb中的过滤器可以拦截所有访问web资源的请求或响应操作
2、Filter快速入门
- 步骤
- 创建一个类实现Filter接口
- 重写接口中方法,doFilter方法是真正过滤的
- 在web.xml文件中配置
- 注意:在Filter的doFilter方法内如果没有执行chain.doFilter(request,response)那么资源是不会被访问到的
publicclassMyFilterimplementsFilter{
publicMyFilter(){
System.out.println("MyFilter实例化了");
}
publicvoidinit(FilterConfigfilterConfig)throwsServletException {
System.out.println("MyFilter初始化了");
}
publicvoiddoFilter(ServletRequestrequest, ServletResponseresponse,
FilterChainchain)throwsIOException, ServletException {
System.out.println("MyFilter1拦截开始了");
//放行
chain.doFilter(request,response);
System.out.println("拦截结束了");
}
publicvoiddestroy() {
System.out.println("MyFilter销毁了");
}
}
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>com.itheima.filter.MyFilter</filter-class>
<filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- FilterChain
- FilterChain是servlet容器为开发人员提供的对象,它提供了对某一资源的已过滤请求调用链的视图。过滤器使用FilterChain调用链中的下一个过滤器,如果调用的过滤器是链中的最后一个过滤器,则调用链末尾的资源。
- 问题:怎么样可以形成一个Filter链?只要多个Filter对同一资源进行拦截就可以形成Filter链
- 问题:怎样确定Filter的执行顺序?由<filter-mapping>来确定
- Filter生命周期
- Servlet生命周期:实例化、初始化、服务、销毁
- Filter生命周期:
- 当服务器启动,会创建Filter对象,并调用init方法,只调用一次
- 当访问资源时,路径与Filter的拦截路径匹配,会执行Filter中的doFilter方法,这个方法是真正拦截操作的方法
- 当服务器关闭时,会调用Filter的destroy方法来进行销毁操作
- FilterConfig
- 在Filter的init方法上有一个参数,类型就是FilterConfig
- FilterConfig它是Filter的配置对象,它可以完成下列功能
- 获取Filter名称
- 获取Filter初始化参数
- 获取ServletContext对象
- String getFilterName()
- String getInitParameter(String name)
- Enumeration getInitParameterNames()
- ServletContext getServletContext()
- 怎样在Filter中获取一个FilterConfig对象
- publicclassMyFilterConfigTestimplementsFilter{privateFilterConfigfilterConfig;publicvoidinit(FilterConfigfilterConfig)throwsServletException {this.filterConfig= filterConfig;}publicvoiddoFilter(ServletRequestrequest, ServletResponseresponse,FilterChainchain)throwsIOException, ServletException {//通过FilterConfig对象获取到配置文件中的初始化信息Stringencoding= filterConfig.getInitParameter("encoding");System.out.println(encoding);request.setCharacterEncoding(encoding);//放行chain.doFilter(request,response);}publicvoiddestroy() {//TODOAuto-generated method stub}}
- <filter><filter-name>MyFilterConfigTest</filter-name><filter-class>com.itheima.filter.MyFilterConfigTest</filter-class><init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param></filter><filter-mapping><filter-name>MyFilterConfigTest</filter-name><servlet-name>ServletDemo2</servlet-name></filter-mapping>
- Filter配置
- 基本配置
- <filter><filter-name>filter名称</filter-name><filter-class>Filter类的包名.类名</filter-class></filter>
- <filter-mapping><filter-name>filter名称</filter-name><url-pattern>路径</url-pattern></filter-mapping>
- 其他配置
1、<url-pattern>
完全匹配 以"/demo1"开始,不包含通配符*
目录匹配 以"/"开始 以*结束
扩展名匹配 *.xxx 不能写成/*.xxx
2、<servlet-name>
它是对指定的servlet名称的servlet进行拦截的
3、<dispatcher>
可以取的值有 REQUEST FORWARD ERROR INCLUDE
它的作用是:当以什么方式去访问web资源时,进行拦截操作
1、REQUEST 当是从浏览器直接访问资源,或是重定向到某个资源时进行拦截方式配置的,它也是默认值
2、FORWARD 它描述的是请求转发的拦截方式配置
3、ERROR 如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用,除此以外,过滤器不会被调用
4、INCLUDE 如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用,除此以外,过滤器不会被调用
三、自动登录
1、创建库与表
create database day17
use day17
create table user{
id int primary key auto_increment
username varchar(100)
password varchar(100)
}
insert into user values(null,"tom","123");
2、自动登录功能实现
1、当用户登录成功后,判断是否勾选了自动登录,如果勾选了,就将用户名与密码持久化存储到cookie中
2、做一个Filter,对需要自动登录的资源进行拦截
3、问题
1、如果用户想要登录操作,还需要自动登录吗?
2、如果用户已经登陆了,还需要自动登录吗?
4、AutoFilter.java
publicclassAutoLoginFilterimplementsFilter {
publicvoidinit(FilterConfigfilterConfig)throwsServletException {
//TODOAuto-generated method stub
}
publicvoiddoFilter(ServletRequestrequest, ServletResponseresponse,
FilterChainchain)throwsIOException, ServletException {
// 1、转换两个对象HttpServletRequest,HttpServletResponse
HttpServletRequestreq= (HttpServletRequest)request;
HttpServletResponseresp= (HttpServletResponse)response;
Stringuri= req.getRequestURI();// /day17_02_autologin/login.jsp
Stringpath= req.getContextPath();// /day17_02_autologin
path= uri.substring(path.length());// /login.jsp
//如果请求的资源不是login.jsp,也不是/servlet/loginServlet,才往下执行
if(!("/login.jsp".equals(path) || "/servlet/loginServlet".equals(path))) {
Useruser= (User)req.getSession().getAttribute("user");
//如果session得到了user对象,说明已经登录过或自动登录过。
//那么请求下一个资源时就不用执行自动登录了。
//用户没有登录过,我们才执行自动登录
if(user== null) {
System.out.println("aaaaaaaaaaaaaaa");
// 2、处理业务
// 得到cookies数组
Cookie[]cookies= req.getCookies();
Stringusername= "";
Stringpassword= "";
// 从数组中找到想要的user对象的信息
for(inti= 0;cookies!= null && i <cookies.length;i++) {
if("user".equals(cookies[i].getName())) {
Stringvalue= cookies[i].getValue();// tom&123
String[]values= value.split("&");
username= values[0];
password= values[1];
}
}
// 登录操作
UserServiceus= new UserService();
Useru= us.findUser(username,password);
// 如果登录成功,把用户信息存到session中
if(u!= null) {
req.getSession().setAttribute("user",u);
}
}
}
// 3、放行
chain.doFilter(request,response);
}
publicvoiddestroy() {
//TODOAuto-generated method stub
}
}
5、AutoLoginServlet.java
publicclassLoginServletextendsHttpServlet {
publicvoiddoGet(HttpServletRequestrequest, HttpServletResponseresponse)
throwsServletException, IOException {
Stringusername= request.getParameter("username");
Stringpassword= request.getParameter("password");
//MD5加密
password= MD5Utils.md5(password);
UserServiceus= new UserService();
Useruser= us.findUser(username,password);
if(user!=null){
Stringautologin= request.getParameter("autologin");
Cookiecookie= new Cookie("user",user.getUsername()+"&"+user.getPassword());
cookie.setPath("/");
if(autologin!=null){//要把用户信息保存到cookie中
cookie.setMaxAge(60*60*24*7);
}else{//要清除cookie对象的数据
cookie.setMaxAge(0);
}
response.addCookie(cookie);//把cookie对象保存到客户端
request.getSession().setAttribute("user",user);
request.getRequestDispatcher("/home.jsp").forward(request,response);
}else{
request.setAttribute("msg","用户名或密码错误,请重新登录!");
request.getRequestDispatcher("/login.jsp").forward(request,response);
}
}
publicvoiddoPost(HttpServletRequestrequest, HttpServletResponseresponse)
throwsServletException, IOException {
doGet(request,response);
}
}
四、MD5加密
1、在mysql中可以对数据进行md5加密
md5(字段)
update user set password = md5(password);
2、在java中也提供了md5加密
publicclassMD5Utils {
/**
* 使用md5的算法进行加密
*/
publicstaticString md5(StringplainText) {
byte[]secretBytes= null;
try{
secretBytes= MessageDigest.getInstance("md5").digest(
plainText.getBytes());
}catch(NoSuchAlgorithmExceptione) {
thrownewRuntimeException("没有md5这个算法!");
}
Stringmd5code= new BigInteger(1, secretBytes).toString(16);
for(inti= 0;i< 32 -md5code.length();i++) {
md5code= "0" + md5code;
}
returnmd5code;
}
}
五、全局的编码过滤器
1、分析:我们之前做的操作,只能对post请求是满足的
req.setCharacterEncoding("utf-8");//只对post方式满足
2、怎么可以做成一个通用的,可以处理post,get所有的请求的?
在java中怎样可以对一个方法进行功能增强?
1、继承
2、装饰设计模式
1、创建一个类让它与被装饰类实现同一个接口或继承同一个父类
2、在装饰类中持有一个被装饰类的引用
3、重写要增强的方法
问题:我们获取请求参数有以下方法:
1、getParameter
2、getParameterValues
3、getParameterMap
这三个方法都可以获取请求参数
分析后,我们知道getParameter与getParameterValue方法可以依赖于getParamterMap方法来实现
3、
// 实现与被包装对象相同的接口
// 定义一个与被包装类相对象的引用
// 定义一个构造方法,把被包装对象传过来
// 对于不需要改写方法,直接调用
// 对于无需要改写方法,写自己的方法体
classMyRequestextendsHttpServletRequestWrapper {
HttpServletRequestrequest;
publicMyRequest(HttpServletRequestrequest) {
super(request);
this.request= request;
}
/*
* @Override public String getParameter(String name) { name =
* request.getParameter(name);//乱码 try { return new
* String(name.getBytes("iso-8859-1"),"UTF-8"); } catch
* (UnsupportedEncodingException e) { e.printStackTrace(); } return null; }
*/
@Override
publicString getParameter(Stringname) {
Map<String, String[]>map= getParameterMap();
returnmap.get(name)[0];
}
@Override
publicString[] getParameterValues(Stringname) {
Map<String, String[]>map= getParameterMap();
returnmap.get(name);
}
privatebooleanflag= true;
@Override
publicMap<String, String[]> getParameterMap() {
Map<String, String[]>map= request.getParameterMap();// 乱码
if(flag) {
for(Map.Entry<String, String[]>m: map.entrySet()) {
String[]values= m.getValue();
for(inti= 0;i< values.length;i++) {
try{
values[i] = newString(
values[i].getBytes("iso-8859-1"),"UTF-8");
}catch(UnsupportedEncodingExceptione) {
e.printStackTrace();
}
}
}
flag= false;
}
returnmap;
}
}
4、过滤器
publicclassMyFilterimplementsFilter {
publicvoidinit(FilterConfigfilterConfig)throwsServletException {
}
publicvoiddoFilter(ServletRequestrequest, ServletResponseresponse,
FilterChainchain)throwsIOException, ServletException {
HttpServletRequestreq= (HttpServletRequest)request;
// 解决post方式
// req.setCharacterEncoding("UTF-8");
req= new MyRequest(req);
chain.doFilter(req,response);
}
publicvoiddestroy() {
}
}
0 0
- Filter & Listener
- Listener&Filter
- Filter & Listener
- Listener && Filter
- Listener&&Filter
- listener&filter
- Listener & Filter
- Listener&Filter
- Listener 、Filter 和 Interceptor
- Filter与Listener
- Listener and Filter
- Filter vs Listener
- Filter与Listener
- filter和listener
- Servlet、Filter和Listener
- Filter和Listener
- JSP-Filter,Listener
- servlet,filter,listener
- oracle创建表空间,授权,创建用户,导入dmp文件
- c++ primer 17.4.1节练习
- 【图像处理】颜色转换 nv21转rgb rgb转lab
- vs Debug模式代码可以跑起来,Release模式报“未能加载文件或程序集”
- 汉密尔顿路径(哈密顿路径)解析
- Listener && Filter
- 验证是否符合IPv4点分十进制表达的正则表达式
- opentsdb特殊字符问题
- 2017阿里巴巴实习生笔试题之扑克牌问题
- RabbitMQ学习笔记2-Work queues
- springboot端口配置
- 回溯法与分支限界法
- H5 拖放事件详解
- 破解IntelliJ IDEA 2017.1到2099年