【Servlet】——Servlet API 详解

个人主页:兜里有颗棉花糖
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创
收录于专栏【Servlet】
本专栏旨在分享学习Servlet的一点学习心得,欢迎大家在评论区交流讨论💌

目录

  • 一、HttpServlet
  • 二、HttpServletRequest
    • 核心方法
    • 代码示例1
    • 如何获取query string和body(form格式)中的数据
    • 获取body(json格式)中的数据
      • jackon依赖的导入
  • 三、HttpServletResponse
    • setStatus
    • setHeader
    • 构造重定向响应
    • 返回一个html界面

API就是一组类和方法,本文中我们学习Servlet API的三个类:HttpServletHttpServletRequestHttpServletResponse

一、HttpServlet

HttpServlet是我们编写Servlet代码用来的核心类,通过继承这个类并重写其中的方法,然后Tomcat去调用其中的代码逻辑。可以这样理解:我们这里写的代码(重写的方法)并不是我们自己手动调用手动执行的,而是将我们写地代码交给Tomcat,让Tomcat帮助我们执行调用这些代码。

核心方法如下:

在这里插入图片描述

  • Init方法:在webapp被加载的时候会调用此方法,可以使用该方法进行初始化操作。
  • destroy方法:在webapp被销毁(或Tomcat结束)的时候执行destroy方法,可以使用该方法进行收尾工作。注意:该方法不能保证一定会被调用到。

这里分为两种情况。

第一种情况:通过8005端口给Tomcat发起一个特殊的请求,然后Tomcat就关闭了(这种情况可以调用到destroy方法)。
第二种情况:直接杀死Tomcat进程,比如说通过任务资源管理器直接结束Tomcat任务进程,此时就无法执行destroy方法。

实际开发中第二种情况占多数(尤其是在Linux中),这就提醒我们不能依赖destroy方法,因为该方法不一定被调用到。

  • service方法:每次收到请求会执行service方法,处理每个请求。一般会使用doXXX方法来替代service方法

对于上述方法,浏览器只能构造Get方法,对于其它的方法浏览器并不方便构造。如果想要构造其它的请求方法,我们可以使用ajax或者postman。

在这里插入图片描述
实际开发中用到的最多的是Get和Post。

二、HttpServletRequest

HttpServletRequestJava Servlet API提供的接口之一,用于表示客户端的HTTP请求。

一个HTTP请求中都有哪些信息都会在HttpServletRequest类中进行体现。当Tomcat接收到Http请求时,它将解析请求并将相关的信息填充到HttpServletRequest对象中,从而使开发人员可以方便地获取和处理这些信息。

核心方法

下图是HttpServletRequest的方法:
在这里插入图片描述

  • URI和URL:URI是唯一资源标识符,URL是唯一资源定位符;URI用来区分不同的资源,而URL就是用来区分不同资源的一种方式。我们可以这样理解,URL是URI的实现方式。实际开发中一般会混着用。

Enumeration getParameterNames()String getParameter(String name)
我们直到请求中可以通过一些方式把自定义数据传递到服务器中,有两种方式:
第一种方式:query stringquery string是键值对结构的数据,Tomcat收到请求后就会把query string解析成Map这样的键值对。然后使用getParameter就可以根据key获取到value;而getParameterNames是拿到所有的key。
第二种方式:body:如果是通过post form表单的形式提交表单的话,此时body中也是键值对的形式(和query string一样)。

getParameterValues方法:即一个key涉及到多个value。

Enumeration getHeaderNames()String getHeader(String name):获取到请求头中的键值对,Tomcat收到请求后也会把请求头解析成Map。getHeader是通过key拿到指定的value;而getHeaderNames是拿到所有的key。

代码示例1

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;

@WebServlet("/request")
public class RequestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 下行代码就是为了显示告诉浏览器,浏览器拿到的内容是html
        resp.setContentType("text/html");

        // 调用req的各个方法,把得到的结果汇总到一个字符串中,然后统一返回到桌面上
        StringBuilder respBody = new StringBuilder();

        // 由于下面的内容在浏览器是按照html展示的,\n在浏览器上并不是换行,所以使用<br>来表示换行
        // 获得HTTP请求协议的版本号
        respBody.append(req.getProtocol());
        respBody.append("<br");
        // 获取HTTP请求方法
        respBody.append(req.getMethod());
        respBody.append("<br>");
        // 获取请求的URI
        respBody.append(req.getRequestURI());
        respBody.append("<br>");
        // 将req.getContextPath()返回的上下文路径添加到respBody中
        respBody.append(req.getContextPath());
        respBody.append("<br>");
        // 返回的查询字符串添加到respBody字符串中的代码
        respBody.append(req.getQueryString());
        respBody.append("<br>");

        // 拼接header
        Enumeration<String> headers = req.getHeaderNames();
        while(headers.hasMoreElements()) {
            String header = headers.nextElement();
            respBody.append("<br>");
            respBody.append(header + ": " + req.getHeader(header));
        }
        resp.getWriter().write(respBody.toString());
    }
}

跑起来之后如下图:
在这里插入图片描述

如何获取query string和body(form格式)中的数据

如何获取query string中的数据

代码如下:

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/parameter")
public class ParameterServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        System.out.println("username=" + username);
        System.out.println("password=" + password);
        resp.getWriter().write("OK");
    }
}

运行结果如下:
在这里插入图片描述
在这里插入图片描述

如何获取中body的数据

由于body有很多种格式,所以这里就拿form表单格式(和query string格式一样是键值对的格式)来举例。这里我们让客户端发送一个Post请求,同时使用form格式的数据在body中把数据进行传递。

代码如下:

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/parameter2")
public class Parameter2Servlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        System.out.println("username=" + username);
        System.out.println("password=" + password);
        resp.getWriter().write("OK");
    }
}

结果如下:
在这里插入图片描述

在这里插入图片描述

总结:使用getParameter()方法可以用于获取query string中的value值以及form表单中的value值。
所以我们完全可以使用一种代码来获取query string中的value值以及form表单中的value值(doPost()方法用于处理POST请求,获取表单中的参数值。doGet()方法用于处理GET请求,获取查询字符串中的参数值)。
注意:上述两份代码的servlet path是不能重复的,否则会出现404报错。

获取body(json格式)中的数据

再来回顾一下json格式:

{
	username:lisi;
	password:9521;
}

json格式虽然在开发中也是经常会用到的一种格式,但是Servlet自身不能够对json格式的数据进行解析。解决方式是引入第三方库来进行解析(将键值对还原成Map这种key value的形式)。

解析json格式的第三方库也是有很多的,我们这里使用jackon来对json进行解析。

jackon依赖的导入

在这里插入图片描述
然后这里选择一个版本(建议选旧版本)
在这里插入图片描述
然后复制粘贴到pom.xml文件中去。
在这里插入图片描述
注意是复制粘贴到<dependencies></dependencies>标签中(一个dependencies标签可以包含多个依赖)。
在这里插入图片描述
最后刷新一下即可。

jackon依赖引入的是一个类两个方法:类是ObjectMapper,用于将Java对象转换为JSON格式的字符串,也可以将JSON字符串转换回相应的Java对象。

现在我们回归正题:获取body(json格式)中的数据(即客户端中的body按照json格式进行传输)。

在这里插入图片描述
readValue方法选择上图中的版本。该方法的作用就是把json格式的字符串解析成Java对象。
第一个参数(InputStream src)可以看到是一个流对象,表示json从哪里来。
第二个参数(JavaType valueType)用于指定一个类型:即json格式的字符串需要解析成什么类型的Java对象(这是一个将json格式的字符串映射成java对象的过程)。
关于第二个参数:我们需要定义一个类,该类的属性名称与 JSON 字符串中的字段匹配(如下图)
在这里插入图片描述
完成代码如下:

import com.fasterxml.jackson.databind.ObjectMapper;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

//{
//    "username":"lisi",
//    "password":"465"
//}

class User {
    public String username;
    public String password;
}


@WebServlet("/json")
public class JsonServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        User user = objectMapper.readValue(req.getInputStream(),User.class);
        System.out.println("username=" + user.username + ", password=" + user.password);
        resp.getWriter().write("OK");
    }
}

运行结果如下:
在这里插入图片描述

在这里插入图片描述

总结:readValue方法将req请求中的body(json格式)中的字符串读取并解析,然后构造成了user对象,而user中的属性就是body(json格式)中所体现的内容。

jackon还提供了一个方法可以将java对象转换成json格式的字符串。该方法为writeValueAsString()
在这里插入图片描述

三、HttpServletResponse

HttpServletResponse是用于构造HTTP响应的对象,提供了一系列方法用于操作响应的状态码、头部信息(header)和响应体数据(body)。它和HTTP响应数据相匹配,可以用于向客户端发送响应数据。然后针对状态码、header、body这些属性就可以进行设置。

注意区分下面两个概念:
请求对象:拿到请求对象之后是为了获取对象中的属性(读操作)。
响应对象:拿到响应对象之后是为了设置对象中的属性(写操作)。

而对于doXXX这样的方法的作用就是根据请求计算响应。
再强调一下:请求对象是Tomcat收到后对Http协议解析得到的对象。
而响应对象是Tomcat创建空的对象,然后在代码中把响应对象的属性设置好。

下面来看HttpServletResponse中的核心方法,如下:
在这里插入图片描述

  • addHeader():可能会出现key相同的两个键值对(一个key可以对应多个value)。另外,Java标准库的Map是不允许key重复的,Tomcat内部也不一定把header解析成Map。
  • setHeader():一个key对应一个value。
  • setCharacterEncoding:告诉浏览器按照什么样的字符集来解析响应的body。
  • sendRedirect:用来设定重定向响应。

setStatus

代码示例1如下:
在这里插入图片描述
运行结果如下:
在这里插入图片描述

代码示例2如下:
在这里插入图片描述
运行结果如下:
在这里插入图片描述

在返回状态码的同时,可以给body写入数据,这样就可以得到比较个性化的错误页面,比如:
在这里插入图片描述
上图就是搜狗的404错误页面。
在这里插入图片描述
上图就是百度的404错误页面。
在这里插入图片描述
上图是哔哩哔哩的404错误页面。

Tomcat同样有一个内置的404报错页面,虽然setStatus方法并没有页面,但是sendError方法是有页面的。代码如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
上图是Tomcat的404报错页面。

setHeader

我们通过使用setHeader方法来设置任意的响应报头。举例:通过refresh属性来设置浏览器自动刷新(比如refresh:2,意思就是浏览器每隔两秒就会自动刷新)。

代码如下:
在这里插入图片描述

运行结果如下(下图中的时间每隔两秒就会改变):在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

构造重定向响应

让页面重定向到百度主页。

注意:使用重定向一定要带有Location属性,然后用这个属性来描述你要重定向到哪个地方

代码如下:
在这里插入图片描述

结果如下:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

补充:
301:永久重定向
302:临时重定向

刚刚上述代码可以等价替换成下面代码:
在这里插入图片描述在这里插入图片描述

resp.sendRedirect("https://www.baidu.com");等价于resp.setStatus(302);resp.setHeader("Location","https://www.baidu.com");(浏览器看到302和https://www.baidu.com这两个字段就知道要跳转到百度)

返回一个html界面

在这里插入图片描述
结果如下:
在这里插入图片描述
为什么会出现乱码呢?

我们要知道,如果在IDEA中直接写一个中文字符串的话是按照utf-8进行编码的。但是浏览器默认是使用操作系统的编码方式来解析和显示页面,而windows简体中文版的默认编码方式是gdk,此时浏览器按照gdk的方式来解析utf-8的话就会出现上图中的乱码。

所以我们要设置一下让浏览器按照utf-8的方式进行解析(如下)。
在这里插入图片描述
在这里插入图片描述

上述代码还存在一个问题,如下(将doGet方法中的两行代码进行互换):
在这里插入图片描述
在这里插入图片描述
可以看到又出现了乱码。在Servlet中,为resp设置属性的时候,需要注意顺序:要先设置header,然后再设置body;否则如果先设置body的话此时header、status就已经定性而来不及修改了

好了,以上就是本文的全部内容了。希望各位友友可以一键三连哈!!!

在这里插入图片描述

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

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

相关文章

图像处理之《可逆重缩放网络及其扩展》论文精读

一、文章摘要 图像重缩放是一种常用的双向操作&#xff0c;它首先将高分辨率图像缩小以适应各种显示器或存储和带宽友好&#xff0c;然后将相应的低分辨率图像放大以恢复原始分辨率或放大图像中的细节。然而&#xff0c;非单射下采样映射丢弃了高频内容&#xff0c;导致逆恢复…

Flink的SQL开发

概叙 Flink有关FlinkSQL的官网: https://nightlies.apache.org/flink/flink-docs-release-1.13/zh/docs/dev/table/sql/overview/ 阿里云有关FlinkSQL的官网: https://help.aliyun.com/zh/flink/developer-reference/overview-5?spma2c4g.11186623.0.0.3f55bbc6H3LVyo Ta…

Mac 下文件编码转换的方法

Windows文件传输到Mac,在Windows上打开是可以看的,但是在Mac上打开是乱码,这是因为Windows默认是GBK编码,而Mac使用的是UTF-8编码,这时候需要对文件编码进行转换,以方便在Mac上查看和使用 iconv macOS 系统中&#xff0c;iconv 命令是一个用于转换文件或文本流的字符编码的实用…

Django模型(八)

一、修改数据 先获取对象,通过对象属性更新数据,再保存 (更新单一数据)通过QuerySet的update函数更新数据 (更新多条数据) #单条记录修改 save c = Cook.objects.get(pk=1) c.name = 安妮 c.save()# 更新多个值 update Cook.objects.filter(sect=粤菜).update(level=5)1.1、…

C# 根据USB设备VID和PID 获取设备总线已报告设备描述

总线已报告设备描述 DEVPKEY_Device_BusReportedDeviceDesc 模式 winform 语言 c# using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Window…

IntelliJ IDEA 2023和Java的JDK详细安装教程

一、软件下载 网盘链接&#xff1a;IntelliJ IDEA 2023 提取码&#xff1a;2syx 二、详细安装教程 1.鼠标右击【JetBrains2023】压缩包&#xff08;win11及以上系统需先点击“显示更多选项”&#xff09;选择【解压到 JetBrains2023】&#xff1b;打开解压后的文件夹&#x…

银行数据仓库体系实践(15)--数据应用之巴塞尔新资本协议

巴塞尔新资本协议介绍 在银行管理中经常会听到巴3、新资本协议等专用词&#xff0c;那这都是指《巴塞尔资本协议》&#xff0c;全称《关于统一国际银行资本衡量和资本标准的协议》。新资本协议的五大目标是&#xff1a;促进金融体系的安全性和稳健性&#xff08;保持总体资本水…

c++阶梯之auto关键字与范围for

auto关键字&#xff08;c11&#xff09; 1. auto关键字的诞生背景 随着程序的逐渐复杂&#xff0c;程序代码中用到的类型也越来越复杂。譬如&#xff1a; 类型难以拼写&#xff1b;含义不明确容易出错。 比如下面一段代码&#xff1a; #include <string> #include &…

(学习日记)2024.02.01:引用变量 / 默认实参 / 一元作用域运算符 / 函数重载

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

踩坑STM32CubeMX生成Makefile工程无法使用printf(“%f“)

过去一年偶有接触STM32开发时都是使用STM32CubeMX生成Makefile的工程&#xff0c;具体开发环境见配置Clion用于STM32开发&#xff08;Makefile&#xff09;&#xff0c;但没想到今天在使用printf打印输出浮点数时无法正常输出&#xff0c;不仅printf无法使用&#xff0c;其他涉…

MongoDB从入门到实战之MongoDB快速入门

前言 上一章节主要概述了MongoDB的优劣势、应用场景和发展史。这一章节将快速的概述一下MongoDB的基本概念&#xff0c;带领大家快速入门MongoDB这个文档型的NoSQL数据库。 MongoDB从入门到实战的相关教程 MongoDB从入门到实战之MongoDB简介&#x1f449; MongoDB从入门到实战…

白皮书发布,石油石化数字孪生加速

近日&#xff0c;《数字石化 孪生智造——石油石化数字孪生白皮书》发布。白皮书聚焦石油石化行业发展机遇&#xff0c;剖析数字孪生技术在行业中的案例实践与应用场景&#xff0c;展望石油石化企业未来孪生发展新态势。 当前&#xff0c;国家大力推动减污降碳协同增效&#x…

【IM】长连接网关设计探索(一)

目录 1.长连接网关的必要性2. 设计目标2.1 技术挑战2.2 技术目标 3. 方案选型3.1 网关IP地址的选择3.1.1 使用httpDNS服务3.1.2 自建http server作为IP config server3.1.3 最佳方案 3.2 高并发收发设计3.2.1 C10K问题3.2.2 方案探索双协程监听channel实现全双工 一个定时器 1…

Unity学习之Unity核心(一)2D相关

文章目录 1. 前言2 图片导入概述3 图片设置的六大部分3.1 纹理类型3.1.1 Default3.1.2 Normal Map 法线贴图格式3.1.3 Editor GUI and Legacy GUI3.1.4 Sprite3.1.5 Cursor 自定义光标3.1.6 Cookie 光源剪影格式3.1.7 LightMap光照贴图格式3.1.8 Single Channel 纹理只需要单通…

【新书推荐】5.1节 16位汇编语言学习环境

第五章 16位汇编学习环境 16位汇编语言的学习环境是建立在8086计算机的基础上的&#xff0c;我将借助于DosBox虚拟机来实现16位汇编语言学习环境的搭建。 5.1节 16位汇编语言学习环境 本节内容&#xff1a;16位汇编学习环境的搭建。 ■汇编语言程序设计编程调试过程&#xff1…

Vulnhub billu b0x

0x01 环境搭建 1. 从官方下载靶机环境&#xff0c;解压到本地&#xff0c;双击OVF文件直接导入到vmware虚拟机里面。2. 将虚拟机的网络适配器调成NAT模式&#xff0c;然后开机即可进行操作了。 0x02 主机发现 nmap -sn 192.168.2.0/24 成功获取靶机IP为192.168.2.129。 0x0…

sqli.labs靶场(23关到28a关)

23、第二十三关 id1单引号闭合 找位置1 and 12 union select 1,2,3 爆库&#xff1a;1 and 12 union select 1,2,database() 爆表名&#xff1a;1 and 12 union select 1,2,group_concat(table_name) from information_schema.tables where table_schemasecurity 爆字段&#…

【大数据】Flink SQL 语法篇(二):WITH、SELECT WHERE、SELECT DISTINCT

Flink SQL 语法篇&#xff08;二&#xff09; 1.WITH 子句2.SELECT & WHERE 子句3.SELECT DISTINCT 子句 1.WITH 子句 应用场景&#xff08;支持 Batch / Streaming&#xff09;&#xff1a;With 语句和离线 Hive SQL With 语句一样的&#xff0c;语法糖 1&#xff0c;使用…

谷歌seo搜索引擎优化需要做什么?

当你要做谷歌seo&#xff0c;经手一个你之前没有接触过的网站&#xff0c;你首先要做的就是分析网站当前的流量数据&#xff0c;如果是新站自然不需要这一步&#xff0c;不过数据分析依旧是件很重要的事情&#xff0c;做seo不懂得分析数据相当于白做 再来就是你要了解网站所在的…

卸载Ubuntu双系统

卸载Ubuntu双系统 我们卸载Ubuntu双系统&#xff0c;可能出于以下原因&#xff1a; 1、Ubuntu系统内核损坏无法正常进入 2、Ubuntu系统分配空间不足&#xff0c;直接扩区较为复杂 3、以后不再使用Ubuntu&#xff0c;清理留出空间 123无论出于哪种原因&#xff0c;我们都是要…