一、过滤器
- java 有过滤器、监听器、拦截器,都是属于 java 的组件。
- 在 tomcat 的容器初始化和启动时,通过责任链模式针对 engine,host,context,wrapper 部分分别进行启动,这四个部分是一个链条,按照规定的顺序执行。
- 过滤器链在 tomcat 启动时就会被创建,如果定义和配置了多个过滤器,就会按照它们在配置文件中的配置顺序把这些过滤加入到过滤器链中。启动时过滤器链是不会执行的,但是它会一直存在于容器中,等待有相应的请求到达才会执行过滤器。
- 创建并配置过滤器:
(1)过滤器必须实现 Filter 接口。
(2)过滤器必须进行配置。
- url-pattern 指定过滤器要过滤的 URL,也就是过滤器的过滤目标,过滤器可以过滤任何 web 资源,无论是静态还是动态的资源都可以过滤。
- dispatche 决定过滤器对什么样的操作才能进行过滤,比如 REQUEST 表示对直接发出的请求进行过滤(直接的和请求重定向);比如 FORWARD ,在请求转发时过滤;比如 INCLUDE,当进行包含操作时要过滤。REQUEST 是默认的。
- 在配置文件中,越先配置的过滤器就越在过滤链的前面,就越先执行。
(3)过滤器中 doFilter() 方法的实现,该方法是过滤器完成任务的方法,传入了请求(ServletRequest)、响应(ServletResponse)和过滤器的对象。一般在使用时把它们转换为与 http 协议处理相关的接口类型。
(4)在过滤器完成对权限的检查,如果会话中没能 user 数据,
- 过滤器的作用:一般对于一些全局化的很多功能都可以用过滤器来实现,比如权限,比如字符转码,比如向 ServletContext 中放置全局的对象,比如数据库连接池,比如线程池,比如处理全局化的配置参数等等。
package dataApp;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* // .::::.
* // .::::::::.
* // :::::::::::
* // ..:::::::::::'
* // '::::::::::::'
* // .::::::::::
* // '::::::::::::::..
* // ..::::::::::::.
* // ``::::::::::::::::
* // ::::``:::::::::' .:::.
* // ::::' ':::::' .::::::::.
* // .::::' :::: .:::::::'::::.
* // .:::' ::::: .:::::::::' ':::::.
* // .::' :::::.:::::::::' ':::::.
* // .::' ::::::::::::::' ``::::.
* // ...::: ::::::::::::' ``::.
* // ````':. ':::::::::' ::::..
* // '.:::::' ':'````..
*
* @author 华韵流风
* @ClassName ${NAME}
* @Description TODO
* @Date 2021/4/26 15:18
* @packageName ${PACKAGE_NAME}
*/
@WebFilter(filterName = "PermissionFilter")
public class PermissionFilter implements Filter {
private FilterConfig config;
@Override
public void destroy() {
System.out.println(config.getFilterName() + "被销毁");
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//转换对象类型为可以处理HTTP相关内容的接口请求
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//对权限进行判断
HttpSession session = request.getSession();
if (session.getAttribute("user") == null) {
//请求不允许到达list.jsp
response.sendRedirect("login.jsp");
return;
}
//通过过滤器链进行放行,执行后一环节的过滤器或servlet或jsp
chain.doFilter(req, resp);
//以下是目标资源执行完成后执行的任务,它就是回头任务
response.getWriter().println("<a href=\"https://www.baidu.com\">百度</a>");
}
@Override
public void init(FilterConfig config) throws ServletException {
//初始化过滤器,容器传入过滤器的配置对象,该对象最主要的功能可以读取配置参数
//生命周期中的第一个调用的方法,由容器调用
//过滤器初始化的时机是容器被启动时
this.config = config;
System.out.println(config.getFilterName() + "被初始化");
}
}
package dataApp;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author 华韵流风
* @ClassName ${NAME}
* @Description TODO
* @Date 2021/4/26 16:25
* @packageName ${PACKAGE_NAME}
*/
@WebFilter(filterName = "CharacterEncodingFilter")
public class CharacterEncodingFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//对post有效,对get无效
request.setCharacterEncoding("utf-8");
//放行是必须的
chain.doFilter(req, resp);
}
@Override
public void init(FilterConfig config) throws ServletException {
System.out.println(config.getFilterName() + "被初始化");
}
}
<!-- 过滤器-->
<filter>
<filter-name>PermissionFilter</filter-name>
<filter-class>dataApp.PermissionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>PermissionFilter</filter-name>
<url-pattern>/list.jsp</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>dataApp.PermissionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/list.jsp</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
二、监听器
- http 协议是无状态的,在 JavaWeb 容器的工作过程中,也需要感知一些事情的发生。tomcat 有一个基础的 LifeCycle,它是生命周期接口,几乎所有的组件都要实现该接口,从而在生命周期的不同阶段去实现一些功能。容器中的一些对象与项目的功能实现是紧密相关的,比如像 application,session,request 对象,它们也都有生命周期,那么我们的项目在执行过程中应该能够感知到它们的生命周期过程。因此就提供了各种监听器,监听以上三个对象当生命周期的过程发生变化时,要能够触发相应的程序执行。
- ServletContextListener 接口,该接口的实现类就是一个监听器,它监听 ServletContext 对象的生命周期。该监听器能够监听的前提是需要在 web.xml 中进行配置。
<listener>
<listener-class>com.zhong.ApplicationListener</listener-class>
</listener>
- 启动容器,可以看到监听器已经在工作,可以监听到应用上下文对象初始化的工作过程。容器会在第一时间就创建应用上下文对象并初始化。
- 应用上下文对象监听器的主要作用:如果一个 JavaWeb 应用程序是基于 spring 框架来工作,就要求在项目启动时,把 spring 的容器加载到内存中并完成初始化,以保证后续的功能可以正常执行。这个时机就是应用上下文对象被初始化的时刻。所以可以通过以上的监听器来完成当应用上下文对象被初始化时去加载和创建 spring 容器。这样当项目被启动后,spring 容器就处于就绪状态。
- HttpSessionListener 接口实现的类也是一个监听器,它可以监听会话对象在生命周期中阶段的变化及操作。
- 结合对话对象的特点,它与客户端紧密相关,没有客户端访问应用就不会创建会话对象。
public void sessionDestroyed(HttpSessionEvent se) {
se.getSession();//可以得到当前被监听的会话对象。比如向对象中放置创建时间,它就是用户登录的时间,另外也可以通过该方法的执行次数来统计当前有多少用户已经登录或者通过本方法来统计有多少用户已退出应用。
}
- 有关 session 的监听器不止一个,HttpSessionAttributeListener 接口的实现类可以监听 session 属性的增删改事件。
- 结合以上2,3两者可以实现对 session 对象全过程的监听。因此对 session 的监听可以实时获得与用户相关的一些数据,这些数据一般是与用户管理及业务实现紧密相关的。
- ServletRequestListener 接口,它的实现类就是对请求对象的监听。
@Override
public void requestDestroyed(ServletRequestEvent sre) {
//监听请求对象的创建
}
@Override
public void requestInitialized(ServletRequestEvent sre) {
//监听请求对象的销毁
}
- 它可以在后台监控每个用户的请求,比如用户发出请求的 url 等,可以统计应用中的哪些功能有多少用户在使用。
三、关于 JavaWeb 应用程序中路径的问题
- 绝对路径,带有盘符的文件路径 D:/temp/文件名,或者以 /项目名/路径/资源,这都是绝对路径的写法。
- 相对路径,不以盘符和 / 开头的,都是相对路径。
- 区别:绝对路径是完整的路径写法,相对路径是部分路径的写法;采用绝对路径可以直接表示资源或文件的位置(如果带有盘符,一定是针对文件的路径,不带盘符就是针对应用中的 jsp,servlet 或 html 静态资源)。相对路径就是相对于书写路径所出现在的资源路径的路径。
- 如果项目中要通过输入流读文件,一定要用绝对路径。项目内部通过某个资源向另一个资源进行转发或重定向,用相对路径比较好,因为项目发布后不一定是原名称。表单的 action 表示表单提交的目标,表单多数是在 jsp 页面中,可以通过 el 表达式,比如 ${pageContext.request.contextPath}/add,add 就是 servlet。
- Servlet 在配置时需要指定 url-pattern,该配置就是这个 servlet 的绝对路径,前面一定要有 /,/ 就是 ${pageContext.request.contextPath},比如 servlet 的路径配成 /user/add,可以理解或看成一个目录,因此 servlet 路径与 jsp 或 html 的路径没有任何区别。