【Servlet、HTTP协议、Request&Response】
Servlet
继承结构体系
Servlet接口有两个实现类:
- GenericServelt:儿子,也是抽象类;
- HttpServlet:孙子,也是抽象类。
GenericServelt
GenericServelt将Servlet接口其他的方法做了默认空实现,只将service()方法作为抽象。
- 将来定义Servlet类时可以继承GenericServelt抽象类,实现service()方法即可。
HttpServlet
HttpServlet是对HTTP协议的封装,简化操作。
- 定义一个类继承HttpServlet抽象类,覆写doGet/doPost方法。
urlPattern配置
urlPattern:Servlet访问路径。
- 一个Servlet可以定义多个访问路径,如,注解配置可以这么写:
@WebServlet({"/demo03","/d3"})
- 路径定义规则:
/xxx
/xxx/xxx
,如:@WebServlet("/user/demo03")
*.do
,*代表通配符
HTTP
HTTP:Hyper Text Transfer Protocol,超文本传输协议。
传输协议:定义了客户端和服务器端通信时发送数据的格式。
HTTP协议特点:
- 基于TCP/IP的高级协议;
- 默认端口号是80;
- 基于请求响应模型的,即一次请求对应一次响应;
- 是无状态的协议:每次请求之间相互独立,不能交互数据。
历史版本(了解);
- 1.0版本:每一次请求响应都会建立新的连接;
- 1.1版本:会复用之前的连接。
请求消息数据格式
请求行
-
格式:请求方式 请求url 请求协议/版本
如:
GET /login.html HTTP/1.1
-
请求方式:HTTP协议中总共又7中请求方式,常用的有2种:
请求方式 特点 GET 1. 请求参数在请求行(url)中
2.请求的url长度是有限制的
3.不太安全POST 1.请求参数在请求体中
2.请求的url长度没有限制
3.较为安全
请求头
请求头:客户端浏览器告诉服务器一些信息。
- 格式:请求头名称:值1,值2,…
如:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: keep-alive
Cookie: Idea-35f3bfe2=fbdfdaaf-f884-4025-96de-0ba8ae3bea74
Host: localhost
Referer: http://localhost/login.html
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36
常见的请求头:
-
User-Agent:浏览器告诉服务器,我访问你使用的浏览器的版本信息;
- 可以在服务器端获取该头的信息来解决浏览器的兼容性问题
-
Referer:告诉服务器,我(当前请求)从哪里来
作用:
- 防盗链
- 统计工作
请求空行
- 空行,用于分隔POST请求的请求头与请求体。
请求体(正文)
- 用于封装POST请求消息的请求参数。
响应消息数据格式
响应行
-
格式:协议/版本 状态码 状态码的描述
如
HTTP/1.1 200 OK
- 状态码:服务器告诉浏览器本次请求和响应的一个状态。
- 状态码都是三位数字,主要分五类:
- 1xx:服务器接收客户端消息,但没有接收完成,等待一段时候后,发送1xx的状态码【很少出现】
- 2xx:成功,代表有:200
- 3xx:重定向,代表有:302(重定向)、304(访问缓存)
- 4xx:客户端错误,代表有:404(请求路径没有对应的资源)、405(请求方式没有对应的doXxx方法)
- 5xx:服务器端错误,代表有:500(服务器内部错误)
- 状态码都是三位数字,主要分五类:
响应头
-
格式:响应头名称:值1,值2,…
-
常见的响应头:
-
Content-Type:服务器告诉客户端本次响应体的数据格式及编码格式
-
Content-disposition:服务器会告诉客户端以什么格式来打开响应体数据
- 默认值:
- in-line:默认值,在当前页面内打开
- attachment:以附件格式打开响应头,如用于文件下载。
- 默认值:
-
相应空行
用于分隔响应消息的响应头与响应体。
响应体
传输的数据。
Request & Response
- Request对象与Response对象是由服务器创建的,我们来使用;
- Request对象是用来获取请求消息的,而Response对象是用来设置响应消息的。
Request
继承体系结构
功能
获取请求消息数据
- 获取请求行数据
- 如,消息行:GET /day12/demo02?username=222 HTTP/1.1
- 方法:
方法 | 获得的数据 |
---|---|
String getMethod() | 获取请求方法,如:GET |
String getContextPath() 【重点】 | 获取虚拟目录,如:/day12 |
String getServletPath() | 获取Servlet路径,如:/demo02 |
String getQueryString() | 获取get方式的请求参数,如:username=222 |
String getRequestURI() 【重点】 | 获取请求URI,如:/day12/demo02 |
StringBuffer getRequestURL() 【重点】 | 获取请求URL,如:http://localhost/day12/demo02 |
String getProtocol() | 获取协议及版本,如:HTTP/1.1 |
String getRemoteAddr() | 获取客户机的IP地址,如:127.0.0.1 |
注意:
URI:统一资源定位符
URL:统一资源标识符,代表的范围更大。
代码演示:
html静态页面代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/day12/demo02" method="get">
<input name="username">
<input type="submit" value="提交">
</form>
</body>
</html>
实现HttpServlet接口的类的代码:
package cn.itcast.web.demo1;
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("/demo02")
public class ServletDemo02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取请求方法
System.out.println(req.getMethod());
//获取虚拟目录
System.out.println(req.getContextPath());
//获取Servlet路径
System.out.println(req.getServletPath());
//获取get方式的请求参数
System.out.println(req.getQueryString());
//获取请求URI
System.out.println(req.getRequestURI());
//获取请求完整URL
System.out.println(req.getRequestURL());
//获取协议及版本
System.out.println(req.getProtocol());
//获取用户IP地址
System.out.println(req.getRemoteAddr());
/*
* 结果:
* GET
* /day12
* /demo02
* username=222
* /day12/demo02
* http://localhost/day12/demo02
* HTTP/1.1
* 0:0:0:0:0:0:0:1
*/
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doPost...");
}
}
-
获取请求头数据
方法 含义 String getHeader(String name)
【重点】通过请求头的名称获取请求头的值 Enumeration<String> getHeaderNames()
获取所有的请求头名称 -
获取请求体数据
请求体:只有POST请求方式才有请求体,在请求体中封装了POST请求的请求参数。
获取的步骤:
- 获取流对象;
- 再从流对象中拿数据。
获取流对象方法:
方法 含义 BufferedReader getReader()
获取字符输入流,只能操作字符数据 ServletInputStream getInputStream()
获取字节输入流,可以操作所有类型数据
其他功能
-
获取请求参数的通用方式【重要】
方法 作用 String getParameter(String name)
根据参数名称获取参数值 String[] getParameterValues(String name)
根据参数名称获取参数值的数组(多用于复选框) Enumeration<String> getParameterNames()
获取所有请求的参数名称 Map<String,String[]> getParameterMap()
获取所有参数的Map集合 注意:中文乱码问题。
- GET方式:tomcat 8已经将GET方式获取中文的乱码问题解决了;
- POST方式:会乱码,解决方案是:在获取参数前,调用
setCharacterEncoding
设置Request对象的编码方式与IDEA的相同。
-
请求转发【重要】
- 请求转发:是一种在服务器内部的资源跳转方式。
- 步骤:
- 通过request对象的
getRequestDispatcher(String path)
获取请求转发器对象RequestDispatcher
; - 使用
RequestDispatcher
对象的forward(ServletRequest request,ServletResponse response)
方法向path中转发request与response对象。
- 通过request对象的
- 特点:
- 浏览器地址栏路径不发生变化;
- 只能转发到当前服务器的内部资源中;
- 转发是一次请求,可以用Request对象共享数据。
-
共享数据
- 域对象:一个有作用范围的对象,可以在范围内共享数据。
- Request域:一次请求的范围,一般用于请求转发的多个资源中共享数据。
- 方法:
方法 含义 void setAttribute(String name,Object o)
存储数据 Object getAttribute(String name)
通过数据名获得数据值 void removeAttribute(String name)
通过数据名删除数据键值对 -
获取ServletContext对象
- 调用Request对象的getServletContext()方法得到的是一个ServletContext对象。
Response
功能:用来设置响应消息的。
设置相应行
主要有设置状态码,方法:
void setStatus(int sc)
设置响应头
void setHeader(String name,String value)
设置响应体
使用步骤:
- 获取输出流;
- 字符输出流:
PrintWriter getWriter()
- 字节输出流:
ServletOutputStream getOutputStream()
- 使用输出流将数据输出到浏览器中。
重定向
//设置状态码为302
resp.setStatus(302);
//设置响应头location
resp.setHeader("location","/day13/servletDemo02");
//简单的重定向方法
resp.sendRedirect("/day13/servletDemo02");
重定向的特点(与请求转发对照理解):
- 地址栏发生变化;
- 重定向可以访问其他站点(服务器外)的资源;
- 地址栏发生变化,不能使用Request对象共享数据。
路径写法
相对路径:通过相对路径不可以确定唯一资源。
- 如:
./login.html
(当前目录)、../login.html
(上一级目录) - 规则:找到当前资源与目标资源之间的相对位置关系
绝对路径:通过绝对路径可以确定唯一资源。
- 如:
http://localhost:8080/day13/servletDemo02
、/day13/servletDemo02
- 规则:判断定义的路径是给谁使用的
- 给客户端浏览器使用:需要加虚拟目录(项目的访问路径)
- 建议虚拟目录动态获取:
req.getContextPath();
- 如:、、重定向
- 建议虚拟目录动态获取:
- 给服务器使用:不需要加虚拟目录
- 如:请求转发路径
- 给客户端浏览器使用:需要加虚拟目录(项目的访问路径)
输出字符数据
步骤:
- 获取字符输出流:
PrintWriter getWriter()
- 使用输出流将数据输出到浏览器中。
注意,乱码问题:
-
PrintWriter pw = resp.getWriter()
获取到的流对象的默认编码是ISO-8859-1; -
设置该流的编码,并告诉浏览器响应体使用的编码:
resp.setContentType("text/html;charset=utf-8");
BeanUtils工具类
BeanUtils工具类,用于封装JavaBean。
JavaBean:标准的Java类,特点:
- 类必须被public修饰;
- 必须提供空参的构造器;
- 成员变量必须使用private修饰;
- 提供public修饰的getXxx\setXxx。
JavaBean的功能,封装数据。
BeanUtils工具类的方法:
方法 | 作用 |
---|---|
populate(Object obj,Map map) | 将Map集合中的键值对信息,封装到对应的JavaBean对象中。 |