集合多天关于JavaWeb开发的学习笔记。利用Servlet开发web应用程序很高效。接下来将学习使用Spring MVC开发web应用程序。
基本概念
- web开发
- web就是网页的意思,如www.baidu.com
- 静态web
- html,css
- 提供给所有人看的数据始终不会发生变化
- 动态web
- 淘宝,几乎是所有网站
- 提供给所有人看的数据始终会发生变化,每个人在不同时间,不同地点看到的网页信息各不相同
- 技术栈:Servlet/JSP,ASP,PHP
- 在Java中,动态web资源开发的技术统称为JavaWeb
- web应用程序:可以提供浏览器访问的程序
- xxx.html…多个web资源,这些资源可以被外界访问,对外界提供服务
- 我们能访问到的任何一个页面或者资源,都存在于这个世界上某一台计算机上
- 统一的web资源会被放在同一个文件夹下,web应用程序–>Tomcat服务器
- 一个web应用由多个部分组成(静态web,动态web)
- html,css,js
- jsp,servlet
- Java程序
- jar包
- 配置文件(properties)
- web应用程序编写完毕后,若想提供给外界访问,需要一个服务器来统一管理
- 静态web
- *.htm,*.html
- 静态web缺点
- web页面无法动态更新,所有用户看到的都是同一个页面
- 轮播图,点击特效:伪动态
- JavaScript:实际开发使用最多
- VBScript
- 无法和数据库交互(数据无法持久化,用户无法交互)
- web页面无法动态更新,所有用户看到的都是同一个页面
- 动态web
- 页面会动态展示,web页面的展示效果因人而异
- 优点
- web页面可以动态更新,提供多样化服务
- 可以于数据库交互(数据持久化:注册,商品信息,用户信息…)
- 缺点
- 若服务器的动态web资源发生错误,需要重新编写后台程序,停机维护,重新发布
web服务器
分类
ASP
- 微软:国内最早流行的服务器
- 在HTML嵌入VB脚本,ASP+COM
- 在ASP开发中,基本一个页面都有几千行业务代码,页面及其混乱
- 维护成本高
- C#
PHP
- PHP开发速度很快,功能很强大,跨平台,代码简单
- 无法承担大访问量
JSP/Servlet
- sun公司主推的B/S架构
- 基于Java语言(所有大公司,或者一些开源组件,都是用Java写的)
- 可以承载三高问题带来的影响
- 语法像ASP
IIS
- 微软windows自带
Tomcat
- 实际上运行JSP页面和Servlet
- 免费开源web服务器,属于轻量级应用服务器
- 在中小型系统和并发用户不多的场合下被普遍使用
- 开发和调试JSP程序的首选
- JavaWeb初学者最佳选择
网站结构
- JavaWeb网站结构
|--RootDir :Tomcat服务器的web目录
|--webapp:网站目录名
|--WEB-INF
|--classes:Java程序
|--lib:web应用所依赖的jar包
|--web.xml:网站配置文件
|--index.html:默认首页
|--static
|--css
|--style.css
|--js
|--img
|--......
Servlet
Servlet简介
- Servlet(Server Applet)是 Java Servlet 的简称,是使用 Java 语言编写的运行在服务器端的程序。具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容
- 通常来说,Servlet 是指所有实现了 Servlet 接口的类
- Servlet 主要用于处理客户端传来的 HTTP 请求,并返回一个响应,它能够处理的请求有 doGet() 和 doPost() 等
- Servlet 由 Servlet 容器提供,Servlet 容器是指提供了 Servlet 功能的服务器(如 Tomcat)
- Servlet 容器会将 Servlet 动态加载到服务器上,然后通过 HTTP 请求和 HTTP 应与客户端进行交互
- Servlet 应用程序的体系结构如下图所示

