Web 开发使用 Controller 基本上可以完成大部分需求,但是我们还可能会用到 Servlet、Filter、Listener、Interceptor 等等。
当使用 Spring-Boot 时,嵌入式 Servlet 容器通过扫描注解的方式注册 Servlet、Filter 和 Servlet 规范的所有监听器(如HttpSessionListener 监听器)。
Spring boot 的主 Servlet 为 DispatcherServlet,其默认的 url-pattern 为“/”。也许我们在应用中还需要定义更多 的 Servlet,该如何使用SpringBoot 来完成呢?
在 spring boot 中添加自己的 Servlet 有两种方法,代码注册 Servlet 和注解自动注册(Filter 和 Listener 也是如此)。
一、代码注册通过 ServletRegistrationBean、 FilterRegistrationBean 和 ServletListenerRegistrationBean 获得
控制。也可以通过实现 ServletContextInitializer 接口直接注册。
二、在 SpringBootApplication 上使用@ServletComponentScan 注解后,Servlet、Filter、Listener 可以直接通 过 @WebServlet、@WebFilter、@WebListener 注解自动注册,无需其他代码。
maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
1、创建一个MyServlet2 类,继承HttpServlet ,重写doGet方法
public class MyServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("myservlet2正在运行。。。。。。。。");
resp.setContentType("text/html;charset=utf-8");
resp.setCharacterEncoding("UTF-8");
PrintWriter out = resp.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Hello World</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>这是:MyServlet2</h1>");
out.println("</body>");
out.println("</html>");
}
}
2、在启动类中是实例化ServletRegistrationBean并注入自定义的servlet
public class ServletApplication {
@Bean
public ServletRegistrationBean registerMyServlet(){
return new ServletRegistrationBean(new MyServlet2(),"/myservlet2/*");
}
public static void main(String[] args) {
SpringApplication.run(ServletApplication.class,args);
}
}
1、创建一个MyServlet1 类,继承HttpServlet ,重写doGet方法,并使用@WebServlet注解,填写访问路径,和servlet名称
@WebServlet(urlPatterns = "/myservlet1/*",name = "myservlet1")
public class MyServlet1 extends HttpServlet {
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
System.out.println("myservlet1正在运行。。。。。。。。");
resp.setContentType("text/html;charset=utf-8");
resp.setCharacterEncoding("UTF-8");
PrintWriter out = resp.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Hello World</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>这是:MyServlet1</h1>");
out.println("</body>");
out.println("</html>");
}
}
2、使用@ServletComponentScan注解自动注册
@SpringBootApplication
@ServletComponentScan
public class ServletApplication {
@Bean
public ServletRegistrationBean registerMyServlet(){
return new ServletRegistrationBean(new MyServlet2(),"/myservlet2/*");
}
public static void main(String[] args) {
SpringApplication.run(ServletApplication.class,args);
}
}
过滤器(Filter)和监听器(Listener)的注册方法和 Servlet 一 样;
下面将直接使用@WebFilter 和@WebListener 的方式,完成一个Filter 和一个 Listener;使用注解@ServletComponentScan//这个就是扫描相应的 Servlet 包;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@Slf4j
@WebListener
public class MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
log.info("监听器:listener=====>contextInitialized");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
log.info("监听器:listener=====>contextDestroyed");
}
}
import lombok.extern.slf4j.Slf4j;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* 过滤器是要什么,拦截器是不要什么
*/
@Slf4j
@WebFilter(urlPatterns = "/*",filterName = "myFilter")
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {
log.info("过滤器:filter=====>init");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
log.info("过滤器:filter=====>doFilter");
log.info("过滤器:filter=====>before filter");
filterChain.doFilter(servletRequest,servletResponse);
log.info("过滤器:filter=====>after filter");
}
@Override
public void destroy() {
log.info("过滤器:filter=====>destroy");
}
}
打印结果:
以上可见,监听器执行初始化,之后进行过滤器的初始化,然后执行过滤器的filterChain.doFilter,再执行servlet方法
过滤器属于 Servlet 范畴的 API,与 Spring 没什么关系。
Web 开发中,我们除了使用 Filter 来过滤请 web 求外,还可以使用 Spring 提供的 HandlerInterceptor(拦 截器)。
HandlerInterceptor 的功能跟过滤器类似,但是提供更精细的的控制能力:在 request 被响应之前、request 被响
应之后、视图渲染之前以及 request 全部结束之后。我们不能通过拦截器修改 request 内容,但是可以通过抛出
异常(或者返回 false)来暂停 request 的执行。(意思是:不能修改request内容,但是可以获取request内容后进行判断是否需要停止此次request的执行)
实现 UserRoleAuthorizationInterceptor 的拦截器有:
ConversionServiceExposingInterceptor
CorsInterceptor
LocaleChangeInterceptor
PathExposingHandlerInterceptor
ResourceUrlProviderExposingInterceptor
ThemeChangeInterceptor
UriTemplateVariablesHandlerInterceptor
UserRoleAuthorizationInterceptor
其中 LocaleChangeInterceptor 和 ThemeChangeInterceptor 比较常用。
配 置 拦 截 器 也很简单, Spring 为什么提供了 基 础 类 WebMvcConfigurerAdapter ,我们 只 需 要 重 写
addInterceptors 方法添加注册拦截器。 实现自定义拦截器只需要 3 步:
1、创建我们自己的拦截器类并实现 HandlerInterceptor 接口。
2、创建一个 Java 类继承 WebMvcConfigurer,并重写 addInterceptors 方法。实例化我们自定义的拦截器,然后将对像手动添加到拦截器链中(在 addInterceptors 方法中添加)
3、创建controller类进行测试
1、创建一个MyInterceptor自定义类
import lombok.extern.slf4j.Slf4j;
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;
@Slf4j
@Component
public class MyInterceptor implements HandlerInterceptor {
/**
* 在将请求发送到控制器controller之前执行操作,若返回true就进入控制器,若返回false就不进入控制器了。
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("拦截器======》preHandle");
return true;
}
/**
* 用于在将响应发送到客户端之前执行操作,就是控制器执行完之后返回数据时执行。
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("拦截器======》postHandle");
}
/**
* 在完成请求和响应后执行操作。
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("拦截器======》afterCompletion");
}
}
2、创建WebMvcConfigurer接口的实现类,重写addInterceptors方法
import com.lcj.interceptor.MyInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {
//引入自定义拦截器对象
@Resource
private MyInterceptor myInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//addInterceptor方法向拦截器注册器添加拦截器,addPathPatterns方法添加拦截路径匹配规则("/**"是拦截所有),excludePathPatterns方法是设置白名单,放行哪些路径
// 对于order的顺序:拦截器的preHandle方法是顺序执行,
registry.addInterceptor(myInterceptor).addPathPatterns("/**");
}
}
3、创建controller类测试
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
@RequestMapping
public class MyController {
@RequestMapping("/test")
public String test(){
log.info("进入=====》test");
return "你成功啦";
}
}
测试结果:
总结:拦截器和过滤器是不同的,
1、一个是spring提供的,一个是servlet的范畴的API,
2、拦截器只能作用于controller层,而过滤器可以过来所有客户端发送过来的请求,包括使用原生servlet方式。
3、拦截器不能修改request中的内容,但是可以获取request中的参数进行判断时候需要停止此次的request请求,主要是对request请求内容的拦截预判断,过滤器主要是针对请求的路径进行过滤,判断这个请求能否通过