spring boot拦截器和过滤器_java拦截器的作用

spring boot拦截器和过滤器_java拦截器的作用SpringMVC中有两种很普遍的AOP实现:1.过滤器(Filter)2.拦截器(Interceptor)首先说一下两者之间的区别:过滤器和拦截器非常相似,但是它们有很大的区别a.最简单明了的区别就是过滤器可以修改request,而拦截器不能b.过滤器需要在servlet容器中实现,拦截器可以适用于javaEE,javaSE等各种环境c.拦截器可以调用IOC容器中的各种依赖,而过滤器不能d.过滤器只能在请求的前后使用,而拦截器可以详细到每个方法一、HandlerInterc

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

SpringMVC中有两种很普遍的AOP实现:

1.过滤器(Filter)

2.拦截器(Interceptor)

首先说一下两者之间的区别:

过滤器和拦截器非常相似,但是它们有很大的区别

a.最简单明了的区别就是过滤器可以修改request,而拦截器不能

b.过滤器需要在servlet容器中实现,拦截器可以适用于javaEE,javaSE等各种环境

c.拦截器可以调用IOC容器中的各种依赖,而过滤器不能d.过滤器只能在请求的前后使用,而拦截器可以详细到每个方法

一、HandlerInterceptor定义实现类

拦截器我想大家都并不陌生,最常用的登录拦截、或是权限校验、或是防重复提交、或是根据业务像12306去校验购票时间,总之可以去做很多的事情

应用场景

  1. 日志记录,可以记录请求信息的日志,以便进行信息监控、信息统计等。

  2. 权限检查:如登陆检测,进入处理器检测是否登陆,如果没有直接返回到登陆页面。

  3. 性能监控:典型的是慢日志。 

定义一个Interceptor 非常简单,方式也有几种,我这里简单列举两种:

  1. 类要实现Spring 的HandlerInterceptor 接口;
  2. 类继承实现了HandlerInterceptor 接口的类,例如:已经提供的实现了HandlerInterceptor 接口的抽象类HandlerInterceptorAdapter。
public interface HandlerInterceptor {
 
   /**
     * 预处理回调方法,实现处理器的预处理(如检查登陆),第三个参数为响应的处理器,自定义Controller
     * 返回值:true表示继续流程(如调用下一个拦截器或处理器);false表示流程中断
(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;
   */
    boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception;
 
   /**
     * 后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以
通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
   */
    void postHandle(
            HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
            throws Exception;
 
   /**
    * 整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输
出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中
   */
    void afterCompletion(
            HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception;
 
 
}
  • preHandle:在业务处理器处理请求之前被调用。预处理,可以进行编码、安全控制、权限校验等处理;
  • postHandle:在业务处理器处理请求执行完成后,生成视图之前执行。后处理(调用了Service并返回ModelAndView,但未进行页面渲染),有机会修改ModelAndView (这个博主就基本不怎么用了);
  • afterCompletion:在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面);

拦截器实现

鉴权示例:

import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;

/**
 * 鉴权
 */
@Slf4j
@Component
public class MyInterceptor implements HandlerInterceptor {


    private SecurityUser securityUser;


    public MyInterceptor (SecurityUser securityUser) {
        this.securityUser = securityUser;
    }

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o)
            throws Exception {
        String token = securityUser.getToken(httpServletRequest);
        if (StringUtils.isEmpty(token) || !securityUser.validateToken(token)) {
            log.info("token is empty...");
            httpServletResponse.setContentType("application/json;charset=UTF-8");
            httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
            // 把json数据返回给浏览器:
            final SerializerFeature[] features = {SerializerFeature.DisableCircularReferenceDetect,
                    SerializerFeature.WriteDateUseDateFormat};
            PrintWriter out = httpServletResponse.getWriter();
            out.print(ReturnMapUtils.setFailedMsgRtnJsonStr("鉴权失败"));
            return false;
        } else {
            securityUser.checkRenewal(token);
            return true; // 只有返回true才会继续向下执行,返回false取消当前请求
        }
    }


    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o,
                           ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                                Object o, Exception e) throws Exception {

    }
}

二、WebAppConfigurer

新建WebAppConfigurer:实现WebMvcConfigurer接口,拦截请求

import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.Arrays;


/**
 *
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private SecurityUser securityUser;
    private Logger logger = LoggerUtil.getLogger();

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 自定义拦截器
        registry.addInterceptor(new MyInterceptor(securityUser)).addPathPatterns("/**").excludePathPatterns(Arrays.asList("/components/**", "/js/**", "/images/**", "/css/**", "/img/**", "/img/*"));
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        String storagePathHead = System.getProperty("user.dir");
        String imagesPath = ("file:" + storagePathHead + "/storage/image/");
        String videosPath = ("file:" + storagePathHead + "/storage/video/");
        String xmlPath = ("file:" + storagePathHead + "/storage/xml/");
        logger.info("imagesPath=" + imagesPath);
        logger.info("videosPath=" + videosPath);
        logger.info("xmlPath=" + xmlPath);
        registry.addResourceHandler("/images/**", "/videos/**", "/xml/**").addResourceLocations(imagesPath, videosPath, xmlPath);

        // Swagger2Config
        registry.addResourceHandler("/**")
                .addResourceLocations("classpath:/META-INF/resources/")
                .addResourceLocations("classpath:/resources/")
                .addResourceLocations("classpath:/static/")
                .addResourceLocations("classpath:/public/");
        WebMvcConfigurer.super.addResourceHandlers(registry);
    }


    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "POST", "OPTIONS", "PUT", "DELETE")
                .allowedHeaders("*")
                .allowCredentials(false).maxAge(3600);
        WebMvcConfigurer.super.addCorsMappings(registry);
    }
}

WebMvcConfigurer比较常用的方法:

a.addInterceptors:拦截器

addInterceptor:需要一个实现HandlerInterceptor接口的拦截器实例

addPathPatterns:用于设置拦截器的过滤路径规则,增加url的拦截路径,addPathPatterns(“/**”)对所有请求都拦截

excludePathPatterns:用于设置不需要拦截的过滤规则,排除url的拦截路径,如:”/login”, “/register”意为登录和注册不做拦截;

拦截器主要用途:进行用户登陆状态的拦截,日志的拦截等

b.addResourceHandlers:静态资源

比如,我们想自定义静态资源映射目录的话,只需重写addResourceHandlers方法即可

注意:如果继承WebMvcConfigurationSupport类实现配置时必须要重写该方法

addResourceHandler:指的是对外暴露的访问路径

addResourceLocations:指的是内部文件放置的目录

c.addCorsMappings:跨域

@Override
public void addCorsMappings(CorsRegistry registry) {

    super.addCorsMappings(registry);
    registry.addMapping(“/cors/**”)
            .allowedHeaders(“*”)
            .allowedMethods(“POST”,”GET”)
            .allowedOrigins(“*”);
}

三、过滤器(Filter)

Filter的字面意思:过滤器就是过滤的作用,在web开发中过滤一些我们指定的url;比如:

a.拦截掉我们不需要的接口请求

b.修改请求(request)和响应(response)内容

c.完成CORS跨域请求等等

import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


/**
 *
 */
@Component
public class CorsFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET,OPTIONS");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Expose-Headers", "token");
        response.setHeader("Access-Control-Allow-Headers",
                "x-requested-with,Authorization,origin,Content-Type,accept,contentType,token");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        String options = "OPTIONS";
        if (options.equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            filterChain.doFilter(servletRequest, servletResponse);
        }

    }

    @Override
    public void init(FilterConfig filterConfig) {
    }

    @Override
    public void destroy() {
    }
}

初始化(init)和摧毁(destroy)方法一般不会用到,具体使用看下源码便知

doFilter()是过滤器的核心

注意:在实现接口方法之后,我们要转换request和response类型至HttpServlet,否则接下去的操作可能会报错。

如果过滤通过,执行filterChain.doFilter(request,response);说明这个url已经经过了我们的Filter

可以看到,只需要一个类我们就实现了一个简单的过滤器;当然可以不用注解的方式,配置启动类

https://blog.csdn.net/weixin_36307377/article/details/114901647

https://blog.csdn.net/weixin_44259720/article/details/104615086

https://blog.csdn.net/pengdeman/article/details/105286305

https://blog.csdn.net/A434534658/article/details/112139041

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/172393.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • jediscluster工具类_cannot get jedis connection

    jediscluster工具类_cannot get jedis connectionRedis集群是没法执行批量操作命令的,如mget,pipeline等。这是因为redis将集群划分为16383个哈希槽,不同的key会划分到不同的槽中。原生JedisCluster对批量操作的限制是mgetmset必须在一个槽;四种批量优化的方法1、串行mget在for循环中执行一条条的get; 需要n次网络时间;2、串行IO在客户端对所有key做CR…

    2022年9月25日
    0
  • 智能家居急速扩容 企业标准各异

    智能家居急速扩容 企业标准各异

    2022年3月4日
    29
  • Chrome您的连接不是私密连接解决办法–一个比较实用的技巧分享[通俗易懂]

    Chrome您的连接不是私密连接解决办法–一个比较实用的技巧分享[通俗易懂]问题:运行项目在Chrome中打开出现以下问题您的连接不是私密连接攻击者可能会试图从x.x.x.x窃取您的信息(例如:密码、通讯内容或信用卡信息)。了解详情NET::ERR_CERT_INVALID将您访问的部分网页的网址、有限的系统信息以及部分网页内容发送给Google,以帮助我们提升Chrome的安全性。隐私权政策x.x.x.x通常会使用加密技术来保护您的信息。GoogleChrome此次尝试连接到x.x.x.x时,此网站发回了异常的错误凭据。这可能是因为有攻击者在试图

    2022年5月2日
    164
  • [Elasticsearch] 邻近匹配 (三) – 性能,关联单词查询以及Shingles

    [Elasticsearch] 邻近匹配 (三) – 性能,关联单词查询以及Shingles提高性能短语和邻近度查询比简单的match查询在性能上更昂贵。match查询只是查看词条是否存在于倒排索引(InvertedIndex)中,而match_phrase查询则需要计算和比较多个可能重复词条(Multiplepossiblyrepeated)的位置。在LuceneNightlyBenchmarks中,显示了一个简单的term查询比一个短语查询快大概10倍,比一

    2025年6月12日
    0
  • js三目运算符

    js三目运算符js三目运算符js三目运算符的正常表达为variable=boolean_expression?true_value:false_value;当boolean_expression传入的不是表达式而是变量时,是如何判断的?在es5文档中找到了解释:先将boolean_expression进行计算拿到结果赋给lref,然后根据ToBoolean(lref)拿到是tr

    2022年6月29日
    24
  • 虚拟机安装xp要多久_虚拟机vmware安装教程

    虚拟机安装xp要多久_虚拟机vmware安装教程    最近使用VMware虚拟机安装XP3时老是弹出找不到A:/GHOSTERR.TXT的错误提示信息,开始以为是下载的ISO镜像文件有问题,就又重新下载了一个雨林木风版本的,可是安装时还是遇到同样的问题,说明镜像ISO问题不大。于是上网google了上述提示信息,发现很多人安装XP都遇到过,大致是磁盘或光盘的问题,有人建议对磁盘进行分区或格式化。    于是,利用雨林木风自带的工具将分

    2022年8月16日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号