- Servlet 的请求首先会被 HTTP 服务器(如 Apache)接收,HTTP 服务器只负责静态 HTML 页面的解析,而 Servlet 的请求会转交给 Servlet 容器,Servlet 容器会根据 web.xml 文件中的映射关系,调用相应的 Servlet,Servlet 再将处理的结果返回给 Servlet 容器,并通过 HTTP 服务器将响应传输给客户端
- Servlet技术特点
- 方便
- Servlet 提供了大量的实用工具例程,如处理很难完成的 HTML 表单数据、读取和设置 HTTP 头,以及处理 Cookie 和跟踪会话等
- 跨平台
- Servlet 使用 Java 类编写,可以在不同的操作系统平台和不同的应用服务器平台运行
- 灵活性和可扩展性强
- 采用 Servlet 开发的 Web 应用程序,由于 Java 类的继承性及构造函数等特点,使得应用灵活,可随意扩展
- 除了上述几点以外,Servlet 还具有功能强大、能够在各个程序之间共享数据、安全性强等特点
- 方便
Servlet相关接口和类
在 Servlet 接口中定义了 5 个抽象方法

其中 init()、service() 和 destroy() 方法可以表现 Servlet 的生命周期,它们会在某个特定的时刻被调用Servlet 的接口有两个默认的接口实现类:GenericServlet 和 HttpServlet
- GenericServlet 是一个抽象类,该类为 Servlet 接口提供了部分实现,它并没有实现 HTTP 请求处理
- HttpServlet 是 GenericServlet 的子类,它继承了 GenericServlet 的所有方法,并且为 HTTP 请求中的 GET 和 POST 等类型提供了具体的操作方法。通常情况下,编写的 Servlet 类都继承自 HttpServlet,在开发中使用的也是 HttpServlet 对象
HttpServlet 类中包含两个常用方法

HttpServlet 主要有两大功能,具体如下
- 根据用户请求方式的不同,定义相应的 doXxx() 方法处理用户请求。例如,与 GET 请求方式对应的 doGet() 方法,与 POST 方式对应的 doPost() 方法
- 通过 service() 方法将 HTTP 请求和响应分别强转为 HttpServletRequest 和 HttpServletResponse 类型的对象
需要注意的是,由于 HttpServlet 类在重写的 service() 方法中,为每一种 HTTP 请求方式都定义了对应的 doXxx() 方法,因此,当定义的类继承 HttpServlet 后,只需要根据请求方式重写对应的 doXxx() 方法即可,而不需要重写 service() 方法
Servlet生命周期
Servlet声明周期如下图

