监听器&过滤器

历史回顾

会话技术

在Javaweb中,指的是打开一个浏览器并且访问某一个服务器的站点进行交互。我们称之为开始会话,如果用户关闭浏览器,称为会话结束。

 

客户端会话技术: cookie

服务器会话技术: session

 

Cookie

作用:

1、向客户端本地存储一些比较有用的数据

2、实现会话跟踪技术的一个先决条件

好处:

  1. 减缓服务器压力
  2. 增强用户体验
  3. 可以智能填充数据

如何添加Cookie

Cookie c = new Cookie(”名称”,”对应的值”);

//cookie的存活时间

c.setMaxAge(); //单位:秒

response.addCookie(c);//响应添加

 

如何获取Cookie

Cookie[] c = request.getCookies();

if(null != c){

        //循环遍历

        c.getName();

    c.getValue();

}

 

Session 作用域

作用:维护用户的登录状态。

 

会话跟踪技术

Session本身是一个服务器对象,如果没有会话跟踪那么存活的时间可能很长,为了能够实现与会话同步,借助cookie的默认存储特性,实现了一个与会话同步的session会话的方式。叫做服务端会话

 

实现原理:当用户通过浏览器访问服务器的时候,先根据Cookie中的JSEESIONID判断当前是否已经创建了session。如果已经创建,那么直接使用这个Session,如果没有创建,服务器会新建一个session并且将JSESSIONID发送客户的Cookie中,标志一个新的会话开启了。

 

关于EL获取指定作用域的值

${*Scope.属性名}

监听器

Javaweb来说,Servlet、监听器、过滤器称之为Javaweb的三大组件

监听器实现了特殊监听接口的类,用来监听作用域与session。

监听器(Listener)共有三组:

第一组:监测ServletContext、request、session的创建和销毁 3个

第二组:监测ServletContext、request、session作用域值的变化 3个

第三组:监测session与类的关系    2个

第一组:

1.ServletContext创建与销毁  ServletContextListener

1)web.xml配置模式(非注解模式)

需要创建web.xml文件然后再创建继承了监听接口的监听类,并在里面配置<listener>下的<listener-class>属性,指向的就是监听类

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0">
  <display-name>DAY18</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>

  <listener>
	  <listener-class>servletcontext.MyServletContextListener</listener-class>
  </listener>
</web-app>
package servletcontext;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class MyServletContextListener implements ServletContextListener{
	
	@Override//创建ServletContext监听器
	public void contextInitialized(ServletContextEvent sce) {
		System.out.println("检测到ServletContext监听器创建");
	}
	@Override//销毁ServletContext监听器
	public void contextDestroyed(ServletContextEvent sce) {
		System.out.println("检测到ServletContext监听器销毁");
	}
}

2)注解模式

直接在监听类上写注解:@WebListener即可

package servletcontext;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class MyServletContextListener implements ServletContextListener{
	
	@Override//创建ServletContext监听器
	public void contextInitialized(ServletContextEvent sce) {
		System.out.println("检测到ServletContext监听器创建");
	}
	@Override//销毁ServletContext监听器
	public void contextDestroyed(ServletContextEvent sce) {
		System.out.println("检测到ServletContext监听器销毁");
	}
}

监听结果

启动服务器是监听创建

关闭Tomcat服务器监听销毁(右键-stop)

作用:可以操作对应的作用域及相关信息。

 

2.reqeust创建与销毁   ServletRequestListener

理解:request的创建是每次请求都创建。 请求完成就销毁,即使是404,浏览器也请求了服务器,还是会创建和销毁request监听器。

package servletListener;

import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestEvent;
import javax.servlet.annotation.WebListener;

@WebListener
public class ServletRequestListener implements javax.servlet.ServletRequestListener{
	
	@Override
	public void requestInitialized(ServletRequestEvent sre) {
		ServletRequest request = sre.getServletRequest();//获取Servletrequest对象
		//获取一个前台的参数
		String mark = request.getParameter("mark");
		System.out.println("[监听]-获取到参数:"+mark);
	}
	
	@Override
	public void requestDestroyed(ServletRequestEvent sre) {
		System.out.println("[监听]-request已成功销毁");
	}
}

 

3.session创建与销毁 HttpSessionListener

理解:session为服务器对象,当使用的时候才创建。

servlet是通过request.getSession()创建

jsp 访问页面就创建,内置对象就有session。

