Skip to main content

This guide aims to walk you through the process of building a simple Servlet application using Jakarta Servlet. We’ll start by outlining what we aim to achieve and then step-by-step guide you through setting up your environment, writing code, and deploying the Servlet application. If you’re new to Servlets or Jakarta EE, this guide should be a great starting point.

We’ll develop an application that accomplishes the following:

  • Presents a form asking the user to select their coffee preferences (e.g., black, latte, cold brew).
  • Stores these preferences in a session.
  • Dynamically generates a “Coffee Dashboard,” displaying personalized coffee recommendations.

OK, now that we have specified our requirements, you will need to follow these steps:

Set up your development environment:

  • Install a Java Development Kit (JDK). Please make sure you have Java SE 11 or higher (we have tested with Java SE 11 and Java SE 17). You can choose any vendor distribution of your choice as well as from Adoptium.
  • Install an application server that supports Jakarta EE. Download any of the Jakarta EE-compatible products.
  • Install Maven 3 or higher

To install JDK and Maven, we can use the SDKMan. We can go through the steps mentioned in the how-to guide.

How to complete this guide

In this getting started guide, you may use Eclipse Starter for Jakarta EE, finish each step, or skip fundamental setup stages you already know. You can also begin with an IDE or choose a project structure from well-known Maven archetypes.

Create a new project with Eclipse Starter for Jakarta EE

To use Eclipse Starter for Jakarta EE, we need to take the following steps:

  1. Navigate to https://start.jakarta.ee. This service will set up all the essential dependencies for an application. The current version of the Starter only supports Maven. In the future, we may be able to choose between Gradle and Maven.
    A screenshot of the form from start.jakarta.ee to generate a Jakarta EE project.
  2. Select the desired version of Jakarta EE from the available options. Currently, the options include Jakarta EE 8, Jakarta EE 9.1, and Jakarta EE 10. In addition, you may choose the Jakarta EE Platform or one of the Jakarta EE profiles (Web, Core).
  3. For this project, we have chosen Jakarta EE 10 Platform, Java SE 17 and WildFly as a Runtime.
  4. Once we have selected our desired options, we will click the generate button. This will give us the project structure and sample code, which we can then build and run.

Let’s explore the code structure

When we unpack the generated code, we will have the structure of an application. We can open it in our favourite IDE, and then we can just run it from the command line.

.
├── README.md
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
    └── main
        ├── java
        │   └── org
        │       └── eclipse
        │           └── jakarta
        │               └── hello
        │                   ├── Hello.java
        │                   └── HelloWorldResource.java
        └── webapp
            ├── WEB-INF
            │   └── web.xml
            ├── images
            │   └── jakartaee_logo.jpg
            └── index.html

This generated source code comes with an embedded Maven wrapper. So if you want to use it, make sure you run the following command first for Unix environments (Linux or Mac):

$ chmod +x mvnw

Since we are using WildFly as a runtime, the following command would run the application:

$ ./mvnw clean package wildfly:run

On the other hand, if you have Maven installed, you can run the following command:

$ mvn clean package wildfly:run

For Windows, we don’t need to run chmod command; rather use mvnw.cmd instead of mvnw.

Now, if you hit the browser with the following URL, you will see the result.
http://localhost:8080/jakartaee-hello-world

We have already covered how to test them out in our previous article, so we’re skipping it.

Setting up the Jakarta Servlet

As we aim to kick off our journey with Jakarta Servlets, let’s first grasp the essence of what Jakarta Servlets are all about. Originally part of the Java EE ecosystem and previously known as Java Servlets, Jakarta Servlets are a set of APIs in the Jakarta EE platform that enable server-side Java applications to handle HTTP requests and responses. Unlike traditional methods of dealing directly with low-level socket programming, Jakarta Servlets provides a high-level, component-based approach to building web applications. This makes it easier for developers to focus on business logic, as the underlying protocol handling and lifecycle management are taken care of by the Jakarta Servlet API.

