后端(二):Servlet

我们上一张聊的是Tomcat,它其实就是一个 HTTP 服务器,而Servlet 是基于 Tomcat 的  原生api ,除了 Servlet,后面还有聊到很多 api 。

 Servlet 是什么

Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。

我们先来稍稍了解以下Servlet 的运行原理;

Servlet运行原理

我们说 Servlet 是基于 Tomcat 的,那么Servlet 也要实现 服务器的功能。

当Web服务器接收到一个HTTP请求时,它会先判断请求内容——如果是静态网页数据,Web服务器将会自行处理,然后产生响应信息;如果牵扯到动态的数据,Web服务器会将请求转交给Servlet容器。此时Servlet容器会找到对应的处理该请求的Servlet实例来处理,结果会送回Web服务器,再由Web服务器传回用户端。

针对同一个Servlet,Servlet容器会在第一次收到http请求时建立一个Servlet实例,然后启动一个线程。第二次收到http请求时,Servlet容器无须建立相同的Servlet实例,而是启动第二个线程来服务客户端请求。所以多线程方式不但可以提高Web应用程序的执行效率,也可以降低Web服务器的系统负担。

上述来自:理解Servlet工作原理 - 简书 (jianshu.com)

从上述该原理可知,Servlet 并非一个单独执行的程序,而是写一个代码片段,穿插在 Tomcat 中。

上节课我们只是看到了部署的效果图,那么这里将会介绍servlet 是如何穿插在 Tomcat 中的。

创建第一个Servlet 项目

我们主要分七步走:

1. 创建一个项目

这里创建一个 Maven 项目 JDK 是1.8 的。

创建好之后,有这个 pom.xml;

第一次创建好右下角应该会有一个提示:

Maven projects need to be imported

Import Changed      Import Auto-import

选后面一个就好

2. 引入依赖

上面的 pom.xml 作用就是依赖存放的位置。

Maven Repository: Search/Browse/Explore (mvnrepository.com)

上面的网站是 Maven 中央仓库,我们所需要的依赖一般都来自这里。

我们在 Maven 中央仓库搜索自己需要引入的依赖,例如需要下载 Servlet 的依赖:

往下一拉,哇!这么多,我们需要找于自己版本相匹配的, 小版本无所谓,我们选择下载人数最多的就好。

 点进去之后,将这一段复制下来就好了。

回到 pom.xml 中,我们需要加一个标签:

<dependencies> </ dependencies> 这就是依赖存放的位置。

只需要一个 这个双标签就好,这个双标签内可以放置多个依赖。

第一次可能会爆红,那可能是因为没有下载下来,为了确保它下载到了本地我们给它强制刷新以下:

如何还爆红,那么需要查看以下你的配置是否正确,将你安装的Maven 位置重新配置到 idea 上一般就解决问题了。

这个依赖我们目前就这样,其他的先不关注,等后面遇到一个再说一个。

3. 创建目录

当项目创建好了之后, IDEA 会帮我们自动创建出一些目录.:

这些目录中:

  • src 表示源代码所在的目录
  • main/java 表示源代码的根目录. 后续创建 .java 文件就放到这个目录中.
  • main/resources 表示项目的一些资源文件所在的目录. 此处暂时不关注.
  • test/java 表示测试代码的根目录. 此处暂时不关注

当然,只有这些目录还是不够滴,我们还需要创建一些新的目录/文件。

我们先需要一个 webapp 文件,在这个文件下再创建一个 WEB-INF 文件,再在WEB-INF 中创建一个 web.xml 文件。

如下图:

 WebApp 文件夹是一个专门为 Web 应用程序准备的文件夹,其中包含所有必要的文件和文件夹,以便在服务器上运行和托管 Web 应用程序;

WEB-INF 这个文件代表着目前项目的的结构。

这也是必须要这么写的(具体为啥,我暂时也不知道)。先这样写着,具体为啥,后面学到肯定是有的,到时候再说。

