JavaWeb基础(2)- Web概述、HTTP协议、Servlet、Request与Response

JavaWeb基础(2)- Web概述、HTTP协议、Servlet、Request与Response

文章目录

  • JavaWeb基础(2)- Web概述、HTTP协议、Servlet、Request与Response
    • 3 Web概述
      • 3.1 Web和JavaWeb的概念
      • 3.2 JavaWeb技术栈
        • 3.2.1 B/S架构
        • **3.2.2 静态资源**
        • 3.2.3 动态资源
        • 3.2.4 数据库
        • 3.2.5 Web的访问过程
    • 4 XML
      • 4.1 概述
      • 4.2 语法
      • 4.3 DOM4J进行XML解析
    • 5 HTTP协议
      • 5.1 HTTP协议特点
      • 5.2 请求数据格式
      • 5.3 响应数据格式
      • 5.4 自定义服务器
    • 6 Servlet
      • 6.1 Servlet生命周期
      • 6.2 getServletInfo和getServletConfig(了解)
      • 6.3 执行流程
    • 7 Request(请求)、Response(响应)
      • 7.1 Request对象
        • 7.1.1 Request继承体系
        • 7.1.2 Request获取请求数据
          • 7.1.2.1 获取请求行数据
          • 7.1.2.2 获取请求头数据
          • 7.1.2.3 获取请求体数据
        • 7.1.3 模板
        • 7.1.4 请求参数中文乱码问题
        • 7.1.5 Request请求转发
          • 7.1.5.1 请求转发
          • 7.1.5.2 共享数据
      • 7.2 Response对象
        • 7.2.1 Response设置响应数据功能介绍
          • 7.2.1.1 响应行
          • 7.2.1.2 响应头
          • 7.2.1.3 响应体
        • 7.2.2 Response完成重定向
          • 7.2.2.1 重定向的实现方式
          • 7.2.2.2 请求重定向和请求转发对比
          • 7.2.2.3 虚拟路径添加判断
        • 7.2.3 Response响应字符数据
        • 7.2.4 Response响应字节数据
        • 7.2.3 Response响应字符数据
        • 7.2.4 Response响应字节数据

3 Web概述

3.1 Web和JavaWeb的概念

Web是全球广域网,也称为万维网(www),能够通过浏览器访问的网站。

JavaWeb就是用Java技术来解决相关web互联网领域技术栈

3.2 JavaWeb技术栈

3.2.1 B/S架构

B/S 架构:Browser/Server,浏览器/服务器 架构模式

它的特点是:客户端只需要浏览器,应用程序的逻辑和数据都存储在服务器端
1627031933553

B/S架构的好处: 易于维护升级。服务器端升级后,客户端无需任何部署就可以使用到新的版本

3.2.2 静态资源
  • 静态资源主要包含HTML、CSS、JavaScript、图片等,主要负责页面的展示。
3.2.3 动态资源
  • 动态资源主要包含Servlet、JSP等,主要用来负责逻辑处理

    Servlet

    • Servlet 是 Java 编写的服务器端程序
    • 它们接收来自客户端(通常是浏览器)的请求,处理请求,生成动态内容,并将结果发送回客户端
    • Servlet 可以处理各种类型的请求和响应,如 HTML、XML、JSON 等
    • Servlet 提供了灵活性和控制权,允许程序员直接处理请求和生成响应

    JSP

    • JSP 是一种基于 Java 的服务器端技术,允许开发者在 HTML 页面中嵌入 Java 代码

    • JSP 页面被服务器翻译成 Servlet,然后由 Servlet 容器运行

    • JSP 提供了一种简化创建动态 Web 内容的方式,因为它允许将 Java 代码嵌入到 HTML 中,使得页面的开发更加方便

      <!DOCTYPE html>
      <html lang="en">
      <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>JSP in HTML Example</title>
      </head>
      <body><header><h1>Welcome to My Website</h1></header><section><p>This is a simple example of using JSP in HTML.</p><%-- JSP code to get the current date and time --%><% java.util.Date currentDate = new java.util.Date(); %><p>Current Date and Time: <%= currentDate %></p></section><footer><p>&copy; 2023 My Website. All rights reserved.</p></footer></body>
      </html>
      

      展示效果:

      image-20231229163537444

  • 动态资源处理完逻辑后会把**得到的结果交给静态资源**来进行展示,动态资源和静态资源要结合一起使用

3.2.4 数据库
  • 数据库主要负责存储数据。
3.2.5 Web的访问过程
  • 整个Web的访问过程就如下图所示:

    image-20231229164905951

    (1)浏览器发送一个请求到服务端,去请求所需要的相关资源;
    (2)资源分为动态资源和静态资源,动态资源可以是使用Java代码按照Servlet和JSP的规范编写的内容;
    (3)在Java代码可以进行业务处理也可以从数据库中读取数据;
    (4)拿到数据后,把数据交给HTML页面进行展示,再结合CSS和JavaScript使展示效果更好;
    (5)服务端将静态资源响应给浏览器;
    (6)浏览器将这些资源进行解析;
    (7)解析后将效果展示在浏览器,用户就可以看到最终的结果。

4 XML

4.1 概述

  • XML是EXtensible Markup Language的缩写,翻译过来就是可扩展标记语言
  • 可扩展 三个字表面上的意思是XML允许自定义格式。但这不代表你可以随便写。

  • XML基本语法这个知识点的定位是:我们不需要从零开始,从头到尾的一行一行编写XML文档,而是在第三方应用程序、框架已提供的配置文件的基础上修改。要改成什么样取决于你的需求,而怎么改取决XML基本语法和具体的XML约束。

  • 主要作用:配置信息

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration><database><host>localhost</host><port>3306</port><username>admin</username><password>secretpassword</password></database><appSettings><theme>light</theme><language>en_US</language></appSettings>
    </configuration>
    

回顾:常见的配置文件类型

  1. properties文件,例如druid连接池就是使用properties文件作为配置文件
  2. XML文件,例如Tomcat就是使用XML文件作为配置文件
  3. YAML文件,例如SpringBoot就是使用YAML作为配置文件
  4. json文件,通常用来做文件传输,也可以用来做前端或者移动端的配置文件
  5. 等等…

4.2 语法

XML的基本语法和HTML的基本语法简直如出一辙。

  • XML命名规则

    1、名称可以包含字母、数字以及其他的字符。

    2、名称不能以数字或者标点符号开始。

    3、名称不能以字母 xml(或者 XML、Xml 等等)开始。

    4、名称不能包含空格。

    5、可使用任何名称,没有保留的字词。

    <first_name><last_name>
    
  • XML声明

    <!--声明xml文件,设置xml文件的编码,版本的信息-->
    <?xml version="1.0" encoding="utf-8"?>
    
  • XML元素

    XML 元素指的是从(且包括)开始标签直到(且包括)结束标签的部分

    <?xml version="1.0" encoding="utf-8"?>
    <books><book><name>三国演义</name><author>罗贯中</author><price>39.9</price><version>1.0</version></book>
    </books>
    
  • XML注释

    XML中的注释和html中的注释的写法是一样的

  • XML属性

    书写在标签内的。对标签的数据进行扩展。对标签的进一步描述

    <标签名 属性名=“属性值” 属性名=“属性值”> </标签名> 
    
  • CDATA区

    CDATA区:可以输出特殊字符:原样的显示书写在CDATA的内容。会原封不动的显示出去。

    转义表达符号意义
    &lt;<小于
    &gt;>大于
    &amp;&和号
    &apos ;单引
    &quot ;“”双引

    示例:

    <books><book><name>西游记</name><!--为author添加扩展信息, 如:name , age 等1、多个属性之间用空间分隔2、属性要书写在开始标签内3、在xml中属性一定要用双引或单引,引起来4、属性名要按命名规则来--><author sex="" address="郑州">&lt;吴承恩&gt;</author><pirce>50</pirce><version>1.2</version></book>
    </books>
    

    效果:

    image-20231230151759910

4.3 DOM4J进行XML解析

  1. 导入相关依赖dom4j
  2. 创建解析器对象(SAXReader)
  3. 解析xml 获得Document对象
  4. 获取根节点RootElement
  5. 获取根节点下的子节点

示例:

创建user.xml

<?xml version="1.0" encoding="UTF-8" ?>
<users><user id="10001" country="Chinese" source="Android"><id>10001</id><name>admin</name><password>111111</password></user><user id="10002" country="Chinese" source="ios"><id>10002</id><name>tony</name><password>666666</password></user>
</users>

创建Dom4jParseUserXmlTest类,获取user.xml中相关信息:

