ServletContext上下文环境对象的以和使用案例
详细介绍了ServletContext的概念,以及一些常见使用方法。
javax.servlet.ServletContext作为上下文环境对象的抽象,代表当前的Web应用。一个项目只有一个ServletContext对象,工程内部的所有servlet文件都共享这个对象。我们可以在N多个Servlet文件中来获取这个唯一的对象,使用它可以给多个不同的Servlet文件传递数据!
Web服务器启动的时候,就会创建ServletContext对象,在web服务器关闭的时候,ServletContext对象被销毁。
1 获取ServletContext
常见的,有四种方法获取Servlet对象
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
/*获得ServletContext对象*/
//方法一:ServletConfig提供的方法
ServletContext sc1 = getServletConfig().getServletContext();
//方法二:ServletRequest提供的方法
ServletContext sc2 = req.getServletContext();
System.out.println(sc1 == sc2);
//方法二:GenericServlet提供的方法
ServletContext sc3 = getServletContext();
System.out.println(sc2 == sc3);
//方法三:Session对象提供的方法
ServletContext sc4 = req.getSession().getServletContext();
System.out.println(sc3 == sc4);
}
2 作为域对象使用
域对象可以理解为是服务器在内存上创建的存储空间(一个Map集合),可以储存数据,不同的域对象有不同的作用域,ServletContext的作用域是整个Web应用,因此ServletContext作为域对象主要用于在不同动态资源(servlet)之间传递与共享数据。
域中存储的数据是以key-value形式存放的:key是String类型 value是Object类型。
2.1 域对象方法
凡是域对象,都有如下4个操作数据的方法,Servlet中可以使用的域对象有HttpServletRequest、HttpSession、ServletContext,而JSP中可以多使用一个域对象pageContext。
方法 | 描述 |
---|---|
void setAttribute(String name, Object object) | 将对象绑定到此域对象中的给定属性名称。如果指定的名称已用于属性,则此方法将用新属性的值替换旧的属性。 |
Object getAttribute(String name) | 返回具有给定名称key的包含属性值的value对象,如果不存在与给定名称匹配的属性,则返回 null。 |
void removeAttribute(String name) | 从此域对象中删除具有给定名称的属性。删除后,对getattrit (java.lang.String) 以检索属性值的后续调用将返回 null。如果参数name指定的域属性不存在,那么本方法什么都不做。 |
Enumeration getAttributeNames() | 返回包含此域对象中可用的属性名称的枚举。如果没有则返回空枚举。 |
启动时tomcat就往ServletContext对象中存放了一些域属性和值,存放的一般是一些mime标签和jar包,因此ServletContext一般不为空。
2.2 域对象练习:访问量的统计
@WebServlet("/PV-servlet")
public class PVServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获得域对象
ServletContext sc = getServletContext();
//获取count属性值
Integer num = (Integer) sc.getAttribute("count");
if (num == null) {
num = 1;
} else {
num ;
}
sc.setAttribute("count", num);
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.print("您是第" num "位访问者");
out.flush();
out.close();
}
}
3 全局初始化参数
一个Servlet实例对应一个ServletConfig实例,ServletConfig中获取的是通过init-param配置的单个Servlet的参数信息。而所有的Servlet又都共享一个ServletContext实例,所有Servlet都可以从ServletContext中获取整个Web应用的全局配置参数信息。
在web.xml的< web-app/>标签下可以直接通过< context-param/>标签配置当前应用级别的初始化参数,应用级别的初始化参数在任何的servlet当中都可以访问:
<!--配置应用级别的初始化参数,通过ServletContext来访访问-->
<context-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</context-param>
<context-param>
<param-name>name</param-name>
<param-value>wangwu</param-value>
</context-param>
以下两个方法可以从ServletContext中获取全局初始化参数:
方法名 | 描述 |
---|---|
String getInitParameter(String name) | 获得初始化参数名称对应的值。如果名称不存在,返回null。 |
Enumeration<java.lang.String> getInitParameterNames() | 获得一个枚举类型,获得是所有的初始化参数的名称。或没有初始化参数则返回空枚举。 |
4 获得资源的真实路径
Idea maven的JavaWeb项目,Java源文件在java目录下;一般的资源文件,比如properties放在resources目录下,其他资源比如html、css、js,则放在webapp目录下。
4.1 采用ServletContext对象获取
ServletContext的getRealPath(String path)方法可以获取资源的路径,它具有自己默认定位的目录,并且基于Idea的Maven的Java Web项目采用本地Tomcat部署和采用tomcat插件部署时,默认定位的目录不一样,即使是传统SSM项目,在开发环境中也基本上是通过tomcat插件启动和调试项目的。
getRealPath(String path)方法使用默认定位的真实路径,获取与给定虚拟路径(可以存在或者不存在)相对应的真实路径。在虚拟路径中使用../无效,可以使用\\或者/间隔。返回给定虚拟路径的真实路径,返回的路径以 \ 间隔开,开头没有\。注意返回的“真实”路径的资源可能不存在,或者是如果servlet容器无法将给定的虚拟路径转换为真正的路径,则此方法返回 null。
如下项目结构:
其中在resources、webapp和WEB-INF下面分别有三张图片资源!
4.1.1 Idea 本地tomcat
我们首先采用Idea 本地tomcat来启动项目,项目编译之后目录结构如下:
可以看到,resources下的资源默认是放在classes下面,因此它和java源码在编译后是放在同一个主目录中的,同时,最外层有一个Servlet目录,该目录就类似于Web应用根目录,在打成war包之后的文件名可以通过pom.xml中的finalName标签更改。
实际上,Idea 本地tomcat部署的项目,ServletContext的getRealPath方法会默认定位到编译后的Servlet目录的绝对位置,即Web应用根目录,也就相当于将war包发布到tomcat中部署。我们编写程序尝试输出的路径信息:
@WebServlet("/resources-servlet")
public class ResourcesServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
ServletContext servletContext = getServletContext();
{
//默认目录
String realPath = servletContext.getRealPath("");
System.out.println(realPath);
}
{
String realPath1 = servletContext.getRealPath("/pic.jpg");
System.out.println(realPath1);
String realPath2 = servletContext.getRealPath("pic.jpg");
System.out.println(realPath2);
}
{
String realPath1 = servletContext.getRealPath("/WEB-INF/pic2.jpg");
System.out.println(realPath1);
String realPath2 = servletContext.getRealPath("WEB-INF/pic2.jpg");
System.out.println(realPath2);
}
{
String realPath1 = servletContext.getRealPath("/WEB-INF/classes/pic3.jpg");
System.out.println(realPath1);
String realPath2 = servletContext.getRealPath("WEB-INF/classes/pic3.jpg");
System.out.println(realPath2);
}
}
}
运行之后,输出的目录如下:
E:\Idea\Java-EE\servlet-01\target\Servlet\
E:\Idea\Java-EE\servlet-01\target\Servlet\pic.jpg
E:\Idea\Java-EE\servlet-01\target\Servlet\pic.jpg
E:\Idea\Java-EE\servlet-01\target\Servlet\WEB-INF\pic2.jpg
E:\Idea\Java-EE\servlet-01\target\Servlet\WEB-INF\pic2.jpg
E:\Idea\Java-EE\servlet-01\target\Servlet\WEB-INF\classes\pic3.jpg
E:\Idea\Java-EE\servlet-01\target\Servlet\WEB-INF\classes\pic3.jpg
如果打包成war包部署到webapps下面,那么默认定位的目录就是发布的Web应用的根目录。实际上,war包部署之后的Web应用结构如下:
现在,我们可以直接通过这些真实路径来访问这三张图片资源了。这就是通过ServletContext来访问资源的好处,我们不必知道资源的绝对位置,只需要直到它在编译之后的相对位置即可!
4.1.1 Idea tomcat插件
我们接着采用Idea tomcat插件来启动项目,这是创痛Java Web项目最常见的启动方式,项目编译之后目录结构如下:
我们会发现,并没有Servlet目录生成,也没有webapp下的资源和WEB-INF目录,它和传统tomcat服务器部署的差距还是很大的。
实际上,Idea tomcat插件部署的项目,ServletContext的getRealPath方法会默认定位到src下面的webapp目录的绝对位置,我们运行上面的程序尝试输出的路径信息:
E:\Idea\Java-EE\servlet-01\src\main\webapp
E:\Idea\Java-EE\servlet-01\src\main\webapp\pic.jpg
E:\Idea\Java-EE\servlet-01\src\main\webapp\pic.jpg
E:\Idea\Java-EE\servlet-01\src\main\webapp\WEB-INF\pic2.jpg
E:\Idea\Java-EE\servlet-01\src\main\webapp\WEB-INF\pic2.jpg
E:\Idea\Java-EE\servlet-01\src\main\webapp\WEB-INF\classes\pic3.jpg
E:\Idea\Java-EE\servlet-01\src\main\webapp\WEB-INF\classes\pic3.jpg
可以看到,pic.jpg和pic2.jpg的真实路径下是存在这两张图片的,我们可以直接通过这些路径访问这两张图片资源。但是,对于respurces下面的pic3.jpg的真实路径却是错误的,因此我们不能通过这个路径来访问,pic3.jpg资源。
通常在开发时我们采用tomcat插件,在线上部署项目时则是将项目通过war包部署到tomcat服务器下,从tomcat服务器和tomcat插件部署项目的方式来看,最保险的方法就是将资源放在webapp下面,这样无论是采用哪种方式都能真正的访问所需的资源了。
4.2 采用类的加载器获取
ClassLoader类加载器在所有地方都可以使用,同样能够获得资源的真实路径。getResource方法不能获得一个虚拟路径(不存在的路径)的真实路径,如果虚拟路径对应的的真实路径不存在,那么将返回一个null。
对于tomcat服务器部署的项目,getResource默认定位到编译后的文件的WEB-INF/classes目录的真实路径,所有资源的资源可以访问。设置的参数开头均可以选择加或不加/或\\。
在参数路径中可以使用../获得classes上级目录下的资源的真实路径,可以使用\\或者/。返回的路径以 / 间隔开并且开头有/。
@WebServlet("/classLoader-servlet")
public class ClassLoaderServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
//获得类的加载器,调用getClassLoader方法
ClassLoader cl = this.getClass().getClassLoader();
{
//默认定位到classes目录
URL resource = cl.getResource("");
String path = resource.getPath();
System.out.println(path);
}
{
//如果虚拟路径对应的的真实路径不存在,那么resource为null
URL resource = cl.getResource("/pic3.jpg");
String path = resource.getPath();
System.out.println(path);
}
{
//getResource默认定位到编译后的文件的classes目录的真实路径下。
//对于tomcat插件启动的项目,编译后的文件没有webapp目录,因此默认情况下,webapp下的资源不能访问。
//这里需要通过../定位到classes的上级,然后在从上级进入到webapp下面
URL resource = cl.getResource("../pic2.jpg");
String path = resource.getPath();
System.out.println(path);
}
{
URL resource = cl.getResource("../../pic.jpg");
String path = resource.getPath();
System.out.println(path);
}
}
}
对于tomcat插件启动的项目,getResource默认定位到编译后的文件的target下的classes目录,并且编译后的文件没有webapp目录以及下面的文件,因此webapp下的资源不能访问,设置的参数虚拟路径开头不能添加/,也不可以使用../定位到上级目录。
4.3 通过class对象获取
可以获得所有资源的真实路径,返回的路径以 / 间隔开,并且开头有/。该方法不能获得一个虚拟路径(不存在的路径)的真实路径。
对于tomcat服务器部署的方式,默认定位到WEB-INF 下的classes目录。可以直接通过文件名获得包路径最里层的文件(java是class文件)真实路径,但开头不能加/,也可以通过相对路径方式获得所有资源的真实路径,但是开头必须加/,后面的路径格式可以使用\\或者/。可以通过../访问上级路径。
@WebServlet("/class-servlet")
public class ClassServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
//通过class对象,调用getResource方法,默认定位到classes目录
//通过资源名可以直接获得classes下最里层的资源的真实路径,不能加/,即不加/只对类路径最里层资源有效
URL resource = getClass().getResource("AntServlet.class");
String path2 = resource.getPath();
System.out.println(path2);
//通过相对路径获得最底层的资源的真实路径,但是开头必须加/
URL resource2 = getClass().getResource("/com/example/servlet_01/AntServlet.class");
String path4 = resource2.getPath();
System.out.println(path4);
//获得classes下的直接资源真实路径,虽然位于classes直接目录下.但开头还是必须加/
URL resource1 = getClass().getResource("/pic3.jpg");
String path3 = resource1.getPath();
System.out.println(path3);
//通过../ 获得相对classes上层的资源的真实路径,开头必须加/
URL resource3 = getClass().getResource("/../pic2.jpg");
String path6 = resource3.getPath();
System.out.println(path6);
}
}
对于tomcat插件部署的方式,默认定位到target下的classes目录,因此只能访问resources和源码路径下的资源。webapp下的资源不可访问,也不能使用../定位到上级资源。可以直接通过文件名获得包路径最里层的文件(java是class文件)真实路径,但开头不能加/,也可以通过相对路径方式获得所有资源的真实路径,但是开头必须加/,后面的路径格式可以使用\或者/。
5 获取所有相对路径
获得指定目录下的所有直接资源的相对路径。
ServletContext.getResourcePaths方法可以获取WebRoot(Web应用目录)下的指定目录下所有直接资源,该指定参数目录必须是相对于WebRoot的路径。例如:/WEB-INF/classes等,获得直接资源路径也是相对WebRoot的路径,通过此路径结合ServletContext.getRealPath("")即可求出资源绝对路径。
注意参数路径必须使用/开头,后面的路径可以使用\\或者/分隔。返回的路径以/隔开,开头有/。
@WebServlet("/paths-servlet")
public class PathsServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
ServletContext servletContext = getServletContext();
{
//默认目录
Set<String> resourcePaths = servletContext.getResourcePaths("/");
System.out.println(resourcePaths);
}
{
Set<String> resourcePaths = servletContext.getResourcePaths("/WEB-INF");
System.out.println(resourcePaths);
}
}
}
结果如下:
[/META-INF/, /default.html, /index.jsp, /WEB-INF/, /pic.jpg]
[/WEB-INF/pic2.jpg, /WEB-INF/classes/, /WEB-INF/web.xml]
6 获得资源流
ServletContext不只可以获取资源的路径,还可以直接获取资源流,即把资源以输入流的方式获取,随后我们可以操作资源流中的数据,比如响应给客户端。
通过getResourceAsStream(String path)即可获取资源对应的资源流,将会以inputstream 对象的形式返回位于指定路径上的资源。如果指定路径上不存在任何资源, 则返回null。同样path也可以不以/开头,默认定位到Web应用根目录。
@WebServlet("/pic-servlet")
public class PicServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
ServletContext servletContext = getServletContext();
//获取资源流
InputStream resourceAsStream = servletContext.getResourceAsStream("WEB-INF/pic2.jpg");
//InputStream resourceAsStream = servletContext.getResourceAsStream("pic.jpg");
//InputStream resourceAsStream = servletContext.getResourceAsStream("WEB-INF/classes/pic3.jpg");
int available = resourceAsStream.available();
System.out.println(available);
byte[] bytes = new byte[available];
resourceAsStream.read(bytes);
resp.setContentType("image/jpeg");
ServletOutputStream outputStream = resp.getOutputStream();
outputStream.write(bytes);
outputStream.close();
}
}
同样,通过类加载器和class也可以获取资源流,默认定位到Web应用下的WEB-INF/classes目录和target/classes目录。
如有需要交流,或者文章有误,请直接留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhbgajka
-
photoshop蒙版画笔没反应怎么办
PHP中文网 06-24 -
微信小程序没声音怎么办
PHP中文网 06-15 -
excel图片置于文字下方的方法
PHP中文网 06-27 -
微信提示登录环境异常是什么意思原因
PHP中文网 04-09 -
微信运动停用后别人还能看到步数吗
PHP中文网 07-22 -
使用云服务器搭建个人游戏加速器教程
AuroraJay 07-06 -
微信人名旁边有个图标有什么用
PHP中文网 03-11 -
Excel筛选和排序是灰色的怎么办
PHP中文网 06-22 -
抖音国际版要用什么加速器能流畅刷Tiktok的加速器
TK小达人 08-02 -
键盘上的负数是哪个键
PHP中文网 03-17