The HttpServlet interface plays a pivotal role in the Jakarta Servlet API, serving as the cornerstone for creating HTTP-specific servlets. It is an abstract class that extends the GenericServlet class and provides methods like doGet(), doPost(), doPut(), etc., to handle various types of HTTP requests. When you create a custom servlet, you typically extend the HttpServlet class and override these methods to define the behaviour of your servlet for each HTTP request method.

Creating your own servlet involves a few straightforward steps. First, create a new Java class that extends HttpServlet. Then, override the HTTP methods you want your servlet to handle-commonly doGet() for handling GET requests and doPost() for POST requests. For example, to create a simple servlet that returns a “Hello, World!” message for GET requests, you’d extend HttpServlet and override the doGet() method like so:

import jakarta.servlet.*;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/hello")
public class HelloWorldServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter out = resp.getWriter();
        out.println("Hello, World!");
    }
}

The @WebServlet annotation is a key feature in modern Jakarta Servlets, used to define the configuration and URL mapping of a Servlet class. When you see @WebServlet("/hello") above a class definition, it signifies that this particular Servlet will respond to HTTP requests that target the /hello path within your application’s context root.

Now, if we compile and rerun the application and hit the following URL on the browser, we will be able to see the output.

http://localhost:8080/jakartaee-hello-world/hello

Now that we have accomplished writing a simple hello world servlet application let’s go ahead and try a bit more complex one.

Steps to Create Coffee Servlets

1. Create the Coffee Preferences HTML Form

First, create an HTML file named coffee_preferences.html that includes checkboxes for various coffee types. Place the file in the WEB-INF folder.

<!DOCTYPE html>
<html>
  <head>
     <title>Coffee Preferences</title>
  </head>
  <body>
    <form action="storePreferences" method="post">
       <p>Select your coffee preferences:</p>
       <input type="checkbox" name="coffeeType" value="Black"> Black<br>
       <input type="checkbox" name="coffeeType" value="Latte"> Latte<br>
       <input type="checkbox" name="coffeeType" value="Cold Brew"> Cold Brew<br>

       <input type="submit" value="Submit">
    </form>
  </body>
</html>

The WEB-INF folder in a Jakarta EE or Java EE web application serves as a secure directory to store resources that should not be directly accessible by clients. When you place HTML files (or any other web resources like JSPs) in the WEB-INF folder, they become inaccessible via a direct URL request from the client’s browser. This provides an additional layer of security for application resources that should only be accessible through Servlets or other server-side components.

2. Create the Servlet to Store Preferences

Now, let’s create a Servlet that serves the coffee_preferences.html and captures the selected coffee types and stores them in a session.

package org.eclipse.jakarta.hello;

import jakarta.servlet.*;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.*;

import java.io.IOException;

@WebServlet("/storePreferences")
public class StorePreferencesServlet extends HttpServlet {

   @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       req.getRequestDispatcher("/WEB-INF/coffee_preferences.html").forward(req, resp);
   }

   @Override
   protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       String[] coffeeTypes = req.getParameterValues("coffeeType");
       HttpSession session = req.getSession();
       session.setAttribute("userCoffeeTypes", coffeeTypes);

       resp.sendRedirect("coffeeDashboard");
   }
}

The Jakarta Servlet, StorePreferencesServlet, is written to handle both the displaying and storing of user coffee preferences. The Servlet is mapped to the /storePreferences URL via the @WebServlet annotation. The doGet method forwards the request to an HTML page located at /WEB-INF/coffee_preferences.html, which contains the form for users to select their coffee preferences. The doPost method, on the other hand, captures the user’s coffee preferences from the submitted form. These preferences are stored as an array of strings in an HTTP session under the attribute name userCoffeeTypes. Once the preferences are stored, the user is redirected to the coffeeDashboard servlet.

3. Create the Servlet to Generate Personalized Coffee Recommendations

