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

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

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

Creating entities

Let's create the User class in the entities package , and it will contain two private string variables name and password . Let's create constructors (default and one that would take 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 pick them up for display. However, there is one problem here. 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 to create a common list that would be visible in both of our servlets? If we simply create our own list object in each servlet, then it turns out that we will add users to one list, and display the list of users with the ListServlet servlet— in another. It turns out that we need an object that would be common to both servlets. Generally speaking, we need an object that is common to all classes in our program; the only object in the entire program. I hope you heard something about design patterns. And, perhaps, for someone, this is the first real need to use the Singleton pattern in their program. You can pervert and “cut down” some cool Singleton , with double checks and synchronization (yes, we have a multi-threaded application, since Tomcat servlets are launched in different threads), but I will use the early initialization option, because here it is quite enough, and it is suitable for our purposes.

Model creation

Let's create a class (and implement the Singleton template in it ) in the model package and name it something unusual. Let's say Model . Let's create a private user list object in our class, and implement two methods: one to be able to add a user, and the second to return a list of strings (usernames). Since our user object consists of a name and a password, and we would not want to “shine” 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 have heard about singleton , it means that you have 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 the business logic from the presentation. That is, separate the code that determines what to do from the code that determines how to display. View (view or just views) is responsible for how to present some data. In our case, the views are our jsp pages. That is why I put them in a folder called views . Model- this is actually the data itself with which the program works. In our case, these are users (list of users). Well, controllers are the link between them. They take data from the model and pass it to the 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. So everyone minds their own business:
  • the model stores the data;
  • views draw a beautiful representation of the data;
  • controllers handle the data.
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 especially common (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. If you want to know more - Google to the rescue! Creating a form for adding a user Let's add a form to the add.jsp file that consists of two text input fields (one is normal, the other is a password) and a button for submitting 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 a value of post . This indicates that the data from this form will fly to the server in the form of a POST request. The action attribute is not specified, which means that 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 out from the request object in the doPost ( ) method , process and transfer to the model for saving). It is worth noting that the input fields have the parameter name(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 from the request (inside the servlet already) (the name and password that will be entered) - we will use exactly these name and pass . But more on that later. The send data button itself is again made in the form of a button , and not an output field, as is usually the case. I don’t know how universal this option is, but it works for me (Chrome browser).

Handling a POST Request by a Servlet

Let's go back 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 catch POST requests as well, we need to override the doPost() method as well . It receives similar request and response objects from Tomcat , which we will work with. To begin with, we will pull out the name and pass parameters from the request that the form sent (if you named them differently in the form, then you write exactly those names). After that, we will create our user object using the received data. Then we 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 a 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 already have it, 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 beautifully. 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 pass to the view. Due to the fact that when transferring the execution process from the servlet to the 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 we can our list of user names and get. We have finished with the ListServlet class , so here is the code of 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);
    }
}

java code execution in jsp files

It's time to tackle the list.jsp file . It will only be executed when the ListServlet sends an execution process here. In addition, we have already prepared a list of usernames from the model in that servlet and passed it here in the request object. Since we have a list of names, we can loop through it and output each name. As I said, jsp files can execute java code (which is how they differ from static html pages). In order to execute some code, it is enough to put the construction in the place we need:
<!-- html code -->
<%
    // java code
%>
<!-- html code -->
Inside such a construction, we get access to several variables:
  • request is our request object, which we passed from the servlet, where it was simply called req ;
  • response - the response object, in the servlet it was called resp ;
  • out is an object of type JspWriter (inherited from the usual Writer ), with 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 them!
    out.println() “writes” to the html page, and System.out.println writes to the system output. If you call the System.out.println() jsp method inside the Java code section , you will see the results in the Tomcat console , and not on the page.

About other available objects inside jsp you can search here . Using the request object , we can get the list of names that were passed from the servlet (we attached the appropriate 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 want to display the list only when there are users, and otherwise display a warning that there are no users yet, we can rewrite this section a bit:
<%
    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 know how to 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 we have added 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 whether there is such an attribute in the request, and if so, then a message is displayed that the user has been 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 , into which we pass the current request and response. And the doGet () method already transfers control to the view, where it sends the request object with the added user name attached as an attribute. It remains to tweak add.jsp so that it displays such a notification if such an attribute is present. Final add.jsp :
<%@ 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 page body consists of:
  • div-a with a header;
  • div-container for content, it checks if there is an attribute with the username;
  • div with the form for adding users;
  • well, at the end of the footer with a button to return to the main page.
It may seem like a lot of divs, but we'll use them later when we add styles. The final version of list.jsp :
<%@ 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. It remains only to embellish ... :)

Adding styles. We use the W3.CSS framework

At the moment, our application is working, but absolutely outrageous. Therefore, we will add a background, color for text and buttons, style lists, do alignment, add indents, and the like. If you write styles by hand, 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, it remains only to place the css classes that we want to apply in the right places. In order to add them to our pages, we first need to 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 permanent 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 the Internet connection, download the style file and place it somewhere inside the web folder (for example, web/styles/w3.css ), then go through all 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 have any questions or comments, or vice versa something doesn't work, leave a comment. UPD: if you have problems with 404 error when clicking on buttons, although everything is done correctly, you may need to fix the deployment configuration in the idea. to do this, go to Edit configurations (there at the top near the start button), go to the Deployment tab in the right part of the window and make it so that the Application context is simply / Well, I’ll attach a couple of screenshots of what came out of it all.
Creating a simple web application on servlets and jsp (part 2) - 2
Creating a simple web application on servlets and jsp (part 2) - 3
Creating a simple web application on servlets and jsp (part 2) - 4
And finally. If you want to practice with this project, you can try:
  • make a servlet and a jsp for deleting a user and a couple more for changing/editing an existing user. You will get a real CrUD web application :) on servlets));
  • replace the list (List) with a database, so that the added users do not disappear after the server is restarted :)
Good luck!
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION