三、Servlet基础

注:因为我并不完全是为了从0开始Java开发,因此,我这里先暂时跳过第二章服务器环境相关的内容,直接开始第三章的内容。

3.1、Servlet 的基本结构:

​ 下面的代码给出了一个基本的 Servlet ,它处理 GET 请求。GET 请求是浏览器请求的常见类型,用来请求 Web 页面。用户在地址栏中输入 URL 、点击 Web 页面内的连接、或提交没有指定 METHOD 或 METHOD=“GET” 的 HTML 表单时,浏览器都会生成这个请求。 Servlet 还可以容易地处理 POST 请求(提交 METHOD=“POST” 的 HTML 表单时,会生成 POST 请求)。HTML 表单的使用细节以及 GET 和 POST 之间的区别。

package com.firstweb.study01;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;

public class ServletTemplate extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        
        //Use "request" to read incoming HTTP headers
        //(e.g.,Cookies) and query data from HTML forms .
        
        //Use "response" to specify the HTTP response status
        //code and headers (e.g.,the content type ,cookies)
        
        PrintWriter out = resp.getWriter();
        //Use "out" to send content to browser
    }
}

​ Servlet 一般扩展 HttpServlet ,并依数据发送方式的不同(GET或POST),覆盖 doGet 或 doPost 方法。如果希望 Servlet 对 GET 和 POST 请求采用同样的行动,只需要让 doGet 调用 doPost ,反之,依然。

​ doGet 和 doPost 都接受两个参数:HttpServletRequest 和 HttpServletResponse 。通过 HttpServletRequest,可以得到所有的输入数据;这个类提供相应的方法,通过这些方法可以找出诸如表单(查询)数据、HTTP 请求报头和客户的主机名等信息。通过 HttpServletResponse 可以制定输出信息,比如 HTTP 状态代码(200,404 等)和响应报头(Content-Type,Set-Cookie等)。最重要的是,通过HttpServletResponse 可以获得PrintWriter ,用它可以将文档内容发送给客户。对于简单的 Servlet ,大部分工作都花在用 println 语句生成期望的页面上。

​ 由于 doGet 和 doPost 抛出两种异常(ServletException 和 IOException),所以在方法声明中包括他们。最后,还必须导入 java.io(PrintWrite 等)、javax.servlet(HttpServlet 等)和 javax.servlet.http(HttpServletResponse 和 HttpServletRequest)中的类。

3.2、生成纯文本的 Servlet :

​ 代码 3.2 列出了一个输出纯文本的简单 Servlet,图 3.2 是它的输出。

//代码 3.2 
package com.firstweb.study01;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;

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

​ 图 3.2:

在这里插入图片描述

3.3、生成 HTML 的 Servlet:

​ 大多数的 Servlet 生成 HTML ,而非前述例子中的纯文本。要生成HTML ,需要在刚才介绍的过程中加入如下三步:

  1. 告知浏览器,即将向它发送 HTML 。
  2. 修改 println 语句,构建合法的 Web 页面。
  3. 用形式语法检验其(format syntax validator)检查生成的 HTML。

​ 第一步通过将 HTTP Content-Type 响应报头设为 text/html 来完成。一般而言,报头使用 HttpServletResponse 的 setHeader方法来设置,但由于设置内容的类型是一项十分常见的任务,因而,HttpServletResponse 提供特殊的 setContentType 方法,专门用于这种目的。指明 HTML 的方式是使用 text/html 类型,因此,代码应该如下:

resp.setContentType("text/html");

​ 尽管 HTML 是 Servlet 创建的最常见的文档类型,但是,Servlet 创建其他类型文档的情况也很常见。例如,使用 Servlet 生成的 Excel 表格(内容类型是 application/vnd.ms-excel)、JPEG 图像(内容类型是 image/jpeg )和 XML 文档(内容类型是 text/xml)的情况也是十分常见。同时,一般很少使用 Servlet 生成格式相对固定的 HTML 页面(即每次请求,页面的布局改动很小);这种情况下 JSP 常常更为方便。

