This is the 18th day of my participation in the August Challenge

The concept of Java Servlet as well as the development method and details are introduced in detail.

Basics of Servlet learning:Network based.Java Web.

Servlet is a small program that runs on the server side that implements the Java Servlet specification. JavaWeb is one of the three components of JavaWeb (Servlet, listener-listener, filter-filter). It is a dynamic resource that can dynamically return different responses according to the requested information.

In addition, Servlet learning is the foundation of our in-depth study of the Spring MVC framework!

@[toc]

1 Overview of Servlet interface

The Javax.serlvet.Servlet interface is the top-level interface in the Servlet specification. This interface defines methods to initialize servlets, service requests, and remove servlets from the server. These methods are called the lifecycle methods of servlets, and they are called in a certain order.

In addition to the lifecycle methods, this interface provides the getServletConfig method, which servlets can use to obtain their own configuration information, and the getServetInfo method, which allows the Serverlet to return basic information about itself, such as author, version, and copyright.

To implement a Servlet interface, you must implement the following five API methods:

public interface Servlet {

    /** * The servlet container calls init once the servlet is instantiated. Only after the method completes (without throwing an exception) can the servlet receive any requests. * *@paramConfig contains the ServletConfig object for the configuration and initialization parameters of the servlet. * /
    public void init(ServletConfig config) throws ServletException;


    /** * Returns a ServletConfig object that contains the initialization and startup parameters for this servlet. The ServletConfig object returned is the parameter object passed to the init method. * The implementation of this interface is responsible for storing the ServletConfig object so that this method can return it, which is already done by the GenericServlet class that implements this interface. * *@returnThe ServletConfig object that helps initialize the servlet. * /
    public ServletConfig getServletConfig(a);


    /** * is called by the servlet container (Web server) to allow servlets to process and respond to requests. This method can only be called after the init() method of the servlet completes successfully. * *@paramReq contains the ServletRequest object * requested by the client@paramThe res contains the ServletResponse object */ for the servlet response
    public void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException;


    /** * returns information about the servlet, such as author, version, and copyright. * The string returned by this method is plain text, not any kind of markup language (HTML, XML, etc.). * *@returnReturns the information string */ about the servlet

    public String getServletInfo(a);


    /** * called by the Servlet (Web server) container to indicate that the servlet is being deactivated. * This method is called when the server is normally shut down, giving the servlet a chance to clean up any resources it is holding (for example, memory, file handles, threads) * After the servlet container calls this method, it will no longer call the Service method on this servlet. * /
    public void destroy(a);
}
Copy the code

The above method is actually fairly straightforward. These Servlet instances and methods are called by the Servlet container (the Web server), so our project doesn’t need any main methods, nor does it need to create any Servlet instances.

Three related classes appear in the Servlet interface:

  1. ServletConfig, as a configuration object for the Servlet;
  2. ServletRequest, which represents the object encapsulated by the request;
  3. ServletResponse, which represents the object encapsulated in the response;

None of these objects need to be created either. They are created by the Servlet container (such as the Tomcat server) and passed in by the Web server at runtime. We can use them directly in our methods, as we’ll see later!

2 Servlet lifecycle and request processing logic

  1. The Web server receives the HTTP request and forwards it to the servlet container, which finds the corresponding servlet according to the request path.
  2. If a servlet instance is not already created, a servlet instance is created, and the servlet container then initializes the servlet by calling the servlet’s init() method (which is called only when the servlet is first loaded). The created servlet instances are retained in the container and can be handled when subsequent requests come in, without needing to be recreated or initialized.
  3. The servlet container will parse the incoming HTTP Request, create a Request object, and create a Response Response object. The servlet instance’s Service method is called to pass these two objects as parameters, expecting the business logic in the service method to process the HTTP Request. So the Service method is the one we’re going to focus on.
  4. Our business logic will encapsulate the returned result into the Response object provided by the Servlet container. After the execution of the service method, the Web server will return the dynamically generated result saved in the Response object to the client browser.
  5. If the Servlet instance is destroyed, the destory method is executed by the Servlet container. Servlet destruction is usually done when the server is shut down, and destory is used to free resources!

3. Development of Servlet

When we develop servlets, we need to implement them. Generally speaking, there are three ways to implement this:

  1. Directly implement javax.servlet.Servlet interface.
  2. Inheritance javax.mail. Servlet. GenericServlet abstract classes.
  3. Inheritance javax.mail. Servlet. HTTP. HttpServlet abstract classes.

3.1 Simple Servlet implementation

Let’s briefly implement servlets through the Servlet interface.

Let’s create a new Java Web project:

Maven depends on the following, using the Tomcat plug-in:


      
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>servlet-01</artifactId>
    <version>1.0 the SNAPSHOT</version>
    <name>servlet-01</name>
    <packaging>war</packaging>

    <properties>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
        <junit.version>5.7.0</junit.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>Servlet</finalName>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.tomcat.maven</groupId>
                    <artifactId>tomcat7-maven-plugin</artifactId>
                    <version>2.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.0</version>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>
            <! -- Tomcat plugin control -->
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <configuration>
                    <! -- Port control -->
                    <port>8080</port>
                    <! - project path control means http://localhost:8080/servlet-01-- >
                    <path>/servlet-01</path>
                    <! - - - >
                    <uriEncoding>UTF-8</uriEncoding>
                </configuration>
            </plugin>
            <! Maven plugin control -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>utf-8</encoding>
                </configuration>
            </plugin>

        </plugins>
    </build>
</project>
Copy the code

Develop your first Servlet:

@WebServlet("/first-servlet")
public class FirstServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) {
        System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- --");
        System.out.println("servletConfig: " + servletConfig);
        System.out.println("init");
    }

    @Override
    public ServletConfig getServletConfig(a) {
        System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- --");
        System.out.println("getServletConfig");
        return null;
    }

    /** * The main method we developed **@paramServletRequest request object *@paramServletResponse Response object */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException {
        // Get the requested data
        String message = servletRequest.getParameter("xx");
        // Encapsulate response data
        servletResponse.setContentType("text/html");

        // Hello
        PrintWriter out = servletResponse.getWriter();
        out.println("<html><body>");
        out.println("<h1>" + message + "</h1>");
        out.println("</body></html>");
    }

    @Override
    public String getServletInfo(a) {
        System.out.println("getServletInfo");
        return null;
    }

    @Override
    public void destroy(a) {
        System.out.println("destroy"); }}Copy the code

To run the servlet successfully, you also need to configure the path of the servlet. Here, we use the @webServlet (“/first-servlet”) annotation provided beginning with Servlet 3.0 to configure the path of the servlet. Of course, you could also use web.xml to configure it, but that’s a bit of a hassle! The path must start with a slash and is relative to the current application root directory.

If you are configuring web.xml, you can configure it as follows:

<! Registered - - - >
<servlet>
    <! Internal name of servlet -->
    <servlet-name>firstServlt</servlet-name>
    <! Servlet class full path name -->
    <servlet-class>com.example.servlet_01.FirstServlet</servlet-class>
</servlet>
<! - map -- -- >
<servlet-mapping>
    <! The inner name of the servlet is case insensitive.
    <servlet-name>firstServlt</servlet-name>
    <! Request servlet mapping path -->
    <url-pattern>/first-servlet</url-pattern>
</servlet-mapping>
Copy the code

Will be deployed in tomcat server program, enter http://localhost:8080/servlet-01/first-servlet in your browser, by this time the server will find servlet first – 01 engineering under web. XML, Then find the mapping path /first-servlet of this request, find annotation 1 according to the mapping /first-servlet, then find the mapping internal name of the same servlet annotation 2, and find the internal name of the servlet according to the mapping internal name annotation 3. Finally, it finds the concrete class name of the servlet of the same class, annotation 4. The server then executes the methods of the class that defines the Servlt based on reflection and begins the servlet life cycle…

Start the tomcat plug-in, visit http://localhost:8080/servlet-01/first-servlet? Xx =11, you can find the servlet initialization information:

You can see the parameters passed in the page:

With the request parameters, the response parameters are also changing:

This is the dynamic Web application based on servlets. At the same time, we found that the console did not output any information that the servlet was initialized, indicating that the servlet was initialized only once.

It is important to note that the Tomcat plugin-based Web application does not output destory information when it is closed directly. Using the local Tomcat test, you can see the destroyed information:

3.2 inheritance GenericServlet

Java. Servlet. GenericServlet write servlet class make easier. It provides methods that implement the Servlet interface and from the ServletConfig interface (except for the Service method). The GenericServlet class also implements the log() method, which is defined in the ServletContext interface and has its own init() and log() methods.

Since GenericServlet is an abstract class, to extend the class, you must implement all of the class’s abstract methods. But instead of implementing all the methods of the Servlet interface, it only needs to implement one service to inherit the class. Moreover, other methods of the Servlet interface (such as initialization or destruction methods) are rarely used in real development, so it is more convenient to inherit GenericServlet.

It is more convenient to write your own servlets that extend genericServlets directly than to implement the servlet interface.

Here is a Servlet implementation that inherits GenericServlet:

@WebServlet("/generic-servlet")
public class MyGenericServlet extends GenericServlet {

    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        // Get the requested data
        String message = req.getParameter("xx");
        // Encapsulate response data
        res.setContentType("text/html");

        // Hello
        PrintWriter out = res.getWriter();
        out.println("<html><body>");
        out.println("<h1>" + message + "</h1>");
        out.println("</body></html>"); }}Copy the code

Start the tomcat plug-in, visit http://localhost:8080/servlet-01/generic-servlet? Xx =generic, which is perfectly fine:

3.3 inheritance HttpServlet

In fact, GenericServlet, as a general-purpose Servlet implementation, only provides basic functions, but it is still inconvenient in some cases. For example, our Web applications are basically HTTP based requests, so it is necessary to create a specific HTTP Servlet. Such as processing requests, getting request headers and so on.

Java has provided us such a Servlet implementation, that is javax.mail. Servlet. HTTP. HttpServlet. HTTP requests include DELETE, GET, OPTIONS, POST, PUT, and TRACE. The corresponding service methods are provided in the HttpServlet class: doDelete(), doGet(), doOptions(), doPost(), doPut(), and doTrace().

HttpServlet inherits GenericServlet, which implements the Servlet interface. So you can inherit HttpServlet to create a Servlet specific to HTTP requests.

When creating a Servlet by inheriting HttpServlet, we simply override doGet() for GET requests and doPost() for POST requests, depending on the type of request to handle. No other methods are needed. Easier to develop servlets!

@WebServlet("/http-servlet")
public class MyHttpServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // Get the requested data
        String message = req.getParameter("xx");
        // Encapsulate response data
        resp.setContentType("text/html");
        // Hello
        PrintWriter out = resp.getWriter();
        out.println("<html><body>");
        out.println("<h1>" + message + "</h1>");
        out.println("</body></html>"); }}Copy the code

Start the tomcat plug-in, visit http://localhost:8080/servlet-01/http-servlet? Xx = http-servlet, the result is as follows, absolutely no problem:

3.3.1 Design of HttpServlet

The HttpServlet class provides the service (it, HttpServletResponse) method, this method is a method that the HttpServlet own not inherited from the Servlet.

In HttpServlet rewrite the parent class of service (ServletRequest, ServletResponse) method will reduce the ServletRequest and ServletResponse HttpSe into it and strongly RvletResponse, then call service (it, HttpServletResponse) method, This shows subclasses can go to cover the service (it, HttpServletResponse) method, this wouldn’t have to turn the request and response object.

public abstract class HttpServlet extends GenericServlet {
// Override the service method
    @Override
    public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException {
        HttpServletRequest  request;
        HttpServletResponse response;
        try {
            request = (HttpServletRequest) req;
            response = (HttpServletResponse) res;
        } catch (ClassCastException e) {
            throw new ServletException("non-HTTP request or response");
        }
       // The above part is to install the forced transformation of two objects
       // The following is to call its own service method
        service(request, response);
}
    // its own service method, which determines the HTTP request and selects the corresponding method to call, such as doGet for GET request and doPost for POST request.
protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {... }}Copy the code

Actually the subclass also don’t have to cover the service (it, HttpServletResponse) method, simplified operation because the HttpServlet need to make another step. In the HttpServlet service (it, HttpServletResponse) method to judge the current request is a GET or POST, if is a GET request, then go to call the class doGet () method, The doPost() method is called if it is a POST request, which means we only need to override the doGet() or doPost() methods in the subclass.

In fact, the template method pattern is used here, where the Service method defines the algorithmic skeleton of the request processing, and the specific processing methods are implemented by subclasses.

As you can see from these details, the purpose of HttpServlets is to make it easier to do Web development based on HTTP requests, freeing developers to focus more on business logic rather than Web request parsing.

4 Servlet details

4.1 Servlets and Singletons

Servlets are singletons; in a Web container, they are the same Servlet until the server is shut down. Simultaneous requests are handled by the same servlet! This has the advantage of reducing object creation and improving performance, but we need to be aware of thread-safety issues when developing servlets and try not to define stateful global variables.

4.2 Multiple Mapping Paths

A Servlet can bind multiple mapping paths through which requests are sent to the Servlet.

