day19_Filter&Listener

在这里插入图片描述

Filter:过滤器

1. 概念:
	* 生活中的过滤器:净水器,空气净化器,土匪、
	* web中的过滤器:当访问服务器的资源时,过滤器可以将请求拦截下来,完成一些特殊的功能。
	* 过滤器的作用:
		* 一般用于完成通用的操作。如:登录验证、统一编码处理、敏感字符过滤...

2. 快速入门:
	1. 步骤:
		1. 定义一个类,实现接口Filter
		2. 复写方法
		3. 配置拦截路径
			1. web.xml
			2. 注解
	2. 代码:
		@WebFilter("/*")//访问所有资源之前,都会执行该过滤器
		public class FilterDemo1 implements Filter {
		    @Override
		    public void init(FilterConfig filterConfig) throws ServletException {
		
		    }
		
		    @Override
		    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
		        System.out.println("filterDemo1被执行了....");

​ //放行
​ filterChain.doFilter(servletRequest,servletResponse);
}

		    @Override
		    public void destroy() {
		
		    }
		}


3. 过滤器细节:
	1. web.xml配置	
		<filter>
	        <filter-name>demo1</filter-name>
	        <filter-class>cn.itcast.web.filter.FilterDemo1</filter-class>
	    </filter>
	    <filter-mapping>
	        <filter-name>demo1</filter-name>
			<!-- 拦截路径 -->
	        <url-pattern>/*</url-pattern>
	    </filter-mapping>
	2. 过滤器执行流程
		1. 执行过滤器  doFilter(....)
		2. 放行后( filterChain.doFilter): 执行url 请求的资源, 
		       例如: url请求servlet,那么就执行 servlet中doXxx() 方法; 
		3. 回来执行过滤器放行代码下边的代码
	3. 过滤器生命周期方法
		1. init:在服务器启动后,会创建Filter对象,然后调用init方法。只执行一次。用于加载资源
		2. doFilter:每一次请求被拦截资源时,会执行。执行多次
		3. destroy:在服务器关闭后,Filter对象被销毁。如果服务器是正常关闭,则会执行destroy方法。只执行一次。用于释放资源
		  释放资源-导师有话要说: tomcat 关闭后, JVM内存中所有的资源全部会自动的处理,所以一般我们也不会在destroy 方法中去写代码显示的清除init加载的资源
		 
	4. 过滤器配置详解
		* 拦截路径配置:
			1. 具体资源路径: /index.jsp   只有访问index.jsp资源时,过滤器才会被执行
			2.(重点) 拦截目录: /user/*	访问/user下的所有资源时,过滤器都会被执行
			     导师有话要说: 这种方式,我们一般用来做权限管理。
			3. 后缀名拦截: *.jsp		访问所有后缀名为jsp资源时,过滤器都会被执行
			4.(重点) 拦截所有资源:/*		访问所有资源时,过滤器都会被执行
			     导师有话要说: 拦截所有请求,包括我们的 img .css .js  .html 静态资源也会被拦截,
			       这个事 显得有点没有必要,静态资源不需要进行过滤。
			5. @WebFilter(urlPatterns = {"/updateUserServlet", "/addUserServlet"})
		* (了解)拦截方式配置:资源被访问的方式
		    导师有话要说--这个事显得没有那么的重要,原因如下: 
		    1. 项目中使用的Filter 场景其实并不多
		    2. 一般企业中的Filter 需求都是对 客户端浏览器发起的请求进行拦击,默认就是该拦截方式。
		    3. 企业中一般不会直接使用Filter,一般用企业级框架: Struts SpringMvc 的 intercepter (拦截器)
			* 注解配置:
				* 设置dispatcherTypes属性
					1. REQUEST:默认值。浏览器直接请求资源
					2. FORWARD:转发访问资源
					3. INCLUDE:包含访问资源
					4. ERROR:错误跳转资源
					5. ASYNC:异步访问资源
			* web.xml配置
				* 设置<dispatcher></dispatcher>标签即可
			
	5. 过滤器链(配置多个过滤器)
		* 执行顺序:如果有两个过滤器:过滤器1和过滤器2
			1. 过滤器1
			2. 过滤器2
			3. 资源执行
			4. 过滤器2
			5. 过滤器1 

		* 过滤器先后顺序问题:
			1. 注解配置:按照类名的字符串比较规则比较,值小的先执行
			    * 按照自然顺序进行比较: 什么自然顺序?1 2 3 4 5.... A B C D E....
				* 如: AFilter 和 BFilter,AFilter就先执行了。
			2. web.xml配置: <filter-mapping>谁定义在上边,谁先执行
			
			一般咱企业里,我们只关心我们配置的多个Filter 是否都执行了,往往不关心谁先谁后。
4. 案例:
	1. 案例1_登录验证
		* 需求:
			1. 访问day17_case案例的资源。验证其是否登录
			2. 如果登录了,则直接放行。
			3. 如果没有登录,则跳转到登录页面,提示"您尚未登录,请先登录"。
			@WebFilter("/*")
			public class LoginFilter implements Filter {

				public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
					//先进行强制类型转换,不然不能获取uri
					HttpServletRequest req1 = (HttpServletRequest) req;
					String requestURI = req1.getRequestURI();

					if(requestURI.contains("/login.jsp") || requestURI.contains("/loginServlet") || requestURI.contains("/checkCodeServlet") || requestURI.contains("/css/")|| requestURI.contains("/js/")){
						chain.doFilter(req, resp);
						return;
					}
					Object user = ((HttpServletRequest) req).getSession().getAttribute("user");
					//Object user = req1.getSession().getAttribute("user");
					if(user==null){
						req1.setAttribute("msg" ,"你还没有登录,请先登录!!!");
						req1.getRequestDispatcher("/login.jsp").forward(req,resp);
						return;
					}
					chain.doFilter(req, resp);
				}

	2. 案例2_敏感词汇过滤
		* 需求:
			1. 对day17_case案例录入的数据进行敏感词汇过滤
			2. 敏感词汇参考《敏感词汇.txt》
			3. 如果是敏感词汇,替换为 *** 

		* 分析:
			1. 对request对象进行增强。增强获取参数相关方法
			2. 放行。传递代理对象
				@WebFilter("/*")
				public class MingganFilter implements Filter {
					private List<String> list = new ArrayList<>();

					public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {

						ServletRequest req_proxy = (ServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(), req.getClass().getInterfaces(), new InvocationHandler() {
							@Override
							public Object invoke(Object o, Method method, Object[] objects) throws Throwable {

								if(method.getName().equals("getParameter")){
									String  vlaue = (String) method.invoke(req, objects);
									if (vlaue!=null){
										for (String str : list) {
											if (vlaue.contains(str)){
												vlaue = vlaue.replaceAll(str, "***");
											}
										}
									}
									return vlaue;
								}
								if(method.getName().equals("getParameterValues")){
									String[]  strArr = (String[]) method.invoke(req,objects);
									if(strArr!=null){
										for (String str : list) {
											for (int i = 0; i < strArr.length; i++) {
												if(strArr[i].contains(str)){
													strArr[i]=strArr[i].replaceAll(str,"***");
												}
											}
										}
									}
									return strArr;
								}

								if(method.getName().equals("getParameterMap")){
									Map<String,String[]> map = (Map<String, String[]>) method.invoke(req, objects);
								   if(map!=null){
									   for (String str : list) {
										   Set<Map.Entry<String, String[]>> entries = map.entrySet();
										   for (Map.Entry<String, String[]> entry : entries) {
											   if(entry.getValue()[0].contains(str)){
												   entry.getValue()[0]=entry.getValue()[0].replaceAll(str,"***");
											   }
										   }
									   }
								   }
									return map;
								}

								return method.invoke(req,objects);
							}
						});
						chain.doFilter(req_proxy, resp);

					}

					public void init(FilterConfig config) throws ServletException {
						try {
							String realPath = config.getServletContext().getRealPath("/WEB-INF/classes/敏感词汇.txt");
							BufferedReader br = new BufferedReader(new FileReader(realPath));
							String line;
							while((line =br.readLine())!=null){
								list.add(line);
							}
							br.close();
						} catch (Exception e) {
							e.printStackTrace();
						}
					}


		* 增强对象的功能:
			* 设计模式:一些通用的解决固定问题的方式
			1. 装饰模式
			2. 代理模式
				* 概念:
					1. 真实对象:被代理的对象
					2. 代理对象:
					3. 代理模式:代理对象代理真实对象,达到增强真实对象功能的目的
			 	* 实现方式:
				 	1. 静态代理:有一个类文件描述代理模式
				 	2. 动态代理:在内存中形成代理类
						* 实现步骤:
							1. 代理对象和真实对象实现相同的接口
							2. 代理对象 = Proxy.newProxyInstance();
							3. 使用代理对象调用方法。
							4. 增强方法

						* 增强方式:
							1. 增强参数列表
							2. 增强返回值类型
							3. 增强方法体执行逻辑	
	导师语录: 
	  化学反应就是: 执行目标方法之前,我们可以先调用 增强方法,在增强方法中,可以自行通过代码控制 目标 方法是否调用
	  作用: 可以降低目标方法的代码冗余度,将公共的 代码逻辑 写到我们增强方法中。
	  其他: 我们给 Filter 类 叫做切面, spring 中叫: aop 就是切面。

Listener:监听器

* 概念:web的三大组件之一。
	* 事件监听机制
		* 事件	:一件事情
		* 事件源 :事件发生的地方
		* 监听器 :一个对象
		* 注册监听:将事件、事件源、监听器绑定在一起。 当事件源上发生某个事件后,执行监听器代码


* ServletContextListener:监听ServletContext对象的创建和销毁
	* 方法:
		* void contextDestroyed(ServletContextEvent sce) :ServletContext对象被销毁之前会调用该方法
		* void contextInitialized(ServletContextEvent sce) :ServletContext对象创建后会调用该方法
	* 步骤:
		1. 定义一个类,实现ServletContextListener接口
		2. 复写方法
		3. 配置
			1. web.xml
					<listener>
 					 <listener-class>cn.itcast.web.listener.ContextLoaderListener</listener-class>
					</listener>

					* 指定初始化参数<context-param>
			2. 注解:
				* @WebListener

代码实现:

/**

  • request代理对象

  • 用来过滤Xss 关键字和敏感词汇
    */
    public class ProxyRequest extends HttpServletRequestWrapper {

    public ProxyRequest(HttpServletRequest request) {
    super(request);
    }

    @Override
    public String getParameter(String name) {
    return clearXss(super.getParameter(name));
    }

    @Override
    public String getHeader(String name) {
    return clearXss(super.getHeader(name));
    }

    /**

    • 说明 :想针对每个参数都进行过滤,需要get 请求,

    • post 请求,过滤不掉 文本框中输入<> 标签
      */
      @Override
      public String[] getParameterValues(String name) {

      //从请求报文中获取数据
      String[] values = super.getParameterValues(name) ;
      if(null != values){
      for(int i = 0 ; i < values.length ; i++ ){
      values[i] = clearXss(values[i]) ;
      }
      return values;
      }
      return new String[0];
      }

    @Override
    public Map<String, String[]> getParameterMap() {

    //获取所有请求报文中数据
    Map<String, String[]> parameterMap = super.getParameterMap();
    
    //用来装载处理后的字符串
    Map<String, String[]> newParameterMap = new HashMap<>();
    
    for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
    
        //获取values 数组
        String[] values = entry.getValue();
        if(null != values){
            for(int i = 0 ; i < values.length ; i++ ){
                values[i] = clearXss(values[i]) ;
            }
        }
        //给key重新赋值
        newParameterMap.put(entry.getKey(), values);
    
    }
    
    return newParameterMap;
    

    }

    /**

    • 处理字符转义
      /
      private String clearXss(String value){
      if(value == null || “”.equals(value)){
      return value ;
      }
      //防止标签注入
      value = value.replaceAll("<", “<”).replaceAll(">", “>”);
      //防止() 中写表达式
      value = value.replaceAll("\(", “(”).replace("\)", “)”);
      //防止 sql 注入
      value = value.replaceAll("’", “’”);
      //方式eval脚本
      value = value.replaceAll("eval\((.
      )\)", “”);
      //防止JavaScript 代码片段
      value = value.replaceAll("[\"\’][\s]javascript:(.)[\"\’]", “”"");
      //防止script 脚本出现
      value = value.replace(“script”, “”) ;

      //继续过滤敏感词汇
      return clearSensitiveWords(value) ;
      }

    /**

    • 过滤敏感词汇

    • @param value
      */
      public String clearSensitiveWords(String value){

      if(value == null || “”.equals(value)){
      return value ;
      }

      List list = (List) super.getServletContext().getAttribute(Constants.SERVLETCONTEXT_SENSITIVE_WORDS);
      for (String word: list){
      if(value.contains(word)){
      value = value.replaceAll(word,"*");
      }
      }
      return value;

    }
    }

@WebListener
public class ContextLoaderListener implements ServletContextListener {

/**
 * 监听ServletContext对象创建的。ServletContext对象服务器启动后自动创建。
 *
 * 在服务器启动后自动调用
 * @param servletContextEvent
 */
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
    //加载资源文件
    //1.获取ServletContext对象
    ServletContext servletContext = servletContextEvent.getServletContext();

    //2.加载资源文件
    String contextConfigLocation = servletContext.getInitParameter("sensitiveWords");

    //3.获取真实路径
    String realPath = servletContext.getRealPath(contextConfigLocation);

    List<String> list = new ArrayList<String>();//敏感词汇集合

    //4.加载进内存
    try{
        //2.读取文件
        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(realPath),"UTF-8"));
        //3.将文件的每一行数据添加到list中
        String line = null;
        while((line = br.readLine())!=null){
            list.add(line);
        }
        br.close();
        System.out.println(list);
        //将敏感词汇集合对象存储到域中
        servletContext.setAttribute(Constants.SERVLETCONTEXT_SENSITIVE_WORDS, list);

    }catch (Exception e){
        e.printStackTrace();
    }
    System.out.println("ServletContext对象被创建了。。。");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值