​ 需要注意的是:需要在 PrintWriter 实际返回任何内容之前,设置响应报头。这是由于 HTTP 响应由状态行、一个或多个报头、一个空行和实际的文档一次次序构成。包头的出现次序并不重要,Servlet 会缓冲报头数据,将他们一次法案送到客户端,因此,即使在设定报头之后,依旧可以设置状态代码(属于返回内容的第一行)。但是,Servlet 不是一定要缓冲文档本身,因为对于篇幅较长的页面,用户或许只希望看到部分结果。Servlet 引擎可以缓冲部分输出,但并未规定缓冲区的大小。可以使用 HttpServletResponse 和 getBufferSize 方法确定这个大小,或使用 setBufferSize 指定这个大小。也可以在缓冲区填满,要发往客户时,对报头进行设置。如果不确定缓冲区是否已经发送出去,可以使用 isCommitted 方法来检查。及时如此,最佳的方案还是将 setContentType 行放在任何 PrintWrite 的行之前。

警告:必须在传送实际的文档之前设定内容的类型。

​ 在编写构建 HTML 文档的 Servlet 时,第二步时用 println 语句输出 HTML(不再是纯文本)。代码 303 列出了 HelloServlet.java ,结果如图 3.3 所示,浏览器按照 HTML 来格式化得到的结果,而非按照纯文本:

//代码 3.3
package com.firstweb.study01;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html");
        PrintWriter out = resp.getWriter();
        String docType =
                "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0" +
                        "Transitional//EN\">\n";
        out.println(docType +
                "<HTML>\n" +
                "<HEAD><TITLE>Hello</TITLE><HEAD>\n" +
                "<BODY BGCOLOR=\"#FDF5E6\">\n" +
                "<H1>Hello</H1>\n" +
                "</BODY></HTML>");
    }
}

​ 图 3.3 :

在这里插入图片描述

​ 最后一步时合适生成的 HTML 中,不存在有可能会在不同的浏览器上引起不可预期结果的语法错误。参考 3.5 节中有关 HTML 验证其的论述。

3.4、Servlet 的打包:

​ 在产品开发过程中,多个程序员可能为同一服务器开发 Servlet。因此,将所有的 Servlet 放到同一目录中将会生成数目庞大且难以管理的类,如果两个开发人员为 Servlet 或使用工具类名时,不经意间选择了相同的名称,还会导致命名冲突。现在,通过 Web 应用,可以将内容划分到多个单独的目录中,每个目录都有自己的一套 Servlet、实用工具类、JSP 页面和 HTML 文件,避免了这个问题。然而,由于单个 Web 应用也可能比较庞大,因此,我们依旧需要采用 Java 中用以避免命名冲突的标准解决方案:包。

​ 在将 Servlet 放到包中,需要执行下面两个额外的步骤。

  1. 将文件放到与预定的包名匹配的子目录中。
  2. 在类文件中插入包语句。

3.5、简单的 HTML 构建工具:

​ 由于 HTML 文档的结构如下:

<!DOCTYPE ...>
<HTML>
    <HEAD><TITLE>...</TITLE>...</HEAD>
    <BODY ...>...</BODY>
</HTML>

​ 在使用 Servlet 构建 HTML 时,可能会略去这个结构的某个部分,尤其是 DOCTYPE 行,因为虽然 HTML 规范需要它,但几乎所有主流的浏览器都忽略它。我们极不赞成这种做法。DOCTYPE 行的长处是,它告诉 HTML 验证器您使用的是 HTML 的哪个版本,从而验证器知道应该按照哪种规范对文档进行检查。这些验证器对调试很有价值,能够帮助您捕获那些您的路i兰奇可以推测出来,但其他浏览器在显示时可能会有困难的 HTML 语法错误。

​ 毫无疑问,使用 println 语句生成 HTML 有些笨重,尤其是那些冗长乏味的行,如 DOCTYPE 声明。有些人编写很长的 HTML 生成使用工具程序,然后,在编写 Servlet 时使用这些实用工具程序,,以此来解决这个问题。我们对这类扩展库的有效性持怀疑态度。首先且最重要的是,变成生成 HTML 的不便是 JSP 解决的主要问题之一。其次,用来生成 HTML 的例程可能十分笨重,一般并不支持所有的 HTML 属性。

​ 标准 Servlet 中,Web 页面中的两部分内容(DOCTYPE 和 HEAD)一般不会发生变化,因而可以归结到一个简单的使用工具文件中。代码 3.5 就是这样一个文件,代码 3.6 列出 HelloServlet 类的又一个变体,它使用这个实用工具类。

//代码 3.5
package com.firstweb.study01;

