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

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

已在 Random-ZH 群组中发布
理解本文所需的知识水平:您已经或多或少地了解了 Java Core,并且想了解 JavaEE 技术和 Web 编程。如果您当前正在研究 Java Collections 任务,那么它是最有意义的,它涵盖了与本文接近的主题。 本材料是我的文章在 IntelliJ Idea Enterprise 中创建简单的 Web 项目使用 servlet 和 jsp 创建简单的 Web 应用程序(第 1 部分)- 1的逻辑延续。在其中我演示了如何创建一个可用的 Web 项目模板。这次我将向您展示如何使用 Java Servlet API 和 JavaServer Pages API 技术创建一个简单但漂亮的 Web 应用程序。我们的应用程序将有一个带有两个链接的主页:
  • 到用户添加页面;
  • 进入用户列表查看页面。
我仍将使用 IntelliJ Idea Enterprise Edition、Apache Maven(仅包含一些依赖项)和 Apache Tomcat。最后,我们将使用W3.CSS框架“装饰”我们的应用程序。我们假设目前您已经有一个空项目,我们将在这里开发该项目。如果没有,请阅读第一篇文章并完成它。只需几分钟:)

关于未来应用程序的结构的一些信息

我们的主页 ( / ) 将是最普通的静态 html 页面,带有标题和两个链接/按钮:
  • 添加新用户(将发送到/add);
  • 查看用户列表(发送到/list)。
Tomcat 将捕获对这些地址的请求并将它们发送到我们将创建的两个 servlet 之一(我们将在web.xml文件中描述映射)。Servlet 依次处理请求、准备数据(或者在添加用户时保存数据),并将控制权转移到相应的 jsp 文件,这些文件已经“呈现”结果。我们将数据存储在最常见的列表(List)中。

让我们创建一个静态主页

如果您的 Web 文件夹中有index.jsp,请将其删除。相反,在此文件夹中,我们将创建一个名为index.html的简单 html 文件:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My super project!</title>
</head>
<body>
    <!-- header -->
    <div>
        <h1>Super app!<//h1>
    </div>

    <div>       <!-- content -->
        <div>    <!-- buttons holder -->
            <button onclick="location.href='/list'">List users<//button>
            <button onclick="location.href='/add'">Add user<//button>
        </div>
    </div>
</body>
</html>
这里没有什么复杂的。在标题中,我们表示页面的标题。在页面正文中我们有两个主要的div:标题(header)和内容(content)。在内容中,我们有一个按钮支架,实际上有两个按钮,当单击时,它们会被发送到适当的地址。您可以运行该项目并查看它现在的样子。如果您单击这些按钮,则会打开带有 404 错误的页面,因为我们还没有这些页面。但这表明按钮可以工作。请注意,这不是最通用的选项,因为如果您突然禁用 JavaScript,这些按钮将在浏览器中毫无用处。但我们假设没有人禁用 JavaScript :)。显然可以使用简单的链接,但我更喜欢按钮。你做你最喜欢的事。别看我的例子中会有很多div。然后我们会给它们填充样式,一切都会看起来更漂亮:)。

创建jsp文件来渲染结果

在同一个Web目录中,我们将创建一个文件夹来放置jsp 文件。我将其称为视图,同样,您可以即兴发挥。在此文件夹中我们将创建两个 jsp 文件:
  • add.jsp — 添加用户的页面;
  • list.jsp - 用于显示用户列表的页面。
让我们为他们提供适当的页面标题。像“添加新用户”和“用户列表”之类的东西,我们暂时保留这种状态。

让我们创建两个 servlet

Servlet 将接受并处理 Tomcat 传递给它们的请求。在src/main/java文件夹中,我们将创建一个应用程序包,其中包含我们的源代码。在那里我们将有更多不同的包。因此,为了使这些包不会在彼此内部创建,让我们在应用程序包中创建一些类(然后将其删除)。现在让我们在应用程序包中创建三个不同的包 :
  • 实体- 这是我们的实体所在的位置(类本身,它将描述用户对象);
  • model - 我们的模型将在这里(稍后会详细介绍);
  • servlet - 好吧,这就是我们的 servlet。
