Servlet API
Servlet API 包含以下4个Java包:
1. javax.servlet:其中包含定义Servlet和Servlet容器之间契约的类和接口。
2. javax.servlet.http:主要定义了与HTTP协议相关的HttpServlet类,HttpServletRequest接口和HttpServletResponse接口。
3. javax.servlet.annotation: 其中包含标注Servlet、Filter、Listener的标注。它还为被标注元件定义元数据。
4. javax.servlet.descriptor:其中包含提供程序化登录Web应用程序的配置信息的类型。
Servlet其他接口
ServletConfig接口
ServletConfig 类是为 Servlet 程序的配置信息的类;
一个 Web 应用中可以存在多个 ServletConfig 对象,一个 Servlet 只能对应一个 ServletConfig 对象。即 Servlet 的初始化参数仅对当前 Servlet 有效。
注:Servlet 程序和 ServletConfig 对象都是由 Tomcat 负责创建。
返回值类型 | 方法 | 功能描述 |
String | getInitParameter(String name) | 根据初始化参数名 name,返回对应的初始化参数值。 |
Enumeration<String> | getInitParameterNames() | 返回 Servlet 所有的初始化参数名的枚举集合; 如果该 Servlet 没有初始化参数,则返回一个空的集合。 |
ServletContext | getServletContext() | 返回一个代表当前 Web 应用的 ServletContext 对象。 |
String | getServletName() | 返回 Servlet 的名字,即 web.xml 中 <servlet-name> 元素的值。 |
作用:
【1】获取初始化参数 init-param;
//1. 直接从带参的 init() 方法中提取public class ServletConfigDemo extends HttpServlet {private ServletConfig servletConfig;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//获取Servlet得名字this.servletConfig.getServletName();}@Overridepublic void init(ServletConfig config) throws ServletException {//从带参init方法中,提取ServletConfig对象this.servletConfig = config;}}
【2】配置Servlet初始化参数的方式;
在 web.xml 中可以使用一个或多个 <init-param> 元素为 Servlet 配置初始化参数:
- <init-param> 元素是 <servlet> 的子元素, 需要在 <servlet> 元素内使用,表示只对当前 Servlet 有效 。
- <param-name> 子元素表示参数的名称。
- <param-value> 子元素表示参数的值
web.xml参数配置:<servlet>
<--初始化参数--><init-param><!--参数名--> <param-name>username</param-name><!--参数值--><param-value>root</param-value></init-param><init-param><!--参数名--> <param-name>password</param-name><!--参数值--><param-value>123456</param-value></init-param>
</servlet>
使用 @WebServlet 配置初始化参数:
@WebServlet(urlPatterns = {"/MyServlet"}, initParams = {@WebInitParam(name = "name", value = "编程"), @WebInitParam(name = "URL", value = "www.biancheng.net")})
【3】获取 ServletContext 对象;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;public class DBServlet extends HttpServlet {/*** ServletConfig config 使用流程* 1. 当DBServlet对象初始化时, tomcat会同时创建一个 ServletConfig对象* 2. 这时如果DBServlet init() 方法中你调用 super.init(config),则调用父类 GenericServlet* GenericServlet源码:* public void init(ServletConfig config) throws ServletException {* this.config = config;* this.init();* }* 这时就会把 Tomcat创建的 ServletConfig对象赋给 GenericServlet的属性 config* 3.如果你想在其它方法通过 getServletConfig() 方法获取ServletConfig,则一定要记住 调用 super.init(config);*/@Overridepublic void init(ServletConfig config) throws ServletException {// ConcurrentHashMap, 是一个线程安全的容器.System.out.println("init" + config);super.init(config);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 在DBServlet 执行 doGet()/doPost() 时,可以获取到web.xml配置的用户名和密码/*** 1. getServletConfig() 方法是 GenericServlet* 2. 返回的 servletConfig对象是 GenericServlet private transient ServletConfig config;* 3. 当一个属性被 transient 修饰,表示该属性不会被串行化(有些重要信息,不希望保存到文件)*/ServletConfig servletConfig = getServletConfig();System.out.println("doPost=" + servletConfig);String username = servletConfig.getInitParameter("username");String pwd = servletConfig.getInitParameter("pwd");System.out.println("初始化参数username= " + username);System.out.println("初始化参数pwd= " + pwd);}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {doPost(request, response);}
}
ServletContext对象
当 Tomcat 启动时,Tomcat 会为每个 Web 应用创建一个唯一的 ServletContext 对象;
它与Servlet是一对多的关系,其内部封装的信息可以被同一web 应用内的所有Servlet共享,不同 Servlet 之间可以通过 ServletContext 对象实现数据通讯;因此 ServletContext 对象也被称为 Context 域对象。
它代表当前的 Web 应用,该对象封装了当前 Web 应用的所有信息。可以利用该对象获取整个Web 应用程序的初始化信息、读取资源文件等。
ServletContext 对象 是在 web 工程启动的时候创建,在 web 工程停止的时销毁;
创建方式:
- 可以通过 ServletConfig.getServletContext 方法获得对 ServletContext对象的引用
- 可以通过 this.getServletContext()来获得其对象的引用。
作用:
【1】获取 web.xml 中配置的上下文参数
//通过 web.xml 中的 <context-param> 元素可以为 Web 应用设置一些全局的初始化参数,这些参数被称为上下文初始化参数。//与 Servlet 的初始化参数不同,应用中的所有 Servlet 都共享同一个上下文初始化参数。在 Web 应用的整个生命周期中,上下文初始化参数会一直存在,并且可以随时被任意一个 Servlet 访问<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaeehttp://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0" metadata-complete="false"><!--设置全局初始化参数 --><context-param><param-name>name</param-name><param-value>编程帮</param-value></context-param><context-param><param-name>url</param-name><param-value>www.biancheng.net</param-value></context-param></web-app>对以上标签说明如下:<context-param> 元素用来声明上下文初始化参数,必须在根元素 <web-app> 内使用。<param-name> 子元素表示参数名,参数名在整个 Web 应用中必须是唯一的。<param-value> 子元素表示参数值。
【2】实现 Servlet 之间的数据通讯
ServletContext 的属性与上下文初始化参数都是存放在 ServletContext 对象。
不同点 | ServletContext 的属性 | 上下文初始化参数 |
---|---|---|
创建方式 | ServletContext 的属性通过调用 ServletContext 接口的 setAttribute() 方法创建 | 上下文初始化参数通过 web.xml 使用 <context-param> 元素配置 |
可进行的操作 | ServletContext 的属性可以通过 ServletContext 接口的方法进行读取、新增、修改、移除等操作 | 上下文初始化参数在容器启动后只能被读取,不能进行新增、修改和移除操作 |
生命周期 | ServletContext 中属性的生命周期从创建开始,到该属性被移除(remove)或者容器关闭结束 | 上下文初始化参数的生命周期,从容器启动开始,到 Web 应用被卸载或容器关闭结束 |
作用 | 使用 ServletContext 中的属性可以实现 Servlet 之间的数据通讯 | 使用上下文初始化参数无法实现数据通讯 |
【3】读取 Web 应用下的资源文件
返回值类型 | 方法 | 方法描述 |
---|---|---|
Set | getResourcePaths(String path) | 返回一个 Set 集合,该集合中包含资源目录中的子目录和文件的名称。 |
String | getRealPath(String path) | 返回资源文件的真实路径(文件的绝对路径)。 |
URL | getResource(String path) | 返回映射到资源文件的 URL 对象。 |
InputStream | getResourceAsStream(String path) | 返回映射到资源文件的 InputStream 输入流对象。 |
Request和Response
Servlet 处理 HTTP 请求的流程:
- Tomcat(Servlet容器)接收到来自客户端的 HTTP 请求后,容器会针对该请求分别创建一个 HttpServletRequest 对象和 HttpServletReponse 对象。
- 容器将 HttpServletRequest 对象和 HttpServletReponse 对象以参数的形式传入 service() 方法内,并调用该方法。
- 在 service() 方法中 Servlet 通过 HttpServletRequest 对象获取客户端信息以及请求的相关信息。
- 对 HTTP 请求进行处理。
- 请求处理完成后,将响应信息封装到 HttpServletReponse 对象中。
- Servlet 容器将响应信息返回给客户端。
- 当 Servlet 容器将响应信息返回给客户端后,HttpServletRequest 对象和 HttpServletReponse 对象被销毁
request对象
HttpServletRequest 对象专门用于封装 HTTP 请求消息,简称 request 对象;【HTTP 请求消息分为请求行、请求消息头和请求消息体三部分】
HttpServletRequest 接口中定义了获取请求行、请求头和请求消息体的相关方法。通过调用request,getHeaderf);request.geWrlf );request.getQueryString^()等等方法,都可以得到浏览器当初发送的请求信息。
说明:
【1】中文乱码问题:
请求数据的http中文乱码问题:
1)POST 请求乱码的原因:
POST 提交的数据在请求体中,其所使用的编码格式是页面一致(即 utf-8)。
request 对象接收到数据之后,会将数据放到 request 缓冲区,缓冲区的默认字符集是 ISO-8859-1(该字符集不支持中文),两者使用的字符集不一致导致乱码。2)GET 请求乱码的原因:
Get 请求将请求数据附加到 URL 后面作为参数,浏览器发送文字时采用的编码格式与页面编码保持一致(utf-8)。如果 Tomcat 没有设置字符集,接收 URL 时默认使用 ISO-8859-1 进行解码,ISO-8859-1 不兼容中文,无法正确解码,导致出现乱码。但 Tomcat 8 中已解决了 get 方式提交请求中文乱码的问题。
POST请求乱码解决办法:
//在获取请求参数之前设置 request 缓冲区字符集为 utf-8
request.setCharacterEncoding("utf-8");
// 获取用户名
String username = request.getParameter("username");
response对象
每次 HTTP 请求,Tomcat 会创建一个 HttpServletResponse 对象传递给 Servlet 程序去使用;HttpServletResponse 接口中定义了向客户端发送响应状态码、响应头、响应体的方法;
在传给Servlet时,response 对象是一个空的对象,Servlet逻辑处理后得到结果,最终通过response.write方法,将结果写入response内部的缓冲区。
Tomcat会在Servlet处理结束后,拿到response,遍历里面的信息,组装成HTTP响应发送给客户端。 遍历里面的信息,组装成HTTP响应发给客户端,即针对页面发送的请求做出数据响应,向页面输出信息,包括文本、图片、视频等。
说明:
【1】中文乱码问题:
response 对象向页面输出中文时可能出现乱码:
1)字节流:原因中文转成字节数组时与浏览器打开时采用的字符集不一致。
response.setHeader("Content-Type", "text/html;charset=UTF-8");
// 获取字节输出流
OutputStream os = response.getOutputStream();
byte[] str = "编程帮".getBytes("UTF-8");// 输出中文
os.write(str);
2)字符流:通过字符流输出的内容是存放在 response 缓冲区的,response 缓冲区的默认字符集是 ISO-8859-1,该字符集不支持中文。
解决1:
// 设置response缓冲区的编码,即设置服务器字符集为UTF-8
response.setCharacterEncoding("UTF-8");// 设置浏览器打开文件所采用的编码;即通过响应头,设置浏览器使用UTF-8字符集
response.setHeader("Content-Type", "text/html;charset=UTF-8");// 输出中文
response.getWriter().write("编程");
解决2:
//setContentType会设置服务端和客户端都使用UTF-8字符集,还设置了响应头;
//setContentType要在获取流对象(getWriter)之前调用才有效
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("编程");
三大组件
JavaWeb的三大组件包括Servlet 程序、 Listener 监听器、 Filter 过滤器。
Listener 监听器
介绍
监听器 Listener 是一个实现特定接口的 Java 程序,用来监听某种变化, 从而触发对应方法完成相应的任务;一般就是对象创建/销毁, 属性变化。采用观察者模式。
Servlet 规范中定义了 8 个监听器接口 :
- 目前最常用的是 ServletContextListener;
- 可以用于监听 ServletContext、HttpSession 和 ServletRequest 对象的生命周期和属性变化事件;
注册Servlet监听器的方式:
- 在 web.xml 中注册监听器;
- 使用 @WebListener 注册监听器:在监听器类上使用 @WebListener 注解,可以将该 Java 类注册为一个监听器类。
监听器的使用:
- 定义监听器,根据需求实现对应接口;
- 在web.xml中注册监听器,让监听器工作。
分类
【1】监听对象创建和销毁的监听器
1)ServletContextListener 监听器(接口):
作用:监听 ServletContext 创建或销毁,即生命周期监听。当我们Web 应用启动时,就会创建 ServletContext。
应用场景: (1)加载初始化的配置文件;比如 spring 的配置文件 ;(2)任务调度(配合定时器 Timer/TimerTask)。
相关方法
- void contextInitialized(ServletContextEvent sce):创建 Servletcontext 时触发;
- void contextDestroyed(ServletContextEvent sce) :销毁 Servletcontext 时。
//创建Listen
package com.lhyedu.listen;import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;public class MyServletContextListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent servletContextEvent) {System.out.println("ServletContext 创建,完成 WEB 项目初始化的工作..");}@Overridepublic void contextDestroyed(ServletContextEvent servletContextEvent) {System.out.println("ServletContext 销毁,完成资源回收的工作");}
}web.xml配置;<listener>
<listener-class>com.lhyedu.listen.MyServletContextListener</listener-class></listener>
2)HttpSessionListener 监听器
- 作用:监听 Session 创建或销毁,即生命周期监听
相关方法
- void sessionCreated(HttpSessionEvent se):创建session时调用
- void sessionDestroyed(HttpSessionEvent se): 销毁session时调用;使用方法和前面一样, 可以用于监控用户上线,离线
应用场景: 可以用于监控用户上线,离线
1、定义监听器,根据需求实现对应接口,重写接口的方法//统计网站在线人数监听器:一个用户对应一个session,则统计session的数量即可统计在线人数
public class OnlineCountListener implements HttpSessionListener {@Override//创建session的监听:一旦创建session,就会触发一次这个事件public void sessionCreated(HttpSessionEvent httpSessionEvent) {ServletContext context = httpSessionEvent.getSession().getServletContext();Integer onlineCount = (Integer) context.getAttribute("OnlineCount");System.out.println(httpSessionEvent.getSession().getId());if (onlineCount == null) {onlineCount = new Integer(1);} else {int count = onlineCount.intValue();onlineCount = new Integer(count + 1);}context.setAttribute("OnlineCount", onlineCount);}@Override//销毁session的监听:一旦销毁session就会触发一次这个事件public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {ServletContext context = httpSessionEvent.getSession().getServletContext();Integer onlineCount = (Integer) context.getAttribute("OnlineCount");if (onlineCount == null) {onlineCount = new Integer(0);} else {int count = onlineCount.intValue();onlineCount = new Integer(count - 1);}context.setAttribute("OnlineCount", onlineCount);}
}2、注册监听器:
<!--注册监听器-->
<listener> <listener-class>com.yue.listener.OnlineCountListener</listener-class>
</listener>3、在前端页面显示在线人数:<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html><head><title>$Title$</title></head><body><h1>当前有<span style="color: brown"><%=application.getAttribute("OnlineCount")%></span>在线</h1></body>
</html>
3)ServletRequestListener 监听器
作用:监听 Request 创建或销毁,即 Request 生命周期监听
相关方法
- void requestInitialized(ServletRequestEvent sre):创建 request 时
- void requestDestroyed(ServletRequestEvent sre):销毁 request 时, 可以用来监控, 某个 IP 访问我们网站的频率, 日志记录 ,访问资源的情况.
应用场景:用来监控, 某个 IP 访问我们网站的频率, 日志记录 ,访问资源的情况.
【2】监听对象中属性变更的监听器
事件源 | 监听器 | 监听器描述 | 方法 | 调用时机 |
---|---|---|---|---|
ServletContext | ServletContextAttributeListener | 用于监听 ServletContext 对象的属性新增、移除和替换 | public void attributeAdded (ServletContextAttributeEvent scae) | 当 ServletContext 对象中新增一个属性时 |
public void attributeRemoved (ServletContextAttributeEvent scae) | 当删除 ServletContext 对象中的一个属性时 | |||
public void attributeReplaced (ServletContextAttributeEvent scae) | 当 ServletContext 对象中的某个属性被替换时 | |||
HttpSession | HttpSessionAttributeListener | 用于监听 HttpSession 对象的属性新增、移除和替换 | public void attributeAdded (HttpSessionBindingEvent hsbe) | 当 HttpSession 对象中新增一个属性时 |
public void attributeRemoved (HttpSessionBindingEvent hsbe) | 当删除 HttpSession 对象中的一个属性时 | |||
public void attributeReplaced (HttpSessionBindingEvent hsbe) | 当 HttpSession 对象中的某个属性被替换时 | |||
HttpServletRequest | ServletRequestAttributeListener | 用于监听 HttpServletRequest 对象的属性新增、移除和替换 | public void attributeAdded (ServletRequestAttributeEvent srae) | 当 HttpServletRequest 对象中新增一个属性时 |
public void attributeRemoved (ServletRequestAttributeEvent srae) | 当删除 HttpServletRequest 对象中的一个属性时 | |||
public void attributeReplaced (ServletRequestAttributeEvent srae) | 当 HttpServletRequest 对象中的某个属性被替换时 |
【3】监听 HttpSession 中的对象状态改变的监听器
Session 中的对象的多种状态: 绑定到 Session 中、从 Session 中解除绑定、随 Session 对象持久化到存储设备中(钝化)、随 Session 对象从存储设备中恢复(活化)。
事件源 | 监听器 | 监听器描述 | 方法 | 调用时机 |
---|---|---|---|---|
HttpSession | HttpSessionBindingListener 【感知监听器】 | 用于监听 JavaBean 对象绑定到 HttpSession 对象和从 HttpSession 对象解绑的事件 | void valueBound (HttpSessionBindingEvent event) | 当对象被绑定(添加)到 HttpSession 对象中时 |
void valueUnbound (HttpSessionBindingEvent event) | 当对象从 HttpSession 对象中解除绑定(移除)时 | |||
HttpSessionActivationListener 【感知监听器】 | 用于监听 HttpSession 中对象活化和钝化的过程 | void sessionWillPassivate (HttpSessionBindingEvent event) | 当绑定到 HttpSession 对象中的对象将要随 HttpSession 对象被钝化之前 | |
void sessionDidActive (HttpSessionBindingEvent event) | 当绑定到 HttpSession 对象中的对象将要随 HttpSession 对象被活化之后 |
Filter 过滤器
介绍
Filter 过滤器是 JavaEE 的规范,是接口,采用责任链模式。
作用:拦截请求,过滤响应。它可以对服务器管理的所有 Web 资源(例如 JSP、Servlet、静态 HTML 文件、静态图片等)进行拦截,从而实现一些特殊的功能。
应用场景
- 用户的权限控制、过滤敏感词、设置统一编码格式等
- 例如日志操作、事务管理等
工作流程
- 客户端请求访问容器内的 Web 资源;
- Servlet 容器接收请求,并针对本次请求分别创建一个 request 对象和 response 对象;
- 请求到达 Web 资源之前,先调用 Filter 的 doFilter() 方法,检查 request 对象,修改请求头和请求正文,或对请求进行预处理操作;
- 在 Filter 的 doFilter() 方法内,调用 FilterChain.doFilter() 方法,将请求传递给下一个过滤器或目标资源;
- 目标资源生成响应信息返回客户端之前,处理控制权会再次回到 Filter 的 doFilter() 方法,执行 FilterChain.doFilter() 后的语句,检查 response 对象,修改响应头和响应正文;
- 响应信息返回客户端。
接口
Filter接口
开发过滤器要实现 javax.servlet.Filter 接口,并提供一个公开的不带参的构造方法。
返回值类型 | 方法 | 功能描述 |
---|---|---|
void | init (FilterConfig filterConfig) | 该方法用于初始化过滤器。 |
void | doFilter(ServletRequest request,SeivletResponse response, FilterChain chain) | 该方法完成实际的过滤操作,当客户端请求的 URL 与过滤器映射的 URL 匹配时,容器会先调用该方法对请求进行拦截。 参数 request 和 response 表示请求和响应对象。 参数 chain 代表当前 Filter 链对象,在该方法内部,调用 chain.doFilter() 方法,才能把请求交付给 Filter 链中的下一个 Filter 或者 Web 资源。 |
void | destroy() | 该方法在销毁 Filter 对象之前被调用,用于释放被 Filter 对象占用的资源。 |
FilterConfig 接口
FilterConfig 是 Filter 过滤器的配置类。
- 用于在过滤器初始化期间向其传递信息;通过 filterConfig 对象就可以获得 Filter 的初始化参数。
- 由容器实现,容器将它作为参数传入过滤器的 init() 方法。
Tomcat 每次创建 Filter 的时候,也会创建一个 FilterConfig 对象,这里包含了 Filter 配置文件的配置信息。
返回值类型 | 方法 | 描述 |
---|---|---|
String | getInitParameter(String name) | 根据初始化参数名 name,返回对应的初始化参数值。 |
Enumeration | getInitParameterNames() | 返回过滤器的所有初始化参数名的枚举集合。 |
ServletContext | getServletContext() | 返回 Servlet 上下文对象的引用。 |
String | getFilterName() | 返回过滤器的名称。 |
生命周期
【1】初始化阶段
- Servlet 容器负责加载和实例化 Filter
容器启动时,读取 web.xml 或 @WebFilter 的配置信息对所有的过滤器进行加载和实例化。
加载和实例化完成后,Servlet 容器调用 init() 方法初始化 Filter 实例;
在 Filter 的生命周期内, init() 方法只执行一次;
【2】拦截和过滤阶段,最重要的阶段
- 当客户端请求的 URL 与过滤器映射匹配时,容器将该请求的 request 对象、response 对象以及 FilterChain 对象以参数的形式传递给 Filter 的 doFilter() 方法,并调用该方法对请求/响应进行拦截和过滤
【3】销毁阶段
- Filter 对象创建后会驻留在内存中,直到容器关闭或应用被移除时销毁
- 销毁 Filter 对象之前,容器会先调用 destory() 方法,释放过滤器占用的资源
- 在 Filter 的生命周期内,destory() 只执行一次。
FilterChain(过滤器链)
在处理某些复杂业务时,一个过滤器不够,可以设计多个过滤器共同完成过滤任务,形成过滤器链
javax.servlet 包中提供了一个 FilterChain 接口,该接口由容器实现。
执行顺序:Http 请求 -> A 过滤器 dofilter()-> A 过滤器前置代码 -> A 过滤器 chain.doFilter() -> B 过滤器dofilter() -> B 过滤器前置代码 -> B 过滤器 chain.doFilter() -> 目标文件 -> B 过滤器后置代码 -> A 过滤器后置代码 ->返回给浏览器页面/数据。
多个 filter 和目标资源在一次 http 请求,在同一个线程中
当一个请求 url 和 filter 的 url-pattern 匹配时, 才会被执行;
- 如果有多个匹配上,就会顺序执行,形成一个 filter 调用链。
- 底层可以使用一个数据结构搞定
多个 filter 共同执行时,因为是一次 http 请求, 使用同一个 request 对象;
多个 filter 执行顺序,和 web.xml 配置顺序保持一致;
- 执行顺序由 <filter-mapping> 标签的配置顺序决定
- 通过 @WebFilter 注解配置的 Filter 过滤器,无法进行排序
chain.doFilter(req, resp)方法 将执行下一个过滤器的doFilter 方法,如果后面没有过滤器,则执行目标资源。