可以看官网
http://felord.cn/_doc/_springboot/2.1.5.RELEASE/_book/
28、开发Web应用程序
一、SpringBoot整合Servlet
新建一个项目springboot_web
新建包controller, 新建MyController文件
MyController.java
package xyz.kxq.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class MyController { @RequestMapping("hello") public String hello(){ return "hello, springboot"; } }
运行程序,浏览器访问:
这就是我们之前搭建web项目最简单的一种方式, 可以集成servlet
1、Servlet、Filter与Listener
可以看文档中
28.4、内嵌Servlet容器支持
Spring Boot 包含了对内嵌 Tomcat、Jetty 和 Undertow 服务器的支持
使用servlet可以配置Servlet、Filter、Listener
- Servlet业务逻辑类
- Filter 过滤器
- Listener 监听器
使用内嵌 servlet 容器时,您可以使用 Spring bean 或者扫描方式来注册 Servlet 规范中的 Servlet、Filter 和所有监听器(比如 HttpSessionListener
)。
任何 Servlet
、Filter
或 *Listener
的 Spring bean 实例都将被注册到内嵌容器中。如果您想引用 application.properties
中的某个值,这可能会特别方便。
默认情况下,如果上下文只包含单个 Servlet,它将映射到 /
。在多个 Servlet bean 的情况下,bean 的名称将用作路径的前缀。Filter 将映射到 /*
如果基于约定配置的映射不够灵活,您可以使用 ServletRegistrationBean
、FilterRegistrationBean
和 ServletListenerRegistrationBean
类来完全控制
Spring Boot 附带了许多可以定义 Filter bean 的自动配置。以下是部分过滤器及其执行顺序的(顺序值越低,优先级越高):
Servlet Filter | 顺序 |
---|---|
OrderedCharacterEncodingFilter |
Ordered.HIGHEST_PRECEDENCE |
WebMvcMetricsFilter |
Ordered.HIGHEST_PRECEDENCE + 1 |
ErrorPageFilter |
Ordered.HIGHEST_PRECEDENCE + 1 |
HttpTraceFilter |
Ordered.LOWEST_PRECEDENCE - 10 |
通常 Filter bean 无序放置也是安全的。
如果需要指定顺序,则应避免在 Ordered.HIGHEST_PRECEDENCE
顺序点配置读取请求体的过滤器,因为它的字符编码可能与应用程序的字符编码配置不一致。
如果一个 Servlet 过滤器包装了请求,则应使用小于或等于 OrderedFilter.REQUEST_WRAPPER_FILTER_MAX_ORDER
的顺序点对其进行配置。
2、Servlet上下文初始化
我们一般刚接触web开发的时候第一个接触的都是servlet, 下面我们来使用springboot来整合servlet
- 编写servlet类
- 新建包servlet
- 新建MyServlet文件
-
package xyz.kxq.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @WebServlet(name = "myServlet", urlPatterns = "/srv") public class MyServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("111"); super.doGet(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { super.doPost(req, resp); } }
- 在启动类上添加如下配置
-
@ServletComponentScan, @SpringBootApplication点进去会有一个@ComponentScan
- 会有一个自动扫描的过程
- 需要把Servlet注册为当前SpringBoot容器里面的一个bean
-
package xyz.kxq; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import xyz.kxq.servlet.MyServlet; @SpringBootApplication @ServletComponentScan public class SpringbootWebApplication { public static void main(String[] args) { SpringApplication.run(SpringbootWebApplication.class, args); } @Bean public ServletRegistrationBean<MyServlet> getServletRegistrationBean(){ ServletRegistrationBean<MyServlet> bean = new ServletRegistrationBean<>(new MyServlet(), "/s2"); bean.setLoadOnStartup(1); return bean; }
getServletRegistrationBean: 获取servlet注册的一个Bean对象,可以加路由(/s2),当配置了urlmappings之后,servlet自己的配置就不会生效了
bean.setLoadOnStartup: 设置servlet什么时候启动,配置当前类,设置为1了
-
- 启动服务
- 访问 http://localhost:8080/myServlet/
- 打印结果为
111 111
- 打印结果为
- 所以说可以自己写一个servlet类,然后把servlet类注入到springboot里面就ok了。
二、过滤器
包下新建filter目录,新建MyFilter文件
package xyz.kxq.filter; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; @WebFilter(filterName = "MyFilter", urlPatterns = "/filter") public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("init"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("filter"); chain.doFilter(request, response); } }
重启服务会发现init执行了
2021-10-21 15:41:40.665 INFO 118196 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 725 ms 2021-10-21 15:41:40.700 INFO 118196 --- [ main] o.s.boot.web.servlet.RegistrationBean : Servlet myServlet was not registered (possibly already registered?) init 2021-10-21 15:41:40.929 INFO 118196 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path '' 2021-10-21 15:41:40.936 INFO 118196 --- [ main] xyz.kxq.SpringbootWebApplication : Started SpringbootWebApplication in 1.34 seconds (JVM running for 2.217)
当访问http://localhost:8080/filter, 发现filter执行了
2021-10-21 15:44:47.008 INFO 118196 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-10-21 15:44:47.008 INFO 118196 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2021-10-21 15:44:47.009 INFO 118196 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
filter
如果所有的请求都需要过滤,urlPatterns="/*"
如果用FilterRegistratronBran设置对应注册的类,类似于上面servlet,向里面 new 对象就可以
官网
28.4.1.1、将 Servlet、Filter 和 Listener 注册为 Spring Bean
三、监听器
listener是servlet规范定义的一种特殊类,用于监听servletContext,HttpSession和ServletRequest等域对象的创建和销毁事件。监听域对象的属性发生修改的事件,
用于在事件发生前、发生后做一些必要的处理。可用于一下方面
/* 1、统计在线人数和在线用户 2、系统启动时加载初始化信息 3、统计网站访问量 4、记录用户访问路径 */
新建listener目录,新建MyHttpSessionListener文件
package xyz.kxq.listener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; public class MyHttpSessionListener implements HttpSessionListener { public static int online = 0; @Override public void sessionCreated(HttpSessionEvent se) { System.out.println("创建session"); online++; } @Override public void sessionDestroyed(HttpSessionEvent se) { System.out.println("销毁session"); } }
需要创建session对象,代码中也没有注解,此时可以在SpringbootWebApplication文件加入Bean
重新运行,会看到打印listener
2021-10-22 10:26:49.921 INFO 151208 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext 2021-10-22 10:26:49.921 INFO 151208 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 747 ms listener
添加控制层代码
MyController
package xyz.kxq.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import xyz.kxq.listener.MyHttpSessionListener; @RestController public class MyController { @RequestMapping("hello") public String hello(){ return "hello, springboot"; } @RequestMapping("online") public String online(){ return "当前在线人数: " + MyHttpSessionListener.online + "人"; } }
浏览器访问
刷新一直是0;
原因:
监听器中创建session对象后才online++
发送的请求没有任何session对象的请求,所以不会++
在MyController
package xyz.kxq.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import xyz.kxq.listener.MyHttpSessionListener; import javax.servlet.http.HttpSession; @RestController public class MyController { @RequestMapping("hello") public String hello(HttpSession session){ session.setAttribute("aa", "aa"); return "hello, springboot"; } @RequestMapping("online") public String online(){ return "当前在线人数: " + MyHttpSessionListener.online + "人"; } }
在浏览器访问