过滤器及监听器

一.本次笔记小目标

     重点了解过滤器的实现
            了解过滤器链
            了解监听器的配置
            掌握 Servlet3.0 常用注解的使用

二.过滤器

1.前期介绍

Filter 即为过滤,用于在 Servlet 之外对 Request 或者 Response 进行修改。它主要用于对用户请求进行预处理,也可以对 HttpServletResponse 进行后处理。使用 Filter 的完整流程: Filter 对用户请求进行预处理,接着将请求交给 Servlet进行处理并生成响应,最后 Filter 再 对服务器响应进行后处理。在一个 web 应用中,可以开发编写多个 Filter,这些 Filter 组合 起来称之为一个 Filter 链。

                                      单个过滤器
 

                                       过滤器链

          若是一个过滤器链:先配置先执行(请求时的执行顺序);响应时: 以相反的顺序执行。
 

2. 实现

我们可以通过实现一个叫做 javax.servlet.Fileter 的接口来实现一个过滤器,其中定义了 三个方法, init(), doFilter(), destroy()分别在相应的时机执行。后期观察生命周期。 Filter 的实现只需要两步:
             Step1: 编写 java 类实现 Filter 接口,并实现其 doFilter 方法。
             Step2: 在 web.xml 文件中对编写的 filter 类进行注册,并设置它所能拦截的资源。
 

package com.shsxt.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;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * filter过滤器
 * 	1、在请求到达资源之前,拦截request请求
 * 	2、在响应到达客户端之前,拦截response响应
 * 	3、当访问资源时,如果设置了过滤器的路径,过滤器中需要放行,否则请求无法到达资源
 * 	4、如果有多个过滤器(过滤器链):
 * 		顺序:请求的顺序是配置文件中的先后顺序,响应的顺序反过来即可。
 * 		过滤器链中,第一个过滤器如果没有放行,则无法到达下一个过滤器,资源也无法访问
 * 		原理:会拦截到请求的过滤器:第一个过滤器如果放行,会进入下一个过滤器,如果下一个过滤器不存在,则进入指定资源
 * 	5、chain.doFilter(request, response);方法之前处理请求相关的信息,方法之后处理响应相关的信息
 * @author Lisa Li
 *
 */
public class Filter01 implements Filter {

	/**
	 * 初始化,服务器启动时加载,只会加载一次
	 */
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		System.out.println("Filter01 出生了。。。");
		
	}

	/***
	 * 过滤处理方法
	 */
	@Override
	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
			throws IOException, ServletException {
		System.out.println("Filter01 正在处理...");
		
		// 基于HTTP
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) resp;
		
		// 设置请求的编码
		request.setCharacterEncoding("UTF-8");
		// 响应编码 
		response.setContentType("text/html;charset=UTF-8");
		
		// 放行
		chain.doFilter(request, response);
		
		// 响应
		System.out.println("Filter01 处理完毕...");
		
	}

	/**
	 * 销毁,服务关闭时销毁
	 */
	@Override
	public void destroy() {
		System.out.println("Filter01 die...");
	}

}

Filter 接口中有一个 doFilter 方法,当开发人员编写好 Filter,并配置对哪个 web 资源进行拦截后, Web 服务器每次在调用 web 资源的 service 方法之前,都会先调用一下 filter 的 doFilter 方法。

web 服务器在调用 doFilter 方法时,会传递一个 filterChain 对象进来,filterChain 对象是 filter 接口中最重要的一个对象,它提供了一个 doFilter 方法,开发人员可以根据需求决定 是否调用此方法,调用该方法,则 web 服务器就会调用 web 资源的 service 方法,即 web 资源就会被访问,否则 web 资源不会被访问。(本质是放行,调用 doFilter 方法后,即请求可以到达资源)
 

<filter>
  	<filter-name>filter02</filter-name>
  	<filter-class>com.shsxt.filter.Filter02</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>filter02</filter-name>
  	<url-pattern>/*</url-pattern><!-- 拦截所有资源 -->
  </filter-mapping>

          url-pattern 的配置:
                    ①配置具体路径/index.html/TestServlet.do
                    ②带有通配符的配置*.do /* /user/* *.html *.jsp

3. 过滤器执行的顺序

通过观察 web.xml 中的配置和各个 filter 的执行顺序,找出 filter 执行先后的依据。根据之前观察 Servlet 生命周期的的方式,观察一下过滤器的生命周期。resqust与response相反.

三.监听器

1.自我介绍

web 监听器是一种 Servlet 中的特殊的类,它们能帮助开发者监听 web 中的特定事件, 比如 ServletContext,HttpSession,ServletRequest 的创建和销毁;变量的创建、销毁和修改等。 可以在某些动作前后增加处理,实现监控。例如可以用来统计在线人数等。

  2. 实现

  监听器有三类 8 种: ⑴监听生命周期:实现接口ServletRequestListenerHttpSessionListener 、ServletContextListener⑵监听值的变化:实现接口ServletRequestAttributeListener、 HttpSessionAttributeListener、ServletContextAttributeListener ⑶针对 session 中的对象:监听 session 中的java 对象(javaBean) 是 javaBean 直接实现监听器 的接口

 Step1:创建一个监听器,需要实现某种接口,根据需求选取HttpSessionListener
            Step2:在 web.xml 中配置该监听器
 

package com.shsxt.listener;

import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

public class Listener01 implements HttpSessionListener,HttpSessionAttributeListener {

	/**
	 * 添加域对象
	 */
	@Override
	public void attributeAdded(HttpSessionBindingEvent se) {
		System.out.println("Session添加域对象");
		
	}

	/**
	 * 移除域对象
	 */
	@Override
	public void attributeRemoved(HttpSessionBindingEvent se) {
		System.out.println("Session移除域对象");
		
	}

	/**
	 * 替换域对象
	 */
	@Override
	public void attributeReplaced(HttpSessionBindingEvent se) {
		System.out.println("Session替换域对象");
		
	}

	/**
	 * session对象被创建
	 */
	@Override
	public void sessionCreated(HttpSessionEvent se) {
		System.out.println("session对象被创建");
		
	}

	/**
	 * session对象被销毁
	 */
	@Override
	public void sessionDestroyed(HttpSessionEvent se) {
		System.out.println("session对象被销毁");
		
	}

}

3.在线人数统计及弹幕实现

a.监听器的实现

package com.shsxt.listener;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;


public class OnlineListener02 implements HttpSessionListener, HttpSessionAttributeListener{

	private ServletContext servletContext = null;
	
	private List<String> onlineList = new ArrayList<>();
	
	@Override
	public void sessionCreated(HttpSessionEvent se) {
	
	}

	@Override
	public void sessionDestroyed(HttpSessionEvent se) {
		
	}

	@Override
	public void attributeAdded(HttpSessionBindingEvent se) {
		// 获取session作用域中的用户名
		if ("username".equals(se.getName())) {
			String uname = (String) se.getSession().getAttribute(se.getName());
			onlineList.add(uname);
			servletContext = se.getSession().getServletContext();
			servletContext.setAttribute("onlineList", onlineList);
		}
		
	}

	@Override
	public void attributeRemoved(HttpSessionBindingEvent se) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void attributeReplaced(HttpSessionBindingEvent se) {
		// TODO Auto-generated method stub
		
	}

}

b.Servlet的实现

package com.shsxt.web;

import java.io.IOException;
import java.util.List;
import java.util.Locale;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;


public class OnlineServlet02 extends HttpServlet {
	private static final long serialVersionUID = 1L;

	@SuppressWarnings("unchecked")
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		request.setCharacterEncoding("UTF-8");
		response.setContentType("text/html;charset=UTF-8");

		// 创建session对象
		HttpSession session = request.getSession();
		
		// 得到用户名
		String uname = request.getParameter("uname");
		
		if (uname != null && !"".equals(uname.trim())) {
			// 将用户名存到作用域中
			session.setAttribute("username", uname);
		}
		
		List<String> onlineList = (List<String>) request.getServletContext().getAttribute("onlineList");
		
		if (onlineList != null && onlineList.size() > 0) {
			response.getWriter().write("<h1>当前登录用户: " + uname +"</h1>");
			response.getWriter().write("<h2>用户列表 </h2>");
			String serverName=request.getRemoteHost();//获取远程计算机的名字
			String remoteIp=request.getRemoteAddr();//获取客户端的ip
			System.err.println( remoteIp + " : " + uname );
			for (String string : onlineList) {
				response.getWriter().write("<h3>"+ serverName + "  " + remoteIp + ":" + string + "</h3>");
			}
		}
		
	}
		
	/** 
	 * 获取Ip地址 
	 */  
	protected String getIpAddr(HttpServletRequest request) {  
	    String ip = request.getHeader("x-forwarded-for");  
	    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
	        ip = request.getHeader("Proxy-Client-IP");  
	    }  
	    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
	        ip = request.getHeader("WL-Proxy-Client-IP");  
	    }  
	    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {  
	        ip = request.getRemoteAddr();  
	    }  
	    return ip;  
	}
	
	public void test (HttpServletRequest request) {
		Locale languageType=request.getLocale();//获取用户语言
		String localIp=request.getLocalAddr();//获取本地ip
		int localPort=request.getLocalPort();//获取本地的端口
		String localName=request.getLocalName();//获取本地计算机的名字
		String remoteIp=request.getRemoteAddr();//获取客户端的ip
		int remotePort=request.getRemotePort();//获取客户端的端口号
		String serverName=request.getRemoteHost();//获取远程计算机的名字
		System.out.println("语言类型->" + languageType);
		System.out.println(localName + ": " + serverName);
		System.out.println(localIp + ":" + localPort + " " + remoteIp + ":" + remotePort);
	}

}