Now, let’s create another Servlet that reads the stored coffee preferences and dynamically generates a list of recommended coffee.

package org.eclipse.jakarta.hello;

import jakarta.servlet.*;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.*;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

@WebServlet("/coffeeDashboard")
public class CoffeeDashboardServlet extends HttpServlet {

   //This could ideally  come from a database
   private static final Map<String, String> COFFEE_DESCRIPTIONS = new HashMap<>();

   static {
       COFFEE_DESCRIPTIONS.put("Black", """
           <p>Black coffee has a robust flavor, perfect for those who prefer a coffee with some bite.</p>
           <p>Try brewing methods like French Press or Aeropress for an enjoyable black coffee experience.</p>
       """);
       COFFEE_DESCRIPTIONS.put("Latte", """
           <p>A latte is a creamy delight, suitable for people who enjoy a smoother and less harsh flavor.</p>
           <p>Experimenting with various syrups and sweeteners can elevate your latte experience.</p>
       """);
       COFFEE_DESCRIPTIONS.put("Cold Brew", """
           <p>Cold brew coffee tends to be smoother and less acidic. It's perfect for those hot summer days.</p>
           <p>Try brewing a batch in the fridge overnight for a refreshing morning pick-me-up.</p>
       """);
   }

   @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       HttpSession session = req.getSession();
       String[] coffeeTypes = (String[]) session.getAttribute("userCoffeeTypes");

       if (coffeeTypes == null || coffeeTypes.length == 0) {
           handleNoCoffeeTypes(resp);
           return;
       }

       PrintWriter out = resp.getWriter();
       out.println("""
           <html>
           <body>
           <h1>Your Personalized Coffee Dashboard</h1>
       """);

       for (String coffeeType : coffeeTypes) {
           String additionalInfo = COFFEE_DESCRIPTIONS.get(coffeeType);
           out.println("""
           <h2>Recommended %s</h2>
           <p>Here are some %s blends you might enjoy.</p>
           %s
       """.formatted(coffeeType, coffeeType, additionalInfo));
       }

       out.println("""
           </body>
       </html>
       """);
   }

   private void handleNoCoffeeTypes(HttpServletResponse resp) throws IOException {
       PrintWriter out = resp.getWriter();
       out.println("""
       <html>
           <body>
               <h1>No Coffee Types Found</h1>
               <p>Please select at least one type of coffee.</p>
           </body>
       </html>
       """);
   }
}

The CoffeeDashboardServlet class generates a personalized coffee dashboard based on the user’s coffee preferences. The Servlet is mapped to the URL /coffeeDashboard via the @WebServlet annotation. It employs a static HashMap named COFFEE_DESCRIPTIONS to store descriptions for different types of coffee—this is a stand-in for what could ideally be fetched from a database.

The servlet overrides the doGet method to handle HTTP GET requests. Inside this method, it first retrieves the user’s coffee preferences stored in an HTTP session. If no preferences are found, a default message is displayed by calling the handleNoCoffeeTypes method. Otherwise, it iterates through the selected coffee types and fetches their corresponding descriptions from the COFFEE_DESCRIPTIONS map. Finally, it generates HTML content to display this information in a personalized dashboard.

That’s it. Our application is done; now, we can rerun it again and test it out.

Testing out the application

Once deployed, open a web browser and navigate to: http://localhost:8080/jakartaee-hello-world/storePreferences

It will open the following page:

A webpage with a checklist labelled as "Select your coffee preferences" with three options: "Black"; "Latte"; and "Cold Brew".

Choose your preferred coffee type and hit the ‘Submit’ button; you’ll then be directed to the subsequent page.

A webpage with the heading "Your Personalized Coffee Dashboard", a subheading "Recommended Latte", and body text recommending latte blends that you may enjoy.

Conclusion

Congratulations! You have just learned how to develop an application with Jakarta Servlet.

Back to the top