Request+Response

文章目录

    • [1. 介绍](#1. 介绍)
    • [2. Request对象](#2. Request对象)
    • [3. Response对象](#3. Response对象)
      • [3.0 Response 继承体系](#3.0 Response 继承体系)
      • [3.1 Response设置响应数据的功能介绍](#3.1 Response设置响应数据的功能介绍)
      • [3.2 Response完成重定向](#3.2 Response完成重定向)
      • [3.3 设置响应数据](#3.3 设置响应数据)
        • [1. Response响应字符数据](#1. Response响应字符数据)
        • [2. Response响应字节数据](#2. Response响应字节数据)
    • 4.案例:用户登录/用户注册

1. 介绍

Request+Response

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

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

2. Request对象

2.1 Request继承体系

  • Tomcat需要解析请求数据,封装为request对象并且创建request对象传递到service方法中;

Q1: ServletRequest和HttpServletRequest的关系?

  • ServletRequest是Java Servlet规范中定义的一个接口,它是所有Servlet请求对象的顶级接口
  • HttpServletRequest是ServletRequest的子接口,它扩展了ServletRequest接口,提供了更多与HTTP协议相关的方法和功能。
  • 当Servlet类实现的是Servlet接口的时候,service方法中的参数是ServletRequest和ServletResponse
  • 当Servlet类继承的是HttpServlet类的时候,doGet和doPost方法中的参数就变成HttpServletRequest和HttpServletReponse

2.2 Request获取请求数据

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

1.获取请求行

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

请求行 方法 说明
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
java 复制代码
//获取请求行
@WebServlet("/demo3")
public class ServletDemo3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // String getMethod():获取请求方式: GET
        String method = req.getMethod();
        System.out.println(method);//GET
        // String getContextPath():获取虚拟目录(项目访问路径):/request-demo
        String contextPath = req.getContextPath();
        System.out.println(contextPath);
        // StringBuffer getRequestURL(): 获取URL(统一资源定位符):http://localhost:8080/request-demo/req1
        StringBuffer url = req.getRequestURL();
        System.out.println(url.toString());
        // String getRequestURI():获取URI(统一资源标识符): /request-demo/req1
        String uri = req.getRequestURI();
        System.out.println(uri);
        // String getQueryString():获取请求参数(GET方式): username=zhangsan
        String queryString = req.getQueryString();
        System.out.println(queryString);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    }

}

2.获取请求头

请求头 方法 说明
String getHeader(String name) 获取指定名称的请求头
java 复制代码
```java
/**
 * request 获取请求数据
 */
@WebServlet("/req1")
public class RequestDemo1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取请求头: user-agent: 浏览器的版本信息
        String agent = req.getHeader("user-agent");
		System.out.println(agent);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    }
}

3.获取请求体

请求体: 注意get请求没有请求体,post有

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

具体实现的步骤如下:

1.准备一个页面,在页面中添加form表单,用来发送post请求

2.在Servlet的doPost方法中获取请求体数据

3.在doPost方法中使用request的getReader()或者getInputStream()来获取

4.访问测试

java 复制代码
package com.itheima.web;

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.BufferedReader;
import java.io.IOException;

@WebServlet("/demo4")
public class ServletDemo4 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    }
    @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);
    }
}
xml 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>测试获取请求体信息</title>
</head>
<body>
<h5>hello</h5>
<form action="/demo4" method="post">
  <input type="text" name="username">
  <input type="password" name="password">
  <input type="submit">

</form>

</body>
</html>

4. 请求参数的通用方式

请求参数的获取方式:

  • GET方式:

String getQueryString()

  • POST方式:

BufferedReader getReader();
案例:

(1)发送一个GET请求并携带用户名,后台接收后打印到控制台

(2)发送一个POST请求并携带用户名,后台接收后打印到控制台

java 复制代码
//实现
@WebServlet("/req1")
public class RequestDemo1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String result = req.getQueryString();
        System.out.println(result);

    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        BufferedReader br = req.getReader();
        String result = br.readLine();
        System.out.println(result);
    }
}

Q:既然实现的功能一样,是否可以统一doGet和doPost方法内的代码?

解决方案一:

java 复制代码
@WebServlet("/req1")
public class RequestDemo1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取请求方式
        String method = req.getMethod();
        //获取请求参数
        String params = "";
        if("GET".equals(method)){
            params = req.getQueryString();
        }else if("POST".equals(method)){
            BufferedReader reader = req.getReader();
            params = reader.readLine();
        }
        //将请求参数进行打印控制台
        System.out.println(params);
      
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req,resp);
    }
}

解决方案二:

request对象已经将上述获取请求参数的方法进行了封装,并且request提供的方法实现的功能更强大

步骤:

(1)根据不同的请求方式获取请求参数

(2)把获取到的内容进行分割

(3)把分割后端数据,存入到一个Map集合中

方法 说明
Map<String,String[]> getParameterMap() 获取所有参数Map集合
String[] getParameterValues(String name) 根据名称获取参数值(数组)
String getParameter(String name) 根据名称获取参数值(单个值)
xml 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/req" 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>
java 复制代码
//使用get获取请求信息
@WebServlet("/req")
public class ServletDemo5 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();
            //2.根据key获取值
            System.out.println("------------");
            String[] hobbies = req.getParameterValues("hobby");
            for (String hobby : hobbies) {
                System.out.println(hobby);
            }

            //3.根据key获取单个参数值
            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 {
        super.doPost(req, resp);
    }
}


IDEA模板创建Servlet:102
https://www.bilibili.com/video/BV1Qf4y1T7Hx

5. 解决中文乱码问题

  • GET请求获取请求参数的方式是request.getQueryString()
  • POST请求获取请求参数的方式是request.getReader()

post:

java 复制代码
req.setCharacterEncoding("UTF-8");

解决:https://blog.csdn.net/yiqieanhaowzq/article/details/126279078

java 复制代码
username  = new String(username.getBytes(StandardCharsets.ISO_8859_1),
                StandardCharsets.UTF_8);

2.3 Request请求转发

请求转发是指将当前请求转发给另一个Servlet或JSP页面进行处理,转发后的Servlet或JSP页面会继续处理请求并生成响应。

方法 说明
request.getRequestDispatcher("/destination"); 获取RequestDispatcher对象
dispatcher.forward(request, response); 请求转发
java 复制代码
package com.itheima.web;

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("/demo6")
public class ServletDemo6 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("demo6...get");
        //请求转发
        req.getRequestDispatcher("/demo7").forward(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}
java 复制代码
package com.itheima.web;

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("/demo7")
public class ServletDemo7 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("demo7...get");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}
请求转发资源间共享数据:

请求转发资源间共享数据是指在Java

Servlet中,通过请求转发,将请求从一个Servlet或JSP页面转发到另一个Servlet或JSP页面时,可以在它们之间共享数据。

  • 当一个请求被转发到另一个资源(Servlet或JSP页面)时,原始请求的数据,例如请求参数、属性等,可以通过设置和获取request对象的属性来在转发的资源之间传递和共享。这种方式允许在不暴露数据给客户端的情况下,在服务器端的多个组件之间传递信息。
    请求转发特点:

  • 浏览器地址栏路径不发生变化

  • 只转发当前服务器内部资源

  • 一次请求,可以在转发的资源间使用request共享数据

需要使用request对象提供的三个方法:

方法 说明
void setAttribute(String name,Object o) 存储数据到request域中
Object getAttribute(String name); 根据key,获取值
void removeAttribute(String name); 根据key,删除该键值对
java 复制代码
@WebServlet("/demo6")
public class ServletDemo6 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("demo6...get");

        //存储数据
        req.setAttribute("msg","hello");

        //请求转发
        req.getRequestDispatcher("/demo7").forward(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}
java 复制代码
@WebServlet("/demo7")
public class ServletDemo7 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("demo7...get");

        //获取数据
        Object msg = req.getAttribute("msg");
        System.out.println(msg);
    }

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

3. Response对象

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

3.0 Response 继承体系

3.1 Response设置响应数据的功能介绍

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

1.设置响应行

响应行:

  • 状态行包含了HTTP协议版本号、状态码和相应的状态信息。
  • 它的格式为:HTTP版本号 状态码 状态信息。
  • 例如:HTTP/1.1 200 OK。
方法 说明
void setStatus(int sc); 设置响应状态码

2.设置响应头

响应头部

响应头部包含了关于响应的附加信息,如服务器类型、日期、内容类型等。 它由多个键值对组成,每个键值对占据一行。常见的响应头部字段包括:

  • Content-Type:指定响应体的媒体类型。
  • Content-Length:指定响应体的长度。
  • Date:指定响应的日期和时间。
  • Server:指定响应的服务器软件类型。
方法 说明
void setHeader(String name,String value) 设置响应头键值对

3.设置响应体

响应体:

响应体包含了具体的响应内容。它可以是HTML、JSON、图片等数据。响应体的格式和内容根据具体的请求和服务器的处理结果而定。

方法 说明
PrintWriter getWriter(); 获取字符输出流
ServletOutputStream getOutputStream(); 获取字节输出流

3.2 Response完成重定向

在HTTP协议中,重定向(Redirect)是一种服务器响应的行为,它告诉客户端要求的资源已经被移动到另一个位置,并提供了新的资源位置(URL)供客户端重新请求。

重定向状态码:

  • 301:资源已永久移动到新的URL,客户端应更新其链接。

  • 302 :资源临时移动到新的URL,客户端应使用新的URL重新发起请求。

  • 307 :资源临时移动到新的URL,客户端应保持请求方法不变重新发起请求。

  • 308 :资源已永久移动到新的URL,客户端应保持请求方法不变重新发起请求
    重定向特点:

  • 浏览器地址栏发生变化

  • 可以重定向到任意位置的资源(服务器内部外部均可)

  • 两次请求,不能在多个资源使用request共享资源

java 复制代码
resp.setStatus(302);
resp.setHeader("location","资源B的访问路径");
复制代码
Q:Response重定向和Request请求转发有什么区别?
- 重定向是一种服务器响应行为,要求客户端重新发起请求。
  客户端会接收到新的URL信息,并据此发起新的请求。
- 请求转发是一种服务器内部行为,将客户端的请求转发给其他资源或处理程序来处理。
  客户端对此转发过程是不可见的。
- 重定向会向客户端发送额外的响应,通常包含重定向的状态码和新的URL信息。
  请求转发不需要额外的响应,客户端不知道请求被转发了。
- 重定向可以用于资源移动、负载均衡和认证授权等场景。
  请求转发通常用于服务器内部组织和处理请求的需要。
- 重定向浏览器地址栏会发生变化,请求转发地址栏不会发生变化
java 复制代码
//重定向
@WebServlet("/resp1")
public class ResponseDemo1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("resp1......");

        //重定向
        //1.设置响应状态码302
        resp.setStatus(302);

        //2. 设置响应头
        resp.setHeader("Location","/resp2");


        //简化方式重定向
        resp.sendRedirect("/resp2");

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
    }
}
java 复制代码
@WebServlet("/resp2")
public class ResponseDemo2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("resp2......");
    }

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

3.3 设置响应数据

方法 说明
PrintWriter getWriter(); 获取字符输出流
ServletOutputStream getOutputStream(); 获取字节输出流

1. Response响应字符数据

复制代码
设置响应的内容类型为text/html
 //resp.setHeader("content-type","text/html");
resp.setContentType("text/html");
resp.setContentType("text/html";charset=utf-8);

设置响应的状态码
resp.setStatus(HttpServletResponse.SC_OK);

设置响应的字符编码:
resp.setCharacterEncoding("UTF-8");

设置响应的头部信息:
resp.setHeader("Cache-Control", "no-cache");
resp.setHeader("Expires", "0");

设置响应的重定向:
resp.sendRedirect("https://www.example.com");

设置响应的Cookie:
Cookie cookie = new Cookie("name", "value");
cookie.setMaxAge(3600); // 设置Cookie的有效期
cookie.setPath("/"); // 设置Cookie的作用路径
resp.addCookie(cookie); // 将Cookie添加到响应中

设置响应的内容长度:
resp.setContentLength(content.length());

设置响应的响应类型:
resp.setContentType("application/json");
java 复制代码
@WebServlet("/resp3")
public class ResponseDemo3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("resp3......");
        
        //1.获取字符输出流
        PrintWriter writer = resp.getWriter();
        
        //2.设置响应的内容类型为text/html
        //resp.setHeader("content-type","text/html");
        resp.setContentType("text/html");
        
        //3.向客户端输出文本内容
        writer.write("aaa");
        
        //4.向客户端输出HTML标签
        writer.write("<h1>aaa</h1>");
        
        //5.刷新缓冲区,确保所有内容都被写入响应
        writer.flush();
        
        //6.关闭输出流
        writer.close();
    }

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

2. Response响应字节数据

java 复制代码
//响应字节数据:设置字节数据响应体
@WebServlet("/resp4")
public class ResponseDemo4 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("resp4......");

        //0.读取文件
        FileInputStream fileInputStream = new FileInputStream("C:\\Users\\11445\\Pictures\\Saved Pictures\\头像.jpg");


        //1.获取字节输出留,用于向客户端发送响应的字节数据。
        ServletOutputStream outputStream = resp.getOutputStream();

        //2.完成流的copy
        byte[] bytes = new byte[1024];  //创建一个字节数组,用于存储文件内容。
        int len = 0;  //定义一个变量 len,用于记录每次读取的字节长度。

        //循环读取文件内容,每次最多读取 1024 个字节,直到文件末尾
        while ((len = fileInputStream.read(bytes) )!= -1){
            outputStream.write(bytes,0,len);  //将读取到的字节数据写入到输出流中,发送给客户端。
        }

        fileInputStream.close();

    }

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

简化流的copy

Apache Commons IO 是一个开源的 Java 库,提供了许多实用的 IO

操作工具类,用于简化文件和流的操作。它包含了各种用于文件操作、流操作、拷贝、比较、过滤、监听等功能的工具类。

xml 复制代码
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.6</version>
    </dependency>
java 复制代码
//2.完成流的copy
        IOUtils.copy(fileInputStream,outputStream);

4.案例:用户登录/用户注册

登录注册案例:https://blog.csdn.net/meini32/article/details/132305323

相关推荐
考虑考虑44 分钟前
JDK9中的dropWhile
java·后端·java ee
想躺平的咸鱼干1 小时前
Volatile解决指令重排和单例模式
java·开发语言·单例模式·线程·并发编程
hqxstudying1 小时前
java依赖注入方法
java·spring·log4j·ioc·依赖
·云扬·1 小时前
【Java源码阅读系列37】深度解读Java BufferedReader 源码
java·开发语言
Bug退退退1233 小时前
RabbitMQ 高级特性之重试机制
java·分布式·spring·rabbitmq
小皮侠3 小时前
nginx的使用
java·运维·服务器·前端·git·nginx·github
Zz_waiting.3 小时前
Javaweb - 10.4 ServletConfig 和 ServletContext
java·开发语言·前端·servlet·servletconfig·servletcontext·域对象
全栈凯哥3 小时前
02.SpringBoot常用Utils工具类详解
java·spring boot·后端
兮动人3 小时前
获取终端外网IP地址
java·网络·网络协议·tcp/ip·获取终端外网ip地址
呆呆的小鳄鱼3 小时前
cin,cin.get()等异同点[面试题系列]
java·算法·面试