拦截器、过滤器、跨域配置

目录

一、跨域

1. @CrossOrigin

2.CorsFilter , spring webmvc 中给出过滤器层面的跨域

3.CorsWebFilter ,spring webflux中的过滤器

4.配置文件 进行跨域设置

5.Filter方式进行设置

6.继承 HandlerInterceptorAdapter

7.实现 WebMvcConfigurer

8.SpringBoot跨域配置

8.1

8.2

二、拦截器

三、过滤器

1.代码实现

2.通过web.xml文件配置

多个Filter的执行顺序

3.中文乱码过滤器


一、跨域

1. @CrossOrigin

解决单个controller跨域问题,直接在需要跨域的Controller的类上添加 @CrossOrigin 跨域注解即可。

@CrossOrigin  //在controller类上添加此注解
@CrossOrigin
@RestController
@RequestMapping("/user")
public class UserController {

	@GetMapping("/{id}")
	public User get(@PathVariable Long id) {
		
	}
}

2.CorsFilter , spring webmvc 中给出过滤器层面的跨域

当一个模块中controlller过多时,添加注解过于繁琐,可以创建一个配置类对象,进行跨域设置,'' FilterRegistrationBean<Corsfilter> ''。

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
 
/**
 * FilterRegistrationBean<CorsFilter> 这个是web MVC中给出的过滤器
 * 解决多个Controller中的跨域问题
 */
@Configuration
public class CorsFilterConfig {
    @Bean
    public FilterRegistrationBean<CorsFilter>
            filterFilterRegistrationBean(){
        UrlBasedCorsConfigurationSource configSource =
                new UrlBasedCorsConfigurationSource();
 
        CorsConfiguration corsConfiguration =
                new CorsConfiguration();
 
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.setAllowCredentials(true);
 
        configSource.registerCorsConfiguration("/**",
                                                corsConfiguration);
        FilterRegistrationBean<CorsFilter> fBean =
                new FilterRegistrationBean<>(
                        new CorsFilter(configSource));
 
        fBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return fBean;
    }
}

3.CorsWebFilter ,spring webflux中的过滤器

一个网关管理多个服务时,设置此配置类对象,可以从网关层面解决多个服务的跨域问题,这就不需要每个服务都写一遍跨域了。

import org.springframework.context.annotation.Bean;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
 
/**
 * CorsWebFilter这个是spring webflux中的过滤器
 * 可以解决网关层面多个服务的跨域问题
 */
@Configuration
public class CorsFilterConfig {
    @Bean
    public CorsWebFilter corsWebFilter(){
 
        UrlBasedCorsConfigurationSource configSource =
                new UrlBasedCorsConfigurationSource();
 
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOrigin("*");
        config.addAllowedMethod("*");
        config.addAllowedHeader("*");
        config.setAllowCredentials(true);
 
        configSource.registerCorsConfiguration("/**",config);
        return new CorsWebFilter(configSource);
    }
}

4.配置文件 进行跨域设置

spring:
  cloud:
    gateway:
      globalcors: #跨域配置
        corsConfigurations:
          '[/**]':
            allowedOrigins: "*"
            allowedHeaders: "*"
            allowedMethods: "*"
            allowCredentials: true

5.Filter方式进行设置

@WebFilter
public class CorsFilter implements Filter {  

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {  
        HttpServletResponse response = (HttpServletResponse) res;  
        response.setHeader("Access-Control-Allow-Origin", "*");  
        response.setHeader("Access-Control-Allow-Methods", "*");  
        response.setHeader("Access-Control-Max-Age", "3600");  
        response.setHeader("Access-Control-Allow-Headers", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        chain.doFilter(req, res);  
    }  
}

6.继承 HandlerInterceptorAdapter

@Component
public class CrossInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        return true;
    }
}

7.实现 WebMvcConfigurer

@Configuration
@SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
public class AppConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")  // 拦截所有的请求
                .allowedOrigins("http://www.abc.com")  // 可跨域的域名,可以为 *
                .allowCredentials(true)
                .allowedMethods("*")   // 允许跨域的方法,可以单独配置
                .allowedHeaders("*");  // 允许跨域的请求头,可以单独配置
    }
}

8.SpringBoot跨域配置

8.1

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

/**
 * @Author: 
 * @CreateTime: 2022-11-28  13:26
 * @Description: 配置跨域
 */
