JavaRush /Java 博客 /Random-ZH /使用 servlet 和 jsp 创建简单的 Web 应用程序(第 2 部分)
Стас Пасинков
第 26 级
Киев

使用 servlet 和 jsp 创建简单的 Web 应用程序(第 2 部分)

已在 Random-ZH 群组中发布
使用 servlet 和 jsp 创建一个简单的 Web 应用程序(第 1 部分) 理解本文所需的知识水平:您已经或多或少地了解了 Java Core,并且希望了解 JavaEE 技术和 Web 编程。如果您当前正在研究 Java Collections 任务,那么它是最有意义的,它涵盖了与本文接近的主题。
使用 servlet 和 jsp 创建简单的 Web 应用程序(第 2 部分)- 1

创建实体

实体包中,我们将创建一个类User,其中有两个私有字符串变量namepassword。让我们创建构造函数(默认的和接受两个值的构造函数)、getters/setters、重写toString()方法(以防万一)以及equals()hashCode()方法。也就是说,我们将做一个合格的 Java 开发人员在创建类时所做的一切。
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;
    }
}
现在我们可以开始创建用户列表。我们将向其中添加用户,并从那里将他们显示出来。然而,有一个问题。我们不创建 servlet 对象,Tomcat为我们做这件事。我们在其中重写的方法也已经为我们定义好了,我们无法添加参数。那么我们如何创建一个对我们的两个 servlet 都可见的共享列表呢?如果我们只是在每个 servlet 中创建自己的列表对象,那么我们将把用户添加到一个列表中,并使用ListServlet servlet 将用户列表显示到另一个列表中。事实证明,我们需要一个两个 servlet 共用的对象。一般来说,我们需要一个对程序中所有类都通用的对象;整个程序的唯一对象。我希望您听说过一些有关设计模式的知识。也许,对于某些人来说,这是在他们的程序中使用单例模式的第一个真正需要。您可以变态并通过双重检查和同步创建一些很酷的单例(是的,我们有一个多线程应用程序,因为 Tomcat 在不同的线程中运行 servlet),但我将使用早期初始化的选项,因为它在这里非常合适足够了,它适合我们的目的。

创建模型

让我们在模型包中创建一个类(并在其中实现单例模式)并将其命名为不寻常的名称。让我们说模型。让我们在类中创建一个私有用户列表对象,并实现两个方法:第一个用于添加用户,第二个用于返回字符串(用户名)列表。由于我们的用户对象由名称和密码组成,并且我们不想“泄露”用户密码,因此我们只有一个名称列表。
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());
    }
}

关于mvc的一些知识

既然您听说过singleton,那么您可能也听说过另一种设计模式 - MVC(模型-视图-控制器,俄语中的模型-视图-控制器,或者就像英语中的模型-视图-控制器)。其本质是将业务逻辑与表示分离。也就是说,将决定做什么的代码与决定如何显示的代码分开。视图(视图或简称视图)负责某些数据的呈现形式。在我们的例子中,视图是我们的 JSP 页面。这就是为什么我将它们放在一个名为“views”的文件夹中。 模型是程序运行时使用的实际数据。在我们的例子中,这些是用户(用户列表)。那么,控制器是它们之间的连接纽带。它们从模型中获取数据并将其传递给视图(或从 Tomcat 接收一些数据,对其进行处理并将其传递给模型)。业务逻辑(程序到底应该做什么)需要在其中描述,而不是在模型或视图中。于是,每个人都做自己的事:
  • 模型存储数据;
  • 视图绘制了数据的漂亮表示;
  • 控制器负责数据处理。
