JavaRush /Java Blog /Random EN /Creating a simple web application using servlets and jsp ...
Стас Пасинков
Level 26
Киев

Creating a simple web application using servlets and jsp (part 2)

Published in the Random EN group
Creating a simple web application using servlets and jsp (part 1) Level of knowledge required to understand the article: you have already more or less understood Java Core and would like to look at JavaEE technologies and web programming. It makes the most sense if you are currently studying the Java Collections quest, which covers topics close to the article.
Creating a simple web application using servlets and jsp (part 2) - 1

Creating Entities

In the entities package, we will create a class User , and in it there will be two private string variables name and password . Let's create constructors (default and one that would accept both values), getters/setters, override the toString() method just in case, as well as the equals() and hashCode() methods . That is, we will do everything that a decent Java developer does when creating a class.

public class User {
    private String name;
    private String password;

    public User() {
    }

    public User(String name, String password) {
        this.name = name;
        this.password = password;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", password='" + password + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        User user = (User) o;

        if (name != null ? !name.equals(user.name) : user.name != null) return false;
        return password != null ? password.equals(user.password) : user.password == null;

    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + (password != null ? password.hashCode() : 0);
        return result;
    }
}
Now we can start creating a list of users. We will add users to it, and from where we will take them for display. However, there is one problem. We don’t create our servlet objects, Tomcat does it for us . The methods that we override in them are also already defined for us, and we cannot add a parameter. How then can we create a shared list that is visible to both of our servlets? If we simply create our own list object in each servlet, it will turn out that we will add users to one list, and display the list of users using the ListServlet servlet to another. It turns out that we need an object that would be common to both servlets. Generally speaking, we need an object that would be common to all classes in our program; the only object for the entire program. I hope you've heard something about design patterns. And, perhaps, for some this is the first real need to use the Singleton pattern in their program. You can get perverted and create some cool Singleton with double checks and synchronization (yes, we have a multi-threaded application, since Tomcat runs servlets in different threads), but I will use the option with early initialization, since it is quite suitable here enough and it suits our purposes.

Creating a model

Let's create a class (and implement the Singleton pattern in it ) in the model package and call it something unusual. Let's say Model . Let's create a private user list object in our class, and implement two methods: one so that we can add a user, and the second to return a list of strings (user names). Since our user object consists of a name and a password, and we would not like to “reveal” user passwords, we will only have a list of names.

public class Model {
    private static Model instance = new Model();

    private List<User> model;

    public static Model getInstance() {
        return instance;
    }

    private Model() {
        model = new ArrayList<>();
    }

    public void add(User user) {
        model.add(user);
    }

    public List<String> list() {
        return model.stream()
                .map(User::getName)
                .collect(Collectors.toList());
    }
}

A little about mvc

Since you’ve heard about singleton , then you’ve probably heard about another design pattern - MVC (model-view-controller, in Russian model-view-controller, or just like in English model-view-controller). Its essence is to separate business logic from presentation. That is, separate the code that determines what to do from the code that determines how to display. View (view or simply views) is responsible for the form in which some data is presented. In our case, views are our JSP pages. That's why I put them in a folder called views . The model is the actual data with which the program works. In our case, these are users (list of users). Well, controllers are the connecting link between them. They take data from the model and pass it to views (or receive some data from Tomcat, process it and pass it to the model). Business logic (what exactly the program should do) needs to be described in them, and not in the model or in the view. Thus, everyone does their own thing:
  • the model stores data;
  • views draw a beautiful representation of the data;
  • controllers handle data processing.
This allows the program to be fairly simple and maintainable, rather than a monstrous dump of all the code in one class. MVC is suitable not only for web programming, but it is in this area that it is found especially often (almost always). In our case, servlets will act as controllers. This is a very superficial and brief description of the pattern, but MVC is not the main topic of this article. Who wants to know more - Google to the rescue! Create a form for adding a user Let's add to the add.jsp file a form consisting of two text input fields (one regular, the other a password) and a button for sending data to the server.

<form method="post">
    <label>Name:
        <input type="text" name="name"><br />
    </label>

    <label>Password:
        <input type="password" name="pass"><br />
    </label>
    <button type="submit">Submit</button>
</form>
Here the form has a method attribute with the value post . This means that the data from this form will be sent to the server in the form of a POST request. The action attribute is not specified, which means the request will be sent to the same address where we went to this page ( /add ). Thus, our servlet, bound to this address, upon receiving a GET request, returns this jsp with the form for adding users, and if it receives a POST request, it means that the form sent its data there (which we will pull from the request object in the doPost() method , process it and transfer it to the model for saving). It is worth noting that the input fields have a name parameter (for a field with a name it has the value name, and for a field with a password it has the value pass ). This is a pretty important point. Since in order to get this data (name and password that will be entered) from the request (already inside the servlet), we will use exactly these name and pass . But more on that later. The button for sending data itself is again made in the form of a button , and not as an output field, as is usually customary. I don’t know how universal this option is, but it works for me (Chrome browser).

Processing a POST request with a servlet

Let's return to the AddServlet servlet . Let me remind you: in order for our servlet to be able to “catch” GET requests, we overridden the doGet() method from the HttpServlet class . To teach our servlet to also catch POST requests, we also need to override the doPost() method . It receives similar request and response objects from Tomcat , which we will work with. First, let’s extract from the request the name and pass parameters that the form sent (if you named them differently in the form, then those are the names you write). After this, we will create our user object using the received data. Then we will get the model object and add the created user to the model.

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String name = req.getParameter("name");
    String password = req.getParameter("pass");
    User user = new User(name, password);
    Model model = Model.getInstance();
    model.add(user);
}

Passing data to view

Let's move on to the ListServlet servlet . The doGet() method has already been implemented here , which simply transfers control to the list.jsp view . If you don’t have this yet, do it by analogy with the same method from the AddServlet servlet . Now it would be nice to get a list of usernames from the model and pass them to the view, which will receive them and display them nicely. To do this, we will again use the request object that we received from Tomcat . We can add an attribute to this object, giving it some name, and, in fact, the object itself, which we would like to transfer to view . Due to the fact that when transferring the execution process from a servlet to a view, we pass there the same request and response objects that the servlet itself received, then by adding our list of names to the request object, we can then from this request object in the view create our list of user names and get. We are done with the ListServlet class , so here is the code for the entire class:

package app.servlets;

import app.model.Model;

import javax.servlet.RequestDispatcher;
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.util.List;

public class ListServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Model model = Model.getInstance();
        List<String> names = model.list();
        req.setAttribute("userNames", names);

        RequestDispatcher requestDispatcher = req.getRequestDispatcher("views/list.jsp");
        requestDispatcher.forward(req, resp);
    }
}

Executing java code in jsp files

It's time to start working on the list.jsp file . It will only execute when the ListServlet passes the execution process here. In addition, in that servlet we have already prepared a list of user names from the model and passed it here in the request object. Since we have a list of names, we can loop through it and print out each name. As I already said, jsp files can execute java code (which is what makes them different from static html pages). In order to execute some code, it is enough to put the following construction in the place we need:

<!-- html code -->
<%
    // java code
%>
<!-- html code -->
Inside this construct we have access to several variables:
  • request is our request object, which we passed from the servlet, where it was simply called req ;
  • responce - response object, called resp in the servlet ;
  • out is an object of the JspWriter type (inherited from the usual Writer ), with the help of which we can “write” something directly into the html page itself. The out.println("Hello world!") entry is very similar to the System.out.println("Hello world!") entry , but don't confuse the two!
    out.println() “writes” to the html page, and System.out.println writes to the system output. If you call the jsp method System.out.println() inside the section with Java code , you will see the results in the Tomcat console , and not on the page.

You can look for other available objects inside jsp here . Using the request object , we can get the list of names that were passed from the servlet (we attached the corresponding attribute to this object), and using the out object , we can display these names. Let's do this (for now just in the form of an html list):

<ul>
    <%
        List<String> names = (List<String>) request.getAttribute("userNames");

        if (names != null && !names.isEmpty()) {
            for (String s : names) {
                out.println("<li>" + s + "</li>");
            }
        }
    %>
</ul>
If you need to display a list only if there are users, and otherwise display a warning that there are no users yet, we can rewrite this section a little:

<%
    List<String> names = (List<String>) request.getAttribute("userNames");

    if (names != null && !names.isEmpty()) {
        out.println("<ui>");
        for (String s : names) {
            out.println("<li>" + s + "</li>");
        }
        out.println("</ui>");
    } else out.println("<p>There are no users yet!</p>");
%>
Now that we can pass data from servlets to views, we can slightly improve our AddServlet so that a notification is displayed when a user has been successfully added. To do this, in the doPost() method , after adding a new user to the model, we can add the name of this user to the attributes of the req object and pass control back to the add.jsp view . And in it already make a section with Java code in which a check is made to see if such an attribute is in the request, and if so, then output a message stating that the user was successfully added. After these changes, the complete AddServlet servlet code will look something like this:

package app.servlets;

import app.entities.User;
import app.model.Model;

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

public class AddServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        RequestDispatcher requestDispatcher = req.getRequestDispatcher("views/add.jsp");
        requestDispatcher.forward(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = req.getParameter("name");
        String password = req.getParameter("pass");
        User user = new User(name, password);
        Model model = Model.getInstance();
        model.add(user);

        req.setAttribute("userName", name);
        doGet(req, resp);
    }
}
Here, at the end of the doPost() method , we set an attribute with the name of the user added to the model, after which we call the doGet() method , to which we pass the current request and response. And the doGet() method already transfers control to the view, where it sends a request object with the name of the added user attached as an attribute. All that remains is to correct add.jsp so that it displays such a notification if such an attribute is present. The final add.jsp is :

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Add new user</title>
    </head>

    <body>
        <div>
            <h1>Super app!</h1>
        </div>

        <div>
            <%
                if (request.getAttribute("userName") != null) {
                    out.println("<p>User '" + request.getAttribute("userName") + "' added!</p>");
                }
            %>
            <div>
                <div>
                    <h2>Add user</h2>
                </div>

                <form method="post">
                    <label>Name:
                        <input type="text" name="name"><br />
                    </label>
                    <label>Password:
                        <input type="password" name="pass"><br />
                    </label>
                    <button type="submit">Submit</button>
                </form>
            </div>
        </div>

        <div>
            <button onclick="location.href='/'">Back to main</button>
        </div>
    </body>
</html>
The body of the page consists of:
  • div-a with header;
  • div container for content, it checks whether an attribute with the username exists;
  • div with a form for adding users;
  • and at the end there is a footer with a button to return to the main page.
It may seem like there are too many divs, but we will use them later when we add styles. The final list.jsp is:

<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Users</title>
    </head>

    <body>
        <div>
            <h1>Super app!</h1>
        </div>

        <div>
            <div>
                <div>
                    <h2>Users</h2>
                </div>
                <%
                    List<String> names = (List<String>) request.getAttribute("userNames");

                    if (names != null && !names.isEmpty()) {
                        out.println("<ui>");
                        for (String s : names) {
                            out.println("<li>" + s + "</li>");
                        }
                        out.println("</ui>");
                    } else out.println("<p>There are no users yet!</p>");
                %>
            </div>
        </div>

        <div>
            <button onclick="location.href='/'">Back to main</button>
        </div>
    </body>
</html>
Thus, we have a fully working web application that can store and add users, as well as display a list of their names. All that remains is to embellish it... :)

Adding styles. We use the W3.CSS framework

At the moment our application is working, but absolutely crazy. Therefore, we will add a background, color of text and buttons, style lists, do alignment, add indents, and the like. If you write styles manually, it can take a lot of time and nerves. Therefore, I suggest using the W3.CSS CSS framework. It already has ready-made classes with styles; all that remains is to place the CSS classes that we want to apply in the right places. In order to add them to our pages, first we will include a file with styles. This can be done in two ways:
  1. go through our pages and in the head section insert a direct link to the file with styles

    <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">

    This option is suitable if you have a constant Internet connection. Then, when you open your pages on a local server, the styles will be pulled from the Internet.


  2. If you want to have all the styles locally and not be dependent on an Internet connection, download the file with styles and place it somewhere inside the web folder (for example, web/styles/w3.css ), then go through all of our pages ( index.html, add.jsp, list.jsp ) and enter a link to this file with styles inside the head section

    <link rel="stylesheet" href="styles/w3.css">

    After that, just go through the tags and add the styles that you like. I will not dwell on this in detail, but will immediately give my ready-made versions of my three files with arranged style classes.

index.html


<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Super app!</title>
        <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
    </head>

    <body class="w3-light-grey">
        <div class="w3-container w3-blue-grey w3-opacity w3-right-align">
            <h1>Super app!</h1>
        </div>

        <div class="w3-container w3-center">
            <div class="w3-bar w3-padding-large w3-padding-24">
                <button class="w3-btn w3-hover-light-blue w3-round-large" onclick="location.href='/list'">List users</button>
                <button class="w3-btn w3-hover-green w3-round-large" onclick="location.href='/add'">Add user</button>
            </div>
        </div>
    </body>
</html>

add.jsp


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Add new user</title>
        <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
    </head>

    <body class="w3-light-grey">
        <div class="w3-container w3-blue-grey w3-opacity w3-right-align">
            <h1>Super app!</h1>
        </div>

        <div class="w3-container w3-padding">
            <%
                if (request.getAttribute("userName") != null) {
                    out.println("<div class=\"w3-panel w3-green w3-display-container w3-card-4 w3-round\">\n" +
                            "   <span onclick=\"this.parentElement.style.display='none'\"\n" +
                            "   class=\"w3-button w3-margin-right w3-display-right w3-round-large w3-hover-green w3-border w3-border-green w3-hover-border-grey\">×</span>\n" +
                            "   <h5>User '" + request.getAttribute("userName") + "' added!</h5>\n" +
                            "</div>");
                }
            %>
            <div class="w3-card-4">
                <div class="w3-container w3-center w3-green">
                    <h2>Add user</h2>
                </div>
                <form method="post" class="w3-selection w3-light-grey w3-padding">
                    <label>Name:
                        <input type="text" name="name" class="w3-input w3-animate-input w3-border w3-round-large" style="width: 30%"><br />
                    </label>
                    <label>Password:
                        <input type="password" name="pass" class="w3-input w3-animate-input w3-border w3-round-large" style="width: 30%"><br />
                    </label>
                    <button type="submit" class="w3-btn w3-green w3-round-large w3-margin-bottom">Submit</button>
                </form>
            </div>
        </div>

        <div class="w3-container w3-grey w3-opacity w3-right-align w3-padding">
            <button class="w3-btn w3-round-large" onclick="location.href='/'">Back to main</button>
        </div>
    </body>
</html>

list.jsp


<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>Users list</title>
        <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
    </head>

    <body class="w3-light-grey">
        <div class="w3-container w3-blue-grey w3-opacity w3-right-align">
            <h1>Super app!</h1>
        </div>

        <div class="w3-container w3-center w3-margin-bottom w3-padding">
            <div class="w3-card-4">
                <div class="w3-container w3-light-blue">
                    <h2>Users</h2>
                </div>
                <%
                    List<String> names = (List<String>) request.getAttribute("userNames");

                    if (names != null && !names.isEmpty()) {
                        out.println("<ul class=\"w3-ul\">");
                        for (String s : names) {
                            out.println("<li class=\"w3-hover-sand\">" + s + "</li>");
                        }
                        out.println("</ul>");

                    } else out.println("<div class=\"w3-panel w3-red w3-display-container w3-card-4 w3-round\">\n"
+
                            "   <span onclick=\"this.parentElement.style.display='none'\"\n" +
                            "   class=\"w3-button w3-margin-right w3-display-right w3-round-large w3-hover-red w3-border w3-border-red w3-hover-border-grey\">×</span>\n" +
                            "   <h5>There are no users yet!</h5>\n" +
                            "</div>");
                %>
            </div>
        </div>

        <div class="w3-container w3-grey w3-opacity w3-right-align w3-padding">
            <button class="w3-btn w3-round-large" onclick="location.href='/'">Back to main</button>
        </div>
    </body>
</html>
That's all :) If you still have any questions or have any comments, or on the contrary, something doesn’t work out - leave a comment. UPD: if you have problems with 404 errors when clicking buttons, although everything was done correctly, perhaps you should correct the deployment configuration in the idea. To do this, you need to go to Edit configurations (at the top near the start button), go to the Deployment tab on the right side of the window and make sure that in the Application context it is simply indicated / Well, I’ll attach a couple of screenshots of what came out of all this.
Creating a simple web application using servlets and jsp (part 2) - 2
Creating a simple web application using servlets and jsp (part 2) - 3
Creating a simple web application using servlets and jsp (part 2) - 4
And finally , if you want to practice with this project, you can try:
  • make a servlet and jsp to delete a user and a couple more to change/edit an existing user. You will get a real CrUD web application :) on servlets));
  • replace the list (List) with working with a database so that added users do not disappear after restarting the server :)
Good luck!
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION