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.