文章目录
- request对象
- 01 HTTP 协议概述[★]
- 02 HTTP 请求概述[★★★★]
- 03 请求行概述[★★★]
- 04 请求头概述[★★★]
- 05 请求体概述[★★★]
- 06 HttpServletRequest 对象概述[★★★]
- 07 获取请求行的相关方法[★★★]
- 08 获取请求头相关方法[★★★]
- 09 获取请求参数相关方法[★★★]
- 10 BeanUtils 工具使用-封装参数[★★★]
- 11 参数的乱码问题[★★★]
- 12 转发和重定向概述[★★★]
- 13 转发和重定向的区别[★★★★]
- 14 Servlet 作用域概述[★★★]
- 15 请求域概述和演示[★★★]
- 16 案例:实现登陆功能-功能分析和环境搭建[★★★]
- 17 案例:实现登录功能-控制器[★★★]
- 18 关于根目录使用说明[★★]
- 总结
request对象
01 HTTP 协议概述[★]
01_01 概念:
HyperText Transfer Protocol
超文本传输协议
01_02 作用:
- 用于浏览器和服务器之间的数据输出
- 规定了浏览器和服务器的传输格式
01_03 特点:
- 无状态:协议对客户端没有状态存储,对事务处理没有“记忆”能力。
- 无连接:HTTP/1.1之前,由于无状态特点,每次请求需要通过TCP三次握手四次挥手,和服务器重新建立连接。比如某个客户机在短时间多次请求同一个资源,服务器并不能区别是否已经响应过用户的请求,所以每次需要重新响应请求,需要耗费不必要的时间和流量。
- 基于请求和响应:基本的特性,由客户端发起请求,服务端响应
- 简单、快速、灵活
- 通信使用文明、请求和响应不会对通信方进行确认、无法保护数据的完整性
01_04 组成:
- 请求:浏览器发送数据给服务器的过程
- 响应:服务器返回数据给浏览器的过程
02 HTTP 请求概述[★★★★]
HTTP 请求:浏览器访问服务器的过程
HTTP 请求的组成:
请求行
请求头
请求体
02_01 查看HTTP请求
- HTML 代码
<!DOCTYPE html>
<html lang="zh_CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--login 是一个 servlet-->
<h2>GET 提交</h2>
<form action="login" method="get">
用户名:
<input type="text" name="username"><br/>
密码:
<input type="password" name="password"><br/>
<input type="submit" value="登录">
</form>
<hr>
<h2>POST 提交</h2>
<form action="login" method="post">
用户名:
<input type="text" name="username"><br/>
密码:
<input type="password" name="password"><br/>
<input type="submit" value="登录">
</form>
</body>
</html>
- 查看浏览器与服务器的通讯
- HTTP 请求:
03 请求行概述[★★★]
请求行格式:
- POST 请求:POST /XXX/login HTTP/1.1
- GET 请求:GET /XXX/login?username=xxx&password=xxx HTTP/1.1
请求行组成:
请求方式
请求地址
协议和版本
03_01 POST & GET 区别
POST | GET | |
---|---|---|
地址栏 | 数据在请求体中发送,所以地址上不显示参数 | 因为是请求行中发送数据,所以在地址栏上可以看参数 |
大小 | 理论上没有限制大小4 | 不同的浏览器有区别,1K |
安全性 | 安全性更高 | 安全性更低 |
缓存 | POST 邮寄,发送数据不使用本地缓存 | GET 拿,从服务器上获取数据,会使用缓存。如果本地浏览器已经缓存页面,而且服务器的数据没有修改,不再从服务上得到数据。 |
04 请求头概述[★★★]
- 常见请求头
常见请求头 | 作用 |
---|---|
Referer | 服务器端获取浏览器上一次访问地址 |
If-Modified-Since | 服务器端获取浏览器缓存页面的时间 |
User-Agent | 服务器获取客户端操作系统的类型和浏览器类型 |
Connection | 获取 HTTP 协议连接状态 1.1 保持连接 keep-alice 1.0 断开连接 close |
Host | 获取服务器的地址和端口 |
05 请求体概述[★★★]
请求头:
- 用户输入的内容
- 只要用户输入并提交给服务器的数据都可以统称为请求参数
问题
POST 和 GET 请求都有请求体吗?
- Post 才有,Get 没有请求体
06 HttpServletRequest 对象概述[★★★]
问题
HttpServletRequest 对象是谁创建的?
- web 服务器:Tomcat
HttpServletRequest 对象的作用?
- 用来封装浏览器发送给服务器的所有数据:请求行、请求头、请求体
需要调用 request 对象的方法获得请求数据
07 获取请求行的相关方法[★★★]
- 需求:将请求行相关信息输出到网页上
- HttpServletRequest 对象的方法
HttpServletRequest对象的方法 | 功能说明 |
---|---|
String getMethod() | 获取请求方式 |
String getRequestURI() | 获得统一资源标识符 |
StringBuffer getRequestURL() | 获得统一资源定位符:网址 |
String getProtocol() | 获得协议和版本 |
String getContextPath() | 获得项目访问路径 |
String getRemoteAddr() | 获得客户端IP地址 |
- Java 代码
@WebServlet(urlPatterns = "/line")
public class RequestLineServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置内容类型和编码
response.setContentType("text/html;charset=utf-8");
// 获得字符打印流
PrintWriter out = response.getWriter();
// 请求方式 192.168.32.166
out.println("请求方式:" + request.getMethod() + "<br/>");
// 统一资源标识符: /day02/line isbn 唯一
out.println("统一资源标识符:" + request.getRequestURI() + "<br/>" );
// 统一资源定位符: http://localhost:8080/day02/line
out.println("统一资源定位符:" + request.getRequestURL()+ "<br/>");
// 协议和版本
out.println("协议和版本:" + request.getProtocol() + "<br/>" );
// 上下文路径:项目的访问路径
out.println("项目的访问路径:" + request.getContextPath() + "<br/>");
// 客户端IP地址
out.println("客户端IP地址:" + request.getRemoteAddr()+ "<br/>");
}
}
- 网页显示如下
08 获取请求头相关方法[★★★]
- 需求:获取请求头信息并输出
- HttpServletRequest 对象的方法
HttpServletRequest 对象的方法 | 功能描述 |
---|---|
String getHeader(String headName) | 根据请求头名字获得值 |
Enumeration getHeaderNames() | 获得所有请求头的名字 返回的一个迭代器 hasMoreElement:判断是否有下一个元素 nextElement:获得下一个元素 |
- Java 代码
@WebServlet(urlPatterns = "/header")
public class RequestHeaderServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置内容类型和编码
response.setContentType("text/html;charset=utf-8");
// 获得字符打印流
PrintWriter out = response.getWriter();
// 根据请求头名字获得值
String host = request.getHeader("host");
out.println("host = " + host + "<hr>");
// 获得所有请求头名字
// Enumeration 是迭代器的前身 Iterator
Enumeration<String> it = request.getHeaderNames();
// 判断是否有下一个元素
while (it.hasMoreElements()){
// 获得下一个元素
String headerName = it.nextElement();
// 根据请求头名获取值
String headerValue = request.getHeader(headerName);
out.println(headerName+":"+headerValue + "<br>");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
09 获取请求参数相关方法[★★★]
- 需求:用户注册得到表单提交的参数
- HttpServletRequest对象的方法
HttpServletRequest对象的方法 | 描述 |
---|---|
String getParameter(String name) | 根据参数名获得参数值 |
String[] getParameterValues(String name) | 根据参数名获得多个参数值 返回是数组 |
Enumeration getParameterNames() | 获得所有请求参数的名字 返回迭代器对象 |
Map<String,String[]> getParameterMap() | 获得所有请求参数信息 返回map集合 key:参数名 value:参数值 |
- HTML 代码
<h2>用户注册</h2>
<form action="register" method="post">
用户名: <input type="text" name="name"><br/>
性别: <input type="radio" name="gender" value="男" checked="checked"/>男
<input type="radio" name="gender" value="女"/>女 <br/>
城市:
<select name="city">
<option value="广州">广州</option>
<option value="深圳">深圳</option>
<option value="珠海">珠海</option>
</select>
<br/>
爱好:
<input type="checkbox" name="hobby" value="上网"/>上网
<input type="checkbox" name="hobby" value="上学"/>上学
<input type="checkbox" name="hobby" value="上车"/>上车
<input type="checkbox" name="hobby" value="上吊"/>上吊
<br/>
<input type="submit" value="注册"/>
</form>
- Java 代码
@WebServlet(urlPatterns = "/register")
public class RegisterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
// 设置内容类型和编码
response.setContentType("text/html;charset=utf-8");
// 获得字符打印流
PrintWriter out = response.getWriter();
// 根据参数名获得参数值
String username = request.getParameter("username");
out.println("username = " + username + "<br>");
// 根据参数名获得多个参数值
String[] hobbies = request.getParameterValues("hobby");
out.println("hobbies = " + Arrays.toString(hobbies) + "<hr>");
// 获得所有请求参数的名字
Enumeration<String> it = request.getParameterNames();
// 遍历所有名字
while (it.hasMoreElements()) {
// 获得参数名字
String name = it.nextElement();
// 根据参数名获得值
String[] values = request.getParameterValues(name);
out.println(name + " = " + Arrays.toString(values) + "<br>");
}
out.println("<hr>");
// 获得所有请求参数信息:封装到map集合中
// key:参数名 value:参数的值
Map<String, String[]> map = request.getParameterMap();
for (Map.Entry<String, String[]> entry : map.entrySet()) {
out.println(entry.getKey() + " = " + Arrays.toString(entry.getValue()) + "<br>");
}
}
}
10 BeanUtils 工具使用-封装参数[★★★]
- 需求:使用 BeanUtils 封装请求参数到 JavaBean 对象中
- BeanUtils常用方法
BeanUtils常用方法 | 作用 |
---|---|
void populate(Object bean, Map<String, Object> properties) | 将map集合的数据封装到指定的bean对象 简单记忆:后付钱(后面的参数赋值给前面的对象) |
- Java JavaBean/entity User 代码
public class User {
// 成员变量
private String username;
private String gender;
private String[] hobby;
private String city;
public String getUsername() {return username;}
public void setUsername(String username){this.username = username;}
public String getGender() {return gender;}
public void setGender(String gender) {this.gender = gender;}
public String[] getHobby() {return hobby;}
public void setHobby(String[] hobby) {this.hobby = hobby;}
public String getCity() {return city;}
public void setCity(String city) {this.city = city;}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", gender='" + gender + '\'' +
", hobby=" + Arrays.toString(hobby) +
", city='" + city + '\'' +
'}';
}
}
- 利用 BeanUtils 将表单参数封装到 User 对象中
import org.apache.commons.beanutils.BeanUtils;
@WebServlet(urlPatterns = "/register")
public class RegisterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try{
request.setCharacterEncoding("utf-8");
// 设置内容类型和编码
response.setContentType("text/html;charset=utf-8");
// 获得请求参数信息
Map<String, String[]> map = request.getParameterMap();
// 创建User对象
User user = new User();
System.out.println("封装前:" + user);
// 使用BeanUtils工具类的方法封装请求参数
// populate:将map集合的数据封装到指定的对象中
// 参数1:Object bean 自定义的JavaBean对象
// 参数2:Map<String, ? extends Object> properties map集合
// map集合的key和对象的成员变量名要一致才会封装
BeanUtils.populate(user,map);
System.out.println("封装后:" + user);
} catch(Exception e){
e.printStackTrace();
}
只要满足三个条件的类就是一个 JavaBean
- 类必须是 public 修饰的
- 类必须有 public 的无参数构造方法
- 成员变量必须提供对应的 setter & getter 方法
11 参数的乱码问题[★★★]
请求参数乱码的原因:编码和解码使用的码表不一样
- 编码:将文本内容转换为二进制数据的过程 utf8或gbk
- 解码:将二进制数据转换为文本的过程
Tomcat 默认使用的码表是欧洲码表:iso-8859-1 不支持汉字
解决:设置请求参数的(编码)码表,通过请求对象的方法设置
request.setcharacterEncoding("utf-8")
注意: 设置请求参数的编码方法不能在获取请求参数之后设置
Tomcat8.0开始,GET方式请求不需要考虑乱码问题了,如果使用Tomcat8.0之前的版本,则也需要手动处理乱码问题,详情参考:https://blog.csdn.net/lxf512666/article/details/52939573/
12 转发和重定向概述[★★★]
转发和重定向的作用:实现页面的跳转
实现转发和重定向的方法
- 转发方法
request.getRequestDispatcher("转发的页面地址").forward(request,response);
- 重定向方法
response.sendRedirect("转发地址")
- 需求:使用转发和重定向实现页面跳转
- Java 代码
@WebServlet(urlPatterns = "/one")
public class OneServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 实际开发会先处理业务逻辑
// 转发到TwoServlet
// 获得转发器对象
RequestDispatcher requestDispatcher = request.getRequestDispatcher("two");
// 调用转发器的方法执行转发操作:页面跳转
requestDispatcher.forward(request, response);
// 简化代码
request.getRequestDispatcher("two").forward(request, response);
// 重定向到TwoServlet
response.sendRedirect("two");
}
}
13 转发和重定向的区别[★★★★]
区别 | 转发 | 重定向 |
---|---|---|
地址栏 | 不会变化 | 会变成重定向的页面地址 |
跳转位置 | 服务器内部执行的跳转 | 浏览器端执行的跳转 |
请求次数 | 1次 | 2次 |
请求域数据 | 不会丢失 | 会丢失 |
面试题:
转发或重定向后续代码还会执行吗?
- 会执行,但没有意义了,一般不会再后面编写代码
什么时候使用转发?什么时候使用重定向?
- 如果需要请求域的数据,则只能只用转发,否则可以随便选择
14 Servlet 作用域概述[★★★]
作用域:
服务器端的一小块内存区,底层结构就是一个map集合,用于 Servlet 之间共享数据
Servlet 的三个作用域:
请求域、会话域、上下文域
- 作用域相关方法
请求域相关方法 | 作用 |
---|---|
Object getAttribute(“键”) | 根据键从请求域中获得值 |
void setAttribute(“键”,Object数据) | 往请求域中存储键值对数据 |
void removeAttribute(“键”) | 根据键从请求域中删除键值对数据 |
15 请求域概述和演示[★★★]
请求域的作用范围:在同一次请求中有效
-
需求:FirstServlet 创建一个键和值,转发到另一个 SecondServlet,从 SecondServlet 中取出键和值,并且输出。
-
FirstServlet 代码
@WebServlet(urlPatterns = "/first")
public class FirstServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 往请求域中存储键值对数据
request.setAttribute("username", "lily");
// 转发到second
request.getRequestDispatcher("second").forward(request, response);
// 重定向second
// response.sendRedirect("second");
}
}
- SecondServlet 代码
@WebServlet(urlPatterns = "/second")
public class SecondServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置内容类型和编码
response.setContentType("text/html;charset=utf-8");
// 获得字符打印流
PrintWriter out = response.getWriter();
// 从请求域中获取数据
Object username = request.getAttribute("username");
out.println("用户名:" + username);
}
}
16 案例:实现登陆功能-功能分析和环境搭建[★★★]
- 需求
1.用户名和密码正确,将用户信息保存再请求域中,转发到另一个 Servlet,显示用户登陆成功
2.用户名和密码错误,重定向到另一个 html 页面,显示登陆失败
3.使用表示层,业务层,数据访问层的三层结构实现 - 案例流程图
- 登陆页面 HTML 代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>用户登录</title>
</head>
<body>
<h2>用户登录</h2>
<form action="login" method="post">
<table>
<tr>
<td>用户名</td>
<td><input type="text" name="username"/></td>
</tr>
<tr>
<td>密码</td>
<td><input type="password" name="password"/></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="登录"/></td>
</tr>
</table>
</form>
</body>
</html>
17 案例:实现登录功能-控制器[★★★]
-
步骤:
1.接收请求参数:用户名和密码
2.判断用户名和密码是否正确
3.用户名密码正确跳转转发到欢迎页面(Servlet),获取用户名显示信息
4.不正确跳转重定向到失败页面(html) -
LoginServlet 代码
@WebServlet(urlPatterns = "/login")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置请求参数的编码
request.setCharacterEncoding("utf-8");
// 接收请求参数:用户名和密码
String username = request.getParameter("username");
String password = request.getParameter("password");
// 判断用户名和密码是否正确:admin 123
if ("admin".equals(username) && "123".equals(password)) {
// 往请求域中存储数据:用户数据(用户对象)
request.setAttribute("username", username);
// 用户名和密码正确则跳转到欢迎页面(Servlet):获取用户信息显示
request.getRequestDispatcher("welcome").forward(request,response);
return;
}
// 用户名和密码不正确则跳转到失败页面(html)
response.sendRedirect("login.html");
}
}
- WelcomeServlet 代码
@WebServlet(urlPatterns = "/welcome")
public class WelcomeServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置内容类型和编码
response.setContentType("text/html;charset=utf-8");
// 获得打印字符流
PrintWriter out = response.getWriter();
// 从请求域获得用户名
Object username = request.getAttribute("username");
out.println("欢迎你回来:" + username);
}
}
18 关于根目录使用说明[★★]
18_01 根目录 /
- 需求:当浏览器访问OneServlet时转发或重定向到TwoServlet
/:代表根目录
/:如果使用在客户端(浏览器)则代表浏览器端的根目录
/:如果使用在服务器端则代表服务器端的根目录
浏览器端的根目录:http://localhost:8080/
服务器端的根目录:http://localhost:8080/项目访问地址/
总结
HTTP 协议的作用:用于浏览器和服务器之间数据传输
HTTP 协议的组成内容:请求(浏览器访问服务器)和响应(服务器返回数据给浏览器)
请求的组成:请求行、请求头、请求体
请求行的组成:请求方式、请求地址、协议和地址
请求头的含义:
- referer:浏览器上一个访问的页面地址
- If-Modified-Since:浏览器缓存页面的时间
- user-agent:客户端的系统类型和浏览器类型
HTTPServletRequest 对象的作用:
- 用来封装浏览器发送给服务器的所有数据
HTTPServletRequest 对象的常用方法:
- 请求行方法:
获取请求方式:String getMethod();
获得项目访问地址:String getContextPath();
获得协议版本:String getProtocol();
获得统一资源标识符:String getRequestURL();
获得统一资源定位符:StringBuffer getRequestURL();
获取客户端 IP 地址:String getRemoteAddr();
- 请求头方法:
根据请求头名获得值:String getHeader(String headerName)
获取所有请求头名字,返回迭代器对象:Enumeration getHeaderNames();
- 请求参数方法(用户提交数据):
根据参数名获得参数值:String getParameter(String name)
根据参数名获得多个参数值:String[] getParameterValues(String name);
获得所有请求参数名字:Enumeration getParameterNames();
获得所有请求参数信息,返回Map集合:Map<String,String[]> getParameterMap();
BeanUtils工具类常用方法:
void populate(Object bean,Map<String,String[]> map);
- 将map集合数据封装到指定的bean对象中
- 要求:map键的名称和对象的成员变量名要一致
请求参数乱码的原因和解决方案:
- 原因:Tomcat默认使用欧洲码表:iso-8859-1 不支持汉字
- 解决:在获取请求参数之前设置请求参数编码:
request.setCharacterEncoding("utf8");
转发和重定向:
- 作用:用于页面跳转
- 方法:
转发:request.getRequestDispatcher("要跳转的页面地址").forward(request,response);
重定向:response.sendRedirect("要跳转的页面地址");
Servlet 的作用域:
- 概念:服务器内部的一小块内存区
- 作用:用于 servlet 之间共享数据,底层是map结构
- 分类:请求域、会话域、上下文域
Request 域对象(三个方法)
- 往作用域中存储数据:
request.setAttribute(String key,Object value)
- 根据键从作用域中获取数据:
request.getAttribute(String key)
- 根据键从作用域删除键值对:
request.removeAttribute(String key)