• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

ServletContext上下文环境对象的以和使用案例

武飞扬头像
刘Java
帮助1

详细介绍了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
系列文章
更多 icon
同类精品
更多 icon
继续加载