无论是浏览器访问JSP创建还是直接经过后台创建都是会话对象,而且都具备会话功能,所以都会创建session

关闭无法销毁是因为本身session存在超时才执行销毁

停止服务器不执行销毁是因为有活化与钝化操作。

正常销毁:30分钟后

直接访问jsp页面会创建session,因为session就是jsp中的九大对象之一,会自动创建

JESSIONID的值和我们获取的值一样,当浏览器关闭后会重新指定一个session值

         

直接访问后台Servlet也会创建session,因为直接访问后台也是要通过浏览器,也会创建会话。

Servlet

package HttpservletListener;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@WebServlet("/ss")
public class SessionListenerServlet extends HttpServlet{
	private static final long serialVersionUID = 1L;
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		HttpSession session = request.getSession();
		String id = session.getId();
		System.out.println("sessionServlet:"+id);
	}
}

sessionListener

package HttpservletListener;

import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

@WebListener
public class SessionListener implements HttpSessionListener{
	@Override//创建sessionlisten
	public void sessionCreated(HttpSessionEvent se) {
		System.out.println("[监听]-session创建了");
		HttpSession session = se.getSession();
		System.out.println("session监听器:"+session.getId());
	}
	@Override//销毁sessionlistener
	public void sessionDestroyed(HttpSessionEvent se) {
		System.out.println("[监听]-session销毁了");
	}
}

第二组

1.监测ServletContext值 ---  ServletContextAttributeListener

ServletContextAttributeEvent这个对象是ServletContext的子类,我们可以直接调用父类中的方法获得ServletContext对象

getAttribute()方法的返回值是Object,我们已知返回类型的时候可以强制转型

Servlet

package servletListener;

import java.io.IOException;

import javax.servlet.ServletContext;
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("/myServlet")
public class MyServlet extends HttpServlet{
	private static final long serialVersionUID = 1L;
	@Override
	protected void service(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException {
		ServletContext context = this.getServletContext();//ServletContext是从父类继承下来,可以直接调用
		context.setAttribute("con", "哈哈");//添加值
		context.setAttribute("con", "吼吼");//替换值
		context.removeAttribute("con");//移除
	}
}

ServletContextAttributeListener

package HttpservletListener;

import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class MyServletContextAttributeListener implements ServletContextAttributeListener{
	@Override//添加
	public void attributeAdded(ServletContextAttributeEvent event) {
		
		//ServletContextAttributeEvent这个对象是ServletContext的子类,我们可以直接调用父类中的方法获得ServletContext对象
		String con = (String)event.getServletContext().getAttribute("con");
		System.out.println("添加值:"+con);
	}
	
	@Override//替换
	public void attributeReplaced(ServletContextAttributeEvent event) {
		String con = (String)event.getServletContext().getAttribute("con");
		System.out.println("移除值:"+con);
	}
	
	@Override//移除
	public void attributeRemoved(ServletContextAttributeEvent event) {
		String con = (String)event.getServletContext().getAttribute("con");
		System.out.println("替换值:"+con);
	}
	
}

2.监测request值---ServletRequestAttributeListener

request添加的时候多了一次替换,可以理解为添加的时候服务器默认给添加的元素赋了一个默认值null

Servlet

package servletListener;

import java.io.IOException;

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("/MyRequestServlet")
public class MyRequestServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;

	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setAttribute("req", "我是添加");//添加
		request.setAttribute("req", "我是修改");//修改
		request.removeAttribute("req");//移除
	}
}

MyServletRequestListener

package HttpservletListener;

import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class MyServletRequestAttributeListener implements ServletRequestAttributeListener {

	@Override//添加方法
	public void attributeAdded(ServletRequestAttributeEvent servletrequestattributeevent) {
		String req = (String)servletrequestattributeevent.getServletRequest().getAttribute("req");
		System.out.println("添加值:"+req);
	}
	
	@Override//替换方法
	public void attributeReplaced(ServletRequestAttributeEvent servletrequestattributeevent) {
		String req = (String)servletrequestattributeevent.getServletRequest().getAttribute("req");
		System.out.println("替换值:"+req);
	}
	
	@Override//移除方法
	public void attributeRemoved(ServletRequestAttributeEvent servletrequestattributeevent) {
		String req = (String)servletrequestattributeevent.getServletRequest().getAttribute("req");
		System.out.println("移除值:"+req);
	}
}

3.监测session值---HttpSessionAttributeListener

servlet

