Servlet学习之ServletContext
一、ServletContext概述:
-
ServletContext即Servlet上下文对象,该对象表示当前的web应用环境信息,一个Web应用只会创建一个ServletContext对象。
-
web容器在启动时,他会为每个web应用程序创建一个对应的ServletContext对象,它代表当前的web应用。
-
由于一个Web应用中的所有Servlet共享一个ServletContext对象,所以多个Servlet通过ServletContext对象实现数据共享。
-
ServletConfig对象中维护了ServletContext对象的引用,在开发编写servlet时,可以通过ServletConfig.getServletContext()方法获得ServletContext对象
-
ServletContext对象通常称为Context域对象。
ServletContext对象的三种获取方法:
1、ServletContext context1 = config.getServletContext();
通过继承GenericServlet类或HttpServlet类,调用GenericServlet类或HttpServlet类的getServletContext()方法获取。
2、ServletContext context2 = this.getServletContext();
通过ServletConfig对象的this.getServletContext()方法获取。
3、ServletContext context3 = request.getSession().getServletContext();
采用request.getSession().getServletContext()方法获取。
二、ServletContext的作用:
1、获取web应用的初始化全局配置参数
涉及的方法:
方法 | 作用 |
---|---|
ServletContext context = this.getServletContext(); | 获得ServletContext域对象 |
public String getInitParameter(String name) | 返回包含指定上下文范围初始化参数值的 String,如果参数不存在,则返回 null。 |
public java.util.Enumeration getInitParameterNames() | 以 String 对象的 Enumeration 的形式返回上下文初始化参数的名称,如果该上下文没有初始化参数,则返回一个空的 Enumeration。 |
web.xml中配置全局信息信息:
获取web.xml中配置的信息测试代码:
public class ContextTest01 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1、获得ServletContext对象
ServletContext context = this.getServletContext();
// 2、获得单个数据,并逐一打印
String username = context.getInitParameter("username");
String password = context.getInitParameter("password");
System.out.println(username);
System.out.println(password);
// 3、获得多个数据并进行遍历打印
Enumeration<String> names = context.getInitParameterNames();
while (names.hasMoreElements()) {
String name = names.nextElement();
String value = context.getInitParameter(name);
System.out.println(name + ":" + value);
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
2、实现数据共享
域对象(多个Servlet共享数据) 网站计数器:统计网站的访问量,每次用户进行访问(MyVisitContext类),网站计数器count就会进行加一操作。最后将访问量展示出来(MyShowContext类)!
- 涉及到的方法:
方法 | 作用 |
---|---|
public void setAttribute(String name, Object object) | 往域对象里面添加数据,添加时以key-value形式添加 |
public Object getAttribute(String name) | 根据指定的key读取域对象里面的数据 |
public void removeAttribute(String name) | 根据指定的key从域对象里面删除数据 |
MyVisitContext.java
public class MyVisitContext extends HttpServlet {
// ServletContext context = null;
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext context = getServletContext();
Integer count = (Integer) context.getAttribute("count");
if (count == null) {
count = 1;
} else {
count += 1;
}
context.setAttribute("count", count);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
MyShowContext.java
public class MyShowContext extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext context = getServletContext();
//获取访问的次数
int conut = (int) context.getAttribute("count");
//设置响应的编码类型
response.setContentType("text/html;charset=utf-8");
//得到输出对象
PrintWriter out = response.getWriter();
out.println("<H1>共访问MyVisitContext"+conut+"次</H1>");
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
运行结果展示:
3、实现Servlet的请求转发
方法 | 作用 |
---|---|
public RequestDispatcher getRequestDispatcher(String path) | 返回一个 RequestDispatcher 对象,它充当位于给定路径上的资源的包装器。可以使用 RequestDispatcher 对象将请求转发到资源,或者在响应中包含资源。资源可以是动态的,也可以是静态的。 |
HTTP的协议
* 请求
* referer 记住当前网页的来源
* user-agent 浏览器版本信息
* if-modefied-since
* 响应
* 响应头
* location 和302一起来完成重定向的操作
* refresh 页面的定时刷新
* last-modefied和 if-modefied-since和304状态码一起来控制缓存。
区别两个重要的概念:
请求转发:服务器内不进行资源流转 (一次请求一次响应,来实现资源流转)
1、地址栏不会改变
2、只能跳转到项目内的资源,不能跳转项目外的资源。
3、浏览器向服务器发出一次请求,那么可以使用请求作为域对象共享数据。
重定向(重新定位方向):302+Location(两次请求两次响应):
1、地址栏会改变,变成重定向到的地址
2、可以转跳到项目内资源,也可以转跳到项目外资源
3、浏览器向服务器发送两次请求,不可以使用请求来作为域对象来共享数据
举例说明:
- 重定向:你找我借钱,我没有,我告诉你谁有,你自己去找他借钱
- 请求转发:你找我借钱,我没有,我去给你借钱,但是你不需要考虑钱是哪里来的(我自己内部的事情)。反正你找我借钱我借给你了
ContextTest03.java
public class ContextTest03 extends HttpServlet {
/**
* 实现请求转发
*/
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
//实现请求转发的关键代码
RequestDispatcher dispatcher = this.getServletContext().getRequestDispatcher("/ContextTest04");
//执行完这一行将转跳到ContextTest04的servlet类中
dispatcher.forward(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
ContextTest04.java
public class ContextTest04 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
out.println("我是ContextTest03请求转发得到的");
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
运行结果:
4、读取web项目的资源文件
常用方法介绍:
方法 | 作用 |
---|---|
public String getContextPath() | 返回 Web 应用程序的上下文路径。(工程名字) |
public String getRealPath(String path) | getRealPath()获得的是绝对路径 |
public java.net.URL getResource(String path) | getResource()获得的是相对路径 |
public java.util.Set getResourcePaths(String path) | 返回指向 Web 应用程序中资源的所有路径的类似目录的清单,这些路径中最长的子路径与提供的 path 参数匹配。 |
public java.io.InputStream getResourceAsStream(String path) | 以 InputStream 对象的形式返回位于指定路径上的资源。 如果指定路径上没有资源,则此方法返回 null。 |
涉及到的知识点:
-
getRealPath()和getResource()区别:
1、getRealPath()获得的是绝对路径,getResource()获得的是相对路径; 2、对于 开发人员来说都是使用相对路径,因为使用的是绝对路径一旦你换了服务器或者系统,那便会出现路径或者类加载的错误。 3、典型的:如果你在windows下可能有C,D盘之分,但是在linux系统下便没有盘符之分了,所以建议使用getResource()。 4、如果你使用的是getResource()你在用myeclipse或者eclipse时把项目压 缩成war包后对你的部署工作不会存在影响,但是如果是用的绝对路径,一定会有影响!
-
URL中的getFile()和getPath()方法的区别:
获取此URL的文件名。 返回的文件部分将与getPath()相同,加上getQuery()的值的串联(如果有)。 如果没有查询部分,则此方法和getPath()将返回相同的结果
分别创建txt文件1,2,3,4:
1.txt在WebRoot 外 — > 不会发布到tomcat服务器,无法在服务器端读取
2.txt 位于WEB-INF下 — > getServletContext().getResource("/WEB-INF/2.txt").getPath();
3.txt 位于WebRoot下 — > getServletContext().getResource("/3.txt").getPath();
4.txt 位于src下,复制到WEB-INF/classes下 —> getServletContext().getResource("/WEB-INF/classes/4.txt").getPath();
测试代码:
public class ContextTest extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获得ServletContext
ServletContext context = this.getServletContext();
// getContextPath()方法
String path1 = context.getContextPath();
// getRealPath()方法
String path2 = context.getRealPath("/");
String path3 = context.getRealPath("");
// getResource()方法,getPath()和getPath();
String path4 = context.getResource("/").getPath();
String path5 = context.getResource("").getPath();
System.out.println(path1);
System.out.println(path2);
System.out.println(path3);
System.out.println(path4);
System.out.println(path5);
// System.out.println("-------------------------------读取文件1.txt---------------------------------");
// 读取文件1.txt,因为在WebRoot外面不会发布到tomcat服务器上,无法在服务器端读取
// String filename1 = "";
// readfile(filename1);Q
System.out.println("-------------------------------读取文件2.txt---------------------------------");
// 读取文件2.txt。
String filename2 = context.getResource("/WEB-INF/2.txt").getPath();
readfile(filename2);
// D:/tomcat8/apache-tomcat-8.0.53-windows-x64/apache-tomcat-8.0.53/webapps/day03_2/WEB-INF/2.txt
// 2222222222222222222222
System.out.println("-------------------------------读取文件3.txt---------------------------------");
// 读取文件3.txt
String filename3 = context.getResource("/3.txt").getPath();
readfile(filename3);
// D:/tomcat8/apache-tomcat-8.0.53-windows-x64/apache-tomcat-8.0.53/webapps/day03_2/3.txt
// 33333333333333333333333333333333
// D:\tomcat8\apache-tomcat-8.0.53-windows-x64\apache-tomcat-8.0.53\webapps\day03_1\3.txt
// 3333333333333333333333333
System.out.println("-------------------------------读取文件4.txt---------------------------------");
// 读取文件4.txt
String filename4 = context.getResource("/WEB-INF/classes/4.txt").getPath();
readfile(filename4);
// D:/tomcat8/apache-tomcat-8.0.53-windows-x64/apache-tomcat-8.0.53/webapps/day03_2/WEB-INF/classes/4.txt
// 444444444444444444444
System.out.println("-------------------------------读取文件4.txt(类加载器)---------------------------------");
// getResource
// public URL getResource(String name)查找带有给定名称的资源。
// 查找与给定类相关的资源的规则是通过定义类的 class loader 实现的。
// 此方法委托给此对象的类加载器。如果此对象通过引导类加载器加载,
// 则此方法将委托给 ClassLoader.getSystemResource(java.lang.String)。
// 使用类加载器进行4.txt的读取
URL url = ContextTest.class.getResource("/4.txt");
// 将上面的url转化为字符串
String file1 = ContextTest.class.getResource("/4.txt").getFile();
String file2 = ContextTest.class.getResource("/4.txt").getPath();
System.out.println(url);
System.out.println(file1);
System.out.println(file2);
readfile(file2);
// file:/D:/tomcat8/apache-tomcat-8.0.53-windows-x64/apache-tomcat-8.0.53/webapps/day03_2/WEB-INF/classes/4.txt
// /D:/tomcat8/apache-tomcat-8.0.53-windows-x64/apache-tomcat-8.0.53/webapps/day03_2/WEB-INF/classes/4.txt
// /D:/tomcat8/apache-tomcat-8.0.53-windows-x64/apache-tomcat-8.0.53/webapps/day03_2/WEB-INF/classes/4.txt
// /D:/tomcat8/apache-tomcat-8.0.53-windows-x64/apache-tomcat-8.0.53/webapps/day03_2/WEB-INF/classes/4.txt
// 444444444444444444444
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
public void readfile(String filename) throws IOException {
System.out.println(filename);
BufferedReader bufferedReader = new BufferedReader(new FileReader(filename));
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
bufferedReader.close();
}
}
getResourceAsStream方法读取配置文件:
-
在WEB-INF下面创建db1.properties文件
-
在src.com.syj.getResourceAsStream下面创建db2.properties文件
配置信息如下://db1.properties文件 id=001 username=tom password=123456 //db2.properties文件 id=002 username=xiaoming password=654321
public class test extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Test("/WEB-INF/classes/com/syj/getResourceAsStream/db2.properties");
Test("/WEB-INF/db1.properties");
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
public void Test(String filename) throws IOException {
InputStream is = getServletContext().getResourceAsStream(filename);
Properties properties = new Properties();
properties.load(is);
String id = properties.getProperty("id");
String username = properties.getProperty("username");
String password = properties.getProperty("possword");
System.out.println(id);
System.out.println(username);
System.out.println(password);
}
}
结果:
三、ServletContext的总结:
- WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。
- 由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象。
- 创建:该web应用被加载(服务器启动或发布web应用(前提,服务器启动状态))
- 销毁:web应用被卸载(服务器关闭,移除该web应用)
四、扩展:
- 如果写硬盘的路径D:\tomcat8\apache-tomcat-8.0.53-windows-x64\apache-tomcat-8.0.53\webapps\项目名\资源,可以找到资源,但是只要一换发布环境,这个硬盘路径很可能是错误的,同样不行。
为了解决这样的问题,ServletContext提供了getRealPath方法,在这个方法中传入一个路径,这个方法的底层会在传入的路径的前面拼接当前web应用的硬盘路径,从而得到当前资源的硬盘路径(即当前项目的路径),这种方式即使换了发布环境,方法的底层也能得到正确的web应用的路径从而永远都是正确的资源的路径。 - 1、getRealPath()获得的是绝对路径,getResource()获得的是相对路径;
2、对于 开发人员来说都是使用相对路径,因为使用的是绝对路径一旦你换了服务器或者系统,那便会出现路径或者类加载的错误。
3、典型的:如果你在windows下可能有C,D盘之分,但是在linux系统下便没有盘符之分了,所以建议使用getResource()。
4、如果你使用的是getResource()你在用myeclipse或者eclipse时把项目压
缩成war包后对你的部署工作不会存在影响,但是如果是用的绝对路径,一定会有影响! - 类路径classpath(src下)
* 通过字节码对象读取Class
getResource("/info.txt").getFile()
* 获取字节码对象Class
类名.class ——静态方法获取
对象.getClass() —— 实例方法 - 使用基本的FileInputStream 读取相对路径时 是相对于Tomcat安装程序的bin目录,而要想相对路径在Tomcat的webapps的当前应用的根路径,就需要使用 getResourceAsStream()方法。
- 1、使用带有main函数java程序普通的java应用(Java Application)读取文件,可以使用相对路径和绝对路径、这个是属于在本地读取。
2、在Servlet中读取资源文件,必须使用磁盘绝对路径 (服务器读取)
平时的小知识积累,在此以笔记的形式记录下来,如有错误欢迎指正
不积跬步,无以至千里;不积小流,无以成江海