这里 web.xml 文件中需要添加以下内容:

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>Archetype Created Web Application</display-name>
</web-app>

我们把这段内容之间复制上去就好了。

4. 编写代码

我们的重点来了,我们之前不是需要引入依赖嘛,我们就是需要依赖中 提供的各个 api 。

而我们引入的 servlet 依赖,就包含了 HttpServlet 这个类。

还记得之前学习的网络编程那一块嘛?

我们这里重写了一个 doGet 方法,就是来处理 从客户端发送过来的请求, 这里提供的参数 req 就代表这请求,resp 就代表的响应。

这里是没有main 方法的,至于为什么,就回去看看之前网络编程那一块内容。

 回到 doGet 方法中,它默认就调用了 父类的doGet 方法,我们也可以点开看看 父类的 doGet 方法做了什么事情:

为了让,doGet 方法 执行我们自己编写的代码,所以我们要将这句 删掉,否则就会报错。

我们这里就随便写写,没有逻辑,主要是为了展示:

这个编写内容到这里就完了,Tomcat 内部会按照 HttpServlet 的引用方式调用 doGet 方法,

由于现在创建了这个子类,在 Tomcat 中大概率会形成如下代码:

HttpServlet servlet = new HttpServlet();
servlet.doGet(req, resp);

 具体的 Tomcat 源码我也不知道,以后有机会等我把源码看看,会再写一篇博客,讲讲这个。

虽然说,代码是写完了,我们是认识了这写代码,但是浏览器还不认识啊,我们得给它加上一个 Servlet path ,这个 路径马上就会提到了,马上就会认识了。

怎么加呢?如下图: 

我们这里参考参考人家的博客了解以下Servlet 的注解:

@WebServlet注解(Servlet注解) (biancheng.net)

5. 打包

我们这里的代码并不能直接运行,必须放到 Tomcat 中才可以运行(这一步就是部署)。

部署的前提就是要打包;

对于一个项目,都不会只有一个 .java 文件,进一步就会产生很多 .clsass 文件,此时将这些 .class 文件打成一个压缩包在进行拷贝就很有必要了。

我们有一些常见的 压缩包: 以 .zip 、 .rar 为后缀。

Java中 常见的有两个:.jar 、 .war

jar 包就是普通的 Java程序打包出来的,而 war 包是专门为 Tomcat 部署 定制的。

jar 包 和 war 包 其实本质上没有区别,都是把一堆 .class 文件打包进去,但是 war 包是属于 tomcat 格式的;里面会带有特定的目录格式和文件,例如:web.xml

后续 tomcat 要识别这些内容加载 webapp 

来看看如何打包:

1. 先在 pom.xml 文件中添加两个标签:

<packaging>war</packaging>
<build>
    <finalName>HelloWorld</finalName>
</build>

含义如下:

 2.   打包

我们先单击 右边的 Maven 找到你要打包的目录,双击package ,就可以打包了;如果出了啥问题,我们可以将问题拷贝下来去搜索,一般都是需要添加几条命令就解决了(都很简单)。

打包成功,就会出现上图,我们需要将这个 war 包 copy 到tomcat 上:

 

将war 包拷贝到该目录下。

6. 部署

这一步很简单,前面没问题的话,这一步就不会有问题。

我们直接运行 tomcat 服务器,tomcat 会自动解析 war 包。

他就成功解析出了这个文件。

7. 验证程序

 为了确保其他主机可以访问,我们先用自己的主机访问一次:

我们上述中的localhost 其实也就是 127.0.0.1 地址,这个叫做环回地址,表示就是你的主机地址(将其改为 127.0.0.1 也可以访问到);我的tomcat 也是部署在本机上的, 所以可以访问到这个网站,如果需要让其他主机访问到有两种情况:

  1. 同一个局域网中,可以在 Windows 命令提示符(即 cmd)中输入:ipconfig 找到自己在局域网下的 ip 地址。
  2. 不在同一个局域网下,那就必须得拿到你的外网 ip 地址,我们之前说到过,外网地址是无法直接访问内网地址的。

