官方文档译文

Spring Boot 包括对嵌入式TomcatJettyUndertow服务器的支持。大多数开发人员使用适当的“Starter”来获取完全配置的实例。默认情况下,嵌入式服务器在 port 8080上侦听 HTTP 请求。

如果选择在CentOS上使用 Tomcat,请注意,默认情况下,临时目录用于存储已编译的 JSP,文件上载等。当 application 正在运行时,tmpwatch可能会删除此目录,从而导致失败。要避免此行为,您可能希望自定义tmpwatch configuration,以便不删除tomcat.*目录或配置server.tomcat.basedir,以便嵌入式 Tomcat 使用不同的位置。

1 Servlets,Filters 和 listeners

使用嵌入式 servlet 容器时,可以使用 Spring beans 或扫描 Servlet 组件,从 Servlet 规范中注册 servlets,过滤器和所有 listeners(如HttpSessionListener)。

将 Servlets,Filters 和 Listeners 注册为 Spring Beans

作为 Spring bean 的任何ServletFilter或 servlet *Listener实例都在嵌入式容器中注册。如果要在 configuration 期间从application.properties引用 value,这可能特别方便。

默认情况下,如果 context 仅包含一个 Servlet,则它将映射到/。在多个 servlet beans 的情况下, bean name 用作路径前缀。将 map 过滤为/*

如果 convention-based mapping 不够灵活,您可以使用ServletRegistrationBeanFilterRegistrationBeanServletListenerRegistrationBean classes 进行完全控制。

Spring Boot 附带了许多可能定义 Filter beans 的 auto-configurations。以下是过滤器及其各自 order 的一些示例(lower order value 表示更高的优先级):

Servlet 过滤器 订购
OrderedCharacterEncodingFilter Ordered.HIGHEST_PRECEDENCE
WebMvcMetricsFilter Ordered.HIGHEST_PRECEDENCE + 1
ErrorPageFilter Ordered.HIGHEST_PRECEDENCE + 1
HttpTraceFilter Ordered.LOWEST_PRECEDENCE - 10

将 Filter beans 无序排列通常是安全的。

如果需要特定的 order,则应避免配置在Ordered.HIGHEST_PRECEDENCE处读取请求正文的 Filter,因为它可能违反 application 的字符编码 configuration。如果 Servlet 过滤器包装请求,则应使用小于或等于OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER的 order 进行配置。

2 Servlet Context 初始化

嵌入式 servlet 容器不直接执行 Servlet 3.0 javax.servlet.ServletContainerInitializer接口或 Spring 的org.springframework.web.WebApplicationInitializer接口。这是一个故意的设计决定,旨在降低第方库设计为 war 内部 war 的风险可能 break Spring Boot applications。

如果需要在 Spring Boot application 中执行 servlet context 初始化,则应注册实现org.springframework.boot.web.servlet.ServletContextInitializer接口的 bean。单个onStartup方法提供对ServletContext的访问,如果需要,可以很容易地用作现有WebApplicationInitializer的适配器。

扫描 Servlet,过滤器和 listeners

使用嵌入式容器时,可以使用@ServletComponentScan启用使用@WebServlet@WebFilter@WebListener注释的 classes 的自动注册。

@ServletComponentScan在独立容器中没有任何效果,而是使用容器的 built-in 发现机制。

3 ServletWebServerApplicationContext

在引擎盖下,Spring Boot 使用不同类型的ApplicationContext来嵌入 servlet 容器支持。 ServletWebServerApplicationContext是一种特殊类型的WebApplicationContext,它通过搜索单个ServletWebServerFactory bean 来引导自己。通常TomcatServletWebServerFactoryJettyServletWebServerFactoryUndertowServletWebServerFactory已经是 auto-configured。

您通常不需要知道这些 implementation classes。大多数 applications 都是 auto-configured,并且代表您创建了适当的ApplicationContextServletWebServerFactory

4 自定义嵌入式 Servlet 容器

可以使用 Spring Environment properties 配置 Common servlet 容器设置。通常,您将在application.properties文件中定义 properties。

Common 服务器设置包括:

  • 网络设置:监听传入 HTTP 请求的 port(server.port),绑定到server.address的接口地址,依此类推。

  • Session 设置:session 是持久性的(server.servlet.session.persistence),session 超时(server.servlet.session.timeout),session 数据的位置(server.servlet.session.store-dir)和 session-cookie configuration(server.servlet.session.cookie.*)。

  • 错误 management:错误页面的位置(server.error.path)等。

  • SSL

  • HTTP 压缩

Spring Boot 尝试尽可能多地暴露 common 设置,但这并不总是可行。对于这些情况,专用命名空间提供 server-specific 自定义(请参阅server.tomcatserver.undertow)。例如,可以使用嵌入的 servlet 容器的特定 features 配置访问日志

有关完整列表,请参阅ServerProperties class。

程序化定制

如果需要以编程方式配置嵌入式 servlet 容器,可以注册实现WebServerFactoryCustomizer接口的 Spring bean。 WebServerFactoryCustomizer提供对ConfigurableServletWebServerFactory的访问,其中包括许多自定义 setter 方法。以下 example 以编程方式显示 port:

import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.stereotype.Component;

@Component
public class CustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {

@Override
public void customize(ConfigurableServletWebServerFactory server) {
server.setPort(9000);
}

}

TomcatServletWebServerFactoryJettyServletWebServerFactoryUndertowServletWebServerFactoryConfigurableServletWebServerFactory的专用变体,它们分别为 Tomcat,Jetty 和 Undertow 提供了额外的自定义 setter 方法。

直接自定义 ConfigurableServletWebServerFactory

如果前面的自定义技术太有限,您可以自己注册TomcatServletWebServerFactoryJettyServletWebServerFactoryUndertowServletWebServerFactorybean。

@Bean
public ConfigurableServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.setPort(9000);
factory.setSessionTimeout(10, TimeUnit.MINUTES);
factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notfound.html"));
return factory;
}

为许多 configuration 选项提供了 setter。如果您需要做一些更具异国情调的事情,还会提供一些受保护的方法“挂钩”。有关详细信息,请参阅source code 文档

5 JSP 限制

当 running 使用嵌入式 servlet 容器的 Spring Boot application(并打包为可执行存档)时,JSP 支持存在一些限制。

  • 使用 Jetty 和 Tomcat,如果使用 war 包装,它应该可以工作。可执行的 war 在使用java -jar启动时将起作用,并且还可以部署到任何标准容器。使用可执行文件 jar 时不支持 JSP。

  • Undertow 不支持 JSP。

  • 创建自定义error.jsp页面不会覆盖错误处理的默认视图。应该使用自定义错误页面代替。

有一个JSP sample,所以你可以看到如何设置。

代码

1 Filter

  • 启动类

    @SpringBootApplication
    @ServletComponentScan
    public class FilterApplication {

    public static void main(String[] args) {
    SpringApplication.run(FilterApplication.class, args);
    }

    }
  • 过滤器

    **
    * @author WGR
    * @create 2019/11/14 -- 21:25
    */
    @WebFilter(urlPatterns = "/api/*", filterName = "loginFilter")
    public class LoginFilter implements Filter {

    /**
    * 容器加载的时候调用
    */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    System.out.println("init loginFilter");
    }


    /**
    * 请求被拦截的时候进行调用
    */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    System.out.println("doFilter loginFilter");

    HttpServletRequest req = (HttpServletRequest) servletRequest;
    HttpServletResponse resp = (HttpServletResponse) servletResponse;
    String username = req.getParameter("username");

    if ("topcheer".equals(username)) {
    filterChain.doFilter(servletRequest,servletResponse);
    } else {
    resp.sendRedirect("/index.html");
    return;
    }

    }

    /**
    * 容器被销毁的时候被调用
    */
    @Override
    public void destroy() {
    System.out.println("destroy loginFilter");
    }
    }
  • web层

    /**
    * @author WGR
    * @create 2019/11/14 -- 21:32
    */

    @RestController
    public class LoginController {

    @GetMapping("/api/test_request")
    public Object testRequest(String username){
    return username;
    }
    }
  • html

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
    index static
    <h1>topcheer</h1>
    </body>
    </html>
  • 测试

