tutorials / java-server / servlets

Servlets

tutorial java

So far, we’ve learned how to run a Jetty server and how to set up a static web app. This tutorial walks through servlets and dynamic web apps.

Servlet Classes

A servlet is a Java class that runs certain functions when a user requests a URL from a server. These functions contain code that reacts to a user’s actions, such as saving data to a database, executing logic, and returning information needed to render a page.

To define a servlet, we create a class that extends the HttpServlet class, and we define a service handler function. We’ll talk more about those later, but for now let’s just define a doGet() function.

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

public class HelloWorldServlet extends HttpServlet {

	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
		PrintWriter out = response.getWriter();
		out.println("<h1>Hello world!</h1>");
		out.println("<p>This is our first servlet.</p>");
	}
}

This is pretty much just like any other Java class you’ve seen. It defines a HelloWorldServlet class, which extends the HttpServlet class. It overrides the doGet() function, which takes a HttpServletRequest and a HttpServletResponse as parameters. Inside the doGet() function, we get a PrintWriter from the response and we output some HTML content to it.

Save this to a file named HelloWorldServlet.java. You can put this file anywhere you want.

Just like any other Java file, we have to compile this into a .class file. The only trick is that we need to make sure the Java servlet API is on our classpath.

The Java servlet API is a library that comes with Jetty (or with any other server). It’s located in the lib folder inside our Jetty directory. For example, mine is located at C:/Users/kevin/Desktop/jetty/lib/servlet-api-3.1.jar. So to compile my HelloWorldServlet class, I would add that .jar file to my classpath using the -cp argument, like this:

javac -cp C:/Users/kevin/Desktop/jetty/lib/servlet-api-3.1.jar HelloWorldServlet.java

This should create a HelloWorldServlet.class file.

The web.xml File

Even though HelloWorldServlet is a normal Java class, it doesn’t have a main() function, so how do we run it? The answer is we don’t! Instead, we need to tell our server to run it for us when a user requests a certain URL from it. To do that, save this XML into a file named web.xml:

<web-app>

	<servlet>
		<servlet-name>MyHelloWorldServlet</servlet-name>
		<servlet-class>HelloWorldServlet</servlet-class>
	</servlet>

	<servlet-mapping>
		<servlet-name>MyHelloWorldServlet</servlet-name>
		<url-pattern>/index.html</url-pattern>
	</servlet-mapping>

</web-app>

This might look confusing at first, but let’s take it one step at a time:

So, this web.xml file tells our server that when a user requests the index.html URL, it should trigger our HelloWorldServlet class.

Dynamic Web App Directory Structure

Now that we have our HelloWorldServlet.class and web.xml files, we can bundle them up into a web app. To do that, we need to put together a specific set of directories inside Jetty’s webapp folder.

First, we need to create a directory that contains our webapp: let’s name it HelloWorldWebApp. Inside that directory, create another directory named WEB-INF. Inside that directory, put the web.xml file, and one more directory named classes. Inside the classes directory, put the HelloWorldServlet.class file. Copy the whole HelloWorldWebApp directory inside Jetty’s webapps folder.

In other words, our directory structure should look like this:

Now our web app is setup, so run the Jetty server and open a web browser to http://localhost:8080/HelloWorldWebApp/index.html, and you should see this:

hello world servlet

Let’s take a closer look at the URL and examine what our server does with each part:

Back in our HelloWorldServlet class, the server calls the doGet() function (because the request is asking to get the index.html file). The out.println() statements in our doGet() function allow us to build HTML that is then sent back to the client. Try viewing the source of the index.html page. To the client, it’s the exact same thing as a regular index.html file, but the server generated it using Java code instead of reading it from a file!

WEB-INF

An important thing to note about the WEB-INF directory is that everything inside it is invisible to the user. In other words, users can’t get to it by going to a URL like http://localhost:8080/HelloWorldWebApp/WEB-INF/web.xml. Even if you put .html files in here, the user can’t get to them!

This is a good thing. You usually don’t want the user to know exactly what your server is doing. You just want them to see the final output.

Query Parameters

So far, we’ve been mapping a single URL to a servlet. But we can make more advanced requests.

For example, we can read query parameters in our servlet and use them in our Java code. We do this using the request.getParameter() function, like this:

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

public class HelloWorldServlet extends HttpServlet {

	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {

		String name = request.getParameter("name");
		
		PrintWriter out = response.getWriter();
		out.println("<h1>Hello " + name + "</h1>");
		out.println("<p>Nice to meet you!</p>");
	}
}

This servlet uses the request.getParameter() function to get the name parameter, and it uses that to output a greeting in HTML. Make this change to your servlet and then visit http://localhost:8080/HelloWorldWebApp/index.html?name=Kevin to see this:

hello world servlet

Try changing the query parameter to see different names!

URL Paths

Remember that the <url-patten> tag inside web.xml file defines a URL to map to a servlet class. For example, this XML maps the index.html URL to our servlet:

	<servlet-mapping>
		<servlet-name>MyHelloWorldServlet</servlet-name>
		<url-pattern>/index.html</url-pattern>
	</servlet-mapping>

In addition to single URLs, we can also use the asterisk * wildcard symbol to map multiple URLs to the same servlet. Here’s an example:

<web-app>

	<servlet>
		<servlet-name>MyHelloWorldServlet</servlet-name>
		<servlet-class>HelloWorldServlet</servlet-class>
	</servlet>

	<servlet-mapping>
		<servlet-name>MyHelloWorldServlet</servlet-name>
		<url-pattern>/hello/*</url-pattern>
	</servlet-mapping>

</web-app>

This XML maps any URL that starts with /hello/ to our servlet. So any of these URLs would trigger our servlet:

This allows us to generate different content depending on the URL. In our servlet, we can use the request.getRequestURI() function, which gives us the URL after the domain (the http://localhost:8080 part).

So if we visit http://localhost:8080/HelloWorldWebApp/hello/Kevin, we can get the /HelloWorldWebApp/hello/Kevin part using the request.getRequestURI() function. Then to get the Kevin part, we can use the substring() function. Putting it all together, it looks like this:

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

public class HelloWorldServlet extends HttpServlet {

	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {

		String requestUrl = request.getRequestURI();
		String name = requestUrl.substring("/HelloWorldWebApp/hello/".length());

		PrintWriter out = response.getWriter();
		out.println("<h1>Hello " + name + "</h1>");
		out.println("<p>Nice to meet you!</p>");
	}
}

Compile this class and move it into the classes directory inside our web app. Then visit http://localhost:8080/HelloWorldWebApp/hello/Kevin and you should see this:

hello world servlet

Now try going to different URLs to change the greeting. Imagine doing this with static files!

Multiple Servlets

So far, all of our web apps have contained a single servlet. But we aren’t limited to just using one servlet at a time. Our web app can contain multiple servlets!

Let’s add another servlet to our web app by creating another class that extends the HttpServlet class:

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

public class DateServlet extends HttpServlet {

	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {

		Date now = new Date();

		PrintWriter out = response.getWriter();
		out.println("<p>Current time: " + now.toString() + "</p>");
	}
}

Then we compile that using this command:

javac -cp C:/Users/kevin/Desktop/jetty/lib/servlet-api-3.1.jar HelloWorldServlet.java

We copy that into the classes folder of our web app directory, and we add it to our web.xml file:

<web-app>

	<servlet>
		<servlet-name>MyHelloWorldServlet</servlet-name>
		<servlet-class>HelloWorldServlet</servlet-class>
	</servlet>

	<servlet>
		<servlet-name>MyDateServlet</servlet-name>
		<servlet-class>DateServlet</servlet-class>
	</servlet>
	
	<servlet-mapping>
		<servlet-name>MyHelloWorldServlet</servlet-name>
		<url-pattern>/hello/*</url-pattern>
	</servlet-mapping>
	
	<servlet-mapping>
		<servlet-name>MyDateServlet</servlet-name>
		<url-pattern>/date.html</url-pattern>
	</servlet-mapping>

</web-app>

Now our web.xml file contains the definition and URL mapping for two <servlet> tags: one for our HelloWorldServlet, and another one for the new DateServlet.

Now open a browser to http://localhost:8080/HelloWorldWebApp/date.html, and you should see this:

hello world servlet

You can also still visit URLs like http://localhost:8080/HelloWorldWebApp/hello/Felicia to activate the other servlet.

Splitting your web app into multiple servlets isn’t an exact science, but most web apps will consist of multiple servlets.

Mixing Static and Dynamic Content

In the Jetty setup tutorial, we learned how to serve static files from our server. And this tutorial showed you how to create dynamic files using a servlet class. But it’s not an either-or thing: you can serve both static files and dynamic pages from the same server!

For example, let’s add this static index.html page to our web app:

<!DOCTYPE html>
<html>
	<head>
		<title>My Web App</title>
	</head>
	<body>
		<h1>Welcome to my web app!</h1>
		<p>Here are some names in the greeting servlet:</p>
		<ul>
			<li><a href="http://localhost:8080/HelloWorldWebApp/hello/Ada">Ada<a></li>
			<li><a href="http://localhost:8080/HelloWorldWebApp/hello/Grace">Grace<a></li>
			<li><a href="http://localhost:8080/HelloWorldWebApp/hello/Hal">Hal<a></li>		
		</ul>
		<p><a href="http://localhost:8080/HelloWorldWebApp/date.html">Here</a> is the current time servlet.</p>
	</body>
</html>

Save this to a file named index.html inside the HelloWorldWebApp directory (but not inside the WEB-INF folder!), so your whole directory structure looks like this:

Now open a browser to http://localhost:8080/HelloWorldWebApp/index.html, and you should see this:

static page in dynamic web app

This new index.html file is a static page that links to our dynamic servlets. This approach of mixing static and dynamic content is useful when you have some sites that should always be the same (like a homepage or an about page), but other pages that should change (like user profiles or data fetched from a database). It’s also useful for storing stuff like CSS files and images, which you can use in your HTML.

Outputting HTML

Note that in the examples above, our servlets didn’t output a full HTML page. I did this mostly to keep them shorter, but note you would still want to output a full HTML page. That might look like this:

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

public class MyServlet extends HttpServlet {

	@Override
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
		PrintWriter out = response.getWriter();
		out.println("<!DOCTYPE html>");
		out.println("<html>");
		out.println("<head>");
		out.println("<title>My Web App</title>");
		out.println("</head>");
		out.println("<body>");
		out.println("<h1>My Web App</h1>");
		out.println("<p>The current time is: " + new Date().toString() + "</p>");
		out.println("</body>");
		out.println("</html>");
	}
}

This code is just showing you an example of outputting a full HTML page to the client. It’s pretty unwieldy though, so we’ll learn better ways to do that in the next tutorial.