For web. XML, you can configure multiple servlet-mapping. Their servlet-names are consistent, but their URL-patterns are inconsistent.

<! Registered - - - >
<servlet>
    <! Internal name of servlet -->
    <servlet-name>firstServlt</servlet-name>
    <! Servlet class full path name -->
    <servlet-class>com.example.servlet_01.FirstServlet</servlet-class>
</servlet>
<! - map -- -- >
<servlet-mapping>
    <! The inner name of the servlet is case insensitive.
    <servlet-name>firstServlt</servlet-name>
    <! Request servlet mapping path -->
    <url-pattern>/first-servlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <! The inner name of the servlet is case insensitive.
    <servlet-name>firstServlt</servlet-name>
    <! Request servlet mapping path -->
    <url-pattern>/first-servlet2</url-pattern>
</servlet-mapping>
Copy the code

Or configure multiple URl-patterns in a servlet-mapping:

<servlet-mapping>
    <! The inner name of the servlet is case insensitive.
    <servlet-name>firstServlt</servlet-name>
    <! Request servlet mapping path -->
    <url-pattern>/first-servlet3</url-pattern>
    <url-pattern>/first-servlet4</url-pattern>
    <url-pattern>/first-servlet5</url-pattern>
</servlet-mapping>
Copy the code

The @webServlet annotation is even simpler, and the value of the annotation is an array of i-strings, so we just pass an array of multiple path addresses:

@WebServlet({"/generic-servlet","/generic-servlet2","/generic-servlet3"})
Copy the code

4.3 Mapping path Wildcards

Servlet mapping paths can use the wildcard “*”, which can match any string:

  1. If the path is/ *End, matches all paths with the specified prefix path (highest priority)! If the path is/ *, it will block all requests, including access to direct static resources, JSP files.
  2. If the path is*. ExtensionsIs matched with any path ending with the suffix.
  3. The two formats should not be mixed.

Servlet mapping path priority:

  1. For a specific access path, the Servlet has the highest priority if there is a Servlet mapping for that path.
  2. If not, then have”/ *The Servlet with the wildcard path ending in “has the highest priority.
  3. If not, then have”*. SuffixThe Servlet with the wildcard path ending in “has the highest priority.
  4. If it doesn’t exist, then finally it has./“Default path wildcard Servlet, also known as the default Servlet.

If “is used/ *“Wildcard Servlet, so when there is a request include, forward, redirect to other resources that do not show the specified path (e.g. forward to a JSP, static resource, etc.), then the request will remain in this Servlet./ *“The wildcard Servlet loops until an exception is thrown, because the forwarding path did not match the mapping of the specific Servlet in the first step, and then matches the wildcard Servlet itself, which then forwards again.

4.3.1 JspServlet

Access paths ending in “*.jsp” are handled by default by a JspServlet configured in the Conf /web.xml configuration file of the Tomcat container named JSP. It is defined as follows:

Its mapping is as follows:

In the following example, the path of the Servlet is “*.jsp” :

@WebServlet("*.jsp")
public class AntServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // Encapsulate response data
        resp.setContentType("text/html");
        // AntServlet
        PrintWriter out = resp.getWriter();
        out.println("<html><body>");
        out.println("<h1>" + "AntServlet" + "</h1>");
        out.println("</body></html>"); }}Copy the code

So we access to the JSP. At the end of the resources, such as http://localhost:8080/servlet-01/11/222.jsp, at this time will be forwarded to the Servlet in:

4.4 the default Servlet

All requests of Java Web applications are requests to corresponding servlets. Dynamic resources have their own paths, needless to say. For static resources, such as HTML, CSS, JS, images, etc., although the URL in the request appears to be the address of the accessed static resources, However, a default Servlet is still used to find the resource and 404 is returned if it is not found.

Like JspServlet, the default servlet is configured for us in the Tomcat container in the conf/web.xml configuration file named default. It is defined as follows:

Its mapping is as follows:

Therefore, static resource requests will be intercepted and processed by the DefaultServlet configured for us by Tomcat. In this Servlet, the static resource corresponding to the URL path of the request will be searched during the meeting, and the resource will be returned if it is found, and 404!

If you customize the mapping path to”/The Servlet will override the container’s configured DefaultServlet for us and go with the logic of our configured Servlet instead!

Let’s create a default.html under webApp:

By direct access to the URL http://localhost:8080/servlet-01/default.html:

If we configure the default Servlet:

@WebServlet("/")
public class DefaultServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // Encapsulate response data
        resp.setContentType("text/html");
        // Hello
        PrintWriter out = resp.getWriter();
        out.println("<html><body>");
        out.println("<h1>" + "The default Servlet." + "</h1>");
        out.println("</body></html>"); }}Copy the code

Again to access the static resource, http://localhost:8080/servlet-01/default.html, found that it will automatically access we configure the default Servlet:

4.5 Servlet initialization Time

Servlets by default are initialized only when the corresponding request first arrives. You can also configure some servlets to be initialized immediately when the server is started. The advantage of this is that no Servlet objects are created on the first request, which increases processing speed, but the disadvantage is that there are more objects to start the server, which may prolong server startup time.

For web.xml, add a load-on-startup subtag to the servlet tag, which indicates whether the container should load the servlet (instantiate and call its init method) as soon as the Web application starts.

<! Registered - - - >
<servlet>
    <servlet-name>firstServlt</servlet-name>
    <servlet-class>com.example.servlet_01.FirstServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>
Copy the code

The label is filled in with the startup priority:

  1. Its value must be an integer, 0 or greater, which means that the container loads and initializes the servlet when the application starts. The smaller the value, the higher the priority of the servlet and the first the application is loaded when it starts.
  2. If the value of this element is negative or not set, the container will load it when the Servlet is requested.
  3. When the values are the same, the container will load in the order it chooses.

For the @webServlet annotation, you can configure this feature in the loadOnStartup property.

5 ServletConfig

Javax.mail. Servlet. ServletConfig encapsulates the configuration of a servlet initialization information, this feature will configure information from Java file mentioned in the XML file or annotations, can be unified management configuration, more flexible, it can be seen as primitive way of configuration and code separation.

After the servlet has configured its initialization parameters, the Web container automatically wraps these initialization parameters into a ServletConfig object when it creates the servlet instance object and passes the ServletConfig object to the servlet when it calls the servlet’s init method. Furthermore, the programmer can obtain the initialization parameter information of the current Servlet from the Servlet object and customize the initialization logic.

The related API methods are as follows:

The method name describe
String getServletName(a) Get the name of the current servlet object (as configured in web.xml)
Enumeration<java.lang.String> getInitParameterNames(a) Gets an enumeration of key names for all passed key-value pairs. Returns an empty enumeration if no
String getInitParameter(String name) Retrieves the value of the key by specifying it.
ServletContext getServletContext(a) Return the ServletContext object of the project. A (running) project has only one context object.

5.1 Initialization Parameters

Under the Servlet TAB in web-INF’s web.xml file, you can add initialization parameter key-value pairs, that is, servlet-level initialization parameters.

The following Servlet:

public class InitParamServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletConfig servletConfig = getServletConfig();
        Enumeration<String> initParameterNames = servletConfig.getInitParameterNames();
        while (initParameterNames.hasMoreElements()) {
            String s = initParameterNames.nextElement();
            System.out.println("paramName: " + s);
            System.out.println("paramValue: "+ servletConfig.getInitParameter(s)); }}}Copy the code

In the Servlet tag of web.xml, you can configure some initialization parameters for a Servlet with one or more < init-param/> tags.

<servlet>
    <servlet-name>InitParamServlet</servlet-name>
    <servlet-class>com.example.servlet_01.InitParamServlet</servlet-class>
    <! Pass initialization parameters to the current servlet -- key-value pairs -->
    <init-param>
        <param-name>username</param-name>
        <param-value>lisi</param-value>
    </init-param>
    <init-param>
        <param-name>age</param-name>
        <param-value>22</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>InitParamServlet</servlet-name>
    <url-pattern>/initParam-servlet</url-pattern>
</servlet-mapping>
Copy the code

Run the tomcat plug-in, visit http://localhost:8080/servlet-01/initParam-servlet, can see the output in the console parameter information:

You can also configure the current Servlet initialization information with the initParams property in @webServlet:

@WebServlet(value = "/initParam-servlet", initParams = {@WebInitParam(name = "username", value = "zhangsan"), @WebInitParam(name = "age", value = "11")})
Copy the code

6 summarizes

In this article we briefly introduce the early Servlet development methods, the most common is the HttpServlet inheritance method, but after using the framework, even the Servlet “see”, so this article is basically not needed, but if you want to understand the principle of the framework, Like Spring MVC, you still need to know something about the original Servlet API.

We will continue to delve into the original Serlet API and related knowledge, such as Session, Cookie technology, HttpServletResponse, HttpServletRequest, and asynchronous request processing. Stay tuned!

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!