SpringBoot 过滤器、监听器、拦截器

        在很多Web项目中,都会用到过滤器( Filter ),如参数过滤、防止SQL注入、防止页面攻击、空参数矫正、Token 验证、Session验证、点击率统计等。

认识过滤器

为什么要使用过滤器

在Web开发中,常常会有这样的需求:在所有接口中去除用户输入的非法字符,以防止引起业务异常。要实现这个功能,可以有很多方法,如:

  • 在前端参数传入时进行校验,先过滤掉非法字符,然后,返回用户界面提示用户重新输入。
  • 后端接收前端没有过滤的数据,然后过滤非法字符。
  • 利用 Fiter 处理项目中所有非法字符。

很明显前两种实现方法会存在重复代码,因为每个前端页面或后端都需要处理,这样会导致代码极难维护。如果用过滤器来实现, 则只需要用过滤器对所有接口进行过滤处理。这样非常方便,同时不会出现冗余代码。

使用 Filter 的步骤

  1. 新建类,实现Filer抽象类
  2. 重写init、doFilter、 destroy 方法。
  3. 在Spring Boot入口中添加注解 @ServletComponentScan,以注册 Filter

在重写3个方法后,还可以进一步修改 request 参数使用的封装方式,如:

  1. 编写 ParameterRequestWrapper 类继承 HttpServletRequestWrapper 类。
  2. 编写 ParameterRequestWrapper 类构造器。
  3. 在构造器中覆写父类构造器,并将 request.getParameterMap 加入子类的成员变量。
  4. 編写 addParam 方法。
  5. 修改参数并调用 ParamelerRequstWrapper 实例,并保存params
  6. 调用 doFilter 方法中的 FiteChain 变量,以重新封装修改后的 request。

 编写过滤器类

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

//作用范围
@WebFilter(urlPatterns = "/*")
public class FilterDemo01 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //init逻辑,该init将在服务器启动时调用
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //request处理逻辑
        //request在封装逻辑
        //chain重新写回request和response
        System.out.println("过滤器");
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        //写destroy逻辑,该destroy逻辑将在服务器关闭时调用
    }
}

在入口类中开启 Servlet 支持

直接在入口类加入 @ServletComponentScan 即可。因为通过注解 @WebFilter(urlPatterns = "/*") 定义了 urlPatterns 的变量值为“*”,代表“所有的路径”。

测试

@RestController
@RequestMapping("test")
public class TestController {
	
	/**
	 * 测试get方法
	 * @param userName
	 * @return
	 */
	@RequestMapping(value="get",method = RequestMethod.GET)
	public String testGet(String userName){
		System.out.println("get使用参数:"+userName);
		return userName;
	}
	
	/**
	 * 测试post方法
	 * @param userName
	 * @return
	 */
	@RequestMapping(value="post",method = RequestMethod.POST)
	public String testPost(String userName){
		System.out.println("post使用参数:"+userName);
		return userName;
	}
}

所以,用户在访问本项目下的任何路径的页面时,此过滤器都会在控制台输出以下信息: 

认识监听器

监听器(Listener)用于监听 Web 应用程序中某些对象或信息的创建、销毁、增加、修改、删除等动作,然后做出相应的响应处理。当对象的状态发生变化时,服务器自动调用监听器的方法。临听器常用于统计在线人数、在线用户、系统加载时的信息初始化等。

Servlet中的监听器分为以下3种类型:

1、监听ServletContext、Request、 Session 作用域的创建和销毁

  • ServletContextListener:监听 ServeltContext。
  • HttpSessionListener:监听新的 Session 创建事件。
  • ServletRequestListener:监听 ServletRequest 的初始化和销毁。

2、监听ServletContext、Request、Session 作用域中属性的变化(增加、修改、删除)

  • ServletContextAttributeListener:监听 Servlet 上下文参数的变化。
  • HttpSessionAttributeListener:监听 HttpSession 参数的变化。
  • ServletRequestAttributeListener:监听 ServletRequest 参数的变化。

3、监听HttpSession中对象状态的改变(被绑定、解除绑定、钝化、活化)

  • HttpSessionBindingListener:监听 HttpSession ,并绑定及解除绑定。
  • HtpSessonActivationListener:监听钝化和活动的 HttpSession 状态改变。

实现监听器

创建监听器类,监听 ServeltContext

通过注解  @WebListener 标注此类是监听类,代码如下:

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

@WebListener
public class listenerDemo implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("ServletContex初始化");
        System.out.println(servletContextEvent.getServletContext().getServerInfo());
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("ServletContex销毁");
        System.out.println(servletContextEvent.getServletContext().getServerInfo());
    }
}

开启监听器 Bean 扫描

在入口类上,添加注解 @ServletComponentScan

启动项目后,控制台输出:

如果不停止,在端口占用的情况下重新启动,则会显示:

创建监听器类,监听新的 Session 创建事件

import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
 
@WebListener
public class listenerDemo implements HttpSessionListener{
 
    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        System.out.println("MyListener sessionCreated-----");
    }
 
    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        System.out.println("MyListener sessionDestroyed-----");
    }
}

创建控制器 

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

@RestController
@RequestMapping("test")
public class TestController {

    @RequestMapping(value = "sessionTestSet", method = RequestMethod.GET)
    public String sessionTestSet(HttpSession session) {
        session.setAttribute("session", "测试监视器的 Session");
        return "sessionTestSet";
    }

    @RequestMapping(value = "sessionTestGet", method = RequestMethod.GET)
    public String sessionTestGet(HttpSession session) {
        Object s = session.getAttribute("session");
        session.removeAttribute("session");
        return s.toString();
    }
}

测试结果:

认识拦截器

拦截器的使用场景

处理所有请求共性问题:

  1. 乱码问题:用request,response参数去设置编码;
  2. 解决权限验证问题(是否登陆,取session对象查看);

拦截器与过滤器的区别

  1. 拦截器 Interceptor 依赖于框架容器,基于反射机制,只过滤请求;
  2. 过滤器 Filter 依赖于 Servlet 容器,基于回调函数,过滤范围大;

创建一个拦截器实现HandlerInterceptor接口

package com.jia.config;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyHandlerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        System.out.println("在controller执行之前调用");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("controller执行之后,且页面渲染之前调用");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("页面渲染之后调用,一般用于资源清理操作");
    }
}

新建配置类来管理拦截器,并将之前的拦截器注入其中

package com.jia.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

//扩展springmvc
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
    // 拦截器配置
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyHandlerInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/index","/","/css/**","/js/**","img/**");
    }
}

添加拦截:

addPathPatterns("/**")

排除拦截:

excludePathPatterns("/index","/","/css/**","/js/**","img/**")

控制类

    @RequestMapping("interceptorTest")
    public String interceptorTest() {
        System.out.println("测试拦截器");
        return "测试拦截器";
    }

测试结果

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值