public class ServletUtilities {
    public static final String DOCTYPE =
            "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 " + "\n" +
                    "Transitional//EN\">";
    public static String headWithTitle(String title){
        return (DOCTYPE + "\n" +
                "<HTML>\n" +
                "<HEAD><TITLE>" + title + "</TITLE><HEAD>\n");
    }
}
//代码 3.6
package com.firstweb.study01;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/hello")
public class HelloServlet3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html");
        PrintWriter out = resp.getWriter();
        String title = "hello3";
        out.println(ServletUtilities.headWithTitle(title) +
                "<BODY BGCOLOR=\"#FDF5E6\">\n" +
                "<H1>" + title + "</H1>\n" +
                "</BODY></HTML>");
    }
}

​ 编译完 HelloServlet3.java 之后(会导致自动编译 ServletUtilities.java),需要将这两个类文件移动到服务器默认部署位置(…/WEB-INF/classes)中,的相应的包中。最后结果如下图所示:

在这里插入图片描述

3.6、Servlet 的生命周期:

​ 服务器只创建每个 Servlet 的单一实例,每个用户请求都会引发新的线程——将用户请求交付给相应的 doGet 或 doPost 进行处理。

​ 首次创建 Servlet 时,它的 init 方法会得到调用,因此,init 是放置一次性设置代码的地方。在这之后,针对每个用户请求,都会创造一个线程,该线程调用前面创建的实例的 Servlet 方法。多个并发请求一般会导致多个线程同时调用 service。之后由 service 方法依据接收到的 HTTP 请求的类型,调用 doGet,doPost,或其他 doXxx方法。最后,如果服务器决定卸载某个 Servlet ,它会首先调用 Servlet 的 destroy 方法。

3.6.1、service 方法:

​ 服务器每次接收到对 Servlet 的请求,都会产生一个新的线程,调用 service 方法。service 方法检查 HTTP 请求的类型(GET,POST,PUT,DELETE等)并相应地调用 doGet,doPost,doPut,doDelete 等方法。

​ 如果需要在 Servlet 中等同地处理 POST 和 GET 请求,只需要让 doPost 调用 doGet 或者反过来即可,尽量别直接覆盖 service 方法。

​ 虽然这种方法要多出几行代码,但相对于直接覆盖 service ,它有几个有点。首先,之后还可以加入 doPut,doTrace等,支持其他的 HTTP 请求方法。直接覆盖 service 则排除了这种可能性。其次,还可以通过添加 getLastModified 方法,加入对修改日期的支持,由于 getLastModified 由默认的 service 方法调用,所以覆盖 service 方法也就失去了这个选项。最后,service 提供对 HEAD,OPTION 和 TRACE 请求的自动支持。

3.6.2、doGet,doPost 和 doXxx 方法:

​ 这些部分才是 Servlet 的主体。因此,可以覆盖 doGet 和 doPost。如果愿意,也可以覆盖 DELETE 请求的 doDelete、PUT 请求的 doPut 、OPTIONS 请求的 doOptions 以及 TRACE 请求的 doTrace。然而,要记住已经拥有对 OPTION 和 TRACE 的自动支持。

​ 一般情况下,不需要实现 doHead 以处理 HEAD 请求(HEAD 请求规定,服务器应该只返回正常的 HTTP 报头,不含与之相关联的文档)。由于系统会自动调用 doGet ,并用生成的状态行和报头设定来应答 HEAD 请求,故而,一般不需要实现 doHead 。有时,为了能够更快地生成对 HEAD 请求的响应,会实现 doHead 方法。

3.6.3、init 方法:

​ 大多数时候,Servlet 只需处理单个请求的数据,doGet 或 doPost 是生命周期中唯一需要的方法。然而,有时候希望在 Servlet 首次载入时,执行复杂的初始化任务,但并不想每个请求都重复这些任务。init 方法就是专门针对这种情况设计;它在 Servlet 初次创建时被调用,之后处理每个用户的请求时,则不再调用这个方法。因此,它主要用于一次性的初始化,和 applet 的 init 方法相同。Servlet 一般在用户首次调用对应的 Servlet 的 URL 时创建,但也可以指定 Servlet 在服务器启动后载入。

​ init 方法执行两种类型的初始化:常规初始化,以及由初始化参数控制的初始化。

  1. 常规初始化:

    init 只是创建或载入在 Servlet 声明周期内用到的一些数据,或者执行某些一次性的计算。

  2. 由初始化参数控制的初始化:

3.6.4、destroy 方法:

​ 服务器可能会决定移除之前载入的 Servlet 实例,或许因为服务器的管理员要求它这样做。但是,在服务器移除 Servlet 的实例之前,它会调用 Servlet 的 destroy 方法,从而使得 Servlet 有机会关闭数据库连接、停止后台的线程、将 Cookie 列表和点击计数写入到磁盘、并执行其他清理活动。但是,要意识到 Web 服务器有可能崩溃。因此,不要将 destroy 机制作为向磁盘上保存状态的唯一机制。如果服务器执行诸如点击计数,或对 Cookie 值的列表进行累加等活动,应该主动地定期将数据写到磁盘上。

3.7、SingleThreadModel 接口:

注:由于我缺少前置知识,所以这部分内容先临时跳过,借鉴我的博客内容学习的师傅可以去支持下这本书。

3.8、Servlet 的调试:

​ 如下,书中列出了一部分的调试技巧:

  1. 使用打印语句。
  2. 使用集成在 IDE 中的调试器。
  3. 使用日志文件。
  4. 使用 Apache Log4J。
  5. 编写独立类。
  6. 预先做好数据缺失或异常的准备。
  7. 检查 HTML 源代码。
  8. 单独检查请求数据。
  9. 单独检查响应数据。
  10. 停止和重启服务器。
    注:由于我缺少前置知识,所以这部分内容先临时跳过,借鉴我的博客内容学习的师傅可以去支持下这本书。

3.8、Servlet 的调试:

​ 如下,书中列出了一部分的调试技巧:

  1. 使用打印语句。
  2. 使用集成在 IDE 中的调试器。
  3. 使用日志文件。
  4. 使用 Apache Log4J。
  5. 编写独立类。
  6. 预先做好数据缺失或异常的准备。
  7. 检查 HTML 源代码。
  8. 单独检查请求数据。
  9. 单独检查响应数据。
  10. 停止和重启服务器。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/649001.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

QtXlsx库编译使用

文章目录 一、前言二、Windows编译使用2.1 用法①&#xff1a;QtXlsx作为Qt的附加模块2.1.1 检验是否安装Perl2.1.2 下载并解压QtXlsx源码2.1.3 MinGW 64-bit安装模块2.1.4 测试 2.2 用法②&#xff1a;直接使用源码 三、Linus编译使用3.1、安装Qt5开发软件包&#xff1a;qtbas…

翻译《The Old New Thing》- Why are INI files deprecated in favor of the registry?

Why are INI files deprecated in favor of the registry? - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20071126-00/?p24383 Raymond Chen 2007年11月26日 为什么弃用 INI 文件而改用注册表&#xff1f; 欢迎&#xff0c;Slashdot的读…

【再探】设计模式—职责链模式、命令模式及迭代器模式

行为型设计模式研究系统在运行时对象之间的交互&#xff0c;进一步明确对象的职责。有职责链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式及访问模式共11种。 1 职责链模式 需求&#xff1a;1) 请求能被多…

2024可信赖的企业级生成式 AI 白皮书

来源&#xff1a;COPU&IBM&#xff1a; 近期历史回顾&#xff1a;

[随笔] 在CSDN的6周年纪念日随笔

纪念 转眼已过6年&#xff0c;大一的时候学习编程&#xff0c;潜水 CSDN 学习各类博文&#xff0c;才学浅薄就没有主动写博文记录自己的学习历程。 过了段时间刚刚到了大二&#xff0c;很喜欢 Todolist&#xff0c;意气风发的写下《一份清爽的编程计划》&#xff0c;哈哈。 …

新浪测试社招要个25K,第一次面大厂挂了

一面 1、讲下被测系统和你负责测试的模块功能&#xff1f; 2、为什么选择这个测试框架&#xff0c;这个测试框架有什么优缺点&#xff1f; 3、测试文件的目录&#xff0c;包含哪些包&#xff0c;这些之间是怎么调用的&#xff1f; 4、UI自动化和接口自动化都是怎么做的&…

FFmpeg之转码

文章目录 概述transcode小结 概述 上一篇说了主要的流程&#xff0c;也就是ffmpeg_parse_options的流程&#xff0c;如下图&#xff1a; 红色箭头的流程说的差不多了&#xff0c;接下来看看绿色框框&#xff0c;也就是transcode的流程。 transcode 还是先给出我画的流程图&…

SPSS之因子分析

SPSS中因子分析功能在【分析】--【降维】--【因子分析】中完成&#xff08;在SPSS软件中&#xff0c;主成分分析与因子分析均在【因子分析】模块中完成&#xff09;。 因子分析的求解通常从分析原始变量的协方差矩阵或相关矩阵着手。 &#xff08;1&#xff09;当变量取值的度…