按照功能的不同,大致可以将 Servlet 的生命周期分为三个阶段,分别是初始化阶段、运行阶段和销毁阶段
初始化阶段
- 当客户端向 Servlet 容器发出 HTTP 请求要求访问 Servlet 时,Servlet 容器首先会解析请求,检查内存中是否已经有了该 Servlet 对象,如果有,则直接使用该 Servlet 对象,如果没有,则创建 Servlet 实例对象,然后通过调用 init() 方法实现 Servlet 的初始化工作。需要注意的是,在 Servlet 的整个生命周期内,它的 init() 方法只能被调用一次
运行阶段
- 这是 Servlet 生命周期中最重要的阶段,在这个阶段中,Servlet 容器会为这个请求创建代表 HTTP 请求的 ServletRequest 对象和代表 HTTP 响应的 ServletResponse 对象,然后将它们作为参数传递给 Servlet 的 service() 方法
- service() 方法从 ServletRequest 对象中获得客户请求信息并处理该请求,通过 ServletResponse 对象生成响应结果
- 在 Servlet 的整个生命周期内,对于 Servlet 的每一次访问请求,Servlet 容器都会调用一次 Servlet 的 service() 方法,并且创建新的 ServletRequest 和 ServletResponse 对象,也就是说,service() 方法在 Servlet 的整个生命周期中会被调用多次
销毁阶段
- 当服务器关闭或 Web 应用被移除出容器时,Servlet 随着 Web 应用的关闭而销毁。在销毁 Servlet 之前,Servlet 容器会调用 Servlet 的 destroy() 方法,以便让 Servlet 对象释放它所占用的资源。在 Servlet 的整个生命周期中,destroy() 方法也只能被调用一次
需要注意的是,Servlet 对象一旦创建就会驻留在内存中等待客户端的访问,直到服务器关闭或 Web 应用被移除出容器时,Servlet 对象才会销毁
Servlet配置虚拟路径映射
- 在 web.xml 文件中,一个 <servlert-mapping> 元素用于映射一个 Servlet 的对外访问路径,该路径也称为虚拟路径
- 创建好的 Servlet 只有映射成虚拟路径,客户端才能对其进行访问
Servlet多重映射
- Servlet 的多重映射指同一个 Servlet 可以被映射成多条虚拟路径。也就是说,客户端可以通过多条路径实现对同一个 Servlet 的访问。Servlet 实现多重映射的两种方式:
- 配置多个 <servlet-mapping> 元素
可以通过浏览器输入地址http://localhost:8080/dmeo/Test01和http://localhost:8080/dmeo/TestServlet01访问同一个servlet对象<servlet-mapping> <!-- 映射为Test01 --> <servlet-name>TestServlet01</servlet-name> <url-pattern>/Test01</url-pattern> </servlet-mapping> <servlet-mapping> <!-- 映射为TestServlet01--> <servlet-name>TestServlet01</servlet-name> <url-pattern>/TestServlet01</url-pattern> </servlet-mapping> - 配置多个 <url-pattern> 子元素
<servlet-mapping> <!-- 映射为TestServlet01和Test01 --> <servlet-name>TestServlet01</servlet-name> <url-pattern>/TestServlet01</url-pattern> <url-pattern>/Test01</url-pattern> </servlet-mapping>
- 配置多个 <servlet-mapping> 元素
Servlet映射路径中使用通配符
- 在实际开发过程中,开发者有时会希望某个目录下的所有路径都可以访问同一个 Servlet,这时,可以在 Servlet 映射的路径中使用通配符*。通配符的格式有两种,具体如下。
- 格式为“*.扩展名”,例如 *.do 匹配以 .do 结尾的所有 URL 地址
- 格式为 /*,例如 /abc/* 匹配以 /abc 开始的所有 URL 地址
- 以上两种通配符的格式不能混合使用。例如,/abc/*.do 是不合法的映射路径
- 另外,当客户端访问一个 Servlet 时,如果请求的 URL 地址能够匹配多条虚拟路径,那么 Tomcat 将采取最具体匹配原则查找与请求 URL 最接近的虚拟映射路径
默认Servlet
- 如果某个 Servlet 的映射路径仅仅是一个正斜线(/),那么这个 Servlet 就是当前 Web 应用的默认 Servlet
- Servlet 服务器在接收到访问请求时,如果在 web.xml 文件中找不到匹配的 <servlet-mapping> 元素的 URL,则会将访问请求交给默认 Servlet 处理,也就是说,默认 Servlet 用于处理其他 Servlet 都不处理的访问请求
- 配置默认Servlet
<servlet> <servlet-name>DefaultServlet</servlet-name> <servlet-class>com.xxx.servlet.DefaultServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>DefaultServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
Servlet Config接口
在运行 Servlet 程序时,可能需要一些辅助信息,例如,文件使用的编码、使用 Servlet 程序的共享信息等,这些信息可以在 web.xml 文件中使用一个或多个 <init-param> 元素进行配置
当 Tomcat 初始化一个 Servlet 时,会将该 Servlet 的配置信息封装到 ServletConfig 对象中,此时可以通过调用 init(ServletConfig config)方法将 ServletConfig 对象传递给 Servlet
ServletConfig接口的常用方法

参数信息配置代码
<servlet> <servlet-name>ServletDemo</servlet-name> <servlet-class>com.demo.servlet.ServletDemo</servlet-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>ServletDemo</servlet-name> <url-pattern>/ServletDemo</url-pattern> </servlet-mapping>
Servlet Context接口
- 当 Tomcat 启动时,Tomcat 会为每个 Web 应用创建一个唯一的 ServletContext 对象代表当前的 Web 应用,该对象封装了当前 Web 应用的所有信息。可以利用该对象获取 Web 应用程序的初始化信息、数据共享、读取资源文件等
获取 Web 应用程序的初始化参数
- 在 web.xml 文件中,配置整个 Web 应用的初始化信息
<context-param> 元素位于根元素 <web-app> 中,它的子元素 <param-name> 和 <param-value> 分别用于指定参数的名字和参数值。要想获取这些参数名和参数值的信息,可以使用 ServletContext 接口中定义的<context-param> <param-name>XXX</param-name> <param-value>xxx</param-value> </context-param> <context-param> <param-name>yyy</param-name> <param-value>yyy</param-value> </context-param>getInitParameterNames()和getInitParameter(String name)方法分别获取
在不同Servlet中进行数据通信
- 可以在一个Servlet中通过
getServletContext方法获得web应用中唯一的context对象 - Servlet可以通过context对象的
setAttribute方法,设定参数名和参数值,并保存在context中 - 另一个Servlet同样可以通过
getServletContext方法获得context对象,并通过context对象的getAttribute方法获得另一个Servlet设定的参数值
读取 Web 应用下的资源文件
- 在实际开发中,有时会需要读取 Web 应用中的一些资源文件,如配置文件和日志文件等。为此,在 ServletContext 接口中定义了一些读取 Web 资源的方法,这些方法是依靠 Servlet 容器实现的
- Servlet 容器根据资源文件相对于 Web 应用的路径,返回关联资源文件的 I/O 流或资源文件在系统的绝对路径等
- ServletContext 接口中用于获取资源路径的相关方法

Servlet处理用户请求的完整流程
- 针对 Servlet 的每次请求,Web 服务器在调用 service() 方法之前,都会创建 HttpServletRequest 和 HttpServletResponse 对象
- HttpServletRequest 对象用于封装 HTTP 请求消息,简称 request 对象
- HttpServletResponse 对象用于封装 HTTP 响应消息,简称 response 对象
- 浏览器访问Servlet过程

- 首先浏览器向 Web 服务器发送了一个 HTTP 请求,Web 服务器根据收到的请求,会先创建一个 HttpServletRequest 和 HttpServletResponse 对象,然后再调用相应的 Servlet 程序
- 在 Servlet 程序运行时,它首先会从 HttpServletRequest 对象中读取数据信息,然后通过 service() 方法处理请求消息,并将处理后的响应数据写入到 HttpServletResponse 对象中。最后,Web 服务器会从 HttpServletResponse 对象中读取到响应数据,并发送给浏览器
- 在 Web 服务器运行阶段,每个 Servlet 都只会创建一个实例对象,针对每次 HTTP 请求,Web 服务器都会调用所请求 Servlet 实例的 service(HttpServletRequest request,HttpServletResponse response)方法,并重新创建一个 request 对象和一个 response 对象
HttpServlerRequest
HttpServlerResponse
请求转发
当一个 Web 资源收到客户端的请求后,如果希望服务器通知另外一个资源处理请求,那么这时可以通过 RequestDispatcher 接口的实例对象实现。ServletRequest 接口中定义了一个获取 RequestDispatcher 对象的方法
方法 功能 RequestDispatcher getRequestDispatcher(String path) 返回封装了某条路径所指定资源的 RequestDispatcher 对象。其中,参数 path 必须以“/”开头,用于表示当前 Web 应用的根目录。需要注意的是,WEB-INF 目录中的内容对 RequestDispatcher 对象也是可见的。因此,传递给 getRequestDispatcher(String path) 方法的资源可以是 WEB-INF 目录中的文件 获取到 RequestDispatcher 对象后,最重要的工作就是通知其他 Web 资源处理当前的 Servlet 请求,为此,RequestDispatcher 接口定义了两个相关方法
方法 功能 forward(ServletRequest request,ServletResponse response) 该方法用于将请求从一个 Servlet 传递给另一个 Web 资源。在 Servlet 中,可以对请求做一个初步处理,然后通过调用这个方法,将请求传递给其他资源进行响应。需要注意的是,该方法必须在响应提交给客户端之前被调用,否则将抛出 IllegalStateException 异常 include(ServletRequest request,ServletResponse response) 该方法用于将其他的资源作为当前响应内容包含进来 在 Servlet 中,如果当前 Web 资源不想处理请求,则可以通过 forward() 方法将当前请求传递给其他的 Web 资源进行处理,这种方式称为请求转发

当客户端访问 Servlet1 时,可以通过 forward() 方法将请求转发给其他 Web 资源,其他 Web 资源处理完请求后,直接将响应结果返回到客户端
浏览器地址栏中显示的仍然是访问Servlet1的请求路径,但是浏览器却显示出了Servlet2中要输出的内容。这是因为请求转发是发生在服务器内部的行为,从 Servlet1到 Servlet2属于一次请求,在一次请求中是可以使用 request 属性(set,getAttribute)进行数据共享的
重定向
在某些情况下,针对客户端的请求,一个 Servlet 类可能无法完成全部工作。这时,可以使用请求重定向完成这一工作
请求重定向指 Web 服务器接收到客户端的请求后,可能由于某些条件的限制,不能访问当前请求 URL 所指向的 Web 资源,而是指定了一个新的资源路径,让客户端重新发送请求
为了实现请求重定向,HttpServletResponse 接口定义了一个
sendRedirect()方法,该方法用于生成 302 响应码和 Location 响应头,从而通知客户端重新访问 Location 响应头中指定的 URL
重定向方法
public void sendRedirect(java.lang.String location) throws java.io.IOException参数 location 可以使用相对 URL,Web 服务器会自动将相对 URL 翻译成绝对 URL,再生成 Location 头字段
重定向与请求转发的区别
- 请求转发是服务器内部行为,url地址不会发生变化,浏览器只对服务器进行一次访问
- 重定向url地址会发生变化,浏览器对服务器进行两次访问
中文乱码问题解决方法
由于计算机中的数据都是以二进制形式存储的,因此,当传输文本数据时,会发生字符和字节之间的转换。字符与字节之间的转换是通过查码表完成的,将字符转换成字节的过程称为编码,将字节转换成字符的过程称为解码,如果编码和解码使用的码表不一致,则会导致乱码问题
Request中文乱码问题以及解决方案
- 在 HttpServletRequest 接口中提供了一个 setCharacterEncoding() 方法,该方法用于设置 request 对象的解码方式
request.setCharacterEncoding("utf-8"); //设置request对象的解码方式 - 需要注意的是,这种解决乱码的方式只对 POST 方式有效,而对 GET 方式无效
- 为了解决 GET 方式提交表单时出现的中文乱码问题,可以先使用错误码表 ISO-8859-1 将用户名重新编码,然后使用码表 UTF-8 进行解码
name = new String(name.getBytes("iso8859-1"),"utf-8");
- 在 HttpServletRequest 接口中提供了一个 setCharacterEncoding() 方法,该方法用于设置 request 对象的解码方式
Response中文乱码问题以及解决方案
- 方式一
response.setCharacterEncoding("utf-8"); //设置 HttpServletResponse使用utf-8编码 response.setHeader("Content-Type", "text/html;charset=utf-8"); //通知浏览器使用utf-8解码 - 方式二
response.setContentType("text/html;charset=utf-8"); //包含第一种方式的两个功能
- 方式一
使用URL编码解码方式
URLEncoder.encode("中文", "utf-8") URLDecoder.decode(stringName, "utf-8")
Cookie
Cookie常用方法
Cookie[] cookies = req.getCookies(); // 返回cookie数组,cookie可能有多个 cookie.getName() // 获得cookie的名字 cookie.getValue() // 获得cookie的值 Cookie ck = new Cookie("cookieName", "cookieValue") // 新建一个cookie ck.setMaxAge(24*60*60); // 设置cookie有效期,单位为秒 resp.addCookie(ck); // 添加cookie,响应给客户端cookie细节
- cookie一般保存在客户端本地
- 一个cookie只能保存一个信息(键值对)
- 一个web站点可以给浏览器发送多个cookie,最多存放20个cookie
- cookie大小有限制,限制为4kb
- 浏览器cookie上限为300个
删除cookie的方式
- 不设置cookie有效期,关闭浏览器,自动失效
- 设置maxAge为0
Session
session概念
- 服务器会给每个用户(浏览器)创建一个session对象
- 一个session对象独占一个浏览器,只要浏览器没有关闭,这个session就存在
- 用户登录之后,整个网站它都可以以登录状态访问
- 用途有保存用户信息,保存购物车信息和记录登录状态等
注销session设置
- 手动注销
session.invalidate() // 手动注销session - web.xml设置
<session-config> <!--1分钟后session自动失效,以分钟为单位--> <session-timeout>1</session-timeout> </session-config>
- 手动注销
session和cookie区别
- cookie把用户数据写给用户的浏览器,在浏览器中保存(可以保存多个)
- session把用户数据写到用户独占的session中,在服务端保存(保存重要信息,减少服务器资源浪费)
JSP
- JSP全称Java Server Pages,即Java服务端页面,用于动态web技术
- JSP与HTML很相似,它们之间的区别:
- HTML只能给用户提供静态数据
- JSP页面中可以嵌入Java代码,为用户提供动态数据
JSP原理
JSP文件最终会在Tomcat的work工作目录中变成Java程序

并从其变成的Java程序中分析出,JSP最终会被转换成一个继承HttpServlet的Java类,该类实现的功能就是将JSP文件中的内容传输给客户端
所以本质上,浏览器向服务器发送请求,不管访问什么资源,都是在访问Servlet
源码剖析
判断请求方法
if (!javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) { final java.lang.String _jspx_method = request.getMethod(); if ("OPTIONS".equals(_jspx_method)) { response.setHeader("Allow","GET, HEAD, POST, OPTIONS"); return; } if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method)) { response.setHeader("Allow","GET, HEAD, POST, OPTIONS"); response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP 只允许 GET、POST 或 HEAD。Jasper 还允许 OPTIONS"); return; } }输出jsp页面前添加的代码,定义一些对象。这些对象都可以在jsp文件中以
${}的形式直接使用final javax.servlet.jsp.PageContext pageContext; javax.servlet.http.HttpSession session = null; final javax.servlet.ServletContext application; final javax.servlet.ServletConfig config; javax.servlet.jsp.JspWriter out = null; final java.lang.Object page = this; javax.servlet.jsp.JspWriter _jspx_out = null; javax.servlet.jsp.PageContext _jspx_page_context = null;最后给上面定义的对象赋值,并输出页面
response.setContentType("text/html"); pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true); _jspx_page_context = pageContext; application = pageContext.getServletContext(); config = pageContext.getServletConfig(); session = pageContext.getSession(); out = pageContext.getOut(); _jspx_out = out; out.write("<html>\n"); out.write("<body>\n"); out.write("<h2>Hello World!</h2>\n"); out.write("</body>\n"); out.write("</html>\n");
所以,在JSP页面中只要是Java代码,就是原封不动的输出,如果是html代码,则会被转换为文本通过
out.write输出给客户端Java代码以<%%>的形式内嵌
原理流程图

MVC三层架构模型
Model
- 业务处理:业务逻辑(Service层)
- 数据持久化:CRUD(Dao层)
View
- 展示数据
- 给用户提供链接发起Servlet请求
Controller(Servlet)
- 接收用户请求(req:请求参数、session信息等)
- 交给业务层处理相应业务
- 控制试图跳转
典型例子
用户点击登录-->控制层接收用户的登录请求-->控制层处理用户请求(获得用户登录的参数,如账号密码等)-->将参数交给业务层处理登录业务(账号、密码是否正确,还有可能涉及数据库事务处理)-->交给Dao层查询用户名和密码是否正确-->数据库
过滤器(Filter)
Filter是Servlet的过滤器,主要用于完成一些通用的操作,如编码的过滤、判断用户的登录状态、过滤垃圾请求等
Filter 被称为过滤器,其主要作用是对 Servlet 容器调用 Servlet 的过程进行拦截,从而在 Servlet 进行响应处理的前后实现一些特殊功能
Filter拦截过程图示

当用户通过浏览器访问服务器中的目标资源时,首先会被 Filter 拦截,在 Filter 中进行预处理操作,然后再将请求转发给目标资源。当服务器接收到这个请求后会对其进行响应,在服务器处理响应的过程中,也需要将响应结果经过滤器处理后,才发送给客户端本质上,Filter 过滤器就是一个实现了 javax.servlet.Filter 接口的类,在 javax.servlet.Filter 接口中定义了三个方法
方法声明 方法描述 init(FilterConfig filterConfig) init() 方法用于初始化过滤器,开发人员可以在 init() 方法中完成与构造方法类似的初始化功能,如果初始化代码中要使用到 FillerConfig 对象,那么,这些初始化代码就只能在 Filler 的 init() 方法中编写,而不能在构造方法中编写。在 Web 应用程序加载时会被调用,只被调用一次 doFilter(ServletRequest request,SeivletResponse response, FilterChain chain) doFilter() 方法有多个参数,其中,参数 request 和 response 为 Web 服务器或 Filter 链中的上一个 Filter 传递过来的请求和响应对象;参数 chain 代表当前 Filter 链的对象,只有在当前 Filter 对象中的 doFilter() 方法内部需要调用 FilterChain 对象的 doFilter() 方法,才能把请求交付给 Filter 链中的下一个 Filter 或者目标程序处理。会被调用多次(只要客户端有请求时就会被调用),Filter 所有的工作集中在 doFilter() 方法中 destroy() destroy() 方法在 Web 服务器卸载 Filter 对象之前被调用,该方法用于释放被 Filter 对象打开的资源,例如关闭数据库和 I/O 流。在 Web 应用程序卸载(或关闭)时被调用,只被调用一次
过滤器映射方式
- 在web.xml配置文件中,使用Filter 的\ <filter-mapping> 元素用于配置过滤器拦截的资源信息,如果想让过滤器拦截所有的请求,那么可以使用通配符*实现
<filter> <filter-name>FilterName</filter-name> <filter-class>com.demo.filter.FilterName</filter-class> </filter> <filter-mapping> <filter-name>FilterName</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> - 拦截不同方式的访问请求
- 在 web.xml 文件中,每一个 <filter-mapping> 元素都可以配置一个 Filter 所负责拦截的资源。在\ <filter-mapping> 元素中有一个特殊的子元素 <dispatcher>,该元素用于指定过滤器所拦截的资源被 Servlet 容器调用的方式。<dispatcher> 元素的值共有四个

- 以FORWARD为例,xml配置如下
该过滤器会拦截所有以请求转发(forward)的方式访问/first.jsp的所有请求<filter> <filter-name>ForwardFilter</filter-name> <filter-class>com.demo.filter.ForwardFilter</filter-class> </filter> <filter-mapping> <filter-name>ForwardFilter</filter-name> <url-pattern>/first.jsp</url-pattern> <dispatcher>FORWARD</dispatcher> </filter-mapping>
- 在 web.xml 文件中,每一个 <filter-mapping> 元素都可以配置一个 Filter 所负责拦截的资源。在\ <filter-mapping> 元素中有一个特殊的子元素 <dispatcher>,该元素用于指定过滤器所拦截的资源被 Servlet 容器调用的方式。<dispatcher> 元素的值共有四个
过滤器链
- 在一个 Web 应用程序中可以注册多个 Filter 程序,每个 Filter 程序都可以针对某一个 URL 进行拦截。如果多个 Filter 程序都对同一个 URL 进行拦截,那么这些 Filter 就会组成一个Filter 链
- Filter 链用 FilterChain 对象表示,FilterChain 对象中有一个 doFilter() 方法,该方法的作用是让 Filter 链上的当前过滤器放行,使请求进入下一个 Filter
- 因为Filter的拦截作用,可以使用Filter进行权限访问控制,对某些访问没有权限的页面的请求进行拦截,不调用doFilter方法传递给下一个Filter,而将其重定向到权限不足的出错页面
- 拦截过程如下图

- 当浏览器访问 Web 服务器中的资源时,需要经过两个过滤器 Filter1 和 Filter2。首先 Filter1 会对这个请求进行拦截,在 Filter1 中处理完请求后,通过调用 Filter1 的 doFilter() 方法将请求传递给 Filter2,Filter2 处理用户请求后同样调用 doFilter() 方法,最终将请求发送给目标资源。当 Web 服务器对这个请求做出响应时,也会被过滤器拦截,但这个拦截顺序与之前相反,最终将响应结果发送给客户端浏览器
- 需要注意的是,Filter 链中各个 Filter 的拦截顺序与它们在 web.xml 文件中 <filter-mapping> 元素的映射顺序一致
编码过滤器示例
- 编写编码过滤器类
package com.demo.filter; import javax.servlet.*; import java.io.IOException; public class CharacterEncodingFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { Filter.super.init(filterConfig); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); chain.doFilter(request, response); // 过滤器有多个,传递给下一个过滤器,不执行传递则被拦截 } @Override public void destroy() { Filter.super.destroy(); } } - web.xml配置filter,与servlet配置一致
<filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>com.demo.filter.CharacterEncodingFilter</filter-class> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <!--要执行过滤的访问指定url路径的所有请求--> <url-pattern>/servlet/*</url-pattern> </filter-mapping>
Servlet事件监听器
Servlet 事件监听器是一个实现了特定接口的 Java 程序,这个程序专门用于监听 Web 应用中 ServletContext、HttpSession 和 ServletRequest 等域对象的创建和销毁过程、监听这些域对象属性的修改以及感知绑定到 HttpSession 域中的某个对象的状态
Servlet 规范中定义了八种监听器,这八种监听器的类型及作用如下表所示

根据监听事件的不同,可以将表中的监听器分为如下三类
- 用于监听域对象创建和销毁的事件监听器(ServletContextListener 接口、HttpSessionListener 接口、ServletRequestListener 接口)
- 用于监听域对象属性增加和删除的事件监听器(ServletContextAttributeListener 接口、HttpSessionAttributeListener 接口、ServletRequestAttributeListener 接口)
- 用于监听绑定到 HttpSession 域中某个对象状态的事件监听器(HttpSessionBindingListener 接口、HttpSessionActivationListener 接口)
在 Servlet 规范中,这三类事件监听器都定义了相应的接口,在编写事件监听器程序时只需实现对应的接口即可。在使用监听程序时,Web 服务器会根据监听器所实现的接口,把它注册到被监听的对象上,当触发了某个对象的监听事件时,Web 容器将会调用 Servlet 监听器与之相关的方法对事件进行处理