Request & Response

目录

1. Request和Response的概述

2. Request对象

2.1 Request继承体系

2.2 Request获取请求数据

2.2.1 获取请求行数据

2.2.2 获取请求头数据

2.2.3 获取请求体数据(post方式的请求参数)

2.2.4 获取请求参数的通用方式

2.3 请求参数中文乱码问题

2.3.1 post请求解决方案

2.3.2 GET请求解决方案

2.4 Request请求转发

3. Response对象

3.1 Response继承体系

3.2 Response设置响应数据

3.2.1 设置响应行

3.2.2 设置响应头

3.2.3 设置响应体

3.3 Response请求重定向

3.4 路径问题

3.5 Response响应字符数据

3.6 Response响应字节数据


1. Request和Response的概述

request是请求对象,response是响应对象:

  • request对象是用来封装请求数据的对象。
  • response对象是用来封装响应数据的对象。

2. Request对象

2.1 Request继承体系

 实现类RequestFacade:

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

2.2 Request获取请求数据

2.2.1 获取请求行数据

方法说明
getMethod()获取请求方式
getContextPath()获取项目访问路径
getRequestURL获取请求URL
getRequestURI获取请求URI
getQueryString获取get方式的请求参数

2.2.2 获取请求头数据

方法说明
getHeader(String name)根据请求头名称获取对应的值

2.2.3 获取请求体数据(post方式的请求参数)

方法说明
getReader()获取字符输入流(字符数据如纯文本数据)
getInputStream()获取字节输入流(字节数据如文件数据)

       

/**
 * request获取请求数据
 */
@WebServlet("/req1")
public class RequestDemo1 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        /*
        获取请求行数据
         */
        //1.获取请求方式
        String method = req.getMethod();
        //GET
        System.out.println(method);

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

        //3.获取URL(统一资源定位符)
        StringBuffer requestURL = req.getRequestURL();
        //http://localhost:8080/request-demo/req1
        System.out.println(requestURL.toString());

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

        //5.获取get方式的请求参数
        String queryString = req.getQueryString();
        //username=ydh&password=123
        System.out.println(queryString);

        /*
        获取请求头数据
         */
        //根据请求头的键获取对应的值
        String agent = req.getHeader("user-agent");
        //Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36
        System.out.println(agent);
    }

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

2.2.4 获取请求参数的通用方式

request对象已经将上述获取请求参数的方法进行了封装,并把获取到的内容进行分割,存入到一个Map<String,String[]>集合中。

​​

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

方法说明
getParameterMap()
获取所有参数 Map 集合
getParameterValues(String name)
根据名称获取参数值(数组)
getParameter(String name)
根据名称获取参数值 ( 单个值 )

/**
 * request获取请求参数的通用方式
 */
@WebServlet("/req2")
public class RequestDemo2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("get...");
        //1.获取所有参数的Map集合
        Map<String, String[]> map = req.getParameterMap();
        //增强for循环遍历键
        for (String key : map.keySet()) {
            System.out.print(key+":");
            //根据键获取参数值(数组)
            String[] values = map.get(key);
            //增强for循环遍历值
            for (String value : values) {
                System.out.print(value+" ");
            }
            //换行
            System.out.println();
        }

        //2.根据名称获取参数值(数组)
        String[] hobbies = req.getParameterValues("hobby");
        for (String hobby : hobbies) {
            System.out.println(hobby);
        }

        //3.根据名称获取参数值(单个值)
        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 {
        //采用通用方式获取请求参数,直接调用doGet方法
        this.doGet(req,resp);
    }
}

2.3 请求参数中文乱码问题

2.3.1 post请求解决方案

产生中文乱码的原因:

  • POST的请求参数是通过requestgetReader()来获取流中的数据。
  • TOMCAT在获取流的时候采用的编码是ISO-8859-1。
  • ISO-8859-1编码是不支持中文的,所以会出现乱码。

解决方案:

  • 页面设置的编码格式为UTF-8。
  • TOMCAT在获取流数据之前的编码设置为UTF-8。
  • 通过request.setCharacterEncoding("UTF-8")设置编码,UTF-8也可以写成小写。
方法说明
setCharacterEncoding("UTF-8")
设置字符输入流的编码

//1.设置字符输入流的编码(设置的字符集要和页面的字符集一致)
request.setCharacterEncoding("UTF-8");
//2.获取username
String username = request.getParameter("username");
System.out.println(username);

2.3.2 GET请求解决方案

POST 请求的中文乱码解决方案为什么不适用 GET 请求?
  • GET请求获取请求参数的方式是getQueryString() ,POST请求获取请求参数的方式getReader()。
  • setCharacterEncoding("utf-8")是设置request处理流的编码,getQueryString方法并没有通过流的方式获取数据。
GET 请求出现乱码的原因:

URL编码的编码过程

  • 将字符串按照编码方式转为二进制
  • 每个字节转为216进制数并在前边加上%
String username = "张三";
//1.URL编码
String encode = URLEncoder.encode(username, "utf-8");
System.out.println(encode);//%E5%BC%A0%E4%B8%89

//2.URL解码
//String decode = URLDecoder.decode(encode, "utf-8");
//System.out.println(decode);//张三
String decode = URLDecoder.decode(encode, "ISO-8859-1");
System.out.println(decode);//å¼ ä¸

GET请求解决中文乱码方案:

方案说明
username = new String(username.getBytes("ISO-8859-1"),"uft-8");先编码,再解码(也适用于post方式)

//1.获取username
        String username = request.getParameter("username");
//        //2.编码,字符串转为字节数据
//        byte[] bytes = username.getBytes("ISO-8859-1");
//        //3.解码,字节数据转为字符串
//        username = new String(bytes,"utf-8");
//        System.out.println(username);
        username = new String(username.getBytes("ISO-8859-1"), "utf-8");
        System.out.println(username);

注意

  • Tomcat8.0之后,已将GET请求乱码问题解决,设置默认的解码方式为UTF-8。

2.4 Request请求转发

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

请求转发

方法说明
getRequestDispatcher(" 资源 B 路径 ").forward(req,resp)
资源A请求转发到资源B

请求转发资源间共享

方法说明
void setAttribute(String name,Object o)
存储数据到request对象中
Object getAttribute(String name)
根据键获取值
void removeAttribute(String name)
根据键删除该键值对

RequestDemo5.java
@WebServlet("/req5")
public class RequestDemo5 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("demo5...");

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

        //2.请求转发
        request.getRequestDispatcher("/req6").forward(request,response);
    }

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

RequestDemo6.java

@WebServlet("/req6")
public class RequestDemo6 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("demo6...");

        //3.获取数据
        Object msg = request.getAttribute("msg");
        System.out.println(msg);//hello

        //4.删除数据
        request.removeAttribute("msg");
        System.out.println(request.getAttribute("msg"));//null
    }

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

 请求转发的特点

  • 浏览器地址栏路径不发生变化。
  • 只能转发到当前服务器的内部资源。
  • 一次请求,可以在转发资源间使用request共享数据。

3. Response对象

3.1 Response继承体系

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

3.2 Response设置响应数据

3.2.1 设置响应行

方法说明
setStatus(int sc)设置响应状态码

3.2.2 设置响应头

方法

说明

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

3.2.3 设置响应体

对于响应体,是通过字符或者字节输出流的方式往浏览器写。
方法说明
getWriter()
获取字符输出流
getOutputStream()
获取字节输出流

3.3 Response请求重定向

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

方法说明
sendRedirect(String s)重定向

ResponseDemo1.java

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

        /*
        重定向
         */
//        //1.设置响应状态码 302
//        response.setStatus(302);
//        //2.设置响应头
//        response.setHeader("Location","/request-demo/resp2");
        //简单写法,一步搞定
        response.sendRedirect("/request-demo/resp2");
    }

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

ResponseDemo2.java

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

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

 重定向的特点

  • 浏览器地址栏路径会发生变化。
  • 可以重定向到任何位置的资源(服务器内部、外部均可)。
  • 两次请求,不可以在多个资源间使用request共享数据。

3.4 路径问题

虚拟目录(项目的根目录):

  • 浏览器使用:需要加虚拟目录(项目访问路径)。
  • 服务端使用:不需要加虚拟目录。

以下路径中,是否需要加虚拟目录?

<a href="路径">        需要

<form action="路径">        需要

req.getRequestDispatcher("路径")        不需要

resp.sendRediect("路径")        需要

如果虚拟目录变了,那么项目中所有重定向的路径都应该变,代码耦合度太高,因此采取下面这种方式解决。

//动态获取虚拟目录
String contextPath = request.getContextPath();
response.sendRedirect(contextPath + "/resp2");

3.5 Response响应字符数据

方法说明
setContentType("text/html;charset=utf-8")设置的响应数据及数据的编码
getWriter()获取字符输出流
write()通过字符输出流写数据

        //设置的响应数据及数据的编码
        response.setContentType("text/html;charset=utf-8");

        //1.获取字符输出流
        PrintWriter writer = response.getWriter();
//        //2.设置响应头的content-type的值,告诉浏览器返回的数据类型是html类型数据,这样浏览器才会解析html标签
//        response.setHeader("content-type","text/html");
        //3.写数据到浏览器上
        //简单字符串
        writer.write("aaa");
        //html字符串
        writer.write("<h1>bbb</h1>");
        //中文字符串
        writer.write("你好");

注意

  • 设置响应头的content-type的值与调用setContentType的效果是等效的。
  • 一次请求响应结束后, response 对象就会被销毁掉,所以不要手动关闭字符输出流。

3.6 Response响应字节数据

传统方式:

/*
返回一张图片文件给浏览器
*/
//1.读取文件
FileInputStream fileInputStream = new FileInputStream("d://Desert.jpg");
//2.获取response字节输出流
ServletOutputStream outputStream = response.getOutputStream();
//3.完成流的copy
//在内存中开辟1KB的字节数组(缓存区)
byte[] buff = new byte[1024];
int len = 0;
//读取文件数据并将其存放到字节数组中,返回读取的字节数。(-1表示文件末尾)
while((len = fileInputStream.read(buff))!= -1){
    //将字节数组中的数据写到浏览器上
    outputStream.write(buff,0,len);
}
fileInputStream.close();
对于流的 copy 的代码还是比较复杂的,所以我们可以使用别人提供好的方法来简化代码
的开发:
pom.xml中导入依赖坐标:
<dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.6</version>
</dependency>

调用工具类方法:

方法说明
IOUtils.copy(fileInputStream,outputStream)流的copy

/*
返回一张图片文件给浏览器
*/
//1.读取文件
FileInputStream fileInputStream = new FileInputStream("d://Desert.jpg");
//2.获取response字节输出流
ServletOutputStream outputStream = response.getOutputStream();
//3.完成流的copy
IOUtils.copy(fileInputStream,outputStream);
fileInputStream.close();

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值