2 Servlet

  • servlet
@WebServlet(name = "userServlet",urlPatterns = "/v1/api/test/customs")
public class UserServlet extends HttpServlet{ @Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().print("custom sevlet");
resp.getWriter().flush();
resp.getWriter().close();
} @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doGet(req, resp);
} }
  • 测试方法
 @GetMapping("/v1/api/test/customs")
public Object testServlet(){
return "success";
}
  • 测试结果

3 Listener

  • listener
@WebListener
public class RequestListener implements ServletRequestListener { @Override
public void requestDestroyed(ServletRequestEvent sre) {
// TODO Auto-generated method stub
System.out.println("======requestDestroyed========");
} @Override
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("======requestInitialized========"); } }
  • 测试

4 拦截器

@Configuration
public class CustomWebMvcConfigurer implements WebMvcConfigurer { @Override
public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginIntercepter()).addPathPatterns("/api/*/**");
registry.addInterceptor(new TwoIntercepter()).addPathPatterns("/api/*/**"); //.excludePathPatterns("/api2/xxx/**"); //拦截全部 /*/*/** WebMvcConfigurer.super.addInterceptors(registry);
} }
public class LoginIntercepter implements HandlerInterceptor{

    /**
* 进入controller方法之前
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
System.out.println("LoginIntercepter------->preHandle"); // String token = request.getParameter("access_token");
//
// response.getWriter().print("fail"); return HandlerInterceptor.super.preHandle(request, response, handler);
} /**
* 调用完controller之后,视图渲染之前
*/
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception { System.out.println("LoginIntercepter------->postHandle"); HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
} /**
* 整个完成之后,通常用于资源清理
*/
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("LoginIntercepter------->afterCompletion"); HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
} }
public class TwoIntercepter implements HandlerInterceptor{

    /**
* 进入对应的controller方法之前
*/
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception { System.out.println("TwoIntercepter------>preHandle");
return HandlerInterceptor.super.preHandle(request, response, handler);
} /**
* controller处理之后,返回对应的视图之前
*/
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("TwoIntercepter------>postHandle");
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
} /**
* 整个请求结束后调用,视图渲染后,主要用于资源的清理
*/
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("TwoIntercepter------>afterCompletion");
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
} }

测试:

总结:

1、@Configuration
继承WebMvcConfigurationAdapter(SpringBoot2.X之前旧版本)

SpringBoot2.X 新版本配置拦截器 implements WebMvcConfigurer

2、自定义拦截器 HandlerInterceptor
preHandle:调用Controller某个方法之前
postHandle:Controller之后调用,视图渲染之前,如果控制器Controller出现了异常,则不会执行此方法
afterCompletion:不管有没有异常,这个afterCompletion都会被调用,用于资源清理

3、按照注册顺序进行拦截,先注册,先被拦截

拦截器不生效常见问题:
1)是否有加@Configuration
2)拦截路径是否有问题 ** 和 *
3)拦截器最后路径一定要 “/**”, 如果是目录的话则是 /*/

Filter
是基于函数回调 doFilter(),而Interceptor则是基于AOP思想
Filter在只在Servlet前后起作用,而Interceptor够深入到方法前后、异常抛出前后等

依赖于Servlet容器即web应用中,而Interceptor不依赖于Servlet容器所以可以运行在多种环境。

在接口调用的生命周期里,Interceptor可以被多次调用,而Filter只能在容器初始化时调用一次。

Filter和Interceptor的执行顺序

过滤前->拦截前->action执行->拦截后->过滤后

SpringBoot拦截器和 Servlet3.0自定义Filter、Listener的更多相关文章

  1. 【SpringBoot】SpringBoot拦截器实战和 Servlet3.0自定义Filter、Listener

    =================6.SpringBoot拦截器实战和 Servlet3.0自定义Filter.Listener ============ 1.深入SpringBoot2.x过滤器Fi ...

  2. 小D课堂 - 零基础入门SpringBoot2.X到实战_第6节 SpringBoot拦截器实战和 Servlet3.0自定义Filter、Listener_24、深入SpringBoot过滤器和Servlet配置过滤器

    笔记 1.深入SpringBoot2.x过滤器Filter和使用Servlet3.0配置自定义Filter实战(核心知识)     简介:讲解SpringBoot里面Filter讲解和使用Servle ...

  3. springboot + 拦截器 + 注解 实现自定义权限验证

    springboot + 拦截器 + 注解 实现自定义权限验证最近用到一种前端模板技术:jtwig,在权限控制上没有用springSecurity.因此用拦截器和注解结合实现了权限控制. 1.1 定义 ...

  4. SpringBoot 拦截器妙用,让你一个人开发整个系统的鉴权模块!

    我是陈皮,一个在互联网 Coding 的 ITer,微信搜索「陈皮的JavaLib」第一时间阅读最新文章,回复[资料],即可获得我精心整理的技术资料,电子书籍,一线大厂面试资料和优秀简历模板. Han ...

  5. springboot拦截器总结

    Springboot 拦截器总结 拦截器大体分为两类 : handlerInterceptor 和 methodInterceptor 而methodInterceptor 又有XML 配置方法 和A ...

  6. SpringBoot拦截器中Bean无法注入(转)

    问题 这两天遇到SpringBoot拦截器中Bean无法注入问题.下面介绍我的思考过程和解决过程: 1.由于其他bean在service,controller层注入一点问题也没有,开始根本没意识到Be ...

  7. Springboot拦截器实现IP黑名单

    Springboot拦截器实现IP黑名单 一·业务场景和需要实现的功能 以redis作为IP存储地址实现. 业务场景:针对秒杀活动或者常规电商业务场景等,防止恶意脚本不停的刷接口. 实现功能:写一个拦 ...

  8. SpringBoot 拦截器获取http请求参数

    SpringBoot 拦截器获取http请求参数-- 所有骚操作基础 目录 SpringBoot 拦截器获取http请求参数-- 所有骚操作基础 获取http请求参数是一种刚需 定义拦截器获取请求 为 ...

  9. Java结合SpringBoot拦截器实现简单的登录认证模块

    Java结合SpringBoot拦截器实现简单的登录认证模块 之前在做项目时需要实现一个简单的登录认证的功能,就寻思着使用Spring Boot的拦截器来实现,在此记录一下我的整个实现过程,源码见文章 ...

随机推荐

  1. 嵌套的frame

    自动化的测试中,iframe的嵌套也是很常见的,对于嵌套的iframe,我们处理的方式是先进入到iframe的父节点, 再进入到子节点,然后可以对子节点里面的对象进行处理和操作.如下的html代码效果 ...

  2. Java第三周课程总结&实验报告一

    第三周课程总结 1.关于面向对象的一些具体内容,明白了类与对象以及Java的封装性和构造方法以及对对象匿名的相关知识. 2.this关键字,它是表示类的成员属性(变量),使用this构造方法时必须放在 ...

  3. Quartz-第四篇 常规quartz的使用

    1.目录结构 2.主要文件 1>引入的jar包,quartz-2.2.2解压后lib下所有的jar包 2>quartz.properties org.quartz.threadPool.t ...

  4. Spark-Core RDD转换算子-双Value型交互

    1.union(otherDataSet) 作用:求并集. 对源 RDD 和参数 RDD 求并集后返回一个新的 RDD scala> val rdd1 = sc.parallelize(1 to ...

  5. Object.create()的使用方法

    Object.create()的使用方法:https://blog.csdn.net/wang252949/article/details/79109437

  6. [LeetCode] 45. 跳跃游戏 II

    题目链接 : https://leetcode-cn.com/problems/jump-game-ii/ 题目描述: 给定一个非负整数数组,你最初位于数组的第一个位置. 数组中的每个元素代表你在该位 ...

  7. 异步Promise及Async/Await可能最完整入门攻略

    此文只介绍Async/Await与Promise基础知识与实际用到注意的问题,将通过很多代码实例进行说明,两个实例代码是setDelay和setDelaySecond. tips:本文系原创转自我的博 ...

  8. [LOJ 6253] Yazid 的新生舞会

    link $solution:$ 不知道为什么别人的代码能写的非常短,难道就是写差分的好处? 这种题肯定是算每个众数的贡献,考虑通过暴力众数求出个数. 现在考虑众数 $x$ ,则在序列 $a$ 中将等 ...

  9. xss过滤与单例模式(对象的实例永远用一个)

    kindeditor里面可以加入script代码,使用re可以过滤掉python有个专门的模块可以处理这种情况,beautifulsoup4 调用代码: content = XSSFilter().p ...

  10. linux用户管理(useradd、userdel、usermod、groupadd、groupdel、chage、passwd、chpasswd)

    一.用户账户配置文件介绍 /etc/passwd 用户账户信息文件/etc/shadow 用户账户密码文件/etc/group 用户组信息文件/etc/gshadow 用户组密码所在文件(基本废弃)/ ...