当前位置: 首页 > news >正文

JavaWeb-HttpServletRequest请求域接口

文章目录

  • HttpServletRequest请求域接口
    • HttpServletRequest请求域接口简介
    • 关于请求域和应用域的区别
  • 请求域接口中的相关方法
    • 获取前端请求参数(getParameter系列方法)
    • 存储请求域名参数(Attribute系列方法)
    • 获取客户端的相关地址信息
    • 获取项目的根路径
  • 关于转发和重定向的细致剖析
    • 转发代码实现及相关问题
    • 重定向代码实现及相关问题

HttpServletRequest请求域接口

HttpServletRequest请求域接口简介

其实关于请求域这个词也蛮熟悉的, 因为我们之前学习过 应用域 这一概念, 应用域的生命周期很长, 伴随这服务器的启动和终止, 作用范围也很广, 对所有的处于当前 webapp 也就是 web 应用的所有Servlet对象都生效


  • HttpServletRequest 是位于jakarta.servlet.http.*包下面的一个接口

  • 继承了ServletRequest接口
    public interface HttpServletRequest extends ServletRequest

  • 之前我们学习过HTTP协议的相关内容, 这个对象中封装的其实就是网络传输的时候, 发送的HTTP请求(Request)中封装的相关参数内容信息

  • 实现这个接口是Tomcat服务器实现的, 传递对象封装参数也是Tomcat服务器完成好的内容, 我们作为Java程序员, 只需要学习获取其中封装的相关参数即可


关于请求域和应用域的区别

  • 生命周期不同, 应用域伴随着Tomcat的生命周期 而 请求域 只作用域这一次请求之内, 而且http协议的特点就是, 一次请求一次创建一次请求域对象
  • 而且在进行参数设定的时候, 尽量的去选择请求域的参数而不是应用域的参数, 因为小的域的对象占用的资源比较小

请求域接口中的相关方法

上面都说了, 请求域是封装了相关的http协议的参数信息, 所以必定提供了一些方法来让我们程序员获取到这些参数的信息…


获取前端请求参数(getParameter系列方法)

首先我们思考, 前端传递过来的参数应该采用什么数据结构来组织比较好

我们从下面的前端的页面中获取信息

<!DOCTYPE html>
<html lang='en'>
<head><meta charset='UTF-8'><meta name='viewport' content='width=device-width, initial-scale=1.0'><title>个人信息</title>
</head>
<body><h2>个人信息</h2><form action="" method="get">姓名:<input type="text" name="name" value=""><br>年龄:<input type="text" name="age" value=""><br>性别:<input type="radio" name="sex" value=""><input type="radio" name="sex" value=""><br>爱好:<input type="checkbox" name="hobby" value="吃饭"><input type="checkbox" name="hobby" value="睡觉"><input type="checkbox" name="hobby" value="打游戏"><br><input type="submit" value="提交"></form>
</body>
</html>

我们执行 http://127.0.0.1:8080/servlet08/test.html

在这里插入图片描述

我们对URL拆解如下(涉及URLEncoding)

在这里插入图片描述

我们可以发现, 前端向后端提交数据的格式其实并不是单纯的键值对的结构存储的, 因为如果是键值对结构存储的话, 一个key只能对应一个value, 但是复选框这种提交信息的结构, 一个key可以对应多个value信息

所以实际上, 我们的前端发来的数据存储格式是一个特殊的map集合

Map<String, String[]> map = new HashMap<>();

一个String类型的key可以对应一个String[] 数组, 也就是多个value(前端传递参数都是String类型)


上面是一个html页面, 其中包含test类型文本, 单选框, 复选框

在这里插入图片描述

上面的方法的解释:

  • String getParameter(String name): 根据key返回String数组中的第一个参数
  • String[] getParameterValues(String name): 根据key返回完整的String[]数组
  • Enumeration< String > getParameterNames(): 返回一个由所有key组成的集合
  • Map<String, String[]> getParameterMap(): 返回一个key和value组成的完整的集合