所以,如果遇到 404 不要慌

  1. 先查看自己的 地址是否写对了,
  2. 这里没问题,在就查看你的配置是否出了问题,
  3. 都没问题再看看你的操作是否出了问题,文件太多太杂的话,建议重新开一个空白的文件夹,重写。

我们上述讲到的都是一个项目的大致流程,并没有讲到 Servlet 的api,上面只是用到了一个 HttpServlet,接下来讲讲Servlet 的原生 api。

Servlet 的原生 api

HttpServlet

我们写的都是继承自 HttpServlet 这个类的,如上例题: 

我们需要知道,哪些方法是能够被重写的,也就是 HttpServlet 中都有哪些方法,方法的作用是干啥的。

init在 HttpServlet 实例化之后被调用一次
destory  在 HttpServlet 实例不再使用的时候调用一次收到 HTTP 请求的时候调用
service  收到 GET 请求的时候调用(由 service 方法调用)
doGet收到 GET 请求的时候调用(由 service 方法调用)
doPost收到 POST 请求的时候调用(由 service 方法调用)
doPut/doDelete/doOptions/...收到其他请求的时候调用(由 service 方法调用)
  • init 方法:在 HttpServlet 实例化之后被调用一次,使用这个方法来初始化相关工作;只有在首次收到请求的时候会出发,如果服务器没有重启,就不会再触发这个方法
  • destory 方法:  这个方法是该 webapp 被销毁(卸载之前)执行一次,用来处理一些收尾工作。一般来说,都不怎么使用这个方法,我们的 tomcat 端口 有两个;
  1. 8080 端口 叫做业务端口,8005 端口叫做管理窗口;
  2. 如果是通过 8005 这个管理窗口来关闭服务器,那么能执行destory 方法
  3. 如果我们采用直接杀死进程的方法来关闭服务器,那么就不会触发destory 方法
  • service  方法:每次收到路径匹配的请求,就会执行
  • doGet /  doPost 其实实在 service 中被调用的,一般不会重写 service ,只是重写 doXXX 方法就行了。

这里也是个面试题:Servlet 的生命周期

  1. init() 方法

  2. service() 方法 (这里包括了 doGet()和 doPost() 两个方法)

  3. destroy() 方法

在这里插入图片描述

这个图片是我抄的。

 其实学完了  doGet()和 doPost() 两个方法 HttpServlet 类就基本可以结束了。

HttpServletRequest

当 Tomcat 通过 Socket API 读取 HTTP 请求(字符串), 并且按照 HTTP 协议的格式把字符串解析成
HttpServletRequest 对象。

核心方法如下:

方法描述
String getProtocol()返回请求协议的名称和版本。
String getMethod()返回请求的 HTTP 方法的名称,例如,GET、POST 或 PUT。
String getRequestURI()从协议名称直到 HTTP 请求的第一行的查询字符串中,返回该请
求的 URL 的一部分。
String getContextPath()返回指示请求上下文的请求 URI 部分。
String getQueryString()返回包含在路径后的请求 URL 中的查询字符串。
Enumeration
getParameterNames()
返回一个 String 对象的枚举,包含在该请求中包含的参数的名
称。
String getParameter(String
name)
以字符串形式返回请求参数的值,或者如果参数不存在则返回
null。
String[]
getParameterValues(String
name)
返回一个字符串对象的数组,包含所有给定的请求参数的值,如
果参数不存在则返回 null。
Enumeration
getHeaderNames()
返回一个枚举,包含在该请求中包含的所有的头名。
String getHeader(String
name)
以字符串形式返回指定的请求头的值。
String
getCharacterEncoding()
返回请求主体中使用的字符编码的名称。
String getContentType()返回请求主体的 MIME 类型,如果不知道类型则返回 null。
int getContentLength()以字节为单位返回请求主体的长度,并提供输入流,或者如果长
度未知则返回 -1。
InputStream
getInputStream()
用于读取请求的 body 内容. 返回一个 InputStream 对象