package com.baidu;import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;import java.util.List;public class Dom4jParseUserXmlTest {public static void main(String[] args)  {//1、创建解析器对象SAXReader saxReader = new SAXReader();//2、使用解析器对象读取XML文档生成Document对象try {Document document = saxReader.read(Dom4jParseUserXmlTest.class.getClassLoader().getResource("user.xml"));//3、根据Document对象获取XML的元素标签信息/*** 1、org.dom4j.Document常用方法*      Element getRootElement(); 获取XML文件的根节点* 2、org.dom4j.Element常用方法*      String getName();返回*      List<Element>elements();获取标签的子标签*///3.1 获取XML文件的根节点Element rootElement = document.getRootElement();System.out.println("user.xml文件的根节点的名字为"+rootElement.getName());//3.2 获取XML文件的根节点下的子节点System.out.println("获取根标签users的子标签列表");List<Element> usersSubElementList = rootElement.elements();for (Element userElement : usersSubElementList) {//String attributeValue(String name);获取指定属性名称的属性值System.out.println("users标签的子标签"+userElement.getName());System.out.println("users标签的子标签的id属性值是"+userElement.attributeValue("id"));System.out.println("users标签的子标签的country属性值"+userElement.attributeValue("country"));System.out.println("users标签的子标签的sources属性值"+userElement.attributeValue("source"));System.out.println("3、获取user的子标签列表");List<Element> userSubElementList = userElement.elements();for (Element userSubElement : userSubElementList) {System.out.println("user标签下的子标签名字是"+userSubElement.getName());//String getText();获取标签的文本System.out.println("user标签下的子标签的文本是"+userSubElement.getText());}}//获取users标签的第一个user标签Element firstUserElement = rootElement.element("user");//获取第一个user标签下的子标签password属性的文本//String elementText(String name);获取指定名称的子标签的文本String password = firstUserElement.elementText("password");System.out.println("第一个user标签的子标签password的文本"+password);} catch (DocumentException e) {e.printStackTrace();}}
}

输出结果:

image-20231230155438217

5 HTTP协议

  • HyperText Transfer Protocol,超文本传输协议,数据传输的规则
  • 数据传输的规则指的是请求数据和响应数据需要按照指定的格式进行传输
  • 学习HTTP主要就是学习请求和响应数据的**具体格式内容**

5.1 HTTP协议特点

HTTP协议有它自己的一些特点,分别是:

  • 基于TCP协议: 面向连接,安全

    TCP是一种面向连接的(建立连接之前是需要经过三次握手)、可靠的、基于字节流的传输层通信协议,在数据传输方面更安全。

  • 基于请求-响应模型的: 一次请求对应一次响应

  • HTTP协议是无状态协议:**每次请求-响应都是独立的,**对于事物处理没有记忆能力。

    无状态指的是客户端发送HTTP请求给服务端之后,服务端根据请求响应数据,响应完后,不会记录任何信息。这种特性有优点也有缺点,

    • 缺点: 多次请求间不能共享数据
    • 优点: 速度快

    请求之间无法共享数据会引发的问题,如:

    • 京东购物,加入购物车去购物车结算是两次请求,
    • HTTP协议的无状态特性,加入购物车请求响应结束后,并未记录加入购物车是何商品
    • 发起去购物车结算的请求后,因为无法获取哪些商品加入了购物车(即上一次请求所包含的数据),会导致此次请求无法正确展示数据

    **会话技术**可以解决这个问题

5.2 请求数据格式

image-20231230160704380

  • 请求行: HTTP请求中的第一行数据,请求行包含三块内容,分别是 GET[请求方式] /[请求URL路径] HTTP/1.1[HTTP协议及版本]

    请求方式有七种,最常用的是GETPOST

  • 请求头: 第二行开始,格式为key: value形式

    请求头中会包含若干个属性,常见的HTTP请求头有:

    Host: 表示请求的主机名
    User-Agent: 浏览器版本,例如Chrome浏览器的标识类似Mozilla/5.0 ...Chrome/79,IE浏览器的标识类似Mozilla/5.0 (Windows NT ...)like Gecko;
    Accept: 表示浏览器能接收的资源类型,如text/*,image/*或者*/*表示所有;
    Accept-Language: 表示浏览器偏好的语言,服务器可以据此返回不同语言的网页;
    Accept-Encoding: 表示浏览器可以支持的压缩类型,例如gzip, deflate等。
    

    **数据用处:**浏览器兼容问题

  • 请求体: POST请求的最后一部分,存储请求参数

    1627050930378

    如上图红线框的内容就是请求体的内容,请求体和请求头之间是有一个空行隔开。此时浏览器发送的是POST请求,为什么不能使用GET呢?这时就需要回顾GET和POST两个请求之间的区别了:

    • GET请求请求参数在请求行中,没有请求体,POST请求请求参数在请求体中
    • GET请求请求参数大小有限制,POST没有

5.3 响应数据格式

image-20231230161209485

  • 响应行:响应数据的第一行,响应行包含三块内容,分别是 HTTP/1.1[HTTP协议及版本] 200[响应状态码] ok[响应状态码的描述]

    关于响应状态码(主要认识三个):

    • 200 ok 客户端请求成功
    • 404 Not Found 请求资源不存在
    • 500 Internal Server Error 服务端发生不可预期的错误
  • 响应头:第二行开始,格式为key:value形式

    响应头中会包含若干个属性,常见的HTTP响应头有:

    Content-Type:表示该响应内容的类型,例如text/html,image/jpeg;
    Content-Length:表示该响应内容的长度(字节数);
    Content-Encoding:表示该响应压缩算法,例如gzip;
    Cache-Control:指示客户端应如何缓存,例如max-age=300表示可以最多缓存300秒
    
  • 响应体: 最后一部分。存放响应数据

    上图中…这部分内容就是响应体,它和响应头之间有一个空行隔开。

5.4 自定义服务器

自定义一个服务器需要具备哪些基本的功能?

  1. 监听端口: 使用 ServerSocket 监听指定端口,等待客户端的连接请求。

    ServerSocket ss = new ServerSocket(8080);
    
  2. 接受连接: 使用 accept() 方法接受客户端的连接请求,创建一个与客户端通信的 Socket

    Socket sock = ss.accept();
    
  3. 多线程处理连接: 为每个客户端连接创建一个独立的线程,以允许服务器同时处理多个连接。在这个例子中,使用 Handler 类继承自 Thread

    Thread t = new Handler(sock);
    t.start();
    
  4. 处理请求:Handler 类的 run 方法中,通过输入流 (InputStream) 读取客户端发来的HTTP请求,根据请求内容生成相应的响应,然后通过输出流 (OutputStream) 发送响应给客户端。

    包含**读取请求行,解析请求行,读取请求头部**等等;

    private void handle(InputStream input, OutputStream output) throws IOException {// 处理HTTP请求// 1.读取请求行// 2.解析请求行// 3.读取请求头部// 4.....// 发送HTTP响应// 1.发送HTTP响应头// 2.读取并发送响应体// 3.....
    }
    
  5. 关闭连接: 在处理完成后,确保关闭与客户端的连接,释放资源。

    this.sock.close();
    
  6. 错误处理: 处理异常情况,例如客户端断开连接或发生其他错误。

    } catch (Exception e) {// 处理异常并关闭套接字System.out.println("客户端断开连接。");
    }
    
  7. 发送HTTP响应: 根据请求的内容,发送适当的HTTP响应,包括**状态码、响应头和响应体**。

    writer.write("HTTP/1.1 200 OK\r\n");
    writer.write("Connection: keep-alive\r\n");
    writer.write("Content-Type: text/html\r\n");
    writer.write("Content-Length: " + length + "\r\n");
    writer.write("\r\n"); // 空行分隔头部和正文
    writer.write(data.toString());
    writer.flush();
    
  8. 读取文件内容: 从文件中读取内容,用于构建HTTP响应体。

    BufferedReader br = new BufferedReader(new FileReader("http/html/a.html"));
    StringBuilder data = new StringBuilder();
    // 读取文件内容并构建响应体
    // ...
    br.close();
    

这是一个简单的HTTP服务器的基本结构,实际的服务器可能需要更多功能,例如安全性、性能优化、支持更多HTTP方法和状态码、动态内容生成等。

6 Servlet

Tomcat就是一种servlet

Tomcat 是一个 Web 服务器,同时也是一个 Servlet 容器

  • Servlet是JavaWeb最为核心的内容,它是Java提供的一门动态web资源开发技术。

  • Servlet是JavaEE规范之一,其实就是一个接口,将来我们需要定义Servlet类实现Servlet接口,并由web服务器运行Servlet

    image-20231230163028183

6.1 Servlet生命周期

  1. 加载和实例化:默认情况下,当Servlet第一次被访问时,由容器创建Servlet对象

    默认情况,Servlet会在第一次访问被容器创建,但是如果创建Servlet比较耗时的话,那么第一个访问的人等待的时间就比较长,用户的体验就比较差,那么我们能不能把Servlet的创建放到服务器启动的时候来创建,具体如何来配置?

    @WebServlet(urlPatterns = "/demo1",loadOnStartup = 1)
    

    loadOnstartup的取值有两类情况

    • 负整数:第一次访问时创建Servlet对象

    • 0或正整数:服务器启动时创建Servlet对象,数字越小优先级越高

  2. 初始化:在Servlet实例化之后,容器将调用Servlet的**init()方法初始化这个对象,完成一些如加载配置文件、创建连接等初始化的工作。该方法只调用一次**

    void init(ServletConfig config) 
    
  3. 请求处理每次请求Servlet时,Servlet容器都会调用Servlet的**service()**方法对请求进行处理

    void service(ServletRequest req, ServletResponse res)
    
  4. 服务终止:当需要释放内存或者容器关闭时,容器就会调用Servlet实例的**destroy()**方法完成资源的释放。在destroy()方法调用之后,容器会释放这个Servlet实例,该实例随后会被Java的垃圾收集器所回收

    void destroy() 
    

init方法在Servlet对象被创建的时候执行,只执行1次

service方法在Servlet被访问的时候调用,每访问1次就调用1次

destroy方法在Servlet对象被销毁的时候调用,只执行1次

6.2 getServletInfo和getServletConfig(了解)

  • getServletInfo:该方法用来返回Servlet的相关信息,没有什么太大的用处,一般我们返回一个空字符串即可

    String getServletInfo() 
    public String getServletInfo() {return "";
    }
    
  • getServletConfig:获取ServletConfig对象;服务器在创建Servlet对象的时候会调用init方法必定会传入一个ServletConfig对象,我们只需要将服务器传过来的ServletConfig进行返回即可

    public void init(ServletConfig config) throws ServletException {this.servletConfig = config;System.out.println("init...");
    }
    public ServletConfig getServletConfig() {return servletConfig;
    }
    

6.3 执行流程

环境搭建:

  1. 创建Web项目mvc_project,导入Servlet依赖坐标
<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><!--此处为什么需要添加该标签?provided指的是在编译和测试过程中有效,最后生成的war包时不会加入因为Tomcat的lib目录中已经有servlet-api这个jar包,如果在生成war包的时候生效就会和Tomcat中的jar包冲突,导致报错--><scope>provided</scope>
</dependency>
  1. 创建:定义一个类,实现Servlet接口,并重写接口中所有方法,并在service方法中输入一句话
package com.baidu.web;import javax.servlet.*;
import java.io.IOException;public class ServletDemo1 implements Servlet {public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {System.out.println("this service is running.........");}public void init(ServletConfig servletConfig) throws ServletException {}public ServletConfig getServletConfig() {return null;}public String getServletInfo() {return null;}public void destroy() {}
}
  1. 配置:在类上使用@WebServlet注解,配置该Servlet的访问路径
@WebServlet("/demo1")
  1. 访问:启动Tomcat,浏览器中输入URL地址访问该Servlet
http://localhost:8081/mvc_project_war/demo1
  1. 器访问后,在控制台会打印this service is running......... 说明servlet程序已经成功运行。

    image-20231230170106300

    image-20231230165957546

执行流程图:

image-20231230165156542

  • 浏览器发出http://localhost:8080/web-demo/demo1请求,从请求中可以解析出三部分内容,分别是localhost:8080web-demodemo1
    • 根据localhost:8080可以找到要访问的Tomcat Web**服务器**
    • 根据web-demo可以找到部署在Tomcat服务器上的web-demo**项目**
    • 根据demo1可以找到要访问的是项目中的哪个**Servlet类**,根据@WebServlet后面的值进行匹配
  • 找到ServletDemo1这个类后,Tomcat Web服务器就会为ServletDemo1这个类创建一个对象,然后调用对象中的service方法
    • ServletDemo1实现了Servlet接口,所以类中必然会重写service方法供Tomcat Web服务器进行调用
    • service方法中有ServletRequest和ServletResponse两个参数,ServletRequest封装的是请求数据ServletResponse封装的是响应数据,后期我们可以通过这两个参数实现前后端的数据交互

7 Request(请求)、Response(响应)

Request是请求对象,Response是响应对象

image-20231230204828059

  • request:获取请求数据
    • 浏览器会发送HTTP请求到后台服务器[Tomcat]
    • HTTP的请求中会包含很多请求数据[请求行+请求头+请求体]
    • 后台服务器[Tomcat]会对HTTP请求中的数据进行解析并把解析结果存入到一个对象中
    • 所存入的对象即为request对象,所以我们可以从request对象中获取请求的相关参数
    • 获取到数据后就可以继续后续的业务,比如获取用户名和密码就可以实现登录操作的相关业务
  • response:设置响应数据
    • 业务处理完后,后台就需要给前端返回业务处理的结果即响应数据
    • 把响应数据封装到response对象中
    • 后台服务器[Tomcat]会解析response对象, 按照[响应行+响应头+响应体]格式拼接结果
    • 浏览器最终解析结果,把内容展示在浏览器给用户浏览

7.1 Request对象

7.1.1 Request继承体系

image-20231230205450156

ServletRequest和HttpServletRequest是继承关系,并且两个都是接口,接口是无法创建对象的;

image-20231230205755543

传入的对象都是RequestFacade

  • 该类实现了HttpServletRequest接口,也间接实现了ServletRequest接口
  • Servlet类中的service方法、doGet方法或者是doPost方法最终都是由Web服务器[Tomcat]来调用的,Tomcat提供了方法参数接口的具体实现类,并完成了对象的创建
  • 要想了解RequestFacade中都提供了哪些方法,我们可以直接查看JavaEE的API文档中关于ServletRequest和HttpServletRequest的接口文档,因为RequestFacade实现了其接口就需要重写接口中的方法
7.1.2 Request获取请求数据

HTTP请求数据总共分为三部分内容,分别是请求行、请求头、请求体。

7.1.2.1 获取请求行数据

请求行包含三块内容,分别是请求方式请求资源路径HTTP协议及版本

1628748240075

  • String getMethod():获取请求方式: GET

  • String getContextPath():获取虚拟目录(项目访问路径): /request-demo

  • StringBuffer getRequestURL():获取URL(统一资源定位符): http://localhost:8080/request-demo/req1

  • String getRequestURI():获取URI(统一资源标识符): /request-demo/req1

  • String getQueryString():获取请求参数(GET方式): username=zhangsan&password=123

/*** request 获取请求数据*/
@WebServlet("/demo2")
public class RequestDemo1 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// String getMethod():获取请求方式: GETString method = req.getMethod();System.out.println(method);//GET// String getContextPath():获取虚拟目录(项目访问路径):/mvc_project_warString contextPath = req.getContextPath();System.out.println(contextPath);// StringBuffer getRequestURL(): 获取URL(统一资源定位符):http://localhost:8081/mvc_project_war/demo2StringBuffer url = req.getRequestURL();System.out.println(url.toString());// String getRequestURI():获取URI(统一资源标识符): /mvc_project_war/demo2String uri = req.getRequestURI();System.out.println(uri);// String getQueryString():获取请求参数(GET方式): username=zhangsan&passwrod=123String queryString = req.getQueryString();System.out.println(queryString);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {}
}

请求路径:

http://localhost:8081/mvc_project_war/demo2?username=zhangsan&passwrod=123

image-20231230214216742

tips:

如果添加了相关Servlet之后,启动服务器却显示404,没找到相关资源,可尝试将当前项目从服务器的部署中删除,然后再重新部署进去

先删除,再添加部署

image-20231230214748430

7.1.2.2 获取请求头数据

String getHeader(String name):根据请求头名称获取对应值

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//获取请求头: user-agent: 浏览器的版本信息String agent = req.getHeader("user-agent");System.out.println(agent);
}

打印信息:

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0
7.1.2.3 获取请求体数据

浏览器在发送GET请求的时候是没有请求体的,POST才会有请求体

Request有两种方式来获取请求体中的数据

  • 获取字节输入流,如果前端发送的是字节数据,比如传递的是文件数据,则使用该方法
ServletInputStream getInputStream()
该方法可以获取字节
  • 获取字符输入流,如果前端发送的是纯文本数据,则使用该方法
BufferedReader getReader()

用html的表单测试:

前端:

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

后端:

@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);
}

结果:

image-20231231165711416

后端:

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//获取post 请求体:请求参数//1. 获取字符输入流BufferedReader br = req.getReader();//2. 读取数据String line = br.readLine();System.out.println(line);
}

结果:

image-20231231170300575

用postman发送一个POST请求,并携带相关数据(为什么会失败?)

创建新的workspace:

image-20231231153508825

image-20231231153624669

image-20231231153852204

创建成功:

image-20231231153927379

选择刚才所创建的workspace:

image-20231231154056725

image-20231231154223696

可以新建一个文件夹,用于测试的分类

image-20231231154313832

右键,点击添加请求

image-20231231154412063

image-20231231154721818

image-20231231154828068

测试结果为什么是:

image-20231231155050116

为什么?

image-20231231155839339

7.1.3 模板

可以使用IDEA提供的模板来制作一个Servlet的模板

image-20240101201618604

7.1.4 请求参数中文乱码问题

原因:

  • POSTTOMCAT在获取流的时候采用的编码是ISO-8859-1;ISO-8859-1编码是不支持中文的,所以会出现乱码

    解决办法:把TOMCAT在获取流数据之前的编码设置为UTF-8

    //1. 解决乱码: POST getReader()
    //设置字符输入流的编码,设置的字符集要和页面保持一致
    request.setCharacterEncoding("UTF-8");
    //2. 获取username
    String username = request.getParameter("username");
    System.out.println(username);
    
  • GET:如图

    由于前后编码与解码采用的格式不一样,就会导致后台获取到的数据为乱码。

    image-20240101202337931

    解决办法:

    1.按照ISO-8859-1编码获取乱码字符对应的字节数组

    2.按照UTF-8编码获取字节数组对应的字符串

    3.API

    编码:

    java.net.URLEncoder.encode("需要被编码的内容","字符集(UTF-8)")
    

    解码:

    java.net.URLDecoder.decode("需要被解码的内容","字符集(UTF-8)")
    
    String username = request.getParameter("username");
    System.out.println("解决乱码前:"+username);
    username  = new String(username.getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8);
    System.out.println("解决乱码后:"+username);
    

    image-20240101203416747

7.1.5 Request请求转发
7.1.5.1 请求转发

请求转发(forward): 一种在服务器内部的资源跳转方式

(1)浏览器发送请求给服务器,服务器中对应的资源A接收到请求

(2)资源A处理完请求后将请求发给资源B

(3)资源B处理完后将结果响应给浏览器

(4)请求从资源A到资源B的过程就叫请求转发

(5)请求转发的实现方式:

req.getRequestDispatcher("资源B路径").forward(req,resp);

image-20240101203522378

示例:

/*** 请求转发*/
@WebServlet("/req5")
public class RequestDemo5 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println("demo5...");//请求转发request.getRequestDispatcher("/req6").forward(request,response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {this.doGet(request, response);}
}
7.1.5.2 共享数据

请求转发资源间共享数据: 使用Request对象

三个方法:

void setAttribute(String name,Object o); 存储数据到request域[范围,数据是存储在request对象]中

Object getAttribute(String name); 根据key获取值

void removeAttribute(String name); 根据key删除该键值对

7.2 Response对象

对比:

  • Request: 使用request对象来获取请求数据
  • Response: 使用response对象来设置响应数据

Reponse的继承体系和Request的继承体系也非常相似:

1628857761317

7.2.1 Response设置响应数据功能介绍

HTTP响应数据总共分为三部分内容,分别是响应行、响应头、响应体

7.2.1.1 响应行

image-20240101145314533

void setStatus(int sc):设置响应状态码

7.2.1.2 响应头

image-20240101145348635

void setHeader(String name,String value):设置响应头键值对

7.2.1.3 响应体

image-20240101145420339

对于响应体,是通过字符、字节输出流的方式往浏览器

PrintWriter getWriter(); 获取字符输出流:

ServletOutputStream getOutputStream(); 获取字节输出流

7.2.2 Response完成重定向

Response重定向(redirect): 一种资源跳转方式

image-20240101145556017

(1)浏览器发送请求给服务器,服务器中对应的资源A接收到请求

(2)资源A现在无法处理该请求,就**会给浏览器响应一个302的状态码+location的一个访问资源B的路径**

(3)浏览器接收到响应状态码为302就会重新发送请求到location对应的访问地址去访问资源B

(4**)资源B接收到请求后进行处理并最终给浏览器响应结果**,这整个过程就叫重定向

7.2.2.1 重定向的实现方式
//重定向
//1.设置响应状态码 302
response.setStatus(302);
//2. 设置响应头 Location
response.setHeader("Location","/request-demo/resp2");

或者简化代码:

resposne.sendRedirect("/request-demo/resp2")
7.2.2.2 请求重定向和请求转发对比

image-20240101204107801

7.2.2.3 虚拟路径添加判断

image-20240101204205809

  • 对于转发来说,因为是在服务端进行的,所以不需要加虚拟目录
  • 对于重定向来说,路径最终是由浏览器来发送请求,就需要添加虚拟目录
7.2.3 Response响应字符数据

要想将字符数据写回到浏览器

  • 通过Response对象获取字符输出流: PrintWriter writer = resp.getWriter();

  • 通过字符输出流写数据: writer.write(“aaa”);

可以写html文件,但要告诉浏览器返回的数据类型是HTML类型数据,这样浏览器才会解析HTML标签

response.setHeader("content-type","text/html");
writer.write("<h1>aaa</h1>");

返回中文的字符串,需要注意设置响应数据的编码为utf-8

//设置响应的数据格式及数据的编码
response.setContentType("text/html;charset=utf-8");
writer.write("你好");
7.2.4 Response响应字节数据

要想将字节数据(例如在写图片时可能会用到)写回到浏览器,我们需要两个步骤:

  • 通过Response对象获取字节输出流:ServletOutputStream outputStream = resp.getOutputStream();

  • 通过字节输出流写数据: outputStream.write(字节数据);

示例:

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1. 读取文件FileInputStream fis = new FileInputStream("d://a.jpg");//2. 获取response字节输出流ServletOutputStream os = response.getOutputStream();//3. 完成流的copybyte[] buff = new byte[1024];int len = 0;while ((len = fis.read(buff))!= -1){os.write(buff,0,len);}fis.close();
}

添加虚拟目录**

7.2.3 Response响应字符数据

要想将字符数据写回到浏览器

  • 通过Response对象获取字符输出流: PrintWriter writer = resp.getWriter();

  • 通过字符输出流写数据: writer.write(“aaa”);

可以写html文件,但要告诉浏览器返回的数据类型是HTML类型数据,这样浏览器才会解析HTML标签

response.setHeader("content-type","text/html");
writer.write("<h1>aaa</h1>");

返回中文的字符串,需要注意设置响应数据的编码为utf-8

//设置响应的数据格式及数据的编码
response.setContentType("text/html;charset=utf-8");
writer.write("你好");
7.2.4 Response响应字节数据

要想将字节数据(例如在写图片时可能会用到)写回到浏览器,我们需要两个步骤:

  • 通过Response对象获取字节输出流:ServletOutputStream outputStream = resp.getOutputStream();

  • 通过字节输出流写数据: outputStream.write(字节数据);

示例:

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1. 读取文件FileInputStream fis = new FileInputStream("d://a.jpg");//2. 获取response字节输出流ServletOutputStream os = response.getOutputStream();//3. 完成流的copybyte[] buff = new byte[1024];int len = 0;while ((len = fis.read(buff))!= -1){os.write(buff,0,len);}fis.close();
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

6 网关和配置服务器

文章目录 网关模式Spring Cloud网关Spring Cloud网关微服务其他项目的变更运行和测试小结 运行状况Spring Boot Actuator在微服务中包含Actuator 服务发现和负载均衡ConsulSpring Cloud ConsulSpring Cloud负载均衡器网关中的服务发现和负载均衡使用服务发现和负载均衡 环境配置…

微信多功能投票小程序源码系统:送礼物+在线充值+票数汇总+创建活动+完整的代码安装包 附带完整的搭建教程

微信已成为人们日常生活中不可或缺的一部分。因此&#xff0c;微信小程序也受到了广大用户的欢迎。在这个背景下&#xff0c;多功能投票小程序应运而生&#xff0c;为各种活动提供了方便快捷的投票方式。本文将介绍一款微信多功能投票小程序源码系统&#xff0c;该系统具有送礼…

stable diffusion 基础教程-图生图

界面 图生图大概有以下几个功能: 图生图涂鸦绘制局部绘制局部绘制(涂鸦蒙版)其常用的也就上面四个,接下来逐步讲解。 以图反推提示词 图生图可以根据反推提示词来获取相应图片的提示词,目前3种主流方式,如下: CLIP反推提示词:推导出的文本倾向于自然语言的描述方式,…

BAT036:TXT与DOC格式互转、DOC与DOCX格式互转

引言:编写批处理程序,可实现txt与doc文档格式互转、doc与docx文档格式互转。 一、新建Windows批处理文件 参考博客: BAT002:在右键菜单新建中添加【Windows批处理文件】_为右键菜单添加bat-CSDN博客 二、TXT与DOC格式互转 1.右键新建的批处理文件,点击【编辑】。 ​ …

2024,启动(回顾我的2023)

零.前言 打开博客想写个年度总结&#xff0c;发现已经半年没有更新文章了&#xff0c;排名从几千掉到了几万&#xff0c;不过数据量还是不错的。 时间过得可真快&#xff0c;2023年是充满动荡的一年&#xff0c;上半年gpt横空出世&#xff0c;下半年各种翻车暴雷吃瓜吃到嘴软…

企业培训系统开发:构建灵活高效的学习平台

企业培训系统的开发在当今数字化时代是至关重要的。本文将介绍一些关键技术和代码示例&#xff0c;以帮助您构建一个灵活、高效的企业培训系统。 1. 技术选型 在开始企业培训系统的开发之前&#xff0c;首先需要选择合适的技术栈。以下是一个基本的技术选型示例&#xff1a;…

Linux_CentOS_7.9_MySQL_5.7配置数据库服务开机自启动之简易记录

前言&#xff1a; 作为运维保障&#xff0c;都无法准确预估硬件宕机的突发阶段&#xff0c;其生产数据实时在产出&#xff0c;那作为dba数据库服务的其重要性、必要性就突显而出。这里拿虚拟机试验做个配置记录&#xff0c;便于大家学习参考。 # 如出现服务器重启后登入报错无…

【本科生通信原理】【实验报告】【北京航空航天大学】实验二:AM、DSB调制/解调

一、实验目的 二、实验内容 三、实验程序 1、 function q1() N 1024; %采样点数 A 2; %直流分量 t0 5; %信号时长 dt t0 / N; %时间分辨率 fs 1 / dt; %系统采样频率…

pytorch08:学习率调整策略

目录 一、为什么要调整学习率&#xff1f;1.1 class _LRScheduler 二、pytorch的六种学习率调整策略2.1 StepLR2.2 MultiStepLR2.3 ExponentialLR2.4 CosineAnnealingLR2.5 ReduceLRonPlateau2.6 LambdaLR 三、学习率调整小结四、学习率初始化 一、为什么要调整学习率&#xff…

苹果电脑菜单栏应用管理软件Bartender 4 mac软件特点

Bartender mac是一款可以帮助用户更好地管理和组织菜单栏图标的 macOS 软件。它允许用户隐藏和重新排列菜单栏图标&#xff0c;从而减少混乱和杂乱。 Bartender mac软件特点 菜单栏图标隐藏&#xff1a;Bartender 允许用户隐藏菜单栏图标&#xff0c;只在需要时显示。这样可以…

Windows PowerShell的安全目标——安全警报

Windows PowerShell的安全目标——安全警报 1. 保证Shell安全 ​ 自从2006年年底PowerShell发布以来&#xff0c;微软在安全和脚本方面并没有取得很好的名声。毕竟那个时候&#xff0c;**VBScript和Windows Script Host(WSH)**是两个最流行的病毒和恶意软件的载体&#xff0c…

Linux环境vscode clang-format格式化:vscode clang format command is not available

问题现象 vscode安装了clang-format插件&#xff0c;但是使用就报错 问题原因 设置中配置的clang-format插件工具路径不正确。 解决方案 确认本地安装了clang-format工具&#xff1a;终端输入clang-format&#xff08;也可能是clang-format-13等版本&#xff0c;建议tab自…

Jenkins工具使用

学习目录&#xff1a; 1、jenkins的安装 2、junkins的常规使用 3、jenkins在接口自动化测试实践 具体内容&#xff1a; 1、jenkins的安装 安装包下载&#xff1a;推荐Index of /jenkins/war/latest/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror&#xff0c;…

系列十一、(一)Sentinel简介

一、Sentinel简介 1.1、官网 【英文文档】 https://github.com/alibaba/Sentinel/wiki【中文文档】 https://github.com/alibaba/Sentinel/wiki/%E4%B8%BB%E9%A1%B5 1.2、概述 1.3、功能

前端开发加速器:十个VSCode插件精选

前端开发是一个不断发展的领域&#xff0c;随着技术的进步&#xff0c;工具也在不断更新。Visual Studio Code&#xff08;VSCode&#xff09;是前端开发者广泛使用的编辑器之一&#xff0c;得益于其强大的插件系统&#xff0c;可以帮助开发者提升工作效率。以下是十个对于前端…

ubuntu22.04配置双网卡绑定提升带宽

这里写自定义目录标题 Bonding简介配置验证参考链接 Bonding简介 bonding(绑定)是一种linux系统下的网卡绑定技术&#xff0c;可以把服务器上n个物理网卡在系统内部抽象(绑定)成一个逻辑上的网卡&#xff0c;能够提升网络吞吐量、实现网络冗余、负载均衡等功能&#xff0c;有很…

ArkTS - @Prop、@Link

一、作用 Prop 装饰器 和Link装饰器都是父组件向子组件传递参数&#xff0c;子组件接收父组件参数的时候用的&#xff0c;变量前边需要加上Prop或者Link装饰器即可。&#xff08;跟前端vue中父组件向子组件传递参数类似&#xff09; // 子组件 Component struct SonCom {Prop…

thingsboard前端缓存--nginx

thingsboardnginx thingsboard部署到阿里云服务器之后&#xff0c;由于登录界面要发送的文件很大&#xff0c;并且服务器的带宽目前有限&#xff0c;因此配置一个nginx&#xff0c;进行前端页面的一些缓存&#xff0c;参考了https://qianchenzhumeng.github.io/posts/Nginx%E5…

《设计模式》之策略模式

策略模式定义 比如对象的某个行为&#xff0c;在不同场景有不同实现方式&#xff0c;可以将这些行为的具体实现定义为一组策略&#xff0c;每个实现类实现种策略&#xff0c;在不同场景使用不同的实现&#xff0c;并且可以自由切换策略。 策略模式结构 策略模式需要一个策略…

MySQL所有常见问题

一、事务 定义:一组操作要么全部成功,要么全部失败,目的是为了保证数据最终的一致性 在MySQL中,提供了一系列事务相关的命令: start transaction | begin | begin work:开启一个事务commit:提交一个事务rollback:回滚一个事务事务的ACID 原子性(Atomicity):当前事…