之后,您可以安全地从应用程序包中删除该类(当然,如果您创建了它)。在servlets包中,我们将创建两个类:
  • AddServlet - 将处理在/add收到的请求;
  • ListServlet - 将处理在/list收到的请求。

连接 Maven 中的依赖项

Tomcat 版本 9.* 实现了 Servlet 版本 4.0 和 JavaServer Pages 版本 2.3 规范。这是Tomcat 9官方文档中第二行第一段中写的。这意味着,如果您像我一样正在使用此版本的 Tomcat,那么我们编写并发送运行的代码将完全使用指定的版本。但我们希望在我们的项目中拥有这些规范,以便使用它们的代码至少能够成功编译。为此,我们需要将它们加载到我们的项目中。这就是 Maven 发挥作用的地方。

一般规则是这样的:如果您需要使用 Maven 将某些内容连接到您的项目:

  • 转到 Maven 存储库网站;
  • 在那里查找您需要的库和版本;
  • 您获得需要插入到 pom.xml 中的依赖项代码;
  • 插入!:)
那么让我们开始吧。首先,我们准备一个pom文件在/version之后但/project之前的某个位置,插入以下内容:
<dependencies>

</dependencies>
因此,我们表明在这些标签内我们将列出我们需要的依赖项。现在访问mvnrepository.com,顶部会有一个搜索字段。首先,在搜索中输入 servlet。第一个结果有七千多种用途,很适合我们。我们记得我们需要 4.0 版本(对于 Tomcat 9;对于其他版本,旧的实现可能适合)。这是一个相当新的版本,所以没有太多用途,但它是我们需要的。将打开一个页面,您可以在其中获取各种包管理器的此依赖项的代码,您甚至可以直接下载它。但由于我们想使用 Maven 连接它,因此我们选择 Maven 选项卡上的代码。我们复制并粘贴到 pom 文件的依赖项部分中。如果 IDEA 右下角出现通知询问我们是否要启用自动导入,我们同意。如果您不小心拒绝,请转到“设置”并手动启用自动导入:设置 (Ctrl + Alt + S) -> 构建、执行、部署 -> Maven -> 导入 这将保留pom 文件和 IDEA 配置文件项目同步。现在,使用相同的原理,我们将找到并连接 JavaServer Pages 版本 2.3(在搜索中输入 jsp)。既然我们已经使用了 Maven,那么我们立即告诉它我们的源代码符合 Java 8 语法,并且它们需要编译成相同版本的字节码。经过所有这些操作后,我们的pom.xml将如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>ru.javarush.info.fatfaggy</groupId>
    <artifactId>my-super-project</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>1.8</maven.compile.source>
        <maven.compiler.target>1.8</maven.compile.target>
    </properties>

    <dependencies>
        <!-- Servlet API 4.0 for tomcat 9 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.0</version>
            <scope>provided</scope>
        </dependency>

        <!-- JavaServer Pages API 2.3 for tomcat 9 -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

</project>

使我们的 servlet 成为真正的 servlet

此时,我们创建的几个 servlet 实际上只是常规类。它们没有任何功能。但现在我们已经将 Servlet API 连接到我们的项目,如果是这样,我们可以使用那里的类。为了使我们的 servlet 成为“真正的”servlet,我们只需从HttpServlet类继承它们即可。

映射或分区

现在,最好以某种方式告诉 Tomcat,以便来自/add的请求由我们的AddServlet servlet处理,因此来自/list 的请求由ListServlet servlet处理。这个过程称为映射。这是根据以下原则 在web.xml文件中完成的:
  • 首先我们描述 servlet(我们给出一些名称并指出类本身的路​​径);
  • 然后我们将此 servlet 绑定到特定地址(我们指示我们刚刚提供的 servlet 的名称,并指示应将请求发送到此 servlet 的地址)。
