Java Web 开发:Web 组件
前言
学习目标
- 掌握ServletContextListener的使用,并且理解其执行时机
- 掌握Filter的使用,并且理解其执行时机
- 能够使用Filter解决一些实际的问题
前置知识准备
-
Servlet的执行
-
ServletContext的功能和使用
Web组件
JavaEE的Web组件 三大Web组件
- Servlet → 处理请求对应的业务
- Listener → 监听器
- Filter → 过滤器
Listener监听器
顾名思义就是监听东西的,其实和命名有关系,我们提供的是什么监听器就是监听什么的。
监听器在监听到主体做了XX事情,就会触发对应的事件。
ServletContextListener
监听的主体就是ServletContext,当发现ServletContext做了事情,监听器就会执行该事件特定的方法
- ServletContext如果初始化,则会执行监听器的初始化方法contextInitialized
- ServletContext应用程序启动的时候初始化,它初始化,就意味着应用程序启动
- ServletContext如果销毁,则会执行监听器的销毁方法contextDestroy
- ServletContext应用程序关闭的时候销毁,它销毁,意味着应用程序关闭
应用程序启动的时候会执行ServletContextListener的contextInitialized方法;应用程序关闭的时候会执行contextDestroy
执行过程
当应用程序启动的过程中,逐步加载Web组件
- 首先会加载ServletContext和Listener组件
- ServletContext伴随着应用程序初始化,它开始初始化,然后ServletContextListener监听到ServletContext初始化,会执行Listener的Initialized方法
- 然后初始化loadOnStartup为正数的Servlet

改造之前的业务代码,之前整合MyBatis时,SqlSessionFactory的初始化是通过Servlet的生命周期init方法,当前可以通过ServletContextListener,在应用程序启动的时候,执行contextInitialized方法,在该方法中进行SqlSessionFactory初始化过程,并将其放到ServletContext中
@WebListenerpublic class CustomServletContextListener implements ServletContextListener { // 当ServletContext初始化的时候执行 // 应用程序启动的时候向ServletContext中塞入一些数据 @Override public void contextInitialized(ServletContextEvent servletContextEvent) { ServletContext servletContext = servletContextEvent.getServletContext(); SqlSessionFactory sqlSessionFactory = null; try { sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis.xml")); System.out.println("ServletContext初始化"); System.out.println("sqlSessionFactory = " + sqlSessionFactory); } catch (IOException e) { e.printStackTrace(); } servletContext.setAttribute("SqlSessionFactory",sqlSessionFactory); }
// 当ServletContext销毁的时候执行 @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { System.out.println("ServletContext销毁");
}}@WebServlet("/hello")public class HelloServlet extends HttpServlet {
SqlSessionFactory sqlSessionFactory;
@Override public void init() throws ServletException { ServletContext servletContext = getServletContext(); sqlSessionFactory = (SqlSessionFactory) servletContext.getAttribute("SqlSessionFactory"); System.out.println("Servlet初始化"); System.out.println("sqlSessionFactory = " + sqlSessionFactory); }
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { }
@Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); }}
提供Listener,其实主要就是去初始化这个ServletContext
后面的话SpringMVC就是基于这样的特点去实现的
Filter过滤器
Filter是一个执行过滤任务的一个对象。它既可以作用于Request对象,也可以作用于Response对
象,或者两者均作用。
也就是Servlet中获取请求之前,Servlet响应之后

Filter和Servlet的执行
URL-Pattern和Servlet之间存在着映射关系,URL-Pattern和Filter之间也存在着映射关系。
- 1个URL-Pattern只能对应一个Servlet,但是可以对应多个Filter
- Servlet和URL-Pattern之间是一对多的关系,但是URL-Pattern和Servlet之间是一对一
其实就意味着一件事,当我们发起一个请求的时候,其实就是一个URL-Pattern对应的请求
- 对应1个Servlet
- 对应多个Filter

如果只有一个过滤器那么执行流程如下

多个过滤器,就是就组成了一个过滤器的链,依次执行过滤器

如果增加上对应的方法

有一个问题,是否每一次都会继续执行到下一个拦截器,或Servlet?不一定,去界定是否 是放行状态
doFilter这个方法中,提供了一个形参,形参叫filterChain,filterChain中提供了一个doFilter方法,如果执行这个方法就是放行,如果不执行,则中断流程

使用
/** * localhost:8080/demo5/hello * localhost:8080/demo5/bye * URL-Pattern对于上面两个请求都能起作用,那么我们的URL-Pattern可以设置为 /* * @author stone * @date 2023/02/22 10:45 */@WebFilter("/*")public class URLPrintFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException {
}
@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; String url = request.getRequestURL().toString(); System.out.println("url = " + url); System.out.println("Filter的前半部分"); //放行 filterChain.doFilter(servletRequest,servletResponse); System.out.println("Filter的后半部分"); }
@Override public void destroy() {
}}就算没有Servlet,仍然是可以执行到Filter的


Filter能否继续执行,取决于FilterChain的doFilter方法是否执行
案例
给请求和响应设置字符集
Post请求中文乱码
request.setCharacterEncoding(“utf-8”)
响应的时候,响应的字符中文乱码
response.setContentType(“text/html;charset=utf-8”)
@WebFilter("/*")public class CharacterEncodingFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException {
}
@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse;
request.setCharacterEncoding("utf-8"); //response.setContentType("text/html;charset=utf-8"); response.setContentType("application/json;charset=utf-8"); filterChain.doFilter(request, response); }
@Override public void destroy() {
}}登录案例
Http://localhost:8080/demo6/user/login
Http://localhost:8080/demo6/user/info
在Session中是否有存储用户的信息
/user/login
/user/logout
/user/info
/order/list
增加白名单功能

小结
Web组件
- 核心是Servlet,处理核心业务
- Listener,用来做资源的初始化
- Filter,在Servlet处理前后增加通用的处理

文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!