这里的方法我就不一一演示了,我们来挑选几个最重要的来看看就好。

 

 

getParameter  方法

在本章中,我们重点介绍 getParameter 这个方法。

以字符串形式返回请求参数的值,或者如果参数不存在则返回 null。

为什么这里它作为重点呢?

我们要做网站,前后端之间的交互是非常重要的,而 getParameter 方法,就是 后端用来接收前端传递的数据。

前端在给后端传递数据 经常以如下几种方式传递:

  1. 通过 query string 传递
  2. 通过 body(form 表单) 传递
  3. 通过 body(json 这个常用)传递

通过 query string 传递

前后端在交互之前都需要相互约定,彼此用的是什么格式,相关程序员就知道后面具体该用哪个 api 已经知道需要怎么转换。

比如约定好 前端使用 query string 传递 账号密码,这个 query string 中的键值对都是程序员自定义的。

通过 body 传递(form)

相当于 body 里存储的数据格式,就和 query string 一样,但是 Content-type 是 application/x-www-form-urlencoded 这样的格式。

如果是这样的格式,此时也是通过 getParameter 来获取键值对了。

这里没有具体的栗子讲的可能不是很清楚,先将就将就,后面正式写项目再去补充。

通过 body 传递(json)

这个是咱的重点,在项目的时候,用的最多的就是这小子。

假设,前端发送了一个登录请求,可以通过抓包看看发送的请求

这里我们可以看到发送的账号和密码。

json 也是个键值对格式的数据,但是 Servlet 自身没有内置 json 解析功能,此时就需要借助第三方库(可以去Maven 中央仓库搜索一下)。

这个第三方库有很多,常见的有这几种:

fastjson、gson、jackson(这个属于spring官方指定库)。

这里就稍稍看个栗子就好了,后面会有具体的代码,到了再具体介绍。

假设左上角是请求的 body ,右下脚是我们约定的类,此时我们需要调用 objectMapper 这个方法下的 readValue 这个方法,对前端传输来的请求进行解析。

 这里 readValue 要做的事情:

  1. 解析 json 字符串,将其转化为若干个 键值对。
  2. 第二个参数 User.class 就是反射,拿到前后端之间约定的格式,然后依次为 蓝本 ,进行拆分 键值对,获取需要的信息。
  3. 遍历属性,根据属性的名字,去上述准备好的键值对里(可以通过反射来完成),查询,看看这个属性的名字是否存在对应的 value ,如果存在,九八 value 复制到该属性中。

HttpServletRequest 使用这个类,主要就是用于获取到请求各个方面的信息,尤其是前端传过来的 自定义 数据。

HttpServletResponse

方法描述
void setStatus(int sc)为该响应设置状态码。
void setHeader(String name,
String value)
设置一个带有给定的名称和值的 header. 如果 name 已经存在,
则覆盖旧的值.
void addHeader(String
name, String value)
添加一个带有给定的名称和值的 header. 如果 name 已经存在,
不覆盖旧的值, 并列添加新的键值对
void setContentType(String
type)
设置被发送到客户端的响应的内容类型。
void
setCharacterEncoding(String
charset)
设置被发送到客户端的响应的字符编码(MIME 字符集)例如,
UTF-8。
void sendRedirect(String
location)
使用指定的重定向位置 URL 发送临时重定向响应到客户端。
PrintWriter getWriter()用于往 body 中写入文本格式数据.
OutputStream
getOutputStream()
用于往 body 中写入二进制格式数据.

这里也不过多介绍了,看名字大概都能猜到是啥意思。

其实这个 api 也就这样,没啥难的,学会上面的一个,另外两个都是触类旁通的,后面的 sping 等等,也就这样,没听过名字听起来就好高大上,学完了 Servlet 也就这么回事,到时候多写写也就熟悉了。

纸上得来终觉浅 绝知此事要躬行。

继续加油吧!!!

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

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

