1. Introduction of problems

When we were first introduced to servlets, our development looked something like this:

  • To write a user login, let’s create a new oneLoginServlet.
  • To write a user registration function, let’s create a new oneSignUpServlet.
  • To write a user update, let’s create a new oneUserUpdateServlet.
  • To write a user delete function, let’s create a new oneUserDeleteServlet.
  • In order to…

Haha, this is still a simple User, but obviously two-digit entity classes are normal on normal projects.

Do we need to create N servlets for each entity class operation as above? Wouldn’t it take dozens of servlets to develop functionality…

Next, this article will solve this puzzle for you


2. How does the Servlet respond to our request?

Before we discuss how to solve this problem, let’s take a look at how the Servlet responds to the request we make.

Here is a standard Servlet that we access by making a GET or POST request

But, have you ever wondered why our GET/POST request can call the corresponding doGet/doPost method?


So, let’s find out!

First let’s take a look at the structure diagram of the LoginServlet we just created

From the figure, you can see the inheritance relationship of servlets. The Servlet interface is on the top layer, and GenericServlet implements the servlet interface.

Let’s take a look at the top servlet interface and focus on the service method. Okay

/ / servlet interface

public interface Servlet {

    // The initialization method used when the servlet is created

    void init(ServletConfig var1) throws ServletException;



    ServletConfig getServletConfig(a);



    // Called by the servlet container to allow the servlet to respond to a request.

    Called by the Servlet container to allow the Servlet to respond to requests.

    void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;



    String getServletInfo(a);



    void destroy(a);

}

Copy the code

Thus, we know that the Service method in the Servlet interface is used to respond to requests.

However, an interface just defines a set of specifications, and we’ll have to see what the implementation is.

So let’s move on to GenericServlet that implements the servlet interface.

However, when we clicked on the source code of GenericServlet, we found that it was an abstract class that enriched some methods on top of the servlet.

At the same time, the service method is an abstract method, which we suspect is implemented by its subclass HttpServlet

public abstract class GenericServlet implements Servlet.ServletConfig.Serializable {

    // It's a long one.

    public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

}

Copy the code


So let’s move on to the HttpServlet that inherits GenericServlet.

We see that the Service method is implemented here!


Ha, ha, ha, ha, ha, ha, ha.

Well, let’s check it out.

We can see that there are a lot of if judgments in there.

The doGet method is called below if (method.equals(“GET”)), as is the Post method.

// HttpServlet

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    // Get the request type, such as Post, Get, and so on

    String method = req.getMethod();

    long lastModified;

    // if GET

    if (method.equals("GET")) {

        lastModified = this.getLastModified(req);

        if (lastModified == -1L) {

            / / call doGet

            this.doGet(req, resp);

        } else {

            long ifModifiedSince;

            try {

                ifModifiedSince = req.getDateHeader("If-Modified-Since");

            } catch (IllegalArgumentException var9) {

                ifModifiedSince = -1L;

            }



            if (ifModifiedSince < lastModified / 1000L * 1000L) {

                this.maybeSetLastModified(resp, lastModified);

                this.doGet(req, resp);

            } else {

                resp.setStatus(304);

            }

        }

    } else if (method.equals("HEAD")) {

        lastModified = this.getLastModified(req);

        this.maybeSetLastModified(resp, lastModified);

        this.doHead(req, resp);

        // If it is Post

    } else if (method.equals("POST")) {

        / / call the doPost

        this.doPost(req, resp);

    } else if (method.equals("PUT")) {

        this.doPut(req, resp);

    } else if (method.equals("DELETE")) {

        this.doDelete(req, resp);

    } else if (method.equals("OPTIONS")) {

        this.doOptions(req, resp);

    } else if (method.equals("TRACE")) {

        this.doTrace(req, resp);

    } else {

        String errMsg = lStrings.getString("http.method_not_implemented");

        Object[] errArgs = new Object[]{method};

        errMsg = MessageFormat.format(errMsg, errArgs);

        resp.sendError(501, errMsg);

    }



}

Copy the code


At this point, we have a rough idea of how the Servlet responds to the request we make.

Summary: If our servlet does not override the service method, then the servlet will call the service method implemented by httpServlet in response to the request. Depending on the type of request, different methods are invoked.


3. Preparation of BaseServlet

Next, the core of this article is BaseServlet!!

Ideas:

  1. Write aBaseServletinheritanceHttpServletAnd overwrite itserviceMethods.
  2. Using the reflection mechanism, completeA single ServletThe multi-purpose.
  3. Let’s be normalBusiness ServletGo to inheritBaseServlet
  4. Normal use (described below)

Let’s talk about it in code, and it’ll make it a little bit easier.


3.0 How to use it first

Here is a brief introduction to how to use

  1. First of all,@WebSerlvetwritten/xxxx/In the form of ', this'/'Match all
  2. Write your own methods
  3. The front-end sends the URL written similarly(omitted)/UserServlet/xxOk, this onexxIs the name of a self-written method.

Ha ha, isn’t it very easy and quick to use!

And, most importantly, we were able to write multiple methods instead of just one per Servlet, which fulfilled our goal of modularity!


But don’t worry, let’s get to the most importantBaseServletThe writing of


3.1 Compilation of BaseServlet

In a word, BaseServlet uses reflection to accomplish the above functions.


We want to manage the idea of specific operation, the best code.

  1. First, we need to know what method the front end wants us to invoke, such as login or registration.

    A: With the /xx/* in the @webServlet annotation, we can specify /xx/login if we need to call a login method, and login (the method name) is the key we use to identify which method to call.

  2. Gets the name of the called method, so what if we call this method?

    A: Get the method by reflection and call it.


Complete code and parsing:

public class BaseServlet extends HttpServlet {

    // Override the service method

    @Override

    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {



        / / 1. Access the URL or URI can be here, URI: / lemonfish/UserServlet/login URL: http://localhost/lemonfish/UserServlet/login

        String requestURI = req.getRequestURI();

        // 2. Get the index of the last '/'

        int beginIndex = requestURI.lastIndexOf("/");

        // 3. Use substring to obtain the method name

        String methodName = requestURI.substring(beginIndex + 1);

        try {

            / * * *

* Remember who called the "service" method, this is who,

* Because the UserServlet we wrote ourselves inherits from BaseServlet

* Therefore, the service method also belongs to the UserServlet

* The front end accesses the UserServlet

* Thus this is an object of the UserServlet

             * 

* 4. Here we use reflection to get the method of the UserServlet based on the method name and the class type of the method parameter.

             * 

* If you don't understand these two lines of code, you can review reflection first.

* * * /


            Method method = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);



            // 5. Call this method with this.

            method.invoke(this, req, resp);

        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {

            e.printStackTrace();

        }

    }

}

Copy the code


4, BaseServlet example demonstration

4.1 Write a BaseServlet

As above


4.2 Write a UserServlet and inherit from BaseServlet

The UserServlet has two methods: login and signUp


4.3 Starting Tomcat and accessing UserServlet

We start tomcat and enter http://localhost/lemonfish/UserServlet/login in the address bar (according to their own port and route adjustment, here I here port is 80, And the applicationContext is Lemonfish), press Enter.

So what’s the output from the console?

Knock knock knock!!

So Log In was printed, which means we’re halfway there.

But wait, let’s try the signUp method again

Ha ha, now we can rest assured!

We successfully used BaseServlet to access a Servlet while using multiple methods.

In this way, we can write the corresponding xxxServlet according to our business requirements at the time of development.


4.4 Handling Forwarding Pits

Remember to add/oh when writing forward paths. This will append directly to the root path

If written as hello.jsp, it is appended to the current path (under UserServlet),

The service method will then look under the UserServlet for a method named hello.jsp and get an error!

request.getRequestDispatcher("/hello.jsp").forward(request, response);

Copy the code


5. DEMO source address

For your convenience, I decided to upload the demo source directly to Github

Just one item for a smooth reading and one item for a Star(●’◡’).


I used to use the code cloud a lot, but I think I’ll be using Github more recently.


6. Write at the end

Encapsulating a BaseServlet made a big difference to our development efficiency, especially before we touched the framework.

One item: ‘plus-one item’

If you think it is helpful, please click 👍b( ̄▽ ̄)d is the best thing