四.Servlet3.0 注解

1. @WebServlet

开发 servlet 项目,使用@WebServlet 将一个继承于javax.servlet.http.HttpServlet 的类定义为 Servlet 组件。在 Servlet3.0 中 , 可以使用@WebServlet 注解将一个继承于 javax.servlet.http.HttpServlet 的类标注为可以处理用户请求的 Servlet。

a.用注解配置 Servlet

b.配置多个 urlPatterns 来指定多个访问路径

c.常用这种形式:@WebServlet("/s01")

package com.shsxt.servlet;

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("/s01")
//@WebServlet(value = "/s01")
//@WebServlet(value = {"/s01","/s02"})
//@WebServlet(urlPatterns = "/s01")
//@WebServlet(urlPatterns = {"/s01","/s02"})
//@WebServlet(urlPatterns = "/s01",loadOnStartup = 1,name="Servlet01")
public class Servlet01 extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("Servlet01...");
	}

}

2. @WebFilter

@WebFilter 用来配置过滤器

 使用注解时:过滤器链按照类名的字母排序(大部分情况)

package com.shsxt.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;
import javax.servlet.annotation.WebFilter;

/**
 * Servlet Filter implementation class Filter01
 */
//@WebFilter(urlPatterns = "/*")
@WebFilter("/*")
public class Filter01 implements Filter {

    /**
     * Default constructor. 
     */
    public Filter01() {
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see Filter#destroy()
	 */
	public void destroy() {
		// TODO Auto-generated method stub
	}

	/**
	 * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
	 */
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		// TODO Auto-generated method stub
		// place your code here

		// pass the request along the filter chain
		chain.doFilter(request, response);
	}

	/**
	 * @see Filter#init(FilterConfig)
	 */
	public void init(FilterConfig fConfig) throws ServletException {
		// TODO Auto-generated method stub
	}

}

3. @WebListener

Servlet3.0 提供@WebListener 注解将一个实现了特定监听器接口的类定义为监听器。将 实现了 ServletContextListener 接口的 MyServletContextListener标注为监听器。

package com.shsxt.listener;

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

/**
 * Application Lifecycle Listener implementation class Listener
 *
 */
@WebListener
public class Listener01 implements HttpSessionListener {

    /**
     * Default constructor. 
     */
    public Listener01() {
        // TODO Auto-generated constructor stub
    }

	/**
     * @see HttpSessionListener#sessionCreated(HttpSessionEvent)
     */
    public void sessionCreated(HttpSessionEvent se)  { 
         // TODO Auto-generated method stub
    }

	/**
     * @see HttpSessionListener#sessionDestroyed(HttpSessionEvent)
     */
    public void sessionDestroyed(HttpSessionEvent se)  { 
         // TODO Auto-generated method stub
    }
	
}

4. @MultipartConfig

使用注解@MultipartConfig 将一个 Servlet 标识为支持文件上传。Servlet3.0 将 multipart/form-data 的 POST 请求封装成 Part,通过 Part 对上传的文件进行操作。

上传的前台页面:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>文件上传</title>
</head>
<body>
	<!-- 
		如果是文件上传表单
			1、必须设置enctype="multipart/form-data",设置MIME编码
			2、请求方式为POST
			3、文件域需要设置name属性值
	 -->
	<form action="upload" method="post" enctype="multipart/form-data">
		用戶名:<input type="text" name="uname" />
		文件名:<input type="file" name="myfile" />
		<input type="submit" />
	</form>
</body>
</html>

上传的后台页面:

package com.shsxt.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

/**
 * servlet3.0上传文件
 */
@WebServlet("/upload")
/*
 * 使用注解@MultipartConfig 将一个 Servlet 标识为支持文件上传。
	Servlet3.0 将 multipart/form-data 的 POST 请求封装成 Part,通过 Part 对上传的文件进行操作
 */
//@MultipartConfig
public class UploadServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		// 得到参数
		String uname = request.getParameter("uname");
		System.out.println(uname);
		
		// 得到上传对象
		Part part = request.getPart("myfile"); // getPart(name):前台表单的文件域的name属性值
		// 得到服务器的服务器的真实路径
		String realPath = getServletContext().getRealPath("/");
		// 得到上传的文件名
		String fileName = part.getSubmittedFileName();
		// 上传文件到指定位置
		part.write(realPath + fileName); 
	
	}

}



 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值