Servlet-01
文章目录
- Servlet
- 创建Servlet
- 探究Servlet的生命周期
- HttpServlet
- @WebServlet注解详解
- 重定向与请求转发
- ServletContext
- ServletContext中的接口
- HttpServletRequest
- HttpServletResponse
- 状态码解释
- Cookie
Servlet
Q:它能做什么呢?
A:我们可以通过实现Servlet来进行动态网页响应,使用Servlet,不再是直接由Tomcat服务器发送我们编写好的静态网页内容(HTML文件),而是由我们通过Java代码进行动态拼接的结果,它能够很好地实现动态网页的返回。
当然,Servlet并不是专用于HTTP协议通信,也可以用于其他的通信,但是一般都是用于HTTP。
创建Servlet
我们只需要实现Servlet类即可,并添加注解@WebServlet来进行注册。
@WebServlet("/test")
public class TestServlet implements Servlet {...实现接口方法
}
除了直接编写一个类,我们也可以在web.xml中进行注册,现将类上@WebServlet的注解去掉:
<servlet><servlet-name>test</servlet-name><servlet-class>com.example.webtest.TestServlet</servlet-class>
</servlet>
<servlet-mapping><servlet-name>test</servlet-name><url-pattern>/test</url-pattern>
</servlet-mapping>
这样的方式也能注册Servlet
实际上,Tomcat服务器会为我们提供一些默认的Servlet,也就是说在服务器启动后,即使我们什么都不编写,Tomcat也自带了几个默认的Servlet,他们编写在conf目录下的web.xml中:
<!-- The mapping for the default servlet --><servlet-mapping><servlet-name>default</servlet-name><url-pattern>/</url-pattern></servlet-mapping><!-- The mappings for the JSP servlet --><servlet-mapping><servlet-name>jsp</servlet-name><url-pattern>*.jsp</url-pattern><url-pattern>*.jspx</url-pattern></servlet-mapping>
我们发现,默认的Servlet实际上可以帮助我们去访问一些静态资源,这也是为什么我们启动Tomcat服务器之后,能够直接访问webapp目录下的静态页面。
探究Servlet的生命周期
Q:一个Servlet是如何运行的。
A:首先我们需要了解,Servlet中的方法各自是在什么时候被调用的,我们先编写一个打印语句来看看:
public class TestServlet implements Servlet {public TestServlet(){System.out.println("我是构造方法!");}@Overridepublic void init(ServletConfig servletConfig) throws ServletException {System.out.println("我是init");}@Overridepublic ServletConfig getServletConfig() {System.out.println("我是getServletConfig");return null;}@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {System.out.println("我是service");}@Overridepublic String getServletInfo() {System.out.println("我是getServletInfo");return null;}@Overridepublic void destroy() {System.out.println("我是destroy");}
}
我们首先启动一次服务器,然后访问我们定义的页面,然后再关闭服务器,得到如下的顺序:
我是构造方法!
我是init
我是service
我是service(出现两次是因为浏览器请求了2次,是因为有一次是请求favicon.ico,浏览器通病)我是destroy
我们可以多次尝试去访问此页面,但是init和构造方法只会执行一次,而每次访问都会执行的是service方法,因此,一个Servlet的生命周期为:
- 首先执行构造方法完成 Servlet 初始化
- Servlet 初始化后调用 init () 方法。
- Servlet 调用 service() 方法来处理客户端的请求。
- Servlet 销毁前调用 destroy() 方法。
- 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
现在我们发现,实际上在Web应用程序运行时,每当浏览器向服务器发起一个请求时,都会创建一个线程执行一次service方法,来让我们处理用户的请求,并将结果响应给用户。
我们发现service方法中,还有两个参数,ServletRequest和ServletResponse,实际上,用户发起的HTTP请求,就被Tomcat服务器封装为了一个ServletRequest对象,我们得到是其实是Tomcat服务器帮助我们创建的一个实现类,HTTP请求报文中的所有内容,都可以从ServletRequest对象中获取,同理,ServletResponse就是我们需要返回给浏览器的HTTP响应报文实体类封装。
那么我们来看看ServletRequest中有哪些内容,我们可以获取请求的一些信息:
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {//首先将其转换为HttpServletRequest(继承自ServletRequest,一般是此接口实现)HttpServletRequest request = (HttpServletRequest) servletRequest;System.out.println(request.getProtocol()); //获取协议版本System.out.println(request.getRemoteAddr()); //获取访问者的IP地址System.out.println(request.getMethod()); //获取请求方法//获取头部信息Enumeration<String> enumeration = request.getHeaderNames();while (enumeration.hasMoreElements()){String name = enumeration.nextElement();System.out.println(name + ": " + request.getHeader(name));}
}
我们发现,整个HTTP请求报文中的所有内容,都可以通过HttpServletRequest对象来获取,当然,它的作用肯定不仅仅是获取头部信息
那么我们再来看看ServletResponse,这个是服务端的响应内容,我们可以在这里填写我们想要发送给浏览器显示的内容:
//转换为HttpServletResponse(同上)
HttpServletResponse response = (HttpServletResponse) servletResponse;
//设定内容类型以及编码格式(普通HTML文本使用text/html,之后会讲解文件传输)
response.setHeader("Content-type", "text/html;charset=UTF-8");
//获取Writer直接写入内容
response.getWriter().write("我是响应内容!");
//所有内容写入完成之后,再发送给浏览器
现在我们在浏览器中打开此页面,就能够收到服务器发来的响应内容了。其中,响应头部分,是由Tomcat帮助我们生成的一个默认响应头。

HttpServlet
Servlet有一个直接实现抽象类GenericServlet,那么我们来看看此类做了什么事情。
我们发现,这个类完善了配置文件读取和Servlet信息相关的的操作,但是依然没有去实现service方法,因此此类仅仅是用于完善一个Servlet的基本操作,那么我们接着来看HttpServlet,它是遵循HTTP协议的一种Servlet,继承自GenericServlet,它根据HTTP协议的规则,完善了service方法。
在阅读了HttpServlet源码之后,我们发现,其实我们只需要继承HttpServlet来编写我们的Servlet就可以了,并且它已经帮助我们提前实现了一些操作,这样就会给我们省去很多的时间。
@WebServlet("/test")
public class TestServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setContentType("text/html;charset=UTF-8");resp.getWriter().write("<h1>恭喜你解锁了全新玩法</h1>");}
}
现在,我们只需要重写对应的请求方式,就可以快速完成Servlet的编写。
@WebServlet注解详解
我们接着来看WebServlet注解,我们前面已经得知,可以直接使用此注解来快速注册一个Servlet,那么我们来想细看看此注解还有什么其他的玩法。
首先name属性就是Servlet名称,而urlPatterns和value实际上是同样功能,就是代表当前Servlet的访问路径,它不仅仅可以是一个固定值,还可以进行通配符匹配:
@WebServlet("/test/*")
上面的路径表示,所有匹配/test/随便什么的路径名称,都可以访问此Servlet,我们可以在浏览器中尝试一下。
也可以进行某个扩展名称的匹配:
@WebServlet("*.js")
这样的话,获取任何以js结尾的文件,都会由我们自己定义的Servlet处理。
那么如果我们的路径为/呢?
@WebServlet("/")
此路径和Tomcat默认为我们提供的Servlet冲突,会直接替换掉默认的,而使用我们的,此路径的意思为,如果没有找到匹配当前访问路径的Servlet,那么久会使用此Servlet进行处理。
我们还可以为一个Servlet配置多个访问路径:
@WebServlet({"/test1", "/test2"})
我们接着来看loadOnStartup属性,此属性决定了是否在Tomcat启动时就加载此Servlet,默认情况下,Servlet只有在被访问时才会加载,它的默认值为-1,表示不在启动时加载,我们可以将其修改为大于等于0的数,来开启启动时加载。并且数字的大小决定了此Servlet的启动优先级。
@WebServlet(value = "/test", loadOnStartup = 1)
public class TestServlet extends HttpServlet {@Overridepublic void init() throws ServletException {super.init();log.info("我被初始化了!");}@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setContentType("text/html;charset=UTF-8");resp.getWriter().write("<h1>balbalaba</h1>");}
}
重定向与请求转发
resp.sendRedirect("time");//重定向
req.getRequestDispatcher("/time").forward(req, resp);//请求转发
Q:请求转发有什么好处呢?
A:它可以携带数据!
req.setAttribute("test", "我是请求转发前的数据");
req.getRequestDispatcher("/time").forward(req, resp);
System.out.println(req.getAttribute("test"));
通过setAttribute方法来给当前请求添加一个附加数据,在请求转发后,我们可以直接获取到该数据。
两者的区别为:
- 请求转发是一次请求,重定向是两次请求
- 请求转发地址栏不会发生改变, 重定向地址栏会发生改变
- 请求转发可以共享请求参数 ,重定向之后,就获取不了共享参数了
- 请求转发只能转发给内部的Servlet

ServletContext
ServletContext全局唯一,它是属于整个Web应用程序的,我们可以通过getServletContext()来获取到此对象。
此对象也能设置附加值:
ServletContext context = getServletContext();
context.setAttribute("test", "我是重定向之前的数据");
resp.sendRedirect("time");
System.out.println(getServletContext().getAttribute("test"));
因为无论在哪里,无论什么时间,获取到的ServletContext始终是同一个对象,因此我们可以随时随地获取我们添加的属性。
它不仅仅可以用来进行数据传递,还可以做一些其他的事情,比如请求转发:
context.getRequestDispatcher("/time").forward(req, resp);
它还可以获取根目录下的资源文件(注意是webapp根目录下的,不是resource中的资源)
ServletContext中的接口
Enumeration<String> enumeration = getServletContext().getAttributeNames();//包含了ServletContext中的所有域属性名
Object object=getServletContext().getAttribute("name");//返回与之匹配的域属性值
getServletContext().removeAttribute("name");//删除该属性名对应的域属性
getServletContext().setAttribute("la","巴拉巴拉");//设置ServletContext的域属性,前者为属性名,后者为域属性值
上面的为全局的属性,也可以通过请求转发来实现一写信息的转发(下面还有解释)
req.setAttribute("name", "value");//设置域属性
String name=req.getAttribute("name");//获取域属性值
也可以获取web应用下的资源文件
其他方法遇到了再查,再记录
HttpServletRequest
-
HttpServletRequest对象代表客户端的请求 -
当客户端/浏览器通过 HTTP 协议访问服务器时,HTTP 请求头中的所有信息都封装在这个对象中
HttpServletRequest常用方法:
-
getRequestURI()获取请求的资源路径 -
getRequestURL()获取请求的统一资源定位符(绝对路径 -
getRemoteHost()获取客户端的 主机, getRemoteAddr() -
getHeader()获取请求头 -
getParameter()获取请求的参数 -
getParameterValues()获取请求的参数(多个值的时候使用), 比如 checkbox, 返回的数组 -
getMethod()获取请求的方式 GET 或 POST -
setAttribute(key, value)设置域数据 -
getAttribute(key)获取域数据 -
getRequestDispatcher()获取请求转发对象, 请求转发的核心对象
因为浏览器地址栏会停止在第一个 servlet ,如果你刷新页面,会再次发出请求(并且会 带数据), 所以在支付页面情况下,不要使用请求转发,否则会造成重复支付
HttpServletResponse
他是通过流来给客户端传递数据的
字节流 getOutputStream() 常用于下载(传递二进制数据)
字符流 getWriter() 常用于回传字符串(非常常用)
// 两个流同时只能使用一个,也就是用了字节流就不能用字符流了,用了字符流就不能用字节流了
对于getWriter:
他获取的对象为PrintWriter类型的数据
resp.getWriter().write("hello servlet");
//或者
PrintWriter writer=resp.getWriter();
writer.write("hello ");
在向客户端写入东西时,要设置编码规则!!!
resp.setContentType("text/html;charset=UTF-8");
还有一种方法:setHeader(),应该没上面的好用,就不写了
状态码解释
| 状态码 | 状态码描述 | 说明 |
|---|---|---|
| 200 | OK | 请求已成功,请求所希望的响应头或数据体将随此响应返回。出现此状态码是表示正常状态。 |
| 302 | Move temporarily | 重定向,请求的资源临时从不同的 地址响应请求。 |
| 304 | Not Modified | 从浏览器缓存中读取数据,不从服务器重新获取数据。例如,用户第一次从浏览器访问服务器端图片资源,以后在访问该图片资源的时候就不会再从服务器上加载而直接到浏览器缓存中加载,这样效率更高。 |
| 404 | Not Found | 请求资源不存在。通常是用户路径编写错误,也可能是服务器资源已删除。 |
| 403 | Forbidden | 服务器已经理解请求,但是拒绝执行它 |
| 405 | Method Not Allowed | 请求行中指定的请求方法不能被用于请求相应的资源 |
| 500 | Internal Server Error | 服务器内部错误。通常程序抛异常 |
Cookie
什么是Cookie?它可以在浏览器中保存一些信息,并且在下次请求时,请求头中会携带这些信息。
我们可以编写一个测试用例来看看:
Cookie cookie = new Cookie("test", "yyds");
resp.addCookie(cookie);
resp.sendRedirect("time");
for (Cookie cookie : req.getCookies()) {System.out.println(cookie.getName() + ": " + cookie.getValue());
}
相关文章:
Servlet-01
文章目录 Servlet创建Servlet探究Servlet的生命周期 HttpServletWebServlet注解详解 重定向与请求转发ServletContextServletContext中的接口 HttpServletRequestHttpServletResponse状态码解释Cookie Servlet Q:它能做什么呢? A:我们可以通…...
C语言:链表
链表 介绍单向链表节点结构创建节点插入节点删除节点遍历链表尾部插入查找节点链表反转示例程序程序1程序2 介绍 链表是一种常见的数据结构,用于存储一系列线性数据。与数组不同,链表中的元素在内存中不必是连续存放的,而是通过指针将每个元…...
【git使用二】gitee远程仓库创建与本地git命令用法
目录 gitee介绍 管理者注册gitee账号 管理者在gitee网站上创建远程仓库 每个开发者安装git与基本配置 1.git的下载和安装 2.配置SSH公钥 3.开发者信息配置 git命令用法 gitee介绍 Gitee(又称码云)是一个基于Git的代码托管服务,由开源…...
明星百科大全PHP网站源码
源码介绍 明星百科大全网站源码,国内外明星娱乐音乐、新闻八卦、写真照片、相关影视作品等等的明星百科网站源码。 源码截图 源码下载 明星百科大全PHP网站源码...
白酒:茅台镇白酒的品鉴会与文化交流活动
茅台镇,这个位于中国贵州省的小镇,因其与众不同的自然环境和杰出的酿酒工艺而成为世界著名的白酒产区。云仓酒庄豪迈白酒作为茅台镇的品牌,积极参与各种品鉴会和文化交流活动,向世界展示了中国白酒的魅力和文化底蕴。 近年来&…...
python中列表结构在点云数据处理中用法
1、前言 Python中的列表(list)是一种可变的序列类型,用于存储集合数据。列表用途非常广泛,包括但不限于以下几个方面: 存储集合数据:列表用于存储一系列有序的元素,这些元素可以是任何数据类型&…...
土耳其(小亚细亚)历史上的各个阶段
一个国家的历史书写方式有两种,其一是按本国主体民族的渊源,其二是本国国土内发生的都属于本国史。一般来说,这两种方式相当程度上是重合的,但也有例外,比如本文要讲述的土耳其。 土耳其的国土并不辽阔,其…...
Windows下基于Frida查看内存基址和修改寄存器
使用Frida能够方便地获取到DLL基址,还能修改寄存器值。首先要通过任务管理器获得进程的PID,然后写Python脚本把Frida附加到这个PID进程,根据IDA分析出来的函数地址,HOOK到目标函数,修改寄存器的值,最终实现…...
2024中国网络安全产品用户调查报告(发布版)
自2020年始,人类进入了21世纪的第二个十年,全球进入了百年未有之大变局,新十年的开始即被新冠疫情逆转了全球化发展的历程,而至2022年3月俄乌战争又突然爆发,紧接着2023年7月“巴以冲突"皱起,世界快速…...
手写图片懒加载
参考来自前辈 Aidan路修远i 的文章面试官:请你手写一下!懒加载 - 掘金 (juejin.cn) Hello.vue <template><div><!-- src里面为空,data-original里面写图片真正的url(此处省略) --><img src"" data-origina…...
大型语言模型(LLMs)的后门攻击和防御技术
大型语言模型(LLMs)通过训练在大量文本语料库上,展示了在多种自然语言处理(NLP)应用中取得最先进性能的能力。与基础语言模型相比,LLMs在少样本学习和零样本学习场景中取得了显著的性能提升,这得…...
力扣2594.修车的最少时间
力扣2594.修车的最少时间 二分答案 class Solution {public:long long repairCars(vector<int>& ranks, int cars) {ranges::sort(ranks);auto check [&](long long x) -> bool{long long res 0;for(auto v : ranks){long long k sqrt(x/v);res k;if(r…...
攻防演练之-成功的钓鱼邮件溯源
书接上文,《网络安全攻防演练风云》专栏之攻防演练之-网络安全产品大巡礼二,这里。 演练第一天并没有太大的波澜,白天的时间过得很快。夜色降临,攻防演练中心内的灯光依旧明亮。对于网络安全团队来说,夜晚和白天并没有…...
Gi标签管理
文章目录 前言理解标签创建标签操作标签总结 前言 理解标签 标签,可以理解为对某次commit的一次标识,相当于起起了一个别名。 例如,在项目发布某个版本时候,针对最后一次commit起一个v1.0这样的标签来标识里程碑的意义。 这有什…...
2024福建等保测评公司有哪些?分别叫做什么名字?
2024福建等保测评公司有哪些?分别叫做什么名字? 【回答】:2024年具有资质的福建等保测评公司有6家,其名称以及地址如下: 1、福建省网络与信息安全测评中心,福州市鼓楼区东街8号利达大厦A座8层;…...
王先宏老师厉害了,活页笔记版古琴曲谱拆箱图
王先宏老师走心了,活页笔记版古琴曲谱拆箱图,简直是史上最好的古琴学习利器!送的防滑垫还带铝合金夹层的,养弦膏都是市面上没有的的。 这些古琴谱上的笔记就是老师课堂上用的,直接拿来就可以跟着弹,不用您…...
TalkingData 是一家专注于提供数据统计和分析解决方案的独立第三方数据智能服务平台
TalkingData 是一家专注于提供数据统计和分析解决方案的独立第三方数据智能服务平台。通过搜索结果,我们可以了解到 TalkingData 的一些关键特性和市场情况,并将其与同类型产品进行比较。 TalkingData 产品特性 数据统计与分析:提供专业的数…...
Springboot的小型超市商品展销系统-计算机毕业设计源码01635
摘 要 科技进步的飞速发展引起人们日常生活的巨大变化,电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用。信息时代的到来已成为不可阻挡的时尚潮流,人类发展的历史正进入一个新时代。在现实运用中,应用软件的工作…...
UV胶开裂主要因素有哪些?如何避免?
UV胶开裂主要因素有哪些?如何避免? UV胶开裂的原因可能包括多个方面: 固化不足:UV胶的固化需要足够的紫外线照射。如果照射时间不够,或者紫外线光源的强度不足,胶水可能没有完全固化,从而导致开…...
LogicFlow 学习笔记——3. LogicFlow 基础 节点 Node
节点 Node LogicFlow 内置了一些基础节点,开发者在实际应用场景中,可以基于这些基础节点,定义符合自己业务逻辑的节点。 认识基础节点 LogicFlow是基于svg做的流程图编辑框架,所以我们的节点和连线都是svg基本形状,…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...
