Servlet

Hi there, todaly let's talk about Servlet in a nutshell.

A Servlet is a Java programming language class, which is executed in Web Server and responsible for dynamic content generation in a portable way.

Servlet extends the capabilities of servers that host applications accessed by means of a request-response programming model.

This blog talks about several topics, shown below:

mindmap
    root(Servlet)
        Life Cycle
        Configuration
        Request and Response
        Cookies and Sessions
        Event Listener and Filter

But first, let's talk about the hierarchy of Servlet:

The javax.servlet and javax.servlet.http packages provide interfaces and classes for writing servlets.

javax.servlet is a generic interface, and the javax.servlet.http.HttpServlet is an extension of that interface – adding HTTP specific support – such as doGet and doPost.

When it comes to writing a Servlet, we usually choose to extend HttpServlet and override doGet and doPost.

Life Cycle

The web container maintains the life cycle of a servlet instance

  1. Load

    when the first request is received, Web Container loads the servlet class and initialize an instance

  2. Initialize

    The web container then creates one single servlet instance, to handle all incoming requests on that servlet, even there are concurrent requests.

  3. init()

    The web container calls the init() method only once after creating the servlet instance, to initialize the servlet.

  4. service()

    For every request, servlet creates a separate thread to execute service()

  5. destoy()

    The web container asks servlet to release all the resources associated with it, before removing the servlet instance from the service.

A typical Servlet demo:

snippet of web.xml:

 1<?xml version="1.0" encoding="UTF-8"?>
 2<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3    xmlns="http://java.sun.com/xml/ns/javaee"
 4    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
 5    id="WebApp_ID" version="3.0">
 6     
 7    <servlet>
 8      <servlet-name>ServletLifecycle</servlet-name>
 9      <servlet-class>ServletLifecycleExample</servlet-class>
10    </servlet>
11 
12    <servlet-mapping>
13      <servlet-name>ServletLifecycle</servlet-name>
14      <url-pattern>/</url-pattern>
15    </servlet-mapping>
16</web-app>

snippet of index.jsp:

 1<%@ page language="java" 
 2    contentType="text/html; charset=ISO-8859-1"
 3    pageEncoding="ISO-8859-1"%>
 4<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 5<html>
 6<head>
 7    <title>Servlet Lifecycle Example</title>
 8</head>
 9<body>
10  <form action="ServletLifecycle" method="post">
11      <input type="submit" value="Make request" />
12  </form>
13</body>
14</html>

snippet of ServletLifecycleExample.java:

 1import java.io.IOException;
 2import java.io.PrintWriter;
 3 
 4import javax.servlet.GenericServlet;
 5import javax.servlet.ServletException;
 6import javax.servlet.ServletRequest;
 7import javax.servlet.ServletResponse;
 8 
 9public class ServletLifecycleExample extends GenericServlet {
10     
11    @Override
12    public void init() {
13        System.out.println("Servlet Initialized!");
14    }
15 
16    @Override
17    public void service(ServletRequest request, ServletResponse response)
18            throws ServletException, IOException {
19        response.setContentType("text/html");
20        PrintWriter out = response.getWriter();
21        out.println("Servlet called from jsp page!");
22    }
23     
24    @Override
25    public void destroy() {
26    }
27}

Servlet life time shown in the sequence chart below:

sequenceDiagram
    participant Browser
    participant Server
    participant Servlet
    autonumber
    Browser->>Server: Connect to the server
    Browser->>Server: HTTP GET
    Server->>Server:  Resolve
    Server->>Servlet: Load Servlet and create obj for first access
    Server->>Servlet: invoke `init()`
    Server->>Servlet: invoke `service()`
    Servlet->>Servlet: Execute `service()` and generate Response
    Servlet-->>Server: Response
    Server-->>Browser: Response

Configuration

Tomcat

Tomcat is a servlet container, which is a runtime shell that manages and invokes servlets on behalf of users.

