Java EE Tutorials - Our First Servlet

In this post, we will look at how to write an incredibly simple Java web application with a single Servlet.

A few ground rules before we start. The code for this and future examples will be stored on Github. Here’s the link to the code used today:

https://github.com/taidan19/java-servlet-tutorial

If you aren’t using git, you can download the code as a ZIP file here

You can build and run the example with either Maven or Gradle, so take your pick. Whichever you choose, the example is configured to run in an embedded instance of the Jetty web server. Just type mvn jetty:run (in Maven) or gradle jettyRun in Gradle (hit Ctrl+C to shut the server down). With the server running, access localhost:8080/basic to see the web app. in action.

Let’s look at the structure of our source code:

java-servlet-tutorial/
    src/
        main/
            java/
                ...
            resources/
            webapp/
                WEB-INF/
                    web.xml

Pretty simple, all things considered. Both Maven an Gradle are smart enough to know how to bundle this project structure into a WAR file. Everything in src/main/java/ and src/main/resources will be placed into the WEB-INF/classes folder in the WAR. Any Maven or Gradle dependencies are placed in WEB-INF/lib. The src/main/webapp folder is where we store static web content, as well as the WEB-INF folder (with corresponding web.xml file). These will be placed at the root of the web app, like we discussed in the previous post.

Now for the code. There’s only one Java file, named BasicServlet.java. This is all it contains:

package net.cmw;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * Basic example of a Java Servlet.
 */
public class BasicServlet extends HttpServlet {

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

        /*
         * We can add HTTP Header values to the Response
         */
        resp.addHeader("Content-Type", "text/plain");

        /*
         * The response object contains a PrintWriter, which we can use to add content to the response body.
         */
        PrintWriter writer = resp.getWriter();
        writer.print("This is a test string");
    }
}

This is all we need to write to create a barely functional Java Servlet. You will notice that our class extends HttpServlet. This is an abstract class which serves as the foundation for pretty much any Servlet you might write or use. We only override one method in the abstract class - doGet. This method is called whenever a client sends an HTTP GET request to our Servlet. As you might imagine, there are similar methods named doPost, doPut, and doDelete which map to the other HTTP verbs. You only have to override the methods you intend to use. If your webapp only intends to respond to GETs, for example, you only need to concern yourself with doGet.

The method has two parameters - an object representing the incoming request, and one which represents the outgoing response. It may seem strange that the method does not return the response object, but that’s what we have to work with. Both objects allow you to read and write HTTP header values respectively; they also respectively contain a Reader and Writer object for working with the body of the request/response. These tools are as primitive as it gets, but they’re also flexible enough to let us do everything we need. In our example, we simply stick a simple message into the response, which will be displayed in our web browser when we access the web app. We also set the Content-Type header, to let clients know the MIME type that we’re returning.

Now that we’ve seen the code, let’s take a gander at the web.xml file. This particular example is about as simple as it gets:

<?xml version="1.0" encoding="UTF-8"?>
<web-app 
  version="3.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns="http://java.sun.com/xml/ns/javaee" 
  xsi:schemaLocation="
      http://java.sun.com/xml/ns/javaee
      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

  <display-name>
      Basic Servlet Example
  </display-name>

  <servlet>
    <servlet-name>Example Servlet</servlet-name>
    <servlet-class>
        net.cmw.BasicServlet
    </servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>Example Servlet</servlet-name>
    <url-pattern>/basic</url-pattern>
  </servlet-mapping>

</web-app>

In the <servlet> section, we have to specify two properties. The first is the fully qualified name of our Servlet class, The second is a Servlet name, which is what we will use to reference the Servlet in other sections of the file. We can see an example of this in the <servlet-mapping> section. Here, we map our Servle to a specific URL. The URL mapping is always relative to where the web application is deployed. If we packed up our app. as “testapp.war” and deployed it in a server, our servlet would be accessed at localhost:8080/testapp/basic. Since Jetty simply deploys it to the server’s root folder, the URL for our particular example is simply localhost:8080/basic.

There is far, far more we can do with Servlets, but we’ll stop here for now. Hopefully you can imagine what other tasks you might accomplish with the material we’ve already covered.