后端(二):Servlet

news2025/2/13 12:46:37

我们上一张聊的是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 也就这么回事,到时候多写写也就熟悉了。

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

继续加油吧!!!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【知识点复习】结构体与共用体

结构体和共用体各有什么特点&#xff1a; 1、结构体中每一个成员都有自己的内存空间&#xff0c;计算结构体大小的时候要注意内部字节对齐&#xff1b; 32位占4字节&#xff0c;64位占8字节。 结构体访问成员&#xff1a;点降级访问 2、共用体又叫联合体union&#xff0c;每一…

我的256创作纪念日

机缘 挺开心的&#xff0c;想到自己未曾写过一些非技术类的博客&#xff0c;恰巧今天刚好也是我的256创作纪念日&#xff0c;就乘着这个日子&#xff0c;写一点自己过去的收获、内心的想法和对未来的展望吧。 本人不才&#xff0c;只就读于一所民办本科之中&#xff0c;我挺不想…

ASCON:以“慢而稳”赢得NIST轻量级加密算法标准

1. 引言 自2016年以来&#xff0c;NIST一直在评估轻量级加密方法&#xff0c;并于2022年发布了入围决赛的10种轻量级加密算法&#xff1a; ASCONElephantGIFT-COFBGrain128 AEADISAPPhoton BeetleRomulusSparkleTinyJambuXoodyak 在评估过程中&#xff0c;NIST重点关注&#…

使用Python把文件夹里面的图片放入一个pdf

文章目录 背景介绍代码代码分析展示 背景介绍 在看一位up主的“矩阵分析”课程的时候&#xff0c;up主的课件是以图片形式保存在QQ空间的。图片形式不便于学习&#xff0c;所以想要通过Python代码&#xff0c;把保存在“矩阵分析课件”里面的图片&#xff0c;转换为pdf&#x…

Qt函数运用

setwidget 文件 文件读写 链接 std::ifstream---std::ofstream 头文件--#include <fstream> 执行都是类&#xff0c;用这些类操作文件都要建立对象流。 1&#xff0c;建立对象流 流对象的建立有两种方式&#xff1a; &#xff08;1&#xff09;使用fstream类可以…

内网安全:Socks 代理 || 本地代理 技术.

内网安全&#xff1a;Socks 代理 || 本地代理 技术. Socks 代理又称全能代理&#xff0c;就像有很多跳线的转接板&#xff0c;它只是简单地将一端的系统连接到另外一端。支持多种协议&#xff0c;包括http、ftp请求及其它类型的请求。它分socks 4 和socks 5两种类型&#xff0…

Selenium中的隐式等待和显式等待

在Selenium中&#xff0c;“等待”在执行测试中起着重要作用。在本文中&#xff0c;您将学习Selenium中“隐式”和“显式”等待的各个方面。 在本文中&#xff0c;您将学习到 1. 为什么我们需要在selenium中等待&#xff1f; 2. 隐瞒等待 3. 明确等待 4. 流利的等待 为什么…

15.DIY可视化-拖拽设计1天搞定主流小程序-分类联动文章列表实时刷新

分类联动文章列表实时刷新 本教程均在第一节中项目启动下操作 分类联动文章列表实时刷新前言需求一:功能实现:点击首页分类,对应分类内容显示到当前页一、清空原分类界面:二. 设置选项卡三:设定展示内容字段:1.跨页面复制:文章分类组件到分类![在这里插入图片描述](https://img…

服务器安装cuda版本的pytorch+DGL

1、先创建pytorch环境&#xff1a;conda create -n ljj_torch112 python3.8 看本机的&#xff1a; 先看自己的cuda版本&#xff1a;&#xff08;最权威的看&#xff1a;nvcc --version&#xff09; 10.0的cuda于是不太符合&#xff0c;所以换一个10.2的cuda比较常用&#xff0…

【C++从入门到放弃】list深度剖析及模拟实现

&#x1f9d1;‍&#x1f4bb;作者&#xff1a; 情话0.0 &#x1f4dd;专栏&#xff1a;《C从入门到放弃》 &#x1f466;个人简介&#xff1a;一名双非编程菜鸟&#xff0c;在这里分享自己的编程学习笔记&#xff0c;欢迎大家的指正与点赞&#xff0c;谢谢&#xff01; list …

CANN黑科技解密|昇腾Ascend C编程语言 — 极简易用的算子开发体验

AI应用的大脑是神经网络&#xff0c;而构成神经网络的基石是一个个算子。为了让开发者的网络在昇腾硬件上高效运行&#xff0c;昇腾异构计算架构CANN&#xff08;Compute Architecture for Neural Networks&#xff09;提供了丰富的高性能算子库&#xff0c;包括神经网络库、线…

Python-opcua 编程(1)

任何一项新标准如果不能充分应用是不可能推广的&#xff0c;最近看了一些国外网站&#xff0c;发现类似OPC UA 的应用以及比较广泛了&#xff0c;而且有许多课程。相比之下&#xff0c;我国OPCUA 标准的普及工作仍然停留在概述的阶段&#xff0c;为此&#xff0c;我将逐步介绍一…

复习并发编程的基础知识(一)

时间长了&#xff0c;并发编程的基础知识总忘&#xff0c;来记录一下&#xff1a; 进程和线程 进程&#xff1a;资源分配的最小单元&#xff0c;什么是资源&#xff1f;CPU&#xff0c;内存&#xff0c;网卡等等 线程&#xff1a;进程中的一个实体&#xff0c;不能单独存在&…

七、DMSP/OLS、NPP/VIIRS等夜间灯光数据能源碳排放空间化——能源碳排放增长类型、增长率、总量增长等级分析

一、前言 前文对能源碳排放空间化后的分析角度做了一些介绍,其实无非就是能源碳排放增长类型、增长率等的计算,那么这里强调一下,这个时候不能用利用统计数据计算出来的能源碳排放数据进行计算,而是必须用反演的能源碳排放数据进行划定计算。 二、具体步骤 增长类型 (…

【Excel超实用快捷键!!!办公效率1000%up!up!up!】

目录索引 ctrle&#xff1a;提取数据&#xff1a;合并数据&#xff1a; 普通快捷键&#xff1a;ctrla&#xff1a;ctrlc&#xff1a;ctrlv&#xff1a;ctrlx&#xff1a;ctrlz&#xff1a;ctrly&#xff1a;ctrls&#xff1a;ctrlf&#xff1a; 文字格式快捷键&#xff1a;ctrl…

IMX6ULL裸机篇之SPI实验-SPI主控寄存器

一. SPI主控寄存器 IMX6ULL 芯片的 SPI接口叫做 ECSPI&#xff0c;支持全双工、主丛可配置。 本文学习 IMX6ULL-阿尔法开发板SPI中控芯片的 SPI寄存器部分。后续代码实现需要配置 SPI相关的寄存器。 二. SPI主控的寄存器配置 1. SPI主控芯片寄存器 (1) RXDATA寄存器&am…

DVWA-Command Injection

大约 命令注入攻击的目的是在易受攻击的应用程序中注入和执行攻击者指定的命令。 在这种情况下&#xff0c;执行不需要的系统命令的应用程序就像一个伪系统外壳&#xff0c;攻击者可能会使用它 作为任何授权的系统用户。但是&#xff0c;命令的执行权限和环境与 Web 服务具有的…

【MySQL】创建和管理表

创建和管理表 标识符命名规则MySQL中的数据类型创建和管理数据库使用数据库修改数据库 创建表语法方式一方式二 修改表向表中追加一个列修改一个列重命名一个列删除一个列 重命名表方式一方式2; 删除表清空表 存储数据是处理数据的第一步 。只有正确地把数据存储起来&#xff0…

基于卫星星历计算卫星在CGCS2000大地坐标系中的坐标

目录 一、北斗系统概述 1.空间星座 2.坐标系统 3.时间系统 二、实验目的 三、实验内容 四、实验过程 五、实验结果 一、北斗系统概述 1.空间星座 北斗卫星导航系统简称北斗系统&#xff0c;英文缩写为 BDS&#xff0c;其空间星座由 5 颗地球静止轨道&#xff08;GEO&…

​“前端已死”甚嚣尘上,全栈工程师卷到起飞

海量应届生入场&#xff0c;坑位却还是那多。具备前后端开发能力的全栈工程师兴起&#xff0c;不仅能够开发前端&#xff0c;还能够处理后端业务逻辑和数据库等技术&#xff0c;还能掌握整个软件开发的细节。企业自然会更愿意招聘全栈工程师&#xff0c;说白了&#xff0c;卷啊…