@Configuration
public class GlobalCorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOrigin("*");
        config.setAllowCredentials(true);
        config.addAllowedMethod("*");
        config.addAllowedHeader("*");
        UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
        configSource.registerCorsConfiguration("/**", config);
        return new CorsFilter(configSource);
    }
}

8.2

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
public class CorsConfig{
    @Bean
    public CorsFilter corsFilter() {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true); // 允许cookies跨域
        config.addAllowedOrigin("*");// #允许向该服务器提交请求的URI,*表示全部允许,自定义可以添加多个,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
        config.addAllowedHeader("header1");// #允许访问的头信息,*表示全部,可以添加多个
        config.setMaxAge(18000L);// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
        config.addAllowedMethod("OPTIONS");// 允许提交请求的方法,*表示全部允许,一般OPTIONS,GET,POST三个够了
        config.addAllowedMethod("HEAD");
        config.addAllowedMethod("GET");
        config.addAllowedMethod("PUT");
        config.addAllowedMethod("POST");
        config.addAllowedMethod("DELETE");
        config.addAllowedMethod("PATCH");
        source.registerCorsConfiguration("/**", config);

        return new CorsFilter(source);

    }
}

二、拦截器

1.实现WebMvcConfigurer接口的配置类,重写其中的addCorsMappings()方法【配置跨域信息】和addInterceptors()方法【配置拦截器信息,如拦截路径和开放路径等】

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

/**
 * @Author: 
 * @CreateTime: 2022-11-24  14:08
 * @Description: 定义拦截器
 */
@Configuration//标识这是一个配置类
public class InterceptorAdapterConfig implements WebMvcConfigurer {


    /**
     * 重写addCorsMappings()解决跨域问题
     * 配置:允许http请求进行跨域访问
     *
     * @param registry
     * @Author
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")//指哪些接口URL需要增加跨域设置
                .allowedOrigins("*")//指的是前端哪些域名被允许跨域
                .allowCredentials(true)//需要带cookie等凭证时,设置为true,就会把cookie的相关信息带上
                .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")//指的是允许哪些方法
                .maxAge(3600);//cookie的失效时间,单位为秒(s),若设置为-1,则关闭浏览器就失效
    }

    /**
     * 重写addInterceptors()实现拦截器
     * 配置:要拦截的路径以及不拦截的路径
     *
     * @param registry
     * @Author
     */
    @Override
    public void addInterceptors(InterceptorRegistry interceptorRegistry) {
        //注册Interceptor拦截器(Interceptor这个类是我们自己写的拦截器类)
        InterceptorRegistration registry = interceptorRegistry.addInterceptor(new InterceptorConfigurer());
        // 拦截所有请求   添加需要拦截的路径
        String[] addPaths = {
                "/**"
        };
        //放过的请求路径  添加不拦截的路径
        String[] excludePaths = {
                "/**/*.css", "/**/*.js", "/**/*.png", "/**/*.jpg", "/**/*.jpeg", "/rescue/admin/loginAccount", "/rescue/admin/loginRest",
                "/rescue/admin/activated", "/rescue/admin/reset", "/rescue/admin/set", "/rescue/admin/note", "/rescue/admin/captcha",
                "/rescue/admin/account/avatar", "/rescue/admin/resource/photo", "/rescue/admin/resource/getCityCode",
                "/rescue/admin/product/photoProduct"
        };
        registry.addPathPatterns(addPaths);
        registry.excludePathPatterns(excludePaths);
    }

}

2.实现HandlerInterceptor接口的自定义拦截器,重写其中的preHandle()方法,方法内容为拦截到请求后的处理

import com.admin.api.base.Result;
import com.admin.api.base.SystemCode;
import com.baomidou.mybatisplus.extension.exceptions.ApiException;
import lombok.extern.log4j.Log4j2;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.CrossOrigin;
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.IOException;
import java.io.PrintWriter;

/**
 * @Author: 
 * @CreateTime: 2022-11-24  14:07
 * @Description: 拦截器配置
 */
