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 one
LoginServlet
. - To write a user registration function, let’s create a new one
SignUpServlet
. - To write a user update, let’s create a new one
UserUpdateServlet
. - To write a user delete function, let’s create a new one
UserDeleteServlet
. - 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:
- Write a
BaseServlet
inheritanceHttpServlet
And overwrite itservice
Methods. - Using the reflection mechanism, complete
A single Servlet
The multi-purpose. - Let’s be normal
Business Servlet
Go to inheritBaseServlet
- 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
- First of all,
@WebSerlvet
written/xxxx/In the form of ', this'/'
Match all - Write your own methods
- The front-end sends the URL written similarly
(omitted)/UserServlet/xx
Ok, this onexx
Is 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 importantBaseServlet
The 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.
-
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.
-
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