HttpServletRequest
在Http协议中,有这样两部分,请求与响应,今天介绍请求对象
当我们继承HttpServlet后,需对service(HttpServletRequest req, HttpServletResponse resp)进行重写,那么req和resp是什么时候进行创建的呢?
Web服务器收到一个Http请求后,会针对每个请求创建一个HttpServletRequest对象和HttpServletResponse对象。若需要获取客户端提交的相关信息,则需要从HttpServletRequest对象中获取;若需要向客户端发送数据,则需要通过HttpServletResponse对象来完成。
HttpServletRequest
1、请求的生命周期
当客户端浏览器将请求(字符序列)发送到服务器后,服务器会根据HTTP请求协议的格式对请求进行解析。同时,服务器会创建HttpServletRequest的实现类RequestFacade的对象,即请求对象。然后在调用相应的set方法,将解析出的数据封装到请求对象中。此时HttpServletRequest实例就创建并初始化完毕了。也就是说,请求对象是由服务器创建。
当服务器向客户端发送响应结束后,HttpServletRequest实例对象被服务器销毁。
一次请求对应一个请求对象,另外一个请求对应另外一个请求对象,与之前的请求对象没有任何关系。HttpServletRequset实例的生命周期很短暂。
2.请求参数:
HttpServletRequest对于请求中所携带的参数是以Map的形式接受的,并且该Map的key为String,value为String数组。注意value为String数组。
因为Http请求协议运行一个请求参数具有多个值,例如复选框。
html的代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="registerServlet" method="post">
姓名:<input type="text" name="name"><br/>
年龄:<input type="text" name="age"><br/>
爱好:<input type="checkbox" name="hobby" value="playing">玩游戏
<input type="checkbox" name="hobby" value="swiming">游泳
<input type="checkbox" name="hobby" value="reading">看书<br/>
<input type="submit" value="注册">
</form>
</body>
</html>
 例如存在上面这样一个表单,我们要获取客户端浏览器的请求数据,方法如下:
protected void service(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
//接受指定参数名称的请求参数值
//本质上getParameter("name"),等同于getParameterValues("name")[0]
String name = request.getParameter("name");
int age = Integer.parseInt(request.getParameter("age"));
System.out.println("name = " + name);
System.out.println("age = " + age);
System.out.println("-----------------");
//获取所有的请求参数名称
Enumeration<String> names = request.getParameterNames();
//遍历枚举
while(names.hasMoreElements()){
System.out.println(names.nextElement());
}
System.out.println("-----------------");
//获取指定参数的所有值
String[] hobbys = request.getParameterValues("hobby");
for(String hobby : hobbys){
System.out.println(hobby);
}
System.out.println("-----------------");
//获取存放请求的参数Map
Map<String, String[]> map = request.getParameterMap();
for(Entry<String, String[]> entry : map.entrySet()){
//获取参数名
String key = entry.getKey();
//获取参数值
String[] values = entry.getValue();
for(String value : values){
System.out.println(key + "..." + value);
}
}
}
控制台输出如下:
HttpServletRequest请求常用方法:
getParameter(String str) str为HTML文件中的标签的name属性值
getParameterNames() 获得请求中的所有参数值
getParameterValues(String str) 获去该属性的所有值,例如复选框
getParameterMap() 获取请求中所有的参数和值的映射关系,key为String,value为String[]
3.域属性
在Request中也存在域属性空间,用于存放有名称的数据。该数据只在当前Request请求中可以进行访问。
常用方法:
getAttribute(String name) 获取该属性的值
getAttributeNames() 获取所有的属性名
setAttribute(String key,Object) 在请求中放入属性
removeAttribute(String name) 删除请求中的属性
我们知道,一次请求对应一次响应。当请求没有被销毁时,我们边可以从请求中获取数据。例如存在如下两个Servlet,SomeServelt和OtherServlet。
SomeServlet代码如下:
public class SomeServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//向请求中放入属性
request.setAttribute("name", "wangzhao");
request.setAttribute("age", "120");
//从请求中删除指定域属性
request.removeAttribute("age");
// 将请求转发给otherServlet, 说明请求没有被销毁
request.getRequestDispatcher("/otherServlet").forward(request, response);
}
}
OtherServlet代码如下:
public class OtherServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//从请求中获取指定名称的域属性
String name = (String)request.getAttribute("name");
String age = (String)request.getAttribute("age");
System.out.println(name);
System.out.println(age);
//从请求中获取请求中的所有域属性名称
Enumeration<String> names = request.getAttributeNames();
while(names.hasMoreElements()){
String element = names.nextElement();
System.out.println(element +" = " + request.getAttribute(element));
}
}
}
控制台输出如下:
如何理解上面这一句代码:request.getRequestDispatcher("/otherServlet").forward(request, response);
在之前的示例中,我们只有一个Servlet,所以一个请求只在一个Servlet中有效。但请求转发,让这个请求不再当前Servlet中销毁,发送到其他Servlet中。**例如:你去旅游,原本打算到西安玩完回家。但你又想去成都玩,所以你又去了成都,然后回家。**这就是请求转发,这有什么用?我们是不是通过请求转发实现了不同Servlet之间的通信?当然通信并不只有这一种方法。
4.服务端相关信息
中文乱码问题:
继续以上一个表单为例:我们提交如下信息:
控制台输出:
可以看出name出现了乱码。为什么出现乱码?原因如下:
原因:一旦有浏览器经过Http协议传输,则这些数据均将以字节的形式上传给服务器。因为HTTP协议的底层使用的是TCP传输协议。TCP,是一种面向连接的、可靠的、基于字节流的、端对端的通信协议。在请求中,这些字节均以%开头,并以16进制形式出现。如%5A%3D等。
当用户通过浏览器提交一个UTF-8编码格式的两个字的中文请求时,浏览器会将这两个中文字符变为六个字节(一般一个UTF-8汉字占用三个字节),即形成六个类似%8E的字节表示形式,并将这六个字节上传至Tomcat服务器。
Tomcat服务器在接收到这六个字节后,并不知道他们原始采用的是什么字符编码。而Tomcat默认的编码格式为ISO-8859-1。所以会将这六个字节按照ISO-8859-1的格式进行编码,编码后再控制台显示,所以再控制台会显示乱码。
解决方案:
1、Tomcat9的get提交已经解决了中文乱码问题。
2、Post提交方式,在Service方法添加如下一行代码。(注意,先添加后然后再获取数据,该代码对get提交方式无用)
3、解决其他版本的GET提交:
1.在Tomcat服务器的server.xml中添加 URIEncoding=”UTF-8”(不推荐使用,需重启服务器)
2.万能解决方案(但需要每对一组数据进行操作)