1.1 什么是ServletContext
ServletContext:Servlet的上下文对象。ServletContext对象对Servlet之前和之后的内容都知道。有一个web项目就有一个ServletContext对象(web项目对象)。在服务器启动的时候为每个web项目创建一个单独的ServletContext对象。
ServletContext本身是一个接口,接口的实现类对象由Tomcat引擎提供
获取方式:
方法1.先获取ServletConfig对象,在通过ServletConfig对象中的方法getServletContext获取
ServletConfig config = getServletConfig();
ServletContext context1 = config.getServletContext();
方法2.在父类中GenericServlet中直接封装好了获取ServletContext对象的方式,我们可以直接使用
ServletContext getServletContext()
ServletContext context2 = getServletContext()
extends HttpServlet,HttpServlet extends GenericServlet,在GenericServlet里封装了方法getServletContext()。其实上面的两种方法的本质是一样的。
1.2 ServletContext对象的作用
1.2.1 用来获取web项目信息
因为一个web项目只有一个ServletContext对象,所以这个对象对整个项目的相关内容都是了解的。
方法 | 返回值 | 描述 |
---|---|---|
getMimeType(String file) | String | 获取文件的MIME类型 |
getContextPath() | String | 获取web项目请求工程名 |
getInitParameter(String name) | String | 获取web项目的初始化参数 |
getInitParameterNames() | Enumeration | 获取web项目的初始化参数(返回类型是枚举) |
举例说明:
package com.ccc.demo01ServletContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
@WebServlet(urlPatterns = "/Context1")
public class Demo01ServletContext extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//在父类中GenericServlet中直接封装好了获取ServletContext对象的方式,我们可以直接使用
ServletContext context = getServletContext();
//String getMimeType(String file) 获取文件的MIME类型
String aMimeType = context.getMimeType("a.txt");
System.out.println(aMimeType); //text/plain
//String getContextPath() 获取web项目请求工程名
String contextPath = context.getContextPath();
System.out.println(contextPath);// /day12_web
//String getInitParameter(String name) 获取web项目的初始化参数值
String a = context.getInitParameter("a");
System.out.println(a); //123
//Enumeration<E> getInitParameterNames() 获取web项目的所有初始化参数的名称
Enumeration<String> en = context.getInitParameterNames();
while (en.hasMoreElements()){
String name = en.nextElement();
String value = context.getInitParameter(name);
System.out.println(name+"\t"+value);
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
1.2.2 获取WEB应用程序下任意资源的绝对路径
- 方法: String getRealPath(“资源相对路径”),返回的是资源的绝对路径(在Tomcat服务器中的路径,包含盘符)
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//context对象,方法getRealPath获取任意资源的绝对路径
//获取web目录下的a.txt绝对路径
String aPath = context.getRealPath("a.txt");
System.out.println(aPath);
//获取web目下WEB-INF目录下的b.txt绝对路径
String bPath = context.getRealPath("WEB-INF/b.txt");
System.out.println(bPath);
//获取src目录下的c.txt绝对路径
String cPath = context.getRealPath("WEB-INF/classes/c.txt");
System.out.println(cPath);
//获取WEB03 module下的d.txt绝对路径,获取不到,因为只有发布在Tomcat中的文件,才能获取到。
//此时文件存在根目录下,不会发布到Tomcat中(即是在src文件夹之下),所以也就获取不到。
}
需要注意的是,这个方法它自身不会判断文件的真实性。只会使用字符串的拼接(项目路径+目录),而文件存在与否及这个路径是否正确,它并不会判断。
web中的项目是要发布到Tomcat中的,所以相对路径指的是相对于Tomcat,而Java项目是相对于Java的根目录的。
1.2.3 域对象
ServletContext对象是一个容器,可以存储数据.
对象有个作用域问题,ServletContext作用域是整个WEB应用程序
- 向域对象存储数据: setAttribute(String key, Object value)
- 取出域对象数据: Object getAttribute(String key)
- 移除域对象数据: removeAttribute(String key)
以上的这三个方法(存储、取出、移除)同样适用于其他域对象
注意:
ServletContext对象作用域是整个web项目,即这个web项目里的所有Servlet都可以访问
扩展:(下面是按作用域由大到小排名)
- ServletContext:作用域时整个web项目;即这个web项目里的所有Servlet都可以访问。
- Session:只要浏览器不关闭就有效。就算是访问不同的虚拟地址也可以。但只能保留30分钟。
- Request:只要是地址栏不变,不刷新,就有效,即只能请求一次。转发也有效。但是重定向就无效了。因为转发的地址栏不变,重定向的地址栏发生变化了。
- PageContext:只在jsp本页面有效。
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*
* 域对象的存储和取出
*/
ServletContext context = getServletContext();
//域对象存储数据,键值对(在该项目的任意一个servlet中都能获取到该键值对)
context.setAttribute("heima","java");
//取出域对象存储的键值对
Object value = context.getAttribute("heima");
System.out.println(value);
//移除域对象数据: void removeAttribute(String key)
context.removeAttribute("heima");
}
1.2.4 init方法只会在创建Servlet对象的时候执行一次
利用这个特点,我们可以先将init方法重写,然后把一些需要只执行一次的代码放到init方法里面。但是切记:一定要重写空参数的init方法,因为tomcat在调用完带参init方法之后,会默认调用空参数的(在源码中)。
以下是源码:
源码tomcat在调用完带参init方法之后,会调用空参数init方法。
@WebServlet(urlPatterns = "/context5")
public class Demo05ServletContext extends HttpServlet {
//重写父类GenericServlet中init方法
/*
以后我们重写init方法,不要重写带ServletConfig的init方法
重写空参数的init方法-->tomcat在调用完带参init方法之后,会调用空参数的
*/
@Override
public void init() throws ServletException {
System.out.println("init方法只会在创建Servlet对象的时候执行一次");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取ServletContext域对象
ServletContext context = getServletContext();
System.out.println(context);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
引发问题:ServletContext对象的空指针异常
产生原因:
重写父类GenericServlet中的init的带参方法后。在程序运行的时,它就会优先调用重写后的这个init方法。
解决方案:
以后我们重写init方法时,不要重写带参数(ServletConfig config)的方法。要重写空参数的init方法。因为Tomcat(源代码)在调用完有参数的init方法之后,就会默认调用其空参的方法。所有我们传递一个空参数的init方法(重写)之后,就相当于传递给了底层的有参方法。
1.3 注解开发取代web.xml(修改注解方式Servlet的模版)
WebServlet之后括号里,urlPatterns的赋值,就是客户端访问的虚拟路径。此时就不用配置web.xml了。
若即用注解又用web.xml文件,那将会产生冲突(虚拟路径一样的情况下)。若把虚拟路径改成不一样的,则使用两种方式都能访问到。此功能只有Java6及之后版本才支持。
切记修改模板之后,在新建servlet的对话框中,Name前面加“/”,左下角的勾选框要✔。