还拿我们上面写的那个html页面进行测试(设置一下传递的Servlet路径地址)
(注意, 我们下面的method其实写错了, 实际上是post请求)

在这里插入图片描述

Servlet对象的源码如下

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.*;
import java.util.Enumeration;
import java.util.Map;@WebServlet(urlPatterns = "/getparameter")
public class GetParameterServlet extends HttpServlet {// 由于是form表单提交的数据, 我们尽量采用重写doPost的方式进行测试@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 最好还是设置一下字符集, 防止出现乱码response.setContentType("text/html;charset=UTF-8");PrintWriter out = response.getWriter();// 1. 使用getParameterMap获取整个的map形式参数集合out.print("<h3>使用getParameterMap获取整个集合</h3>");Map<String, String[]> parameterMap = request.getParameterMap();for(Map.Entry<String, String[]> entry : parameterMap.entrySet()){out.print(entry.getKey() + "=");for(String value : entry.getValue()){out.print(value + " ");}}out.print("<br>");out.print("====================================<br>");// 2. 使用getParameterNames获取整个参数集合的keyout.print("<h3>使用getParameterNames获取整个集合中的key</h3>");Enumeration<String> parameterNames = request.getParameterNames();while(parameterNames.hasMoreElements()){String name = parameterNames.nextElement();out.print(name + " ");}out.print("<br>");out.print("====================================<br>");// 3. 使用getParameterValues, 根据key获取参数集合的value数组String[] hobbys = request.getParameterValues("hobby");out.print("hobby=");for(String hobby : hobbys){out.print(hobby + " ");}out.print("<br>");out.print("====================================<br>");// 4. 使用getParameter, 根据key获取到value数组中的第一个值String name = request.getParameter("name");out.print("name=" + name);out.print("<br>");out.print("====================================<br>");}
}

测试:

下面是form表单中提交的数据信息

在这里插入图片描述


下面是在浏览器中输出的内容

在这里插入图片描述


存储请求域名参数(Attribute系列方法)

Attribute 这个词其实我们很熟悉了, 因为之前学习ServletContext就出现过这个词, 也出现了和下面一模一样的一系列方法, 当时是设置应用域对象, 但是现在是设置请求域对象

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

  • void setAttribute(String name, Object o): 设置请求域参数
  • Object getAttribute(String name): 获取请求域参数
  • Enumeration< String > getAttributeNames(): 获取所有请求域的key组成的集合
  • void removeAttribute(String name): 移除 key 为参数的请求域信息

没啥可说的, 直接上测试代码

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.*;
import java.util.Enumeration;// 使用注解来配置Servlet
@WebServlet("/attribute")
public class AttributeInfoServlet extends HttpServlet {// 重写doGet方法@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html");PrintWriter out = response.getWriter();// 1. 使用 void setAttribute(String name, Object o) 设置请求域参数request.setAttribute("name", "Jack");request.setAttribute("age", 18);// 2. 使用 Object getAttribute(String name) 获取请求域参数Object name = request.getAttribute("name");Object age = request.getAttribute("age");out.print("<h3>" + name + " " + age + "</h3>");out.print("<br>========================================<br>");// 3. 使用 Enumeration< String > getAttributeNames() 获取所有的请求域参数key集合Enumeration<String> attributeNames = request.getAttributeNames();while (attributeNames.hasMoreElements()) {String attributeName = attributeNames.nextElement();out.print("<h3>" + attributeName + "</h3>");}out.print("<br>========================================<br>");// 4. 使用 void removeAttribute(String name) 移除参数request.removeAttribute("name");Object name1 = request.getAttribute("name");out.print("<h3>" + name1 + "</h3>");}
}

测试结果如下

在这里插入图片描述

获取客户端的相关地址信息

我们需要掌握下面的三个获取地址相关信息的方法

  • getRemoteAddr(): 获取客户端主机IP
  • getRemotePort(): 获取客户端的应用端port(端口号)
  • getRemoteHost(): 获取客户端主机名称

下面是关于上面的三个方法的测试代码(我们直接给出)

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.*;// 使用注解代替web.xml进行Servlet的配置
@WebServlet(urlPatterns = "/addr")
public class GetAddr extends HttpServlet {// 重写doGet方法@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 设置返回的类型以及获取输出流信息response.setContentType("text/html");PrintWriter out = response.getWriter();// 1. 使用getRemoteAddr获取客户端的IP信息String remoteAddr = request.getRemoteAddr();out.print("<h3>客户端的IP地址为</h3><br>");out.print(remoteAddr);out.print("<br>=====================================");// 2. 使用getRemotePort获取客户端的端口号的信息int remotePort = request.getRemotePort();out.print("<h3>客户端的端口号为</h3><br>");out.print(remotePort);out.print("<br>======================================");// 3. 使用getRemoteHost获取客户端的主机名称String remoteHost = request.getRemoteHost();out.print("<h3>客户端的主机名号为</h3><br>");out.print(remoteHost);}
}

在浏览器上面访问这个资源, 可以得到下面的内容

在这里插入图片描述

注意我们的端口号其实不是固定的, 每一次请求的端口号都是在一个范围之内进行随机的, 因为我们的规范建议客户端的端口号设置为变化的, 服务器端的端口号设置为不变的…


获取项目的根路径

这个方法其实用的还是很多的, 因为我们在大量的场景中都需要动态获取根路径, 也就是项目路径, 我们在先前的内容中其实也提到过这个方法…

  • getContextPath(): 获取项目部署的路径…

测试就省略了, 主要是想说这个方法的作用非常的重要, 我们好多地方获取项目的路径都需要这个方法…


关于转发和重定向的细致剖析

首先要了解, 不管是转发和重定向, 其目的都是为了实现资源的跳转

也就是Java中有两种方式实现资源的跳转

  • 转发
  • 重定向

转发代码实现及相关问题

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

  • getRequestDispatch(String servletName): 通过给定的转发的ServletName地址获取一个分发器对象
  • forward(request, response): 把当前Servlet对象的请求响应对象作为参数传递到转发当中去, 从而实现位于同一个请求域的作用…

转发的代码实现

首先创建一个AServlet对象(相关注释都在代码中)

import bean.User;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.*;// 使用注解信息简化Servlet配置
// 我们把这个 AServlet 作为资源访问的入口, 然后对 BServlet进行资源的转发(所以二者本质上还是一次请求, 共享同一个请求域)
@WebServlet(urlPatterns = "/a")
public class AServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 因为要测试转发是不是在一次请求之内转发(也就是多个Servlet共享同一个request和response对象)// 我们设置相关的请求域参数(我们把用户定义在了另一个包当中, 等会我们复制代码就不展示User类了, 应该可以看懂)request.setAttribute("user", new User("huahua", "19", "zz"));// 获取分发器对象, 调用分发器对象的forward方法对这次请求进行转发RequestDispatcher requestDispatcher = request.getRequestDispatcher("/b");requestDispatcher.forward(request, response);}
}

创建一个BServlet对象作为AServlet的转发请求的地址

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import bean.User;import java.io.*;// 使用注解简化Servlet配置
// 这个BServlet作为转发的接收方, 接收AServlet的转发
@WebServlet(urlPatterns = "/b")
public class BServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html");PrintWriter out = response.getWriter();// 获取AServlet中的应用域的参数Object user = request.getAttribute("user");// 强制类型转化User us = (User) user;// 输出其中的信息内容out.print(us);}
}

在这里插入图片描述

我们现在在浏览器中访问AServlet的资源, 显然, 跳转到了BServlet中

  • 可以发现, 在A中设置的请求域参数, B中同样可以获取, 所以可以判定二者位于同一个请求域
  • 通过URL可以发现, 虽然资源跳转到了BServlet, 但是URL中的地址还是显示的AServlet的地址, 所以我们可以了解到, 其实转发是一种Tomcat服务器内部进行的资源跳转, 和浏览器无关(和重定向区分的重要依据)
  • 根据上面的提示, 我们可以了解到, 转发是同一次请求的转发, 也就是只能在一种方法当中之间进行转发, 全部都在doGet内部转发, 或者全部都在doPost请求中进行转发…

转发不可以在不同的方法之间完成跳转, 测试如下
假设我们把 BServlet中的 doGet 方法转换为 doPost 方法

在这里插入图片描述

其他代码完全不变, 此时再次向AServlet发送请求

在这里插入图片描述

会发现直接报错, 报错信息是 405 method not allowed

其实针对上述问题, 我们还是有解决方案的, 只需要在doGet方法内部调用doPost就可以避免这种问题

在这里插入图片描述

继续访问AServlet, 会发现程序还是可以正常执行
在这里插入图片描述


重定向代码实现及相关问题

和转发不同, 重定向调用的API位于response对象中

通过 response 对象调用 sendReDirect(/项目路径/Servlet路径)方法进行重定向

代码测试

CServlet如下

import bean.User;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.*;// 使用注解简化开发
@WebServlet(urlPatterns = "/c")
public class CServlet extends HttpServlet {// 重写doGet方法@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 在CServlet类中设置请求域参数, 然后在DServlet中获取这个请求域参数, 查看是否可以获取得到...request.setAttribute("user", new User("huahua", "19", "zz"));// 调用 sendRedirt 进行重定向操作(重定向要加上项目的地址), 重定向至DServletresponse.sendRedirect(request.getContextPath() + "/d");}
}

DServlet

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;import java.io.*;// 使用注解简化开发
@WebServlet(urlPatterns = "/d")
public class DServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html");PrintWriter out = response.getWriter();// 尝试接收CServlet中设置的请求域参数, 查看是不是可以获取到(其实本质是查看是不是一次请求)Object user = request.getAttribute("user");out.println(user == null ? "不是一个请求" : "是一个请求");}
}

向CServlet发送请求
在这里插入图片描述

获取响应结果如下

在这里插入图片描述

  • 很明显的看到URL中的资源明显的发生了改变

我们不妨抓个包看一看刚才发生了什么

会发现出现了两次请求…

在这里插入图片描述

第一次向CServlet发送了请求, 这是第一次的请求响应信息

在这里插入图片描述

可以发现, 响应时的状态码是 302 Found

在这里插入图片描述

也就是发生了重定向的操作

第二次请求是直接通过浏览器向DServlet发送了一个请求而不是Tomcat资源内部的跳转, 具体不再演示了



http://www.mrgr.cn/news/93323.html

相关文章:

  • Kubernetes教程(四)Dockerfile构建镜像
  • NLP基础之传统RNN模型
  • 每日一题——接雨水
  • Kubernetes(K8S)部署 Redis Cluster 集群
  • golang反射
  • RabbitMQ 2025/3/5
  • sqli-lab靶场学习(七)——Less23-25(关键字被过滤、二次注入)
  • 基于Matlab的多目标粒子群优化
  • c++ 纯虚函数
  • c++ 接口/多态
  • 国内支持Stable Diffusion模型的平台
  • CSS—属性继承与预处理器:2分钟掌握预处理器
  • 机器学习--特征选择
  • 自然语言模型(NLP)介绍
  • 鬼泣:项目前置设置杂项
  • 【零基础C语言】第四节 数组
  • QT5 GPU使用
  • vLLM代码推理Qwen2-VL多模态大模型(远程服务器解决方案,无需UI)
  • 机器学习数学基础:40.结构方程模型(SEM)中卡方值与卡方自由度比
  • 人工智能神经网络基本原理