Java Web学习 Request

1 Request和Response的概述

(1) request:获取请求数据

//Tomcat需要解析请求数据,封装为request对象,再创建servlet对象,并且将request对象传递到service方法
<1> 浏览器会发送HTTP请求到后台服务器[Tomcat]
<2> HTTP的请求中会包含很多请求数据[请求行+请求头+请求体]
<3> 后台服务器[Tomcat]会对HTTP请求中的数据进行解析并把解析结果存入到一个对象中
<4> 所存入的对象即为request对象,所以我们可以从request对象中获取请求的相关参数
<5> 获取到数据后就可以继续后续的业务,比如获取用户名和密码就可以实现登录操作的相关业务

(2) response:设置响应数据

<1> 业务处理完后,后台就需要给前端返回业务处理的结果即响应数据
<2> 把响应数据封装到response对象中
<3> 后台服务器[Tomcat]会解析response对象,按照[响应行+响应头+响应体]格式拼接结果
<4> 浏览器最终解析结果,把内容展示在浏览器给用户浏览

 

2 Request对象

(1) Request继承体系

//当Servlet类实现的是Servlet接口的时候,service方法中的参数是ServletRequest和ServletResponse
//Servlet类继承的是HttpServlet类的时候,doGet和doPost方法中的参数就变成HttpServletRequest和HttpServletReponse
ServletRequest(Java提供的请求对象根接口)
    |extends
HttpServletRequest(Java提供的对HTTP协议封装的请求对象接口)
//ServletRequest和HttpServletRequest是继承关系,并且两个都是接口,接口是无法创建对象
    |implements
RequestFacade(Tomcat定义的实现类)
//该类实现了HttpServletRequest接口,也间接实现了ServletRequest接口。
//Servlet类中的service方法、doGet方法或者是doPost方法最终都是由Web服务器[Tomcat]来调用的,所以Tomcat提供了方法参数接口的具体实现类,并完成了对象的创建
//要想了解RequestFacade中都提供了哪些方法,我们可以直接查看JavaEE的API文档中关于ServletRequest和HttpServletRequest的接口文档,因为RequestFacade实现了其接口就需要重写接口中的方法

(2) Request获取请求数据

<1> 获取请求行数据
//请求行包含三块内容,分别是 请求方式、 请求资源路径、 HTTP协议及版本
//对于这三部分内容,request对象都提供了对应的API方法来获取
//以下方法,除了getQueryString(),既可以在doGet()方法中使用,也可以在doPost()方法中使用。
<1.1> 获取请求方式
String getMethod()
<1.2> 获取虚拟目录(项目访问路径)
String getContextPath()
<1.3> 获取URL(统一资源定位符)
StringBuffer getRequestURL()
<1.4> 获取URI(统一资源标识符)
String getRequestURI()
<1.5> 获取请求参数(GET方式)
String getQueryString()
......
<2> 获取请求头数据
//对于请求头的数据,格式为 key: value
//以下方法既可以在doGet()方法中使用,也可以在doPost()方法中使用。
String getHeader(String key)
<3> 获取请求体数据
//GET请求的时候是没有请求体的
//以下方法不能在doGet()方法中使用,只能在doPost()方法中使用。
<3.1> 获取字节输入流,当前端发送的是字节数据,比如传递的是文件数据,则使用该方法
ServletInputStream getInputStream()
<3.2> 获取字符输入流,当前端发送的是纯文本数据,则使用该方法
BufferedReader getReader()
<4> 获取请求参数的通用方式
<4.1> 使用request的getMethod()来获取请求方式,根据请求方式的不同分别获取请求参数值
//实现起来比较麻烦,这种方案我们不采用

@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)){//如果是get方式
			params = req.getQueryString();//使用get获取参数方法
		}else if("POST".equals(method)){//如果是post方式
			BufferedReader reader = req.getReader();
			params = reader.readLine();//使用post获取参数方法
		}
		//将请求参数进行打印控制台
		System.out.println(params);
	}
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) hrows ServletException, IOException {
		this.doGet(req,resp);
	}
}