相关文章

动态规划算法(多状态dp1)

动态规划算法专辑之多状态dp问题&#xff08;1&#xff09; 一、什么是多状态 多状态dp问题&#xff0c;指一个规模问题下存在多种状态&#xff0c;我们需要联合关注多种状态间的相互转移&#xff0c;才可以求解目的问题。 多状态问题可以理解为有限状态机&#xff0c;在有限…

centos 7 安装git并配置ssh

一、安装 1、查看是否安装git <span style"color:#333333"><span style"background-color:#ffffff"><code class"language-perl">rpm -qa|<span style"color:#0000ff">grep</span> git </code>…

边缘检测笔记

边缘是什么&#xff1f; 图像的边缘是指图像局部区域中亮度变化明显的部分&#xff0c;边缘位于像素的灰度值产生突变的地方。 边缘的正负之分&#xff1a;由暗到亮为正&#xff0c;由亮变暗为负。 图像的高频信号和低频信号 简单理解为&#xff0c;图像中高频分量&#xff08…

mcu:利用Cortex-M中的DWT实现高精度计时

1、Cortex-M中的DWT 在Cortex-M里面有一个外设叫DWT(Data Watchpoint and Trace)&#xff0c;是用于系统调试及跟踪。 它有一个32位的寄存器叫CYCCNT&#xff0c;它是一个向上的计数器&#xff0c;记录的是内核时钟运行的个数&#xff0c;内核时钟跳动一次&#xff0c;该计数器…

YOLOV5 训练

YOLOV5训练过程 CUDA 和cuDnnan 安装教程 windows上安装可以参考这篇知乎文章 数据集准备 自己准备数据集 可以使用 labelImg 工具&#xff0c;直接 pip install labelimg 就可以安装了。 命令行中输入 labelImg 就可以运行 标注数据的输出结果有多种过格式&#xff0c;V…

前端什么最难学?

前言 个人认为是JS&#xff0c;无论是在平时的项目或者找工作时候JS都是大头&#xff0c;相比起其他的部分&#xff0c;它相对而言是难一点&#xff0c;同时也是十分重要的一部分&#xff0c;学好原生JS&#xff0c;后续的学习才能基于此循序渐进&#xff0c;下面是我总结的关…

GIT学习笔记

团队使用GIT有些时间了&#xff0c;也遇到一些问题&#xff1a; 遇到大量冲突&#xff0c;解决完之后&#xff0c;没有修改的代码也变成蓝色了&#xff0c;如果不push&#xff0c;代码将会丢失代码丢失&#xff08;具体情况&#xff0c;我暂时记不清了&#xff09;git push失败…

数据库入门下篇(如何安装和登录MYSQL数据库)

在这篇文章里&#xff0c;笔者将着重讲解如何在win和Linux系统上安装自己的MySQL数据库软件&#xff0c;以及安装好数据库软件后如何启动和登录&#xff0c;忘了密码怎么办&#xff1f;如何创建一个数据库&#xff0c;如何在数据库中创建一个表等内容 目录 在windows系统上安装…

HNU计算机体系结构-实验一:RISC-V指令理解

HNU计算机体系结构-实验一 前言1.实验目的2.实验步骤1.安装模拟器Ripes2.生成汇编指令3.思考问题1&#xff09;指令add x15, x14, x152&#xff09;指令bge x15 x14 -683&#xff09;指令lw x15, -20 x84&#xff09;指令sw x15, -20 x85&#xff09;简述BranchE信号的作用6&am…

中级前端笔试面试题总结

typeof null 的结果是什么&#xff0c;为什么&#xff1f; typeof null 的结果是Object。 在 JavaScript 第一个版本中&#xff0c;所有值都存储在 32 位的单元中&#xff0c;每个单元包含一个小的 类型标签(1-3 bits) 以及当前要存储值的真实数据。类型标签存储在每个单元的…

(浙大陈越版)数据结构 第三章 树(中) 二叉搜索树和平衡二叉树

