1. 什么是 ServletContext
首先看看官方对其定义:
public interface ServletContext Defines a set of methods that a servlet uses to communicate with its servlet container, for example, to get the MIME type of a file, dispatch requests, or write to a log file.
由此可知,首先它是一个interface,它定义了一系列的方法用来 servlet 和其所在的容器进行通信。context这个词本身的含义为上下文、环境,servlet 容器为 servlet 的运行提供了环境。
当 servlet 容器启动了一个 webapp 后,会为其创建一个 ServletContext 对象,并且这个对象是唯一的。它就像一个 webapp 的管家一样,管理着这个 web 应用内的所有 servlet 对象,与此同时,servlet 对象也可以通过这个“管家”来访问容器内的各种资源。
2. 它提供了哪些方法
该接口定义了大量的方法,对方法的作用进行分类可以分为以下几类:
2.1 webapp范围内共享数据
因为一个 webapp 内只有一个 ServletContext 对象,所以它就可以作为一个“中间人”用来做为数据共享的场所。与此相关的方法包括:
- setAttribute(String name, Object object) - 该方法接受两个参数,类似于 k-v 形式,其中 name 为属性名,object 将一个 java 对象作为共享数据(属性值)存储在 ServletContext 对象中
- getAttribute(String name) - 根据属性名获取属性值,返回一个 Object 对象
- getAttributeNames() - 返回一个 Enumeration 对象,该对象包含了所有的属性名
- removeAttribute(String name) - 从 ServletContext 对象中删除指定的属性
2.2 访问当前 webapp 的资源
- getContextPath() - 返回当前 web 应用的 URL 入口
- getInitParameter(String name) - 根据给定的参数名,返回web应用范围内匹配的初始化参数
- getInitParameterNames() - 返回一个 Enumeration 对象,包括了 web 应用范围内所有初始化参数名
- getServletContextName() - 返回 web 应用的名字
- getRequestDispatcher(String path) - 返回一个用于向其他 web 组件转发请求的 RequestDispatcher 对象
2.3 访问 Servlet 容器中其他 web 应用
- getContext(String uripath) - 根据指定的 uri,返回当前容器内其他 web 应用的 ServletContext 对象
2.4 访问 Servlet 容器的相关信息
- getMajorVersion() - 返回 Servlet 容器支持的 Java Servlet API 的主版本号
- getMinorVersion() - 返回 Servlet 容器支持的 Java Servlet API 的次版本号
- getServerInfo() - 返回 Servlet 容器的名字和版本号
2.5 访问服务器端的文件系统资源
- getRealPath(String path) - 根据参数指定的虚拟路径,返回一个文件系统中的真实路径
- getResource(String path) - 返回一个映射到参数指定路径的 URL
- getResourceAsStream(String path) - 返回一个用于读取参数指定的文件的输入流
- getMimeType(String file) - 返回参数指定文件的 MIME 类型
2.6 输出日志
- log(String msg) - 向 Servlet 的日志文件中写日志
- log(String msg, Throwable throwable) - 向 Servlet 的日志文件中写错误日志,以及异常的堆栈信息
3. 如何获得 ServletContext 对象
通过 getServletContext() 方法就可以获得当前 web 应用的 ServletContext 对象。该方法在ServletConfig 接口中声明,继承关系如下图所示。
4. ServletContext 应用实例
4.1 数据共享
- 在一个servlet中设置一个 ServletContext 对象的属性值,然后通过另一个servlet去访问该属性
HelloServlet.java
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
ServletContext context = this.getServletContext();
context.setAttribute("username", "tianyichen");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
}
GetServlet.java
public class GetServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
ServletContext context = this.getServletContext();
String username = (String) context.getAttribute("username");
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
resp.getWriter().print("username=" + username);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
}
4.2 读取web的初始化参数
public class ReadInitParam extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
ServletContext context = this.getServletContext();
String paramValue = context.getInitParameter("url");
resp.getWriter().print(paramValue);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
}
其中初始化参数存放在 web.xml 的 context-param 元素中。
4.3 请求转发
什么是请求转发?用下图可以很好地解释。客户端请求了 a 这个url,a 将请求转发给了 b,b 将资源传给 a,然后 a 再把资源响应给客户端。虽然图中 a 和 b 用了服务器的图标,但是实际代表的是两个 servlet,通常情况下,一个 servlet 对应一个 url-pattern。
使用这种技术就实现了访问一个指定的 url,却拿到了另一个 url 资源的功能。
Employer类 - 转发请求到 Employee类
--------------------------------
public class EmployeeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html");
resp.getWriter().print("你的请求被转发了!");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
}
public class EmployerServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
ServletContext context = this.getServletContext();
context.getRequestDispatcher("/untouch").forward(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
}
4.4 读取配置文件
public class ReadProp extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
ServletContext context = this.getServletContext();
InputStream is = context.getResourceAsStream("/WEB-INF/classes/mysql.properties");
Properties prop = new Properties();
prop.load(is);
String username = prop.getProperty("username");
String pwd = prop.getProperty("password");
resp.getWriter().print("username=" + username + ", pwd=" + pwd);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
}