# 6.Servlets, Filters, listeners

## 一.Web 开发使用 Controller 基本上可以完成大部分需求，但是我们还可能会用到 Servlet、 Filter、Listener 等等

## 二.在 spring boot 中的三种实现方式

### 方法一：通过注册 ServletRegistrationBean、 FilterRegistrationBean 和 ServletListenerRegistrationBean 获得控制

**自定义 servlet**

```java
/**

* 自定义 servlet

* */

public class CustomServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;


    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        System.out.println("servlet get method");
        doPost(request, response);
    }


    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        System.out.println("servlet post method");
        response.getWriter().write("hello world");

    }

}
```

**自定义 filter**

```java
/**

*自定义 filter

**/
public class CustomFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init filter");
    }


    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("do filter");
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        System.out.println("destroy filter");
    }

}
```

**自定义 listener**

```java
/**
* 自定义 listener
**/

public class CustomListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("contextInitialized");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("contextDestroyed");
    }
}
```

**注册 bean**

```java
@Bean
public ServletRegistrationBean servletRegistrationBean() {
    return new ServletRegistrationBean(new CustomServlet(), "/test");
}

@Bean
public FilterRegistrationBean filterRegistrationBean() {
    return new FilterRegistrationBean(new CustomFilter(), servletRegistrationBean());
}

@Bean
public ServletListenerRegistrationBean<CustomListener> servletListenerRegistrationBean() {
    return new ServletListenerRegistrationBean<CustomListener>(new CustomListener());
}
```

具体实现：

![](/files/-LfnTI5jYrtQxd3nHn3r)

选中的文件就是需要实现的

CustomFilter.java

```java
package com.demotm.example;

import com.demotm.example.util.filter.CustomFilter;
import com.demotm.example.util.listener.CustomListener;
import com.demotm.example.util.servlet.CustomServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class DemotmApplication {

    @Bean
    public ServletRegistrationBean servletRegistrationBean() {
        return new ServletRegistrationBean(new CustomServlet(), "/test");
    }

    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        return new FilterRegistrationBean(new CustomFilter(), servletRegistrationBean());
    }

    @Bean
    public ServletListenerRegistrationBean<CustomListener> servletListenerRegistrationBean() { 
        return new ServletListenerRegistrationBean<CustomListener>(new CustomListener());
    }

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

> 上面的注册也可以配置类方式
>
> ```java
> @Configuration
> public class WebConfig {
>     
>     @Bean
>     public ServletRegistrationBean servletRegistrationBean() {
>         return new ServletRegistrationBean(new CustomServlet(), "/test");
>     }
>
>     @Bean
>     public FilterRegistrationBean filterRegistrationBean() {
>         return new FilterRegistrationBean(new CustomFilter(), servletRegistrationBean());
>     }
>
>     @Bean
>     public ServletListenerRegistrationBean<CustomListener> servletListenerRegistrationBean() { 
>         return new ServletListenerRegistrationBean<CustomListener>(new CustomListener());
>     }
> }
> ```
>
> 示例使用已存在的过滤器，编码过滤器
>
> ```java
> @Configuration
> public class WebConfig {
>     
>     @Bean
>     public FilterRegistrationBean characterEncodingFilterRegister() {
>         
>         FilterRegistrationBean registrationBean = new FilterRegistrationBean();
>         CharacterEncodingFilter filter = new CharacterEncodingFilter("UTF-8");
>         filter.setForceEncoding(true);
>         registrationBean.setFilter(filter);
>         
>         List<String> urls = new ArrayList<>();
>         urls.add("/*"); // 限制使用filter的访问路径
>         registrationBean.setUrlPatterns(urls);
>         
>         return registrationBean;
>     }
>
> }
> ```

CustomListener.java

```java
package com.demotm.example.util.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

/**
* 自定义 listener
**/
public class CustomListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("contextInitialized");
    }


    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("contextDestroyed");
    }
}
```

CustomServlet.java

```java
package com.demotm.example.util.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
* 自定义 servlet
**/

public class CustomServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("servlet get method");
        doPost(request, response);
    }


    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("servlet post method");
        response.getWriter().write("hello world");
    }

}
```

DemotmApplication.java中的代码

```java
package com.demotm.example;

import com.demotm.example.util.filter.CustomFilter;
import com.demotm.example.util.listener.CustomListener;
import com.demotm.example.util.servlet.CustomServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class DemotmApplication {

    @Bean
    public ServletRegistrationBean servletRegistrationBean() {
        return new ServletRegistrationBean(new CustomServlet(), "/test");
    }

    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        return new FilterRegistrationBean(new CustomFilter(), servletRegistrationBean());
    }


    @Bean
    public ServletListenerRegistrationBean<CustomListener> servletListenerRegistrationBean() {
        return new ServletListenerRegistrationBean<CustomListener>(new CustomListener());
    }

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

> 如果想对所有的访问执行filter，如下写，去掉第二个参数
>
> ```java
> @Bean
> public FilterRegistrationBean filterRegistrationBean() {
>     return new FilterRegistrationBean(new CustomFilter());
> }
> ```

访问：<http://localhost:8080/test>

![](/files/-LfnTI5sjvHAhnxvwOro)

控制台中的输出

![](/files/-LfnTI5uCP120P7MFYGI)

### 方法二：通过实现 ServletContextInitializer 接口直接注册

```java
implements ServletContextInitializer {

@Override
public void onStartup(ServletContext servletContext) throws ServletException {

    servletContext.addServlet("customServlet", new CustomServlet()).addMapping("/test");

    servletContext.addFilter("customFilter", new CustomFilter())

    .addMappingForServletNames(EnumSet.of(DispatcherType.REQUES T), true, "customServlet");
    servletContext.addListener(new CustomListener());
}
```

具体实现：

主要是改动方法二中的bean实现方式改成通过实现 ServletContextInitializer 接口直接注册

![](/files/-LfnTI5wWNkY9dbpeo9X)

DemotmApplication.java

```java
package com.demotm.example;

import com.demotm.example.util.filter.CustomFilter;
import com.demotm.example.util.listener.CustomListener;
import com.demotm.example.util.servlet.CustomServlet;
import org.springframework.boot.SpringApplication;


import java.util.EnumSet;

import javax.servlet.DispatcherType;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletContextInitializer;



@SpringBootApplication
public class DemotmApplication implements ServletContextInitializer {

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {

        servletContext.addServlet("customServlet", new CustomServlet()).addMapping("/test");

        servletContext.addFilter("customFilter", new CustomFilter())
                .addMappingForServletNames(EnumSet.of(DispatcherType.REQUEST), true, "customServlet");
        servletContext.addListener(new CustomListener());
    }

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

## 方法三 ：在 SpringBootApplication 上使用@ServletComponentScan 注解后，直接通过@WebServlet、@WebFilter、@WebListener 注解自动注册

具体实现

DemotmApplication.java 加入@ServletComponentScan

main的上面

```java
package com.demotm.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@ServletComponentScan
@SpringBootApplication
public class DemotmApplication {

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

相应的类加入注释

```java
@WebFilter(filterName = "customFilter", urlPatterns = "/*")
public class CustomFilter implements Filter {
 ....省略
}
```

```java
@WebListener
public class CustomListener implements ServletContextListener {
....省略
}
```

```java
@WebServlet(name = "customServlet", urlPatterns = "/test")
public class CustomServlet extends HttpServlet {
....省略
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://spring-boot.shujuwajue.com/webying-yong-kai-fa/6servlets-filters-listeners.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