@Log4j2
public class InterceptorConfigurer implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) {
        try {
            // 逻辑处理
            Result result = new Result();
            String token = TokenUtils.getCookieToken(request);
            log.info("token=" + token);
            if (StringUtils.isNotBlank(token)) {
                int userId = TokenUtils.getUserId(token);
                if (userId <= 0) {//判断用户是否登录
                    result = Result.fail(SystemCode.UNAUTHORIZED.getCode(), SystemCode.UNAUTHORIZED.getMessage());
                }
            } else {
                判断token是否过期
                result = Result.fail(SystemCode.LOSE_TOKEN.getCode(), SystemCode.LOSE_TOKEN.getMessage());
            }
            if (result.getCode() == 401 || result.getCode() == 420) {
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/json;charset=UTF-8");
                PrintWriter out = null;
                try {
                    out = response.getWriter();
                    out.println(JSONObject.fromObject(result));
                } catch (IOException ioException) {
                    ioException.printStackTrace();
                }
                return false;
            }
            // 不做拦截的地址
            if (!checkRequestURI(request)) {

            }
            //这里设置拦截以后重定向的页面,一般设置为登陆页面地址
            response.sendRedirect(request.getContextPath() + "/user/login");
            //如果设置为false时,被请求时,拦截器执行到此处将不会继续操作
            //如果设置为true时,请求将会继续执行后面的操作
            return true;
        } catch (Exception e) {
            throw new ApiException(e.getMessage(), e);
        }
    }

    // 不做拦截的地址
    public Boolean checkRequestURI(HttpServletRequest request) {
        log.info(request.getRequestURI());
        if (request.getRequestURI().equals("")) {
            return true;
        }
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object o, ModelAndView modelAndView) {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object o, Exception e) {

    }

}

三、过滤器

1.代码实现

过滤器的本质就是一个实现了 Filter 接口的 Java 类

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

@WebFilter("/*")//过滤路径
public class MyFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("过滤器初始化了........init... "+filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("过滤前........doFilter "); //放行
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("过滤后.......doFilter");
    }

    @Override
    public void destroy() {
        System.out.println("销毁了.....destroy");
    }

}
  • doFilter(ServletRequest, ServletResponse, FilterChain):这是一个完成过滤行为的方法。这同样是上游过滤器调用的方法。引入的FilterChain对象提供了后续过滤器所要调用的信息。如果该过滤器是过滤器链中的最后一个过滤器,则将请求交给被请求资源。也可以直接给客户端返回响应信息。
  • init(FilterConfig):由Web容器来调用完成过滤器的初始化工作。它保证了在第一次doFilter()调用前由容器调用。您能获取在web.xml 文件中指定的初始化参数。
  • destroy():由Web容器来调用来释放资源,doFilter()中的所有活动都被该实例终止后,调用该方法。

2.通过web.xml文件配置

<filter>
    <filter-name>FilterDemo1</filter-name>
    <filter-class>FilterDemo1</filter-class>
    <init-param>
        <param-name>word_file</param-name>    
        <param-value>/WEB-INF/word.txt</param-value>
    </init-param>
</filter>
 
<filter-mapping>
    <filter-name>FilterDemo1</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<filter>指定一个过滤器。
<filter-name>用于为过滤器指定一个名字,该元素的内容不能为空。
<filter-class>元素用于指定过滤器的完整的限定类名。
<init-param>元素用于为过滤器指定初始化参数
<param-name>指定参数的名字,
<param-value>指定参数的值。

在过滤器中,可以使用FilterConfig接口对象来访问初始化参数。
<filter-mapping>元素用于设置一个 Filter 所负责拦截的资源。一个Filter拦截的资源可通过两种方式来指定:Servlet 名称和资源访问的请求路径
<filter-name>子元素用于设置filter的注册名称。该值必须是在<filter>元素中声明过的过滤器的名字
<url-pattern>设置 filter 所拦截的请求路径(过滤器关联的URL样式)

<servlet-name>指定过滤器所拦截的Servlet名称。
<dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST。用户可以设置多个<dispatcher>子元素用来指定 Filter 对资源的多种调用方式进行拦截。

<dispatcher>子元素可以设置的值及其意义
REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。
INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。
FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。

拦截方式配置:dispatcher
拦截方式配置也就是资源被访问的形式,有这么几个属性

REQUEST:默认值,浏览器直接请求资源
FORWARD:转发访问资源 : RequestDispatcher.forward();
INCLUDE:包含访问资源 : RequestDispatcher.include();
ERROR:错误跳转资源 : 被声明式异常处理机制调用的时候

补充:声明式异常处理即:在web.xml中通过配置来确定不同的异常类型将如何被处理,最后跳转到哪个页面,也就是我们常常看到的一些404错误页面

<error-page>
      <!--异常的类-->
         <exception-type>xxx</exception-type>
      <!--异常发生时跳转的页面-->
        <location>xxx</location>
</error-page>

多个Filter的执行顺序

如果一定要确保执行顺序,就要对配置进行修改了,执行顺序如下:

  • 在web.xml中,filter执行顺序跟的顺序有关,先声明的先执行。
  • 使用注解配置的话,filter的执行顺序跟名称的字母顺序有关,例如AFilter会比BFilter先执行。
  • 如果既有在web.xml中声明的Filter,也有通过注解配置的Filter,那么会优先执行web.xml中配置的Filter

先执行带有url-pattern标签的filter,再执行带有servlet-name标签的filter 如果同为url-pattern或servlet-name,则会按照在web.xml中的声明顺序执行

// ATestFilter
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    System.out.println("in ATestFilter");
    chain.doFilter(request, response);
}
 
 
// TestFilter
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    System.out.println("in TestFilter");
    chain.doFilter(request, response);
}
 
// ServletFilter
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    System.out.println("in ServletFilter");
    chain.doFilter(request, response);
}
<filter>
    <filter-name>servletFilter</filter-name>
    <filter-class>com.test.servletFilter</filter-class>
    <async-supported>true</async-supported>
</filter>
<filter-mapping> 
    <filter-name>servletFilter</filter-name>
    <servlet-name>MVC-dispatchar</servlet-name>
</filter-mapping >

<filter>
    <filter-name>testFilter</filter-name>
    <filter-class>com.test.testFilter</filter-class>
    <async-supported>true</async-supported>
</filter>
<filter- mapping>
    <filter-name>testFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<filter>
    <filter-name>atestFilter</filter-name>
    <filter-class>com.test.atestFilter</filter-class>
    <async-supported>true</async-supported>
</filter>
<filter- mapping>
    <filter-name>atestFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

配置中先有两个/*路径,这两个先执行

in TestFilter

in ATestFilter

in ServletFilter

3.中文乱码过滤器

论在做什么web应用的开发中,中文乱码的问题是很常见的,所以这类问题应该被重视。中文乱码出现的场景非常多,每次都去处理很麻烦,还有可能出现遗漏的情况,所以一个处理中文乱码的过滤器就能很好的解决这个问题。

<filter>
    <filter-name>encoding</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name><!--用来指定一个具体的字符集-->
        <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
        <param-name>forceEncoding</param-name>
<!--true:无论request是否指定了字符集,都是用encoding;false:如果request已指定一个字符集,则不使用encoding-->
        <param-value>false</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
Spring Boot中的拦截器过滤器和监听器都是用于处理请求和响应的组件,但它们在功能和使用方式上有一些区别。 拦截器(Interceptor)是Spring提供的一种机制,用于对请求进行预处理和后处理。拦截器可以拦截特定的URL请求,并在请求前后执行一些自定义的逻辑。拦截器基于Java的动态代理机制实现,可以在请求的处理过程中插入自定义的逻辑。拦截器通常用于进行身份验证、日志记录等通用处理。 过滤器(Filter)是Java Servlet规范提供的一种机制,用于对请求和响应进行过滤和修改。过滤器可以拦截所有的URL请求,并在请求前后对请求进行预处理和后处理。过滤器基于Java的回调函数机制实现,在请求进入Servlet容器之前和响应离开Servlet容器之前进行拦截和处理。过滤器通常用于请求解析、字符编码转换、跨域处理等通用处理。 监听器(Listener)是Java Servlet规范提供的一种机制,用于监听Web应用程序中事件的发生。监听器可以监听Servlet容器中的特定事件,如应用程序的初始化、销毁、会话的创建、销毁等。监听器基于Java的回调函数机制实现,可以在特定事件发生时执行自定义的逻辑。监听器通常用于应用程序的初始化、资源管理等操作。 在Spring Boot中,拦截器过滤器可以直接在配置类中进行配置和注册,而监听器需要通过@WebListener注解或在配置类中手动注册。需要注意的是,拦截器过滤器和监听器的执行顺序是不同的,拦截器在请求进入Controller之前执行,过滤器在请求进入Servlet容器之前执行,而监听器可以监听更多的事件,不仅限于请求和响应。 希望以上信息对你有所帮助!如果你有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值