我们来描述一下 Servlet:
<servlet>
    <servlet-name>add</servlet-name>
    <servlet-class>app.servlets.AddServlet</servlet-class>
</servlet>
现在我们将它绑定到地址:
<servlet-mapping>
    <servlet-name>add</servlet-name>
    <url-pattern>/add</url-pattern>
</servlet-mapping>
正如您所看到的,两种情况下的servlet-name是相同的。因此,Tomcat 知道如果请求到达/add地址,则需要将其传递给app.servlets.AddServlet servlet 。我们对第二个 servlet 执行同样的操作。结果,我们的web.xml大约有以下内容:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <!-- add servlet -->
    <servlet>
        <servlet-name>add</servlet-name>
        <servlet-class>app.servlets.AddServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>add</servlet-name>
        <url-pattern>/add</url-pattern>
    </servlet-mapping>

    <!-- list servlet -->
    <servlet>
        <servlet-name>list</servlet-name>
        <servlet-class>app.servlets.ListServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>list</servlet-name>
        <url-pattern>/list</url-pattern>
    </servlet-mapping>
</web-app>
顺便说一句,我们没有为此处的主页(位于/)创建标记。事实是,在这种情况下我们不需要它。我们的主页是一个简单的html 文件,只显示两个按钮。没有动态内容,因此我们为它创建一个单独的 servlet 是没有意义的,来自地址/的请求将被发送到该 servlet,并且除了将执行转移到某些jsp之外什么也不做(这也必须是创建),如果我们有两个按钮,它就会绘制。我们不需要这个;我们对静态资源很满意。当Tomcat收到一个请求时,它会检查这个地址是否没有一个servlet可以处理该请求,然后它会发现这个地址实际上有一个现成的html文件,它会成功发送该文件。我们可以再次运行我们的应用程序(根据需要重新启动服务器或重新部署)并确保主页已呈现,没有任何损坏,当我们单击按钮时,会发生转换,但现在也会出现错误书面。顺便说一句,如果之前有 404 错误,现在有 405 错误。这意味着映射有效,找到了 servlet,但它们只是没有任何合适的方法来处理请求。如果在这个阶段你仍然得到 404 错误,尽管一切都完成了,也许你应该更正 idea 中的部署配置。为此,您需要转到“编辑配置”(位于顶部靠近“开始”按钮的位置),转到窗口右侧的“部署”选项卡,并确保在“应用程序”上下文中简单地指示/

简短的抒情题外话:“幕后”正在发生什么?