这使得程序相当简单且可维护,而不是一个类中所有代码的巨大转储。 MVC不仅适用于 Web 编程,而且在这个领域中它的身影尤其频繁(几乎总是)。在我们的例子中,Servlet 将充当控制器。这是对该模式的非常肤浅和简短的描述,但MVC不是本文的主要主题。谁想了解更多 - 谷歌来救援!创建用于添加用户的表单 让我们向add.jsp文件中添加一个表单,该表单由两个文本输入字段(一个是常规输入字段,另一个是密码)和一个用于将数据发送到服务器的按钮组成。
<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>
这里的表单有一个值为post 的method属性。这意味着该表单中的数据将以 POST 请求的形式发送到服务器。未指定action属性,这意味着请求将发送到我们访问此页面的同一地址 ( /add )。因此,绑定到该地址的 servlet 在收到 GET 请求后,会返回此 jsp 以及用于添加用户的表单,如果它收到 POST 请求,则意味着该表单已将其数据发送到那里(我们将从doPost() 值得注意的是,输入字段有一个名称参数(对于具有名称的字段,它具有值 name ,对于具有密码的字段,它具有值pass)。这是非常重要的一点。因为为了从请求(已经在 servlet 内部)获取这些数据(将输入的名称和密码),我们将准确使用这些名称pass。但稍后会详细介绍。用于发送数据的按钮本身再次以按钮的形式制作,而不是像通常习惯那样作为输出字段。我不知道这个选项有多通用,但它对我有用(Chrome 浏览器)。

使用 servlet 处理 POST 请求

让我们回到AddServlet servlet 。让我提醒您:为了让我们的 servlet 能够“捕获”GET 请求,我们重写了HttpServlet类中的doGet()方法。为了教我们的 servlet 也捕获 POST 请求,我们还需要重写doPost()方法。它从Tomcat接收类似的请求和响应对象,我们将使用它。首先,让我们从请求中提取名称并传递表单发送的参数(如果您在表单中对它们进行了不同的命名,那么这些就是您编写的名称)。之后,我们将使用接收到的数据创建用户对象。然后我们将获取模型对象并将创建的用户添加到模型中。
@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);
}

传递数据以查看

让我们继续讨论ListServlet servlet 。这里已经实现了doGet()方法,它只是将控制转移到list.jsp视图。如果您还没有,请使用AddServlet servlet 中的相同方法进行类推。现在,最好从模型中获取用户名列表并将它们传递给视图,视图将接收它们并很好地显示它们。为此,我们将再次使用从Tomcat收到的请求对象。我们可以向这个对象添加一个属性,给它一些名称,事实上,我们想要将其传输到view 的对象本身。由于以下事实:当将执行过程从 servlet 转移到视图时,我们将 servlet 本身接收到的相同请求和响应对象传递给那里,然后通过将名称列表添加到请求对象,我们就可以从该请求视图中的对象创建我们的用户名列表并获取。我们已经完成了ListServlet类,所以这里是整个类的代码:
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);
    }
}

执行jsp文件中的java代码

现在是开始处理list.jsp文件的时候了。只有当ListServlet经过这里的执行流程时才会执行。此外,在该 servlet 中,我们已经从模型中准备了用户名列表,并将其传递到请求对象中。由于我们有一个名称列表,因此我们可以循环遍历它打印出每个名称。正如我已经说过的,jsp 文件可以执行 java 代码(这就是它们与静态 html 页面的不同之处)。为了执行一些代码,将以下结构放在我们需要的地方就足够了:
<!-- html code -->
<%
    // java code
%>
<!-- html code -->
在这个构造中,我们可以访问几个变量:
  • request是我们的请求对象,我们从 servlet 传递它,在这里它被简单地称为req
  • responce - 响应对象,在 servlet 中称为resp
  • out是JspWriter类型的对象(继承自通常的Writer),借助它我们可以直接将某些内容“写入”到 html 页面本身中。out.println("Hello world!")条目与System.out.println("Hello world!")条目非常相似,但不要混淆两者!
    out.println() “写入”html页面,而System.out.println写入系统输出。如果您使用 Java 代码调用该部分内的jsp 方法 System.out.println() ,您将在Tomcat控制台中看到结果,而不是在页面上。

您可以在此处 查找 jsp 中的其他可用对象。使用request对象,我们可以获得从 servlet 传递的名称列表(我们将相应的属性附加到该对象),并且使用out对象,我们可以显示这些名称。让我们这样做(现在只是以 html 列表的形式):
<ul>
    <%
        List<String> names = (List<String>) request.getAttribute("userNames");

        if (names != null && !names.isEmpty()) {
            for (String s : names) {
                out.println("<li>" + s + "</li>");
            }
        }
    %>
