【Servlet篇】一文带你吃透Request对象

news2024/9/21 18:55:14

文章目录

  • 1. 前言
  • 2. Request 对象
    • 2.1 Request 继承体系
    • 2.2 Request 获取请求参数
      • 1. 获取请求行数据
      • 2. 获取请求头数据
      • 3. 获取请求体数据
      • 4. 获取请求参数的通用方式
  • 3. IDEA中快速创建 Servlet

你问我青春还剩几年?我的回答是,趁现在,正当时。身边朋友都在问我怎样学好一门编程语言,怎样学好Java?怎样通过 Java 找到一份满意的工作?推荐学习此专栏:Java编程基础教程系列(零基础小白搬砖逆袭)

1. 前言

最近一直在更新 Servlet 的文章,在前面一篇中说到 sevice() 方法由 Servlet 容器调用执行,而该方法中有两个重要的参数,分别是 Request 对象和 Response 对象,下面我们就来探讨这两个参数究竟有何作用。

  • 都2023年了,Servlet还有必要学习吗?一文带你快速了解Servlet

image-20230210223547626

其中,Request 是请求对象,而 Response 是响应对象,例如:

@WebServlet("/demo")
public class ServletDemo implements Servlet {
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("Hello~");
    }
	//省略了Servlet接口中其他方法的重写
}

上面的例子中,Request 用于获取请求数据。浏览器发送 HTTP 请求到 TomCat 服务器,HTTP 请求中包含了很多请求数据,请求行,请求头等。服务器会对 HTTP 请求中的数据进行解析并把解析的结果存入一个对象中,这个对象就是 Request 对象。

服务器解析请求数据并将数据封装在 Request 对象中,此时就可以根据需求进行业务处理,业务处理完以后,服务器需要给客户端浏览器返回响应数据,即业务处理的结果。于是把数据封装在 Response 对象中。服务器会解析 Response 对象中的响应数据并通过 HTTP 协议发送给客户端浏览器展示给用户。

下面是关于 request 和 response 的一个小 demo,我们先来快速感受一下两者的作用:

@WebServlet("/demo")
public class ServletDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //使用request对象 获取请求数据
        String name = request.getParameter("name");//url?name=zhangsan

        //使用response对象 设置响应数据
        response.setHeader("content-type","text/html;charset=utf-8");
        response.getWriter().write("<h1>"+name+",欢迎您!</h1>");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("Post...");
    }
}

在 idea 中快速启动 TomCat 服务器,通过浏览器来访问刚才的 demo,此时浏览器就会根据传入的不同参数在页面上展示不同的数据。

示例1

image-20230210134152042

示例2

image-20230210134240281

现在我们已经知道了 Request 对象用于封装请求数据,Response 对象用于封装响应数据,但是他们具体是怎么实现的呢?我们就需要更加深入的学习。首先我们从下面三个方面来了解 Request 对象:

  • Request 的继承体系
  • Request 如何获取请求参数
  • Request 请求转发

2. Request 对象

2.1 Request 继承体系

在 Request 继承体系中,Java 提供了请求对象的根接口,并且还提供了对 HTTP 协议封装的请求对象接口,而由 TomCat 定义了实现类,三者属于继承关系。

image-20230210140202398

其中 ServletRequest 和 HttpServletRequest 是继承关系,并且都是 Java 提供的接口,我们可以在 JavaEE API 文档中查看这两个类。

之前我们定义的 Servlet 类实现 Servlet 接口或者继承 HttpServlet 类时,在 service() 方法中传入的参数是不同的,如下:

image-20230210141333124

image-20230210140847245

而 ServletRequest 和 HttpServletRequest 都是接口,无法用来实例化对象,那么 service() 方法中的参数对象是由谁来创建的呢?这里就需要用到 Request 继承体系中的 RequestFacade 类,该类实现了 HttpServletRequest 接口,间接实现了 ServletRequest 接口。

Servlet 类中的 service() 方法,doGet() 方法,doPost() 等方法,都是由 Web 服务器 TomCat 来调用的,所以 TomCat 提供了方法参数接口的具体实现类,并完成了对象的创建。

示例:编写一个 Servlet,在对应的方法中直接打印 request 对象。

@WebServlet("/demo")
public class ServletDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println(request);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        
    }
}

重启服务器,在浏览器中访问这个资源,此时控制台就会答应相关内容。如下:

image-20230210143519573

不难看出,这里的 request 是一个 RequestFacade 类对象。

2.2 Request 获取请求参数

HTTP 请求数据一共分为 3 部分,分别是请求行,请求头和请求体。学习 Request 获取请求参数可以从这三部分分别来学习。

1. 获取请求行数据

请求行一共包含 3 部分内容,分别是请求方式,请求资源路径和 HTTP 协及版本。如下:

image-20230210144147382

对于这 3 部分内容,Request 对象提供了对应的 API 方法来获取,具体如下:

获取请求方式:

String getMethod(); 
//示例:GET

获取请求的虚拟目录(项目访问路径):

String getContextPath();
//示例:/servlet-project

获取URL(统一资源定位符):

StringBuffer getRequestURL();
//示例:http://localhost:8080/servlet-project/demo

获取 URI(统一资源标识符):

String getRequestURI();
//示例:/servlet-project/demo

获取请求参数(GET 请求):

String getQueryString();
//示例:username=zhangsan

案例

@WebServlet("/demo")
public class ServletDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取请求方式
        String method = request.getMethod();
        System.out.println(method);
        //获取虚拟目录(项目访问目录)
        String contextPath = request.getContextPath();
        System.out.println(contextPath);
        //获取URL
        StringBuffer requestURL = request.getRequestURL();
        System.out.println(requestURL);
        //获取URI
        String requestURI = request.getRequestURI();
        System.out.println(requestURI);
        //获取GET请求方式的请求参数
        String queryString = request.getQueryString();
        System.out.println(queryString);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

重启服务器,在浏览器中访问 htpp://localhost:8080/servlet-project/demo?name=zhangsan ,结果如下:

image-20230210153239752

2. 获取请求头数据

在请求头数据中,一般格式为 key : value 。如下:

image-20230210150811971

我们可以根据请求头的名称获取其值,方法如下:

String getHeader(String name);

案例:在 Java 代码中获取浏览器版本信息。

@WebServlet("/demo")
public class ServletDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String agent = request.getHeader("user-agent");
        System.out.println(agent);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

结果:

image-20230210151857013

3. 获取请求体数据

我们在浏览器地址栏中输入访问地址后,一般发送 GET 请求给服务器,GET 请求是没有请求体的,其请求参数存放在请求行中。请求体中的数据格式如下:

Request 对象提供了两种方式来获取请求体中数据,分别是:

获取字节输入流:

//该方法用于获取字节数据,例如文件数据
ServletInputStream getInputStream();

获取字符输入流:

//该方法用于获取字符数据,例如纯文本数据
BufferedReader getReader();

我们可以添加一个 form 表单,并修改其 method 属性为 post ,用来验证 POST 请求获取请求体数据。在 webapps 文件目录下创建一个 HTML 页面 req.html ,如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<!--
    action:form表单提交的请求地址
    method:请求方式,指定为post
-->
<form action="/servlet-project/demo" method="post">
  <input type="text" name="username">
  <input type="password" name="password">
  <input type="submit">
</form>
</body>
</html>

在 Servlet 类中的 doPost() 方法中获取请求体数据,如下:

@WebServlet("/demo")
public class ServletDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.获取字符输入流
        BufferedReader br = request.getReader();
        //2.获取数据
        String s = br.readLine();
        System.out.println(s);
    }
}

在浏览器中访问:htpp://localhost:8080/servlet-project/req.html ,在浏览器页面输入数据,点击提交,此时可以在控制台看到客户端浏览器发送的请求体数据。如图:

image-20230210154816746

4. 获取请求参数的通用方式

在上面的例子中,客户端浏览器发送不同的请求,服务器端会执行不同的方法,例如浏览器发送了 GET 请求,在会在服务器端执行 doGet() 方法,这样就导致了不同的方法中出现了大量的相同业务代码,这样程序的维护性和可读性都会降低。

为了解决这个问题,我们可以在 doPost() 方法中调用 doGet() 方法,并同时传入需要的参数信息。

例如

@WebServlet("/demo")
public class ServletDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
           //采用request提供的获取请求参数的通用方式来获取请求参数
           //编写其他的业务代码...
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request,response);
    }
}

然而,两种不同的请求方式获取请求参数的方法是不同的,我们该如何使用一种统一的方法来获取请求参数,从而统一不同方法里面的代码呢?

解决方案一

判断浏览器发送的请求方式,根据不同的请求方式,使用不同的方法来获取请求参数。示例:

@WebServlet("/demo")
public class ServletDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String method = request.getMethod();
        String params=" ";
        if(method.equals("GET")){
            params = request.getQueryString();
        } else if (method.equals("POST")) {
            BufferedReader reader = request.getReader();
            params = reader.readLine();
        }
        System.out.println(params);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request,response);
    }
}

解决方案二

使用方案一的方法时,每个 Servlet 都要写相同的代码,并且获取到的请求参数都是全部的数据作为一个字符串,实现起来非常的麻烦。

request 对象对上述获取请求参数的方法进行了封装,使得操作更加的便捷,我们只需要调用对应的方法就可以轻松的获取请求参数。

其底层是怎么实现的呢?

首先,根据不同的请求方式获取请求参数,如下:

image-20230210163329659

接下来,把获取到的请求参数分割,如下:

在这里插入图片描述

最后,将数据存放在 Map 集合中,由于参数的值可能不止一个,所以使用字符串数组,如下:

image-20230210164003680

request 为我们提供了以下的方法,让我们可以快捷的获取请求参数。

获取所有参数 Map 集合:

Map<String,String[]> getParameterMap();

根据名称获取参数值(数组):

String[] getParameterValue(String name);

根据名称获取参数值(单个值):

String getParameter(String name);

接下来,通过小 demo 练习上面获取请求参数的方法。

准备工作:在 webapps 目录下添加 html 页面,如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>

<form action="/servlet-project/demo" method="get">
  <input type="text" name="username"><br>
  <input type="password" name="password"><br>
  <input type="checkbox" name="hobby" value="1"> 游泳
  <input type="checkbox" name="hobby" value="2"> 爬山 <br>
  <input type="submit">
</form>
</body>
</html>

第二步:获取 GET 请求方式的所有请求参数

@WebServlet("/demo")
public class ServletDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //GET请求逻辑
        System.out.println("get....");
        //1. 获取所有参数的Map集合
        Map<String, String[]> map = req.getParameterMap();
        for (String key : map.keySet()) {
            // username:zhangsan lisi
            System.out.print(key+":");

            //获取值
            String[] values = map.get(key);
            for (String value : values) {
                System.out.print(value + " ");
            }
            
            System.out.println();
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    }
}

image-20230210165411697

第三步:获取 GET 请求方式中的 hobby 数据,结果为数组。

@WebServlet("/req2")
public class ServletDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //GET请求逻辑代码
        //...
        String[] hobbies = req.getParameterValues("hobby");
        for (String hobby : hobbies) {
            System.out.println(hobby);
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    }
}

image-20230210170516246

image-20230210170537545

第四步:获取 GET 请求方式中的用于名和密码,结果为单个数据。

@WebServlet("/demo")
public class ServletDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //GET请求逻辑代码
        //...
        String username = req.getParameter("username");
        String password = req.getParameter("password");

        System.out.println(username);
        System.out.println(password);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    }
}

image-20230210171037151

image-20230210171005535

同样的,我们还可以使用此方法获取 POST 等请求方式的请求参数,只需要将 form 表单中的 method 属性修改为 POST ,并且将逻辑代码写入 doPost 代码块中,这里不过多赘述。

上面的编码方式大大的提高了编码的效率,减少了重复代码,提高了代码的可读性和维护性,所以后期在编写 Servlet 代码时,我们就可以使用下面的固定格式来编写代码。

@WebServlet("/demo")
public class ServletDemo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
           //采用request提供的获取请求参数的通用方式来获取请求参数
           //编写其他的业务代码...
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request,response);
    }
}

既然每次创建 Servlet 都可以使用上面固定的模板,那么我们有没有更加高效的创建方法呢?其实,idea 中提供了模板来快速的创建一个 Servlet。

3. IDEA中快速创建 Servlet

第一步

按照自己的需求,修改 Servlet 创建模板的内容。如图:

image-20230210172231738

第二步

使用 Servlet 模板创建 Servlet 类,右击项目中的包 / new / Servlet 。如图:

image-20230210172518254

接下来给 Servlet 类命名等,我们就成功通过模板快速的创建了一个 Servlet 类,当然我们也可以在设置中修改模板,让我们在快速创建 Servlet 时按照自己理想的模板创建。

下期见。

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

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

相关文章

CS144-Lab2

实验架构 除了写入传入流之外&#xff0c;TCPReceiver 还负责通知 sender 两件事&#xff1a; “First unassembled” 字节的索引&#xff0c;称为“acknowledgment”或 “ackno”。这是接收方需要来自发送方的第一个字节。“first unassembled ” 索引和“first unacceptable…

【项目精选】基于SSH的任务调度系统的设计与实现(视频+源码+论文)

点击下载源码 虽然科技进步在改革开发这几十年来速度飞快&#xff0c;计算机行业也发展迅速&#xff0c;但仍然有大量商家或企业&#xff0c;甚至项目组&#xff0c;采用落后的人工管理方式或者低效的任务调度策略&#xff0c;这无疑是对计算机的一种无视。 计算机处理信息的准…

Python每日一练(20230220)

目录 1. 存在重复元素 II 2. 按要求实现程序功能 3. 分割链表 附录 链表 1. 存在重复元素 II 给定一个整数数组和一个整数 k&#xff0c;判断数组中是否存在两个不同的索引 i 和 j&#xff0c;使得 nums [i] nums [j]&#xff0c;并且 i 和 j 的差的 绝对值 至多为 k。 …

高级数据类型

为了解决单一的业务而存在bitmapsBitmaps类型的基础操作 获取指定key对应偏移量上的bit值getbit key offset 设置指定key对应偏移量上的bit值&#xff0c;value只能是1或0setbit key offset valueBitmaps类型的扩展操作状态位的统计业务需求&#xff1a;1. 统计每天某一部电…

云计算ACP云服务器ECS实例题库(三)

&#x1f618;作者简介&#xff1a;一名99年软件运维应届毕业生&#xff0c;正在自学云计算课程。&#x1f44a;宣言&#xff1a;人生就是B&#xff08;birth&#xff09;和D&#xff08;death&#xff09;之间的C&#xff08;choise&#xff09;&#xff0c;做好每一个选择。&…

关于监控服务器指标、CPU、内存、警报的一些解决方案

文章目录关于监控服务器指标、CPU、内存、警报的一些解决方案Prometheus Grafana 配置 IRIS / Cach 监控服务器Prometheus简介特点架构图Grafana简介特点配置流程自定义Prometheus接口定义配置 Exporter 监控服务器系统资源简介配置流程使用 Alertmanager报警简介配置流程基于…

软考高级-信息系统管理师之知识管理(最新版)

知识管理 知识与知识管理知识管理常用的方法和工具显性知识的管理隐形知识的管理知识管理的工具学习型组织知识产权保护计算机软件保护条例商标法专利法补充建议学的考点:知识与知识管理 1、知识的分类 知识可分为两类,分别是显性知识与隐性知识。 凡是能以文字与数字来表达…

【C++】关联式容器——map和set的使用

文章目录一、关联式容器二、键值对三、树形结构的关联式容器1.set2.multiset3.map4.multimap四、题目练习一、关联式容器 序列式容器&#x1f4d5;:已经接触过STL中的部分容器&#xff0c;比如&#xff1a;vector、list、deque、forward_list(C11)等&#xff0c;这些容器统称为…

新能源汽车,有毒

作者| Mr.K 编辑| Emma来源| 技术领导力(ID&#xff1a;jishulingdaoli)新能源汽车到底有多火&#xff0c;生生逼得奥迪某4S店挂出横幅&#xff1a;我们也有纯电新能源&#xff01;老牌名车的辛酸憋屈溢出屏幕。网友神评补刀“这标语给人‘诺基亚也有智能大屏机’的感觉。”一…

【Java基础】变量

Java基础 变量 variable 变量类型 实例变量(非静态字段) Instance Variables (Non-Static Fields) 类的非静态属性 类变量(静态字段) Class Variables (Static Fields) 类的静态属性 局部变量 Local Variables 参数 Parameters 变量命名 大小写敏感 开头&#xff1a;字…

爬虫基本知识的认知(爬虫流程 HTTP构建)| 爬虫理论课,附赠三体案例

爬虫是指通过程序自动化地从互联网上获取数据的过程。 基本的爬虫流程可以概括为以下几个步骤&#xff1a; 发送 HTTP 请求&#xff1a;通过 HTTP 协议向指定的 URL 发送请求&#xff0c;获取对应的 HTML 页面。解析 HTML 页面&#xff1a;使用 HTML 解析器对获取的 HTML 页面…

linux shell 入门学习笔记4 shell运维和编程语言

shell 运维和编程语言 脚本注释 shell脚本中&#xff0c;#后面的内容表示注释内容&#xff0c;一般是给开发者或使用者观看&#xff0c;解释器会忽略此部分内容注释可以单独写一行&#xff0c;也可以跟在文件末尾保持注释的习惯&#xff0c;尽量使用英文 例子&#xff1a; #…

C++类和对象(2)构造、析构函数

类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。 class Date{}; 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何类在什么都不写时&#xff0c;编译器会自动生成以下6个默认成员 函数。 默认成员函数&#xff1a;用户没有显式实现&…

什么是健康建筑?

WIKIPEDIA健康建筑是指支援建筑和建筑环境中人们&#xff0c;身体、心理和社会健康与福祉的新兴兴趣领域。建筑物可以成为健康和福祉的关键促进者&#xff0c;因为大多数人大部分时间都花在室内。根据全美国人类活动模式调查&#xff0c;美国人「平均 87% 的时间花在封闭的建筑…

redis-如何保证数据库和缓存双写一致性?

前言 数据库和缓存&#xff08;比如&#xff1a;redis&#xff09;双写数据一致性问题&#xff0c;是一个跟开发语言无关的公共问题。尤其在高并发的场景下&#xff0c;这个问题变得更加严重。 我很负责的告诉大家&#xff0c;该问题无论在面试&#xff0c;还是工作中遇到的概率…

windows版Rsync服务端和客户端cwRsync_4.1.0安装测试

下载地址&#xff1a;https://download.csdn.net/download/qq_32421489/87463506 服务端安装&#xff1a; cwRsyncServer&#xff08;服务端&#xff09;配置步骤 1.双击运行wRsyncServer_4.1.0_Installer.exe。 2.这里创建的账户是操作系统的&#xff0c;创建的这个账户是专…

【 RA4M2开发板环境搭建之串口下载1】

【 RA4M2开发板环境搭建1】1. 前言1.1 活动来源1.2 开发环境1.3 RA4M2开发板2. MDK环境准备2.1 keil 5下载安装2.2 安装RA4M2的软件支持包2.3 Renesas Flash Programmer安装3. RA Smart Configurator配置3.1 下载RA Smart Configurator3.2 安装RA Smart Configurator4. 新建RA4…

你是真的“C”——C语言详解求两个正数最小公倍数的3种境界

C语言详解求两个正数最小公倍数的3种境界~&#x1f60e;前言&#x1f64c;必备小知识~&#x1f618;求最小公倍数境界1~ &#x1f60a;求最小公倍数境界2~ &#x1f60a;求最小公倍数境界3~ &#x1f60a;总结撒花&#x1f49e;博客昵称&#xff1a;博客小梦&#x1f60a; 最喜…

[Incognito 4.0] ictf 2023

一周4赛&#xff0c;有点赶不过来呀。只做了一点&#xff0c;队长组队的时候(每次都中间断掉&#xff0c;一大堆写的都得从头来)CryptoAncient这样的第2次见&#xff0c;第1次就不会&#xff0c;这回看了队友wp终于知道是怎么加密的了Templed每个符号可以表示4位10进制数。原题…

〖产品思维训练白宝书 - 核心竞争力篇⑭〗- 产品经理核心竞争力解读之学习能力

大家好&#xff0c;我是 哈士奇 &#xff0c;一位工作了十年的"技术混子"&#xff0c; 致力于为开发者赋能的UP主, 目前正在运营着 TFS_CLUB社区。 &#x1f4ac; 人生格言&#xff1a;优于别人,并不高贵,真正的高贵应该是优于过去的自己。&#x1f4ac; &#x1f4e…