package servletListener;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@WebServlet("/MySessionServlet")
public class MySessionServlet extends HttpServlet {
	
	private static final long serialVersionUID = 1L;

	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		HttpSession session = request.getSession();
		session.setAttribute("session", "我是添加");//添加
		session.setAttribute("session", "我是修改");//修改
		session.removeAttribute("session");//移除
	}
}

HTTPSessionAttributeListener

package HttpservletListener;

import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;

@WebListener
public class MyHttpSessionListener implements HttpSessionAttributeListener {
	@Override//添加
	public void attributeAdded(HttpSessionBindingEvent httpsessionbindingevent) {
		String session = (String)httpsessionbindingevent.getSession().getAttribute("session");
		System.out.println("添加:"+session);
	}
	
	@Override//修改
	public void attributeReplaced(HttpSessionBindingEvent httpsessionbindingevent) {
		String session = (String)httpsessionbindingevent.getSession().getAttribute("session");
		System.out.println("修改:"+session);
	}
	
	@Override//移除
	public void attributeRemoved(HttpSessionBindingEvent httpsessionbindingevent) {
		String session = (String)httpsessionbindingevent.getSession().getAttribute("session");
		System.out.println("移除:"+session);
	}
}

 

 

第三组

1.监听类是否在session中存在---HttpSessionBindingListener

第三组监听是比较特殊的,不需要单独的设定实现类。 所以直接与类绑定即可。在实体类中实现这个接口,改写绑定解绑方法即可。

监听的时机:

只有将绑定的对象放进session或者从session中移除的时候才会进行监听。

重点:只需要在指定的类中实现绑定的监听,不需要使用web.xml配置或者注解标签。

1.我们可以在实体类中绑定监听接口,那么这个类就具有了监听的功能。

2.当具有监听功能的实体类对象被添加到session作用域中后,监听就绑定了,当把这个对象从session中移除后监听解绑。

实体类

package com.offcn.SessionListenerDao;

import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;

public class Student implements HttpSessionBindingListener{
	private String name;
	private int 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 "[name=" + name + ", age=" + age + "]";
	}
	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public Student() {}
	
	/重写监听的方法///
	@Override
	public void valueBound(HttpSessionBindingEvent httpsessionbindingevent) {
		String n = httpsessionbindingevent.getName();
		Object v = httpsessionbindingevent.getValue();
		System.out.println("n:"+n+"..."+"v:"+v);
		System.out.println("绑定");
	}
	
	@Override
	public void valueUnbound(HttpSessionBindingEvent httpsessionbindingevent) {
		System.out.println("解绑");
	}
}

测试用的Servlet

package com.offcn.SessionListenerDao;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@WebServlet("/StudentServlet")
public class StudentServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;

	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		Student student = new Student("小明",23);
		HttpSession session = request.getSession();
		session.setAttribute("sess", student);//当把实现监听接口的实体类对象放到session中时就开始绑定
		System.out.println("将实体类对象放进session中,完成绑定");
		
		session.removeAttribute("sess");
		System.out.println("从session中移除实体类对象,解绑");
	}
}

2.监听存到session中的类的活化与钝化操作---HttpSessionActivationListener

钝化:是指将活跃在内存中的session中对象持久化到本地叫做钝化。

活化:是指将本地存储的Session信息再次读取到内存中。

牵扯到对象持久化,实体类就要实现serializable接口

 

存在的意义: 防止意外发生导致内存中数据丢失。

 

使用方式也同样将这个接口在指定的类中实现,但是需要注意的是因为与本地操作时设计到IO所以必须多实现一个序列化(serializable)接口。

 

钝化的条件:

将对象存到session并且停止服务器。

钝化的路径:tomcat - work ...

活化的条件:

钝化后再次启动服务器,tomcat会自动的将SESSIONS.ser文件中的内容读取到内存,并且删除钝化后的文件

 

测试:钝化的时候存储一个数据。并且打印SessionID

  活化后测试这个数据及SesionID变化。

关闭服务器和浏览器之前:

关闭服务器之后:

不关闭浏览器的情况下开始服务器:JSESSIONID不变,文件被活化到了内存中

当我们关闭浏览器重启服务器的时候:

过滤器

过滤器指的是实现了Filter接口(javax.servlet.Filter;)的Java类。用来拦截请求,以做其他处理。此路是我开,此树是我栽,要从此路过,留下买路财!

过滤器是全局生效的。

 