目录 4.1.1 二叉搜索树及查找 什么是二叉搜索树 定义 二叉搜索树特殊函数集&#xff1a; 查找操作&#xff1a;Find 算法思想 代码实现 补&#xff1a;查找最大和最小元素 4.1.2 二叉搜索树的插入 插入操作&#xff1a;Insert 算法思想 代码实现 例题 4.1.3 二叉…

吴恩达老师《机器学习》课后习题1之线性回归

在学习这些内容之前&#xff0c;需要学习python数据分析相关内容&#xff1a; numpy&#xff1a;科学计算库&#xff0c;处理多维数组&#xff0c;进行数据分析 pandas&#xff1a;基于numpy的一种工具&#xff0c;该工具是为了解决数据分析任务而创建的 matplotlib&#xff1a…

如何进行微服务测试?

微服务测试是一种特殊的测试类型&#xff0c;因为它涉及到多个独立的服务。以下是进行微服务测试的一般性步骤&#xff1a; 1. 确定系统架构 了解微服务架构对成功测试至关重要。确定每个微服务的职责、接口、依赖项和通信方式。了解这些信息可以帮助您更好地规划测试用例和测…

Aop详解

AOP简介 AOP是一种编程思想&#xff0c;就如同面向对象这种编程思想一样&#xff0c;是一种编程范式&#xff0c;用来指导开发者如何组织程序更好的运行 AOP&#xff08;面向切面编程&#xff09; 作用&#xff1a;在不改变原代码的前提下&#xff0c;为其增加功能。 连接点…

Apikit 自学日记:导入第三方产品 API 数据

除了手动创建API文档&#xff0c;系统也提供了一键导入 Swagger、Postman、RAP、YAPI 等产品数据的功能。方便从其他平台进行迁移。 产品支持度导入文件的后缀名Eolinker API 研发管理完全支持.jsonPostman V2.1支持导入API基础信息&#xff0c;超过10级分组的API数据将不会被导…

git在windows及linux(源码编译)环境下安装

git在windows及linux(源码编译)环境下安装 环境信息: 系统版本:CentOS Linux release 7.9.2009 (Core) git指令安装: yum install -y git 一、git在windows下安装 下载地址:https://git-scm.com/ 默认安装即可 验证 git --version 二、git在linux下安装 下载地址…

游戏场景的转换——状态模式

状态模式 游戏比较复杂时&#xff0c;通常会设计成多个场景。 切换场景的好处 1、重复使用场景 跳转切换场景的代码有两种一种是旧版的方法 Application.LoadLevel(“SampleScene”);另一种是新版的方法 SceneManager.LoadScene(“SampleScene”); 例子1&#xff1a;通过场景…

【QT】TCP/UDP详解及实现

TCP/UDP TCP/IP模型TCP协议头部格式三次握手四次挥手 UDP协议头部格式 Socket编程tcpudp代码实现服务端&#xff1a;客户端&#xff1a; 总结 TCP/IP模型 TCP模型是一个常见的网络协议参考模型&#xff0c;也称为TCP/IP模型或互联网模型。它是指TCP/IP协议族中的一组协议&…

Creating Add-in Hooks (C#)

本文介绍如何使一个文件在添加、检入、检出到库时&#xff0c;让add-in 程序在SOLIDWORKS PDM Professional 中通知到你。 注意&#xff1a; 因为 SOLIDWORKS PDM Professional 无法强制重新加载Add-in程序 &#xff0c;必须重新启动所有客户端计算机&#xff0c;以确保使用最…

【Python开发】FastAPI 09:middleware 中间件及跨域

FastAPI 提供了一些中间件来增强它的功能&#xff0c;类似于 Spring 的切面编程&#xff0c;中间件可以在请求处理前或处理后执行一些操作&#xff0c;例如记录日志、添加请求头、鉴权等&#xff0c;跨域也是 FastAPI 中间件的一部分。 目录 1 中间件 1.1 创建中间件 1.2 使…