纯CSS丝滑边框线条动画

在这个网站&#xff08;minimal-portfolio-swart.vercel.app&#xff09;发现一个不错的交互效果&#xff0c;用户体验效果很不错。如封面图所示&#xff0c;这个卡片上有一根白色的线条围绕着卡片移动&#xff0c;且在线条的卡片内部跟随这一块模糊阴影&#xff0c;特别是在线…

无线麦克风哪个品牌音质最好,揭示麦克风什么牌子的音质效果好!

​随着科技的不断发展&#xff0c;无线领夹麦克风已经成为现代演讲、演出和采访中不可或缺的工具。这种小巧便携的设备&#xff0c;能够让我们摆脱线缆的束缚&#xff0c;自由地在舞台上或讲台上移动&#xff0c;同时保持声音的清晰和稳定。在这篇文章中&#xff0c;我们将介绍…

国产操作系统上telnet命令详解 _ 统信 _ 麒麟 _ 中科方德

原文链接&#xff1a;国产操作系统上telnet命令详解 | 统信 | 麒麟 | 中科方德 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇在国产操作系统上使用telnet命令的详细介绍文章。telnet是一个经典的网络协议和工具&#xff0c;广泛用于测试和管理远程服务器。本文将详…

低代码与人工智能:改变软件开发的未来

引言 在当今快速发展的科技时代&#xff0c;软件开发行业也在不断地创新和演进。其中&#xff0c;低代码开发和人工智能技术是两个备受关注的领域&#xff0c;低代码开发通过简化开发流程和降低编码难度&#xff0c;使得软件开发变得更加高效和便捷&#xff0c;而人工智能技术…

收放卷主从轴速度随动增益计算(CODESYS ST代码)

收放卷主从轴速度随动控制,我们需要知道随动增益,如果是利用电子齿轮实现速度随动,我们需要通过增益计算电子齿轮比的分子和分母,具体源代码大家可以参考下面文章链接: 收放卷伺服控制系统详细算法介绍(电子齿轮+张力PID卷绕轴控制功能块)_收放卷伺服控制属于-CSDN博客文…

一文教你如何调用Ascend C算子

Ascend C是CANN针对算子开发场景推出的编程语言&#xff0c;原生支持C和C标准规范&#xff0c;兼具开发效率和运行性能。基于Ascend C编写的算子程序&#xff0c;通过编译器编译和运行时调度&#xff0c;运行在昇腾AI处理器上。使用Ascend C&#xff0c;开发者可以基于昇腾AI硬…

Postman快捷功能-快速填写请求头

大家好&#xff0c;之前给大家分享关于 Postman 工具的基础使用&#xff0c;今天给大家介绍一个快捷功能&#xff0c;可以一定程度提高我们使用 Postman 工具的效率&#xff0c;在我们进行接口测试时&#xff0c;几乎每个接口都需要填写 Headers&#xff0c;且 Headers 中的参数…

MySQL--联合索引应用细节应用规范

目录 一、索引覆盖 1.完全覆盖 2.部分覆盖 3.不覆盖索引-where条件不包含联合索引的最左则不覆盖 二、MySQL8.0在索引中的新特性 1.不可见索引 2.倒序索引 三、索引自优化--索引的索引 四、Change Buffer 五、优化器算法 1.查询优化器算法 2.设置算法 3.索引下推 …

如何使用OutputStream类实现文件的读写操作?

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

如何提升项目经理的汇报能力?从这四点做起

项目经理不仅需要管理项目进度、预算和资源&#xff0c;更需要与各方进行有效的沟通&#xff0c;确保项目的顺利进行。而在所有沟通形式中&#xff0c;当众演讲无疑是难度最大的一种。 他们需要向团队成员传达项目的最新进展和要求&#xff0c;向领导和客户汇报工作成果&…

Java 定义类型处理MySQL point类型数据

1.三个类来处理 引入maven依赖 <!-- 引入 jts 库解析 POINT --><dependency><groupId>com.vividsolutions</groupId><artifactId>jts</artifactId><version>1.13</version></dependency>import javax.validation.constr…

推送邮件接口设置的方法?邮件接口的作用?

推送邮件接口如何与现有系统集成&#xff1f;怎么调试邮件接口&#xff1f; 通过推送邮件接口&#xff0c;应用程序可以自动向用户发送邮件通知&#xff0c;提醒他们重要事件或更新。AokSend将介绍如何设置推送邮件接口&#xff0c;以便您的应用程序能够充分利用这一功能。 推…