<4.2> request对象已经将上述获取请求参数的方法进行了封装,并且request提供的方法实现的功能更强大,以后只需要调用request提供的方法即可。
//request对象根据不同的请求方式获取请求参数,把获取到的请求参数进行分割(根据?=&分割),把分割后端数据,存入到一个Map集合中。
//因为参数的值可能是一个,也可能有多个,所以Map的值的类型为String<>,泛型为<String,String[]>。
//底层仍然是<1><3>中的方法,若为Get方式则通过字符串获取,若为Post方式则通过字符流或数据流获取。
① 获取所有参数Map集合
Map<String,String[]> getParameterMap()
//第一个方法与后两个方法不同,第一个通过map对象获取参数,后两个通过关键字获取参数。
② 根据名称获取参数值(数组)//参数可能包含多个值的,比如爱好。
String[] getParameterValues(String name)
③ 根据名称获取参数值(单个值)//参数只包含一个值的,比如密码。
String getParameter(String name)
<4.3> 代码实现

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    Map<String, String[]> pm = req.getParameterMap();
    Set<String> keys = pm.keySet();
    for (String key : keys){
        System.out.print(key + ":");
        String[] values = pm.get(key);
		//String[] values = req.getParameterValues("key");
		//不能用req通过key获取value
        for (String value : values){
            System.out.print(value + " ");//map容器允许出现有key但没有value
        }
        System.out.println();
    }
    System.out.println("------------------");
    String[] hobbies = req.getParameterValues("hobby");
    System.out.print("hobby:");
    for (String hobby : hobbies){//若hobby为空,此时hobbies为空,会抛出java.lang.nullpointerexception。
        System.out.print(hobby + " ");
    }
    System.out.println();
    System.out.println("------------------");
    String username = req.getParameter("username");
    System.out.println("username:" + username);
}

<4.4> 以后我们再写代码的时候,就只需要按照如下格式来编写:

public class RequestDemo1 extends HttpServlet {
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		//采用request提供的获取请求参数的通用方式来获取请求参数
		//编写其他的业务代码...
	}
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		this.doGet(req,resp);
	}
}

(3) IDEA快速创建Servlet

<1> 创建Servlet
右击java包 -> new -> Servlet
<2> 修改Servlet模板
File -> Setting -> Editor -> File and Code Templates -> Others -> Web -> Java Code Templates -> servlet annnotated class

(4) 请求参数中文乱码问题

<1> POST请求解决方案
<1.1> 出现中文乱码的原因
① POST的请求参数是通过request的getReader()来获取流中的数据
② TOMCAT在获取流的时候采用的编码是ISO-8859-1
③ ISO-8859-1编码是不支持中文的,所以会出现乱码
<1.2> 解决方案
//这种方案不适用于GET请求
① 页面设置的编码格式为UTF-8
② 把TOMCAT在获取流数据之前的编码设置为UTF-8
③ 通过request.setCharacterEncoding("UTF-8")设置编码,UTF-8也可以写成小写
<1.3> 代码实现

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	//1. 解决乱码: POST getReader()
	//设置字符输入流的编码,设置的字符集要和页面保持一致
	request.setCharacterEncoding("UTF-8");
	//2. 获取username
	String username = request.getParameter("username");
	System.out.println(username);
}

<2> GET请求解决方案
<2.1> POST请求的中文乱码解决方案为什么不适用GET请求?
① GET请求获取请求参数的方式是 request.getQueryString()
② POST请求获取请求参数的方式是 request.getReader()
//getParameter()和getParameterValues()方法底层仍是以上两个方法。
request.setCharacterEncoding("utf-8")是设置request处理流的编码
④ getQueryString方法并没有通过流的方式获取数据
<2.2> GET请求出现乱码的原因
① 浏览器通过HTTP协议发送请求和数据给后台服务器(Tomcat)
② 浏览器在发送HTTP的过程中会对中文数据进行URL编码
//编码:编译为二进制机器码
③ 在进行URL编码的时候会采用页面 <meta>标签指定的UTF-8的方式进行编码,比如张三编码后的结果为 %E5%BC%A0%E4%B8%89
④ 后台服务器(Tomcat)接收到 %E5%BC%A0%E4%B8%89后会默认按照 ISO-8859-1进行URL解码
//解码:解译为字符
⑤ 由于前后编码与解码采用的格式不一样,就会导致后台获取到的数据为乱码。
<2.3> 解决方案
① 在进行编码和解码的时候,不管使用的是哪个字符集,他们对应的 %E5%BC%A0%E4%B8%89是一致的
② 那他们对应的二进制值也是一样的,为:1110 0101 1011 1100 1010 0000 1110 0100 1011 1000 1000 1001
③ 所以我们可以考虑把 å¼ ä¸�转换成字节,在把字节转换成 张三,在转换的过程中是它们的编码一致,就可以解决中文乱码问题。
<2.4> 代码实现

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	//1 获取username
	String username = request.getParameter("username");
	System.out.println("解决乱码前:"+username);
	//2 先对乱码数据进行编码:转为字节数组
	byte[] bytes = username.getBytes(StandardCharsets.ISO_8859_1);
	//3 字节数组解码
	username = new String(bytes, StandardCharsets.UTF_8);//若报错,则删除多余的包。
	//更凝练的写法
	//username = new String(username.getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8);
	System.out.println("解决乱码后:"+username);
}
//GET请求参数乱码解决方案同时也可也把POST请求参数乱码的问题也解决了
//只不过对于POST请求参数一般都会比较多,采用这种方式解决乱码起来比较麻烦,所以对于POST请求还是建议使用设置编码的方式进行。
//另外需要说明一点的是Tomcat8.0之后,已将GET请求乱码问题解决,设置默认的解码方式为UTF-8

<2.5> 编码&解码
String encode = URLEncoder.encode("需要被编码的内容","字符集(UTF-8)")//编码
String decode = URLDecoder.decode("需要被解码的内容","字符集(UTF-8)")//解码

(5) Request请求转发

<1> 请求转发(forward):一种在服务器内部的资源跳转方式。
//资源可以理解为servlet
<1.1> 浏览器发送请求给服务器,服务器中对应的资源A接收到请求
<1.2> 资源A处理完请求后将请求发给资源B
<1.3> 资源B处理完后将结果响应给浏览器
<1.4> 请求从资源A到资源B的过程就叫请求转发
<2> 请求转发的实现方式
req.getRequestDispatcher("资源B路径").forward(req,resp);
//资源(即request对象和respond对象)从当前资源转移到B资源路径。
<3> 请求转发资源间共享数据:使用Request对象
//此处主要解决的问题是把请求从 /A 转发到 /B 的时候,如何传递数据给 /B 路径。
//以下方法都是通过request对象调用。
<3.1> 存储数据到request域(范围,即数据所存储的request对象)中
void setAttribute(String name,Object o);
//name代表键,object意味着值可以是任何数据类型。
<3.2> 根据key获取值
Object getAttribute(String name);
<3.3> 根据key删除该键值对
void removeAttribute(String name);
<4> 请求转发的特点
<4.1> 浏览器地址栏路径不发生变化
//虽然后台从 /A转发到 /B,但是浏览器的地址一直是 /A,未发生变化。
<4.2> 只能转发到当前服务器的内部资源
//不能从一个服务器通过转发访问另一台服务器。
<4.3> 一次请求,可以在转发资源间使用request共享数据
//虽然后台从 /A转发到 /B,但是这个只有一次请求、

posted @ 2023-03-17 15:35  10kcheung  阅读(50)  评论(0)    收藏  举报