Tomcat has the following directory structure:

Directory Description
bin startup/shutdown... scripts
conf configuration files including server.xml (Tomcat's global configuration file) and web.xml(sets the default values for web applications deployed in Tomcat)
doc documents regarding Tomcat
lib various jar files that are used by Tomcat
logs log files
src servlet APIs source files, and these are only the empty interfaces and abstract classes that should be implemented by any servlet container
webapps sample web applications
work intermediate files, automatically generated by Tomcat
classes to add additional classes to Tomcat's classpath

Note:

  1. The single most important directory is webapps, where we can manually add our Servlet into it, e.g., if we want to create a servlet named HelloServlet, the first thing we do is to create the directory /webapps/HelloServlet.

  2. The default port for Tomcat is 8080, and if we want to switch the port to 80, we just need to modify /conf/server.xml:

    1 <Connector port="80" protocol="HTTP/1.1"
    2         connectionTimeout="20000"
    3         redirectPort="8443" />
    

web.xml

To deploy servlets and map URLs to the servlets, we have to modify the web.xml file, a deployment descriptor, like this:

 1<web-app>
 2	<servlet>
 3		<servlet-name>servletName</servlet-name>
 4		<servlet-class>servletClass</servlet-class>
 5	</servlet>
 6	<servlet-mapping>
 7		<servlet-name>servletName</servlet-name>
 8		<url-pattern>*.*</url-pattern>
 9	</servlet-mapping> 
10</web-app>  

When a request comes, it is matched with URL pattern in servlet mapping attribute.

When URL matched with URL pattern, Web Server try to find the servlet name in servlet attributes, same as in servlet mapping attribute.

When match found, control goes to the associated servlet class.

ServletConfig

ServletConfig, a servlet configuration object used by a servlet container to pass information to a servlet during initialization.

<init-param> attribute is used to define a init parameter, which refers to the initialization parameters of a servlet or filter. <init-param> attribute has 2 main sub attributes: <param-name> and <param-value>. The <param-name> contains the name of the parameter and <param-value> contains the value of the parameter.

Example:

snippet of web.xml:

1<init-param>
2    <param-name>appUser</param-name>
3    <param-value>jai</param-value>
4</init-param>

snippet of InitParamExample.java:

1ServletConfig config = getServletConfig();
2String appUser = config.getInitParameter("appUser");

This example shows how to read web.xml, and get init parameters "appUser": "jai" for initialization.

ServletContext

ServletContext defines a set of methods that a servlet will use to communicate with its servlet container, to share initial parameters or configuration information to the whole application.

<context-param> attribute is used to define a context parameter, which refers to the initialization parameters for all servlets of an application. <context-param> attribute also has 2 main sub attributes: <param-name> and <param-value>. And also, the <param-name> contains the name of the parameter, the <param-value> contains the value of the parameter.

Example:

snippet of web.xml:

1<context-param>
2    <param-name>appUser</param-name>  
3    <param-value>jai</param-value>  
4</context-param>

snippet of ContextParamExample.java:

1ServletContext context = this.getServletContext();
2String value = (String) context.getAttribute("appUser");

This example shows how to read web.xml, and get context parameters "appUser": "jai" for communication.

load-on-startup

The load-on-startup is the sub attribute of servlet attribute in web.xml. It is used to control when the web server loads the servlet.

As we discussed that servlet is loaded at the time of first request. In this case, response time is increased for first request.

If load-on-startup is specified for a servlet in web.xml, then this servlet will be loaded when the server starts. So the response time will NOT increase for fist request.

Example:

 1<servlet>  
 2    <servlet-name>servlet1</servlet-name>  
 3    <servlet-class>com.w3spoint.business.Servlet1 </servlet-class>
 4    <load-on-startup>0</load-on-startup>  
 5</servlet>  
 6
 7<servlet>  
 8    <servlet-name>servlet2</servlet-name>  
 9    <servlet-class> com.w3spoint.business.Servlet2</servlet-class>
10    <load-on-startup>1</load-on-startup>  
11</servlet>    
12
13<servlet>  
14    <servlet-name>servlet3</servlet-name>  
15    <servlet-class> com.w3spoint.business.Servlet3</servlet-class>
16    <load-on-startup>-1</load-on-startup>  
17</servlet>  

In the example above, Servlet1 and Servlet2 will be loaded when server starts because non-negative value is passed in there load-on-startup. While Servlet3 will be loaded at the time of first request because negative value is passed in there load-on-startup.

Request and Response

There is a method named service() in package javax.servlet, as is mentioned in the 'Life Cycle' section, it has a prototype like this:

1void service(ServletRequest request,
2             ServletResponse response)
3      throws ServletException,
4             IOException

where request is the ServletRequest object that contains the client's request, and response is the ServletResponse object that contains the servlet's response

ServletRequest

ServletRequest defines an object to provide client request information to a servlet.

The servlet container creates a ServletRequest object and passes it as an argument to the servlet's service() method. A ServletRequest object provides data including parameter name and values, attributes, and an input stream.

To transfer data to other component, we can use getAttribute(), setAttribute() of ServletRequest, example code:

 1@WebServlet(name = "LoginServlet", urlPatterns = {"/login.do"})
 2public class LoginServlet extends HttpServlet {
 3    public void doPost(HttpServletRequest  request, 
 4                       HttpServletResponse response)
 5                throws ServletException, IOException {
 6        String  username = request.getParameter("username");
 7        String  password = request.getParameter("password");
 8        if (username.equals("admin") && 
 9            password.equals("5F4DCC3B5AA765D61D8327DEB882CF99")) {
10            // Logged in
11            RequestDispatcher  rd = 
12                    request.getRequestDispatcher("/welcome.jsp");
13            //   to store `username` in request object
14            request.setAttribute("user", username);
15            rd.forward(request, response);
16        } else {
17            // Failed to log in
18            RequestDispatcher  rd = 
19                    request.getRequestDispatcher("/login.jsp");
20            rd.forward(request, response);
21        }
22
23    }
24}

HttpServletRequest

HttpServletRequest interface adds the methods that relates to the HTTP protocol.

classDiagram
    class ServletRequest {
        +getAttribute()
        +getParameter()
    }
    class HttpServletRequest {
        +getMethod()
        +getSession()
    }
    ServletRequest <|-- HttpServletRequest: extends

(Note: could not display <<interface>> for both classes, due to error of Mermaid version 9.4.3 , maybe the Mermaid-js team will fix this issue later)

The servlet container creates an HttpServletRequest object and passes it as an argument to the servlet's service() methods (doGet(), doPost(), etc).

Demo of HttpServletRequest:

snippet of index.html:

1<form method="post" action="check">
2    Name <input type="text" name="user" >
3    <input type="submit" value="submit">
4</form>

snippet of web.xml:

1<servlet>
2    <servlet-name>check</servlet-name>
3    <servlet-class>MyHttpServletRequestServlet</servlet-class>
4</servlet>
5<servlet-mapping>
6    <servlet-name>check</servlet-name>
7    <url-pattern>/check</url-pattern>
8</servlet-mapping>

snippet of MyHttpServletRequestServlet.java:

 1import java.io.*;
 2import javax.servlet.*;
 3import javax.servlet.http.*;
 4
 5public class MyHttpServletRequestServlet extends HttpServlet {
 6
 7  protected void doPost(HttpServletRequest request, 
 8                        HttpServletResponse response)
 9                throws ServletException, IOException {
10       response.setContentType("text/html;charset=UTF-8");
11        PrintWriter out = response.getWriter();
12        try {
13            String user = request.getParameter("user");
14            out.println("<h2> Welcome "+user+"</h2>");
15        } finally {            
16            out.close();
17        }
18    }
19}

RequestDispatcher

RequestDispatcher defines an object that receives requests from the client and sends them to any resource (such as a servlet, HTML file, or JSP file) on the server.

The servlet container creates the RequestDispatcher object, which is used as a wrapper around a server resource located at a particular path or given by a particular name.

Methods of RequestDispacher interface:

1public void forward(ServletRequest request,
2                    ServletResponse response)
3            throws ServletException, IOException
4
5public void include(ServletRequest request,
6                    ServletResponse response)
7            throws ServletException, IOException

To get an object of RequestDispacher:

RequestDispacher object can be gets from HttpServletRequest object.

ServletRequest’s getRequestDispatcher() method is used to get RequestDispatcher object.

Example:

 1protected void doPost(HttpServletRequest request, 
 2                      HttpServletResponse response) 
 3                throws ServletException, IOException {
 4    response.setContentType("text/html"); 
 5    PrintWriter out = response.getWriter();
 6
 7    //get parameters from request object.
 8    String userName = 
 9        request.getParameter("userName").trim();
10    String password = 
11        request.getParameter("password").trim();
12
13    //check for null and empty values.
14    if(userName == null || userName.equals("") 
15            || password == null || password.equals("")){
16        out.print("Please enter both username" +
17                " and password. <br/><br/>");
18        RequestDispatcher requestDispatcher = 
19            request.getRequestDispatcher("/login.html");
20        requestDispatcher.include(request, response);
21    }//Check for valid username and password.
22    else if(userName.equals("jai") && 
23            password.equals("1234")){
24        RequestDispatcher requestDispatcher = 
25            request.getRequestDispatcher("WelcomeServlet");
26        requestDispatcher.forward(request, response);
27    }else{
28        out.print("Wrong username or password. <br/><br/>");
29        RequestDispatcher requestDispatcher = 
30            request.getRequestDispatcher("/login.html");
31        requestDispatcher.include(request, response);
32    }
33}

In brief:

 1// 1. use `requestDispatcher.include()`:
 2//      if invalid `userName` or `password` inputed,
 3//          return to 'login.html' and retry
 4RequestDispatcher requestDispatcher = 
 5    			request.getRequestDispatcher("/login.html");
 6requestDispatcher.include(request, response);
 7
 8// 2. use `requestDispatcher.forward()`:
 9//      if correct `userName` and `password` inputed,
10//          return to 'Welcome Servlet'
11RequestDispatcher requestDispatcher = 
12    			request.getRequestDispatcher("WelcomeServlet");
13requestDispatcher.forward(request, response);

ServletResponse

ServletResponse defines an object to assist a servlet in sending a response to the client.

The servlet container creates a ServletResponse object and passes it as an argument to the servlet's service() method. To send binary data in a MIME body response, use the ServletOutputStream returned by getOutputStream(). To send character data, use the PrintWriter object returned by getWriter(). To mix binary and text data, for example, to create a multipart response, use a ServletOutputStream and manage the character sections manually.

HttpServletResponse

HttpServletResponse extends the ServletResponse interface to provide HTTP-specific functionality in sending a response. For example, it has methods to access HTTP headers and cookies.

The servlet container creates an HttpServletResponse object and passes it as an argument to the servlet's service() methods (doGet(), doPost(), etc).

Cookies and Sessions

There are 2 mechanisms which allow us to store user data between subsequent requests to the server – the cookie and the session

A cookie is a small piece of information as a text file stored on client’s machine by a web application.

The servlet sends cookies to the browser by using the HttpServletResponse.addCookie(javax.servlet.http.Cookie) method, which adds fields to HTTP response headers to send cookies to the browser, one at a time. The browser is expected to support 20 cookies for each Web server, 300 cookies total, and may limit cookie size to 4 KB each.

The browser returns cookies to the servlet by adding fields to HTTP request headers. Cookies can be retrieved from a request by using the HttpServletRequest.getCookies() method. Several cookies might have the same name but different path attributes.

There are 2 types of cookies:

  1. Session cookies (Non-persistent cookies) They are accessible as long as session is open, and they are lost when session is closed by exiting from the web application.

  2. Permanent cookies(Persistent cookies) They are still alive when session is closed by exiting from the web application, and they are lost when they expire.

Example:

 1//create cookie object  
 2Cookie cookie=new Cookie(cookieName,cookieValue);
 3response.addCookie(cookie);
 4
 5//get all cookie objects.
 6Cookie[] cookies = request.getCookies();
 7for(Cookie cookie : cookies){
 8    out.println(Cookie Name:  + cookie.getName());
 9    out.println(Cookie Value:  + cookie.getValue());
10}
11
12//Remove value from cookie
13Cookie cookie = new Cookie(cookieName, “”);
14cookie.setMaxAge(0);
15response.addCookie(cookie);

HttpSession

HttpSession is an interface that provides a way to identify a user in multiple page requests. A unique session id is given to the user when first request comes. This id is stored in a request parameter or in a cookie.

Example:

1HttpSession session = request.getSession();
2session.setAttribute("attName", "attValue");
3String value = (String) session.getAttribute("attName"); 

Filter and Event Listener

In web applications, we use filters to preprocess and postprocess the parameters. And during runtime of web apps, we use event listeners to do callback stuff.

Filter

A filter is an object that is invoked at the preprocessing and postprocessing of a request on the server.

Servlet filters are mainly used for following tasks:

  1. Preprocessing

    Preprocessing of request before it accesses any resource at server side.

  2. Postprocessing

    Postprocessing of response before it sent back to client.

flowchart TD
    Client <--> Listener[Web<br/>Listener]
    Listener <--> Container[Servlet Container]
    Container --> |Request| Filter1 --> Filter2 --> FilterN --> Servlet
    Servlet --> |Response| FilterN --> Filter2 --> Filter1 --> Container

The order in which filters are invoked depends on the order in which they are configured in the web.xml file. The first filter in web.xml is the first one invoked during the request, and the last filter in web.xml is the first one invoked during the response. Note the reverse order during the response.

Filter API (or interface) includes some methods which help us in filtering requests:

1public void init(FilterConfig config)
2public void doFilter(HttpServletRequest request,HttpServletResponse response, FilterChain chain)
3public void destroy()

To create a filter, implement javax.servlet.Filter interface

<filter> attribute is used to define a filter in web.xml:

1<filter>
2    <filter-name>filterName </filter-name>
3    <filter-class>filterClass</filter-class>
4</filter>
5<filter-mapping>
6    <filter-name>filterName</filter-name>
7    <url-pattern>urlPattern</url-pattern>
8</filter-mapping>

FilterChain object is used to call the next filter or a resource, if it is the last filter in filter chaining.

Example:

snippet of MyFilter.java:

 1public class MyFilter implements Filter {
 2
 3	public void init(FilterConfig filterConfig) throws ServletException { }
 4
 5	@Override
 6	public void doFilter(ServletRequest request,
 7						ServletResponse response,
 8						FilterChain chain)
 9		        throws IOException, ServletException
10	{
11
12		PrintWriter out = response.getWriter();
13		System.out.println("preprocessing before servlet");
14        // pass to next filter for more check
15		chain.doFilter(request, response);
16		System.out.println("postProcessing after servlet");
17	}
18
19	public void destroy() {}
20}
21

snippet of index.html:

1<form action="MyFilterServlet">
2    <button type="submit">Click here to go to the Servlet</button>
3</form>
 1<?xml version="1.0" encoding="UTF-8"?>
 2<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3		xmlns="http://xmlns.jcp.org/xml/ns/javaee"
 4		xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
 5							http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
 6		id="WebApp_ID" version="4.0">
 7<display-name>MyFilterServlet</display-name>
 8<welcome-file-list>
 9	<welcome-file>index.html</welcome-file>
10</welcome-file-list>
11	
12<filter>
13	<filter-name>filter1</filter-name>
14	<filter-class>com.app.MyFilterServlet</filter-class>
15</filter>
16	
17<filter-mapping>
18	<filter-name>filter1</filter-name>
19	<url-pattern>/MyFilterServlet</url-pattern>
20</filter-mapping>
21	
22</web-app>
23

snippet of MyFilterServlet.java:

 1@WebServlet("/MyFilterServlet")
 2public class MyFilterServlet extends HttpServlet {
 3
 4	protected void doGet(HttpServletRequest request,
 5						HttpServletResponse response)
 6		            throws ServletException, IOException
 7	{
 8		PrintWriter out = response.getWriter();
 9		out.println("<h1>Welcome to the Servlet.");
10		System.out.println("MyFilterServlet is running");
11	}
12
13	protected void doPost(HttpServletRequest request,
14						HttpServletResponse response)
15		            throws ServletException, IOException 
16    {
17		doGet(request, response);
18	}
19}

Event Listener

Event Listener allows Servlet to track key events in your Web applications through event listeners.

This functionality allows more efficient resource management and automated processing based on event status.

flowchart TD
    Client <--> Listener[Web<br/>Listener]
    Listener <--> Container[Servlet Container]
    Container --> |Request| Servlet
    Servlet --> |Response| Container

There are 2 levels of servlet events:

  1. Servlet context-level (application-level) event

    This event involves resources or state held at the level of the application servlet context object.

  2. Session-level event

    This event involves resources or state associated with the series of requests from a single user session; that is, associated with the HTTP session object.

Listeners handling Servlet Lifecycle Events:

Object: Event Listener Interface Event Class
Web context: Initialization and destruction ServletContextListener ServletContextEvent
Web context: Attribute added, removed, or replaced ServletContextAttributeListener ServletContextAttributeEvent
Session: Creation, invalidation, activation, passivation, and timeout HttpSessionListener, HttpSessionActivationListener HttpSessionEvent
Session: Attribute added, removed, or replaced HttpSessionAttributeListener HttpSessionBindingEvent
Request: A servlet request has started being processed by web components ServletRequestListener ServletRequestEvent
Request: Attribute added, removed, or replaced ServletRequestAttributeListener ServletRequestAttributeEvent

Event classes:

Event Class Methods
ServletRequestEvent getServletContext(), getServletRequest()
ServletContextEvent getServletContext()
ServletRequestAttributeEvent getName(), getValue()
ServletContextAttributeEvent getName(), getValue()
HttpSessionEvent sessionCreated(), sessionDestroyed(), sessionWillPassivate(), sessionDidActivate()
HttpSessionBindingEvent getName(), getSession(), getValue()

Configure the Listener class in the web.xml files:

1<web-app>
2    <listener>
3        <listener-class>myListenerName</listener-class>
4    </listener>
5</web-app>

Note: Except for HttpSessionBindingListener and HttpSessionActivationListener, all Listeners require the aforementioned listener configuration.

Example Code of AppContextAttributeListener:

snippet of web.xml:

1<listener>
2    <listener-class>AppContextAttributeListener</listener-class>
3</listener>

snippet of AppContextAttributeListener.java:

 1@WebListener
 2public class AppContextAttributeListener implements ServletContextAttributeListener {
 3	public void attributeAdded(ServletContextAttributeEvent	event) {
 4		System.out.println( "ServletContext attribute added::{" event.getName() + ","+ event.getValue() + "}");
 5	}
 6
 7	public void	attributeReplaced(ServletContextAttributeEvent event) {
 8        System.out.println( "ServletContext attribute replaced::{" event.getName() + ","+ event.getValue() + "}");
 9	}
10	public void	attributeRemoved(ServletContextAttributeEvent event) {
11
12        System.out.println( "ServletContext attribute removed::{" event.getName() + ","+ event.getValue() + "}");
13	}
14}

* This blog was last updated on 2023-03-30 18:05