This is the 19th day of my participation in the August More Text Challenge

The concept of ServletContext was introduced in detail, as well as some common ways to use it.

Javax.mail. Servlet. ServletContext as context object abstraction, on behalf of the current Web application. A project has only one ServletContext object, which is shared by all servlet files within the project. We can retrieve this unique object in more than N Servlet files and use it to pass data to many different Servlet files!

The ServletContext object is created when the Web server is started and destroyed when the Web server is shut down.

1 get ServletContext

Typically, there are four ways to get Servlet objects

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {

    /* Get the ServletContext object */

    // Method 1: the method provided by ServletConfig
    ServletContext sc1 = getServletConfig().getServletContext();

    // Method two: the method provided by ServletRequest
    ServletContext sc2 = req.getServletContext();
    System.out.println(sc1 == sc2);

    // Method two: methods provided by GenericServlet
    ServletContext sc3 = getServletContext();
    System.out.println(sc2 == sc3);

    // Method three: methods provided by the Session object
    ServletContext sc4 = req.getSession().getServletContext();
    System.out.println(sc3 == sc4);
}
Copy the code

2 is used as a domain object

A domain object can be understood as a storage space (a Map collection) created by the server in memory to store data. Different domain objects have different scopes. The scope of a ServletContext is the entire Web application. Therefore, ServletContext is primarily used as a domain object to transfer and share data between different dynamic resources (servlets).

Data stored in a domain is stored in key-value format. Key is a String and value is an Object.

2.1 Domain object methods

Any domain object, there are the following four methods of manipulating data, Servlet can use the domain object HttpServletRequest, HttpSession, ServletContext, and JSP can use a domain object pageContext.

methods describe
void setAttribute(String name, Object object) Binds the object to the given property name in this domain object. If the name specified is already used for an attribute, this method replaces the old attribute with the value of the new attribute.
Object getAttribute(String name) Returns a value object containing the attribute value with the given name key, or null if no attribute matching the given name exists.
void removeAttribute(String name) Deletes the property with the given name from this domain object. After deletion, subsequent calls to getAttrit (java.lang.string) to retrieve the value of the property will return NULL. If the domain property specified by the parameter name does not exist, this method does nothing.
Enumeration getAttributeNames(a) Returns an enumeration containing the names of properties available in this domain object. If not, an empty enumeration is returned.

Tomcat stores domain properties and values in the ServletContext object at startup, usually mime labels and JAR packages, so the ServletContext is not empty.

2.2 Domain Object Exercise: Traffic statistics

@WebServlet("/PV-servlet")
public class PVServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // Get the domain object
        ServletContext sc = getServletContext();
        // Get the count attribute value
        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("You are the first." + num + "A visitor"); out.flush(); out.close(); }}Copy the code

3 Global initialization parameters

Each Servlet instance corresponds to an instance of ServletConfig, which captures the parameters of a single Servlet configured through init-param. All servlets share a ServletContext instance, from which all servlets can obtain the global configuration parameters of the entire Web application.

Under the < web-app/> tag in web.xml, you can configure the current application-level initialization parameters directly with the < context-param/> tag. The application-level initialization parameters are accessible in any servlet:

<! -- Configure the application level initialization parameters, accessed via the ServletContext call -->
<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>
Copy the code

There are two methods to get global initialization parameters from ServletContext:

The method name describe
String getInitParameter(String name) Gets the value corresponding to the initialization parameter name. If the name does not exist, null is returned.
Enumeration<java.lang.String> getInitParameterNames(a) Gets an enumeration type that is the name of all initialization parameters. Or returns an empty enumeration with no initialization parameters.

4 Obtain the actual path of the resource

Idea + Maven JavaWeb project, Java source files in the Java directory; General resource files, such as Properties, are in the Resources directory, and other resources, such as HTML, CSS, and JS, are in the WebApp directory.

4.1 Using ServletContext

The getRealPath(String Path) method of ServletContext can obtain the path of the resource, which has its own default location directory, and the Java Web project of Maven based on Idea is deployed using local Tomcat and Tomcat plug-in deployment. The default directories are different, and even for traditional SSM projects, the tomcat plug-in is basically used to start and debug projects in the development environment.

The getRealPath(String Path) method uses the default real path to get the real path corresponding to the given virtual path (which may or may not exist). Using.. in virtual paths / is not valid, you can use \\ or/interval. Returns the real path of the given virtual path, separated by \, without \ at the beginning. Note that the resource for the “real” path returned may not exist, or this method returns NULL if the servlet container is unable to convert the given virtual path to a real path.

The project structure is as follows:

There are three image resources under Resources, WebApp and WEB-INF.

4.1.1 Idea+ Local Tomcat

Idea+ local Tomcat was first used to start the project. The directory structure of the project was as follows after compilation:

As you can see, resources are placed under classes by default, so they are compiled in the same home directory as the Java source code. At the same time, the outermost layer of the Servlet directory is similar to the Web application root directory. The file name after the war package can be changed using the finalName tag in POM.xml.

In fact, for Idea + local Tomcat deployment projects, the getRealPath method of ServletContext will default to the absolute location of the compiled Servlet directory, the Web application root directory, which is equivalent to publishing the WAR package to Tomcat for deployment. We write a program to try to output path information:

@WebServlet("/resources-servlet")
public class ResourcesServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        ServletContext servletContext = getServletContext();
        {
            // Default directory
            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); }}}Copy the code

After running, the output directory is as follows:

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
Copy the code

If deployed under Webapps as a WAR package, the default location is the root directory of the published Web application. In fact, the Web application structure after the DEPLOYMENT of the WAR package looks like this:

Now we can access the three image resources directly through these real paths. This is the benefit of using ServletContext to access resources. We don’t need to know the absolute location of the resource, just its relative position after compilation!

4.4.1 Idea + tomcat plug-in

We then used the Idea+ Tomcat plug-in to start the project, which is the most common way to start a painful Java Web project. The directory structure of the project after compilation is as follows:

As you can see, there is no Servlet directory generation, no resources under WebApp and no WEB-INF directory, and it is a far cry from a traditional Tomcat server deployment.

In fact, the getRealPath method of the ServletContext will default to the absolute location of the webApp directory below SRC. We run the above program to try to output the path information:

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
Copy the code

As can be seen, pic.jpg and pic2.jpg exist in the real path of these two images, we can directly access these two image resources through these paths. However, the actual path to pic3.jpg under respurces is incorrect, so we cannot access the pic3.jpg resource through this path.

Generally, tomcat plug-in is used in development, and the project is deployed to the Tomcat server through WAR package when deploying the project online. From the perspective of the deployment mode of Tomcat server and Tomcat plug-in, the safest method is to put resources under WebApp. Either way, you can actually access the resources you need.

4.2 Class loader is used to obtain

The ClassLoader is available everywhere and can also get the real path of the resource. The getResource method cannot obtain the real path of a virtual path (a nonexistent path), and returns null if the real path corresponding to the virtual path does not exist.

For projects deployed on the Tomcat server, getResource defaults to the real path of the compiled file’s WEB-INF/classes directory, where all resources are accessible. Parameters can be set with or without/or \\ at the beginning.

In parameter paths you can use.. / to get the real path to the resource in the classes parent directory, use \\ or /. The return path is separated by/and begins with /.

@WebServlet("/classLoader-servlet")
public class ClassLoaderServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // Get the class loader and call the getClassLoader method
        ClassLoader cl = this.getClass().getClassLoader();

        {
            // Locate the classes directory by default
            URL resource = cl.getResource("");
            String path = resource.getPath();
            System.out.println(path);
        }
        {
            // If the real path corresponding to the virtual path does not exist, then resource is null
            URL resource = cl.getResource("/pic3.jpg");
            String path = resource.getPath();
            System.out.println(path);
        }
        {
            //getResource defaults to the real path of the classes directory of the compiled file.
            // For projects started by the Tomcat plug-in, compiled files do not have a webApp directory, so by default, resources under WebApp cannot be accessed.
            // We need to pass... / navigate to the classes parent, and then go below webApp from the parent
            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); }}}Copy the code

For projects started by the Tomcat plugin, getResource is located to the classes directory of the compiled file by default, and the compiled file does not have the webApp directory and the following files. Therefore, resources under webApp cannot be accessed, and the parameter virtual path cannot start with /. You may not use… / Locate the upper-level directory.

4.3 Obtaining the value from the Class Object

The true path of all resources can be obtained, and the return path is separated by/and begins with /. This method cannot obtain the real path of a virtual path (a path that does not exist).

For tomcat server deployment, the default location is the classes directory under web-INF. You can directly obtain the real path of the innermost file (Java class file) through the file name, but cannot start with a /. You can also obtain the real path of all resources through the relative path, but must start with a /. The following path format can be \\ or /. Can be accessed through.. / Access the upper-level path.

@WebServlet("/class-servlet")
public class ClassServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // Through the class object, call the getResource method to locate the classes directory by default

        // The resource name can be used directly to obtain the real path of the resource at the innermost layer of classes
        URL resource = getClass().getResource("AntServlet.class");
        String path2 = resource.getPath();
        System.out.println(path2);
        // Get the real path of the lowest level resource through the relative path, but must start with a /
        URL resource2 = getClass().getResource("/com/example/servlet_01/AntServlet.class");
        String path4 = resource2.getPath();
        System.out.println(path4);

        // Get the real path of the direct resource under classes, although it is in the direct directory of classes. But you still have to start with a slash
        URL resource1 = getClass().getResource("/pic3.jpg");
        String path3 = resource1.getPath();
        System.out.println(path3);

        / / by.. / To get the real path to the resource relative to classes, you must start with a /
        URL resource3 = getClass().getResource("/.. /pic2.jpg"); String path6 = resource3.getPath(); System.out.println(path6); }}Copy the code

For the way tomcat plug-ins are deployed, the default location is the classes directory under Target, so only resources under the source path can be accessed. Resources under WebApp are inaccessible and cannot be used.. / Locate the upper-layer resource. You can directly obtain the real path of the innermost file (Java class file) through the file name, but cannot start with a /. You can also obtain the real path of all resources through the relative path, but must start with a /. The following path format can be \ or /.

5 Obtain all relative paths

Gets the relative paths of all direct resources in the specified directory.

ServletContext. GetResourcePaths method can obtain WebRoot (Web application directory) under the specified directory of all resources, directly to the specified parameters must be relative to the WebRoot directory path. For example: / WEB – INF/classes, etc., and direct the path of the resource path is also relatively WebRoot, combining the ServletContext. Through this path getRealPath (” “) to find the absolute path to the resource.

Note that the parameter path must start with a /, and subsequent paths can be separated by \\ or /. The returned paths are separated by a slash, starting with a slash.

@WebServlet("/paths-servlet")
public class PathsServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        ServletContext servletContext = getServletContext();
        {
            // Default directory
            Set<String> resourcePaths = servletContext.getResourcePaths("/");
            System.out.println(resourcePaths);
        }
        {
            Set<String> resourcePaths = servletContext.getResourcePaths("/WEB-INF"); System.out.println(resourcePaths); }}}Copy the code

The results are as follows:

[/META-INF/, /default.html, /index.jsp, /WEB-INF/, /pic.jpg]
[/WEB-INF/pic2.jpg, /WEB-INF/classes/, /WEB-INF/web.xml]
Copy the code

6 Obtain the resource flow

ServletContext not only fetches the path to the resource, but also fetches the resource flow directly, that is, fetches the resource as an input stream, and then we can manipulate the data in the resource flow, such as responding to the client.

GetResourceAsStream (String Path) is used to obtain the corresponding resource stream, which will return the resource on the specified path as an InputStream object. If no resource exists on the specified path, null is returned. The path can also be located to the root directory of the Web application without starting with a slash (/).

@WebServlet("/pic-servlet")
public class PicServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        ServletContext servletContext = getServletContext();

        // Get the resource flow
        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(); }}Copy the code

Similarly, resource flows can also be obtained through class loaders and classes, which by default are located in the WEB-INF/classes and target/classes directories of Web applications.

If you need to communicate, or the article is wrong, please leave a message directly. In addition, I hope to like, collect, pay attention to, I will continue to update a variety of Java learning blog!