第一种,非注解配置,在web.xml中配置,和配置Servlet基本相同

xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0">
  <display-name>DAY18</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
  <!-- <listener>
	  <listener-class>servletcontext.MyServletContextListener</listener-class>
  </listener> -->
  
  <filter>
  	<filter-name>fff</filter-name>
  	<filter-class>com.offcn.filter.MyFilter</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>fff</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

测试用Servlet:

package com.offcn.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class MyFilter implements Filter {

	@Override
	public void doFilter(ServletRequest servletrequest, ServletResponse servletresponse, FilterChain filterchain)
			throws IOException, ServletException {
		System.out.println("因为xml中配置了/* 所有东西都被我拦截了!");
	}

}

当xml配置的路径为" /* "时,拦截器会拦截所有,即使该页面不存在也会拦截,不会报404,前提是要在这个项目下访问。

第二种:注解配置。

放行方法:filterchain.doFilter(servletrequest, servletresponse);

案例一:字符编码过滤器

以前写Servlet的时候每一个servlet都需要设置request和Response的编码、现在通过过滤器可以在调用servlet之前进行同意的编码设置工作。

ServletRequest是HttpServletRequest的父类,request==HttpServletRequest

package com.offcn.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

@WebFilter("/*")
public class UnitedEncoding implements Filter{

	@Override
	public void doFilter(ServletRequest servletrequest, ServletResponse servletresponse, FilterChain filterchain)
			throws IOException, ServletException {
		servletrequest.setCharacterEncoding("utf-8");
		servletresponse.setContentType("text/html;charset=utf-8");
		//设置完成之后放行,所有请求响应都必须先满足我们设置的字符集要求才能往下走
		filterchain.doFilter(servletrequest, servletresponse);
	}
}

案例二:拦截登录

思想:除了登录页面和登录的请求是无条件的放行。其他的任意只要不登录全部调转到登录页面,一旦登录全部放行。

拦截器开头我们拦截了所有,首先要仅允许我们设置的登陆页面可以通行,如果不是与登陆页面有关,我们需要判断是否登陆

session.setAttribute("msg")的值不同目的是不同的错误提示不同的信息

登陆页面

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<span style="color:red">${msg }</span>
	<form action="loginServlet" method="post">
		姓名:<input type="text" name="name"><br>
		密码:<input type="password" name="pwd"><br>
		<input type="submit" value="登陆">
	</form>
</body>
</html>

登陆成功页面

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	welcome aboard captain${sessionScope.name },let's go!
</body>
</html>

Servlet页面

package com.offcn.filterLogin;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;

	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String name = request.getParameter("name");
		String pwd = request.getParameter("pwd");
		HttpSession session = request.getSession();
		if("张三丰".equals(name) && "123456".equals(pwd)) {
			session.setAttribute("name", name);
			session.setAttribute("pwd", pwd);//用处不大。。。
			response.sendRedirect("success.jsp");
		}else {
			session.setAttribute("msg", "账号密码错误,别想蒙我");
			request.getRequestDispatcher("login.jsp").forward(request, response);
		}
	}
}

login过滤器

package com.offcn.filterLogin;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@WebFilter("/*")
public class LoginFilter implements Filter {

	@Override
	public void doFilter(ServletRequest servletrequest, ServletResponse servletresponse, FilterChain filterchain)
			throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) servletrequest;// 获得子类HttpServletRequest
		HttpServletResponse response = (HttpServletResponse) servletresponse;
		
		HttpSession session = request.getSession();// 获取session对象,以便获取作用域中的值
		Object name = session.getAttribute("name");// name
		
//		Object pwd = session.getAttribute("pwd");//pwd,实际上用不着

		// 判断
		String uri = request.getRequestURI();// 拦截器开头我们拦截了所有,首先要仅允许我们设置的登陆页面可以通行
		if (uri.contains("login.jsp") || uri.contains("loginServlet")) {
			filterchain.doFilter(servletrequest, servletresponse);

/*
 * 如果不是与登陆页面有关,我们需要判断是否登陆,注意判断是否登陆时只有两种情况,登陆和未登录,登陆后name肯定 有值,
只需要判断name是否为空即可 */
		} else {
			if (null != name) {
				request.getRequestDispatcher("success.jsp").forward(request, response);
			} else {
				request.setAttribute("msg", "非法登陆,还想要蒙我");
				request.getRequestDispatcher("login.jsp").forward(request, response);
			}
		}
	}
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值