您可能已经想知道我们的应用程序在 Tomcat 中如何工作?那里发生了什么事?main()方法在哪里?一旦您在浏览器中输入localhost:8080并访问该地址,浏览器就会通过http协议向该地址发送请求。我希望您已经意识到请求可以有不同的“类型”,最流行的是GETPOST。每个请求都必须有一个答案。GET 请求期望在响应中给出一个现成的html 代码,该代码将返回到浏览器,浏览器将漂亮地用各种字母、按钮和表单替换该代码。POST 请求更有趣一些,因为它还携带一些信息。例如,在用户注册或授权表单中,您输入了数据并单击“发送”。此时,一个 POST 请求已发送到服务器,其中包含您的个人信息。服务器接受此信息,对其进行处理并返回某种响应(例如,包含您的个人资料的html 页面)。它们之间的根本区别在于,GET 请求仅用于从服务器接收数据,而POST 请求则携带一些信息,并且服务器上的数据可能会发生变化(例如,当您将照片上传到服务器时,它会更改)。会飞入POST请求,服务器会将其添加到数据库中,即会发生一些变化,现在我们回到Tomcat,当它收到客户端的一些请求时,它会查看该地址,搜索其数据查看是否有合适的 servlet,它可以处理对这样的地址的请求(或者可以立即返回的现成资源)。如果没有找到任何可返回的内容,则它不会以 html 页面响应,而是以带有 404 响应。如果它找到一个合适的 servlet,“位于”该地址,它会查看收到的请求类型(GET、POST 或其他),然后询问 servlet 是否有一个方法可以处理这种类型的请求。如果 servlet 说它不能处理这种类型,Tomcat 就会用代码 405 响应客户端。这就是我们刚刚发生的情况。但是如果找到了合适的servlet,并且它有合适的方法,Tomcat就会创建这个servlet的对象,在一个新的线程(thread)中运行它,这允许servlet在单独的线程中工作,并且Tomcat继续进一步工作本身,接收和发送请求。此外,Tomcat 还创建了两个对象:一个是HttpServletRequest类型(我将在以后简称为请求),第二个是HttpServletResponse类型(我将其称为答案)。在第一个对象中,它放置了从客户端请求中接收到的所有数据,因此可以从此对象中提取所有数据。好吧,完成这一切之后,它将这两个对象传递给在单独线程中运行的 servlet 的适当方法。一旦 Servlet 完成其工作并准备好发送给客户端的响应,它就会向 Tomcat 举起一个标志,说:“我完成了,一切都准备好了。” Tomcat 接受响应并将其发送给客户端。这使得 Tomcat 可以不间断地接受请求并发送响应,而所有工作都是由在单独线程中运行的 servlet 完成的。因此,当我们编写 servlet 代码时,我们定义了将要执行的工作。是的,您可以将main()方法视为 Tomcat 本身中的方法(是的,它是用 Java 编写的),当我们“启动”Tomcat 时,main().

我们使用 servlet 捕获 GET 方法并发送简单的响应

目前,我们的 servlet 没有合适的方法 (GET),因此 Tomcat 返回 405 错误。让我们来制作它们吧!我们继承 servlet 的HttpServlet类定义了不同的方法。为了给方法设置一些代码,我们只需重写它们即可。在这种情况下,我们需要重写两个 servlet 中的doGet()方法。
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

}
正如你所看到的,这个方法接受两个对象:req(请求)和resp(响应)。这些正是 Tomcat 在调用此 servlet 中的适当方法时将为我们创建和填充的对象。首先,我们来做最简单的回答。为此,请获取resp对象并从中获取PrintWriter对象,该对象可用于撰写响应。好吧,使用它我们将打印一些简单的字符串。
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    PrintWriter writer = resp.getWriter();
    writer.println("Method GET from AddServlet");
}
我们将在ListServlet servlet 中执行类似的操作,然后再次启动服务器。如您所见,一切正常!当您单击按钮时,页面将打开,其中包含我们用 PrintWriter “记录”的文本。只是我们为生成带有答案的页面而准备的jsp没有以任何方式使用。这是因为执行根本没有到达他们手中。现在,Serverlet 本身会生成响应并完成其工作,向 Tomcat 发出信号,表明它已为客户端准备好响应。Tomcat 只是接受此响应并将其发送回客户端。我们将控制从 servlet 转移到jsp。 让我们这样更改方法的代码:
  • 我们从请求对象中获取一个请求管理器对象,在其中传递我们想要将控制权转移到的页面的jsp地址;
  • 使用接收到的对象,我们将控制权转移到指定的jsp页面,并且不要忘记附加我们从 Tomcat 接收到的请求和响应对象。
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    RequestDispatcher requestDispatcher = req.getRequestDispatcher("views/add.jsp");
    requestDispatcher.forward(req, resp);
}
在jsp页面 的body中(body标签内)我们可以写一些东西,这样我们就可以清楚地看到正在显示的是哪个页面。之后,我们重新启动服务器并检查。按下主页上的按钮,打开页面,这意味着请求被发送到 servlet,之后控制权被转移到已经呈现的 jsp 页面。就这样。在本文的下一部分中,我们将讨论应用程序的功能。

还有什么要读的:

在 IntelliJ Idea Enterprise 中创建一个简单的 Web 项目。一步步来,有图


我的聊天记录
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION