JavaWeb:Request & Response

文章目录

1、Request和Response的概述

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

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

2、Request继承体系

首先,我们先来看下Request的继承体系:

从上图中可以看出,ServletRequest和HttpServletRequest都是Java提供的所以ServletRequest和HttpServletRequest是继承关系,并且两个都是接口,接口是无法创建对象,这个时候就引发了下面这个问题:

这个时候,我们就需要用到Request继承体系中的RequestFacade:

  • 该类实现了HttpServletRequest接口,也间接实现了ServletRequest接口。
  • Servlet类中的service方法、doGet方法或者是doPost方法最终都是由Web服务器来调用的,所以Tomcat提供了方法参数接口的具体实现类,并完成了对象的创建

3、Request获取请求数据

HTTP请求数据总共分为三部分内容,分别是请求行、请求头、请求体,对于这三部分内容的数据,分别该如何获取?

3.1、获取请求行数据
方法 说明
String getMethod() 获取请求方式
String getContextPath() 获取虚拟目录(项目访问路径)
StringBuffer getRequestURL() 获取URL(统一资源定位符)
String getQueryString() 获取请求参数(GET方式)
String getRequestURI() 获取URI(统一资源标识符)

代码演示:

前端页面

java 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
<h2>GET方式提交</h2>
<form action="req02" 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" value="登录">
</form>
</body>
</html>

后端代码

java 复制代码
@WebServlet(value = "/req02")
public class request01 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // String getMethod()获取请求方式
        String method = request.getMethod();
        System.out.println(method);

        //String getContextPath()获取虚拟目录(项目访问路径)
        String contextPath = request.getContextPath();
        System.out.println(contextPath);

        //StringBuffer getRequestURL()获取URL(统一资源定位符)
        StringBuffer requestURL = request.getRequestURL();
        System.out.println(requestURL);

        //String getRequestURI()获取URI(统一资源标识符)
        String requestURI = request.getRequestURI();
        System.out.println(requestURI);

        //String getQueryString()获取请求参数(GET方式)
        String queryString = request.getQueryString();
        System.out.println(queryString);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
    }
}
3.2、获取请求头

对于请求头的数据,格式为key: value如下:

所以根据请求头名称获取对应值的方法为:

java 复制代码
String getHeader(String name) // 根据请求头名称,获取值

代码演示:

java 复制代码
@WebServlet(value = "/req02")
public class request01 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 获取浏览 器版本
        String header = request.getHeader("User-Agent");
        System.out.println(header);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
    }
}

因为各个版本的浏览器不太一样,所以一般都有去获取user-agent这个请求头

3.3、获取请求体

浏览器在发送GET请求的时候是没有请求体的,所以需要把请求方式变更为POST,请求体中的数据格式如下:

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

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

代码演示:

前端代码

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
<h2>POST方式提交</h2>
<form action="req02" method="post">
    用户名:<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" value="登录">
</form>
</body>
</html>

后端代码

java 复制代码
@WebServlet(value = "/req02")
public class request01 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1、获取字符输入流
        BufferedReader reader = request.getReader();

        // 2、读取数据 
        String s = reader.readLine();
        System.out.println(s);
    }
}

4、Request通用方式请求参数

对于请求参数的获取,常用的有以下两种:

  • GET方式:

    String getQueryString()

  • POST方式:

    BufferedReader getReader();

有了上述的知识储备,我们来实现一个案例需求:

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

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

此处大家需要注意的是GET请求和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);
    }
}

GET请求方式和POST请求方式区别主要在于获取请求参数的方式不一样,是否可以提供一种统一获取请求参数的方式,从而统一doGet和doPost方法内的代码?

解决方案

(1)根据不同的请求方式获取请求参数,获取的内容如下:

(2)把获取到的内容进行分割,内容如下:

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

注意:因为参数的值可能是一个,也可能有多个,所以Map的值的类型为String数组。

基于上述理论,request对象为我们提供了如下方法:

  • 获取所有参数Map集合

    Map<String,String[]> getParameterMap()

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

    String[] getParameterValues(String name)

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

    String getParameter(String name)

接下来,我们通过案例来把上述的实例演示:

前端代码:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
<h2>GET方式提交</h2>
<form action="req03" 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" value="登录">
</form>
<hr>
<br>
<br>
<h2>POST方式提交</h2>
<form action="req03" method="post">
    用户名:<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" value="登录">
</form>
</body>
</html>

后端代码:

java 复制代码
@WebServlet(value = "/req03")
public class request02 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1、获取map集合
        Map<String, String[]> parameterMap = request.getParameterMap();
        parameterMap.forEach((key,values)->{
            System.out.println(key+"::"+ Arrays.toString(values));
        });

        // 2、根据参数名称获取参数值
        String username = request.getParameter("username");
        System.out.println(username);

        // 3、根据参数名称获取参数数组
        String[] hobbies = request.getParameterValues("hobby");
        System.out.println(Arrays.toString(hobbies));

    }

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

5、POST请求参数乱码解决

  • 分析出现中文乱码的原因:
    • POST的请求参数是通过request的getReader()来获取流中的数据
    • tomcat在获取流的时候采用的编码是ISO-8859-1
    • ISO-8859-1编码是不支持中文的,所以会出现乱码
  • 解决方案:
    • 页面设置的编码格式为UTF-8
    • 把tomcat在获取流数据之前的编码设置为UTF-8
    • 通过request.setCharacterEncoding("UTF-8")设置编码,UTF-8也可以写成小写

解决方案

设置输入流编码

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

重新发送POST请求,就会在控制台看到正常展示的中文结果。

6、Request请求转发

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

​ 浏览器发送请求给服务器,服务器中对应的资源A接收到请求,资源A处理完请求后将请求发给资源B,资源B处理完后将结果响应给浏览器,请求从资源A到资源B的过程就叫请求转发

实现方式

java 复制代码
request.getRequestDispatcher("资源B路径").forward(request,response)

代码演示

1.创建一个Aservlet类,接收/a的请求,在doGet方法中打印a请求,同时进行请求转发

java 复制代码
@WebServlet(value = "/a")
public class AServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("a 请求");

        // 请求转发
        request.getRequestDispatcher("b").forward(request,response);

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
    }
}

2.创建一个Bservlet类,接收/b的请求,在doGet方法中打印b请求

java 复制代码
@WebServlet(value = "/b")
public class BServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("b 请求");

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
    }
}

3、启动tomcat访问a资源

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

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

  • 存储数据到request域范围,数据是存储在request对象中
java 复制代码
void setAttribute(String name,Object o);
  • 根据key获取值
java 复制代码
Object getAttribute(String name);
  • 根据key删除该键值对
java 复制代码
void removeAttribute(String name);

接着上个需求来:

1、在a请求转发前保存资源

java 复制代码
@WebServlet(value = "/a")
public class AServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("a 请求");

        // 保存数据到request中,要在请求转发之前
        request.setAttribute("name","张三");

        // 请求转发
        request.getRequestDispatcher("b").forward(request,response);

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
    }
}

2、在b资源获取数据

java 复制代码
@WebServlet(value = "/req03")
public class request02 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1、获取map集合
        Map<String, String[]> parameterMap = request.getParameterMap();
        parameterMap.forEach((key,values)->{
            System.out.println(key+"::"+ Arrays.toString(values));
        });

        // 2、根据参数名称获取参数值
        String username = request.getParameter("username");
        System.out.println(username);

        // 3、根据参数名称获取参数数组
        String[] hobbies = request.getParameterValues("hobby");
        System.out.println(Arrays.toString(hobbies));

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        doGet(request,response);
    }
}

请求转发的特点

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

  • 只能转发到当前服务器的内部资源,不能从一个服务器通过转发访问另一台服务器

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

7、Response的响应状态码和响应头

HTTP响应数据总共分为三部分内容,分别是响应行、响应头、响应体,对于这三部分内容的数据,respone对象都提供了哪些方法来进行设置?

响应行

对于响应头,比较常用的就是设置响应状态码:

java 复制代码
void setStatus(int sc);

响应头

设置响应头键值对:

复制代码
void setHeader(String name,String value);

响应体

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

获取字符输出流:

复制代码
PrintWriter getWriter();

获取字节输出流

复制代码
ServletOutputStream getOutputStream();

代码演示

java 复制代码
@WebServlet(value = "/resp1")
public class response01 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1、设置响应行
        response.setStatus(200);
        // 2、设置响应头
        response.setHeader("Content-Type","text/html");

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
    }
}

8、Response重定向

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

  1. 浏览器发送请求给服务器,服务器中对应的资源A接收到请求
  2. 资源A现在无法处理该请求,就会给浏览器响应一个302的状态码+location的一个访问资源B的路径
  3. 浏览器接收到响应状态码为302就会重新发送请求到location对应的访问地址去访问资源B
  4. 资源B接收到请求后进行处理并最终给浏览器响应结果

这整个过程就叫重定向

实现方式

方法一:

java 复制代码
response.setStatus(302);
response.Header("location","资源B的路径")

方法二:

java 复制代码
response.sendRedirect("资源B的路径")

代码实现

创建CServlet,输出C并重定向到D

java 复制代码
@WebServlet(value = "/c")
public class CServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("C请求");
        //设置重定向
        response.sendRedirect("d");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
    }
}

创建DSelvet,输出D

java 复制代码
@WebServlet(value = "/d")
public class DServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("D请求");

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
    }
}

重定向的特点

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

    当进行重定向访问的时候,由于是由浏览器发送的两次请求,所以地址会发生变化

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

    因为第一次响应结果中包含了浏览器下次要跳转的路径,所以这个路径是可以任意位置资源。

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

    因为浏览器发送了两次请求,是两个不同的request对象,就无法通过request对象进行共享数据

介绍完请求重定向和请求转发以后,接下来需要把这两个放在一块对比下:

9、Response响应字符数据

实现方式

1、通过response对象获取字符输出流

java 复制代码
PrintWriter writer = response.getWriter();

2、写数据

java 复制代码
writer.writer("aaa");

注意:

  • 该流不需要关闭,随着响应结束,response对象销毁,由服务器关闭

  • 中文数据乱码:原因通过Response获取的字符输出流默认:ISO-8859-1

    java 复制代码
    response.setContentType("text/html;charset=utf-8");

代码演示

java 复制代码
@WebServlet(value = "/resp2")
public class respon02 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1、获取响应输出流
        PrintWriter writer = response.getWriter();
        // 2、写数据
        writer.write("aaa");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
    }
}

10、Response响应字节输出流

实现方式

1、通过Response对象获取字节输出流

java 复制代码
ServletOutStream outputStream = response.getOutputStream();

2、写数据

java 复制代码
outputStream.write("字节数据");

代码演示

java 复制代码
@WebServlet(value = "/resp3")
public class response3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1、获取字节输入流
        FileInputStream fileInputStream = new FileInputStream("D:\\file\\java\\response-request\\src\\main\\webapp\\imgs\\Desert.jpg");

        // 2、获取字节输出流
        ServletOutputStream outputStream = response.getOutputStream();

        // 3、写数据
        byte[] bytes = new byte[1024 * 8];
        int len;
        while ((len = fileInputStream.read(bytes)) != -1){
            outputStream.write(bytes,0,len);
        }

        fileInputStream.close();
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
    }
}
相关推荐
xcl09255 小时前
北京24小时自助健身房系统软件开发实战:从架构到部署全流程指南
java·spring boot·架构
一 乐7 小时前
动漫书销售商城|基于springboot + vue动漫书销售商城(源码+数据库+文档)
java·数据库·vue.js·spring boot·毕业设计
卓怡学长7 小时前
w214基于jsp知道特产网
java·intellij-idea
步行cgn7 小时前
Spring 注解使用详解
java·spring
一条小小yu8 小时前
Spring IoC的理解
java·后端·spring
落魄实习生8 小时前
Agent Scope Java 2.x 系列【7】工具使用
java·开发语言·ai
旺仔学长 哈哈8 小时前
springboot钓鱼爱好者交流平台APP设计与实现
java·spring boot·mysql·充电桩管理系统
自强的小白10 小时前
核心功能(Service接口)
java·mybatis
乌暮11 小时前
深入理解 Java 泛型:把「万能盒子」用对、用稳
java·开发语言·后端·学习