</ul>
如果您需要仅在有用户时显示列表,否则显示还没有用户的警告,我们可以稍微重写此部分:
<%
    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>");
%>
现在我们可以将数据从 servlet 传递到视图,我们可以稍微改进一下AddServlet,以便在成功添加用户时显示通知。为此,在doPost()方法中,将新用户添加到模型后,我们可以将该用户的名称添加到req对象的属性中,并将控制权传递回add.jsp视图。其中已经创建了一个包含 Java 代码的部分,其中检查请求中是否存在这样的属性,如果存在,则输出一条消息,表明用户已成功添加。经过这些更改后,完整的AddServlet servlet 代码将如下所示:
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);
    }
}
在这里,在doPost()方法 的末尾,我们设置一个属性,其中包含添加到模型中的用户名称,然后调用 doGet ()方法,将当前请求和响应传递给该方法。doGet ()方法已将控制权转移到视图,并在其中发送一个请求对象,其中添加的用户名称作为属性附加。剩下的工作就是更正add.jsp,以便在存在此类属性时显示此类通知。最终的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>
页面正文包括:
  • div-a 带标题;
  • div 内容容器,它检查是否存在带有用户名的属性;
  • div 带有用于添加用户的表单;
  • 最后有一个页脚,带有返回主页的按钮。
看起来好像div太多了,但是我们稍后添加样式时会用到它们。最终的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>
因此,我们有一个完全运行的 Web 应用程序,可以存储和添加用户,以及显示他们的姓名列表。剩下的就是修饰它......:)

添加样式。我们使用W3.CSS框架

目前我们的应用程序正在运行,但绝对疯狂。因此,我们将添加背景、文本和按钮的颜色、样式列表、对齐、添加缩进等。如果您手动编写样式,可能会花费大量时间和精力。因此,我建议使用W3.CSS CSS框架。它已经有了带有样式的现成类;剩下的就是将我们想要应用的 CSS 类放置在正确的位置。为了将它们添加到我们的页面中,首先我们将包含一个带有样式的文件。这可以通过两种方式完成:
  1. 浏览我们的页面,并在头部插入带有样式的文件的直接链接

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

    如果您有持续的互联网连接,则此选项适合。然后,当您在本地服务器上打开页面时,样式将从 Internet 中提取。


  2. 如果您想在本地拥有所有样式而不依赖于 Internet 连接,请下载带有样式的文件并将其放置在 web文件夹中的某个位置(例如web/styles/w3.css),然后浏览我们的所有样式页面(index.html、add.jsp、list.jsp)并输入指向此文件的链接,并在head部分中使用样式

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

    之后,只需浏览标签并添加您喜欢的样式即可。我不会详细讨论这一点,但会立即提供我的三个文件的现成版本以及已安排的样式类。

索引.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>

添加.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>

列表.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>
仅此而已 :) 如果您仍有任何问题或有任何意见,或者相反,有些事情没有解决 - 请发表评论。UPD:如果您在单击按钮时遇到 404 错误的问题,尽管一切都正确完成,也许您应该更正 idea 中的部署配置。为此,您需要转到“编辑配置”(位于顶部靠近“开始”按钮的位置),转到窗口右侧的“部署”选项卡,并确保在“应用程序”上下文中简单地指示它/嗯,我'我会附上几张截图来说明这一切的结果。
使用 servlet 和 jsp 创建简单的 Web 应用程序(第 2 部分)- 2
使用 servlet 和 jsp 创建简单的 Web 应用程序(第 2 部分)- 3
使用 servlet 和 jsp 创建简单的 Web 应用程序(第 2 部分)- 4
最后 ,如果你想练习这个项目,你可以尝试:
  • 制作一个 servlet 和 jsp 来删除用户,并制作几个来更改/编辑现有用户。您将获得一个真正的 CrUD Web 应用程序 :) 在 servlet 上));
  • 将列表(List)替换为使用数据库,以便添加的用户在重新启动服务器后不会消失:)
祝你好运!
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION