HTTP & Request
案例目标
- 静态资源-HTML登录页面(帐号框、密码框、登录按钮)
- 登录表单提交至LoginServlet
- 若登录成功,转发至登录成功(LoginSuccessServlet)
- 若登录失败,转发至登录失败(LoginFailureServlet)
第一部分 概念介绍
1 URL
http://localhost:8080
http://127.0.0.1:8080
http://tomcat.apache.org
http://www.itcast.cn
https://www.baidu.com/s?ie=UTF-8&wd=java
https://www.taobao.com
概念
Uniform Resource Locator
统一资源定位符
是对互联网上资源位置的一种表示,互联网上的每个资源都有一个唯一的URL
组成
-
协议
http、https、ftp、file
-
域名/ip
能够帮我们定位到互联网上的某一台服务器
-
端口号
端口号是一个应用程序在一台服务器上的编号。http协议的默认端:80
-
资源位置
用于描述WEB资源在服务器上的位置
-
参数
浏览器和服务器交互传递的数据
2 HTTP
概念
Hyper Text Transfer Protocol
超文本传输协议
复习HTML
Hyper Text Markup Language
超文本标签语言
作用
用来浏览器和服务器之间进行网页内容的传输
组成
- 请求
- 响应
特点
- 一问一答
- 先问后答
- 问和答是一一对应的
第二部分 HTTP请求
1 使用浏览器工具查看HTTP请求
2 组成
请求行
GET /http_request/login?username=user&password=pass HTTP/1.1
-
请求方式
常用的请求方式有GET、POST请求
-
请求地址
URL URI URI Uniform Resource Identifier 统一资源标识符 URL: http://localhost:8080/http_request/login URI: /http_request/login
-
协议及版本
HTTP/1.1
请求头
Host: localhost:8080
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,en-GB;q=0.6
请求体
-
POST
username=user&password=pass
-
GET
GET /http_request/login?username=user&password=pass HTTP/1.1
3 总结
-
HTTP
超文本传输协议
请求
响应
-
请求
行:
GET /http_request/login?username=user&password=pass HTTP/1.1
方式
URI
协议/版本号
头:
多个由key-value组成的数据
体:
GET没有请求体
POST有请求体
第三部分 Request对象 - 入门
1 获取请求行信息
GET /http_request/login?username=user&password=pass HTTP/1.1
相关API
-
String getMethod()
得到请求的方式:GET或POST
-
String getRequestURI()
Uniform Resource Identifier 统一资源标识符,代表一个资源的名字 URI = ContextPath + ServletPath
-
StringBuffer getRequestURL()
Uniform Resource Locator 统一资源定位符,代表一个可以访问地址
-
String getProtocol()
得到协议和版本
-
【重点】String getContextPath()
得到当前项目的访问地址
-
【重点】String getServletPath()
得到当前Servlet的访问地址
案例
- 获取请求行信息并显示在终端上
实现
-
RequestLineServlet.java
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("/request_line") public class RequestLineServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); System.out.println("Method: " + request.getMethod()); System.out.println("RequestURI: " + request.getRequestURI()); System.out.println("RequestURL: " + request.getRequestURL()); System.out.println("Protocol: " + request.getProtocol()); System.out.println("ContextPath: " + request.getContextPath()); System.out.println("ServletPath: " + request.getServletPath()); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
输出
Method: GET
RequestURI: /http_request/request_line
RequestURL: http://localhost:8080/http_request/request_line
Protocol: HTTP/1.1
ContextPath: /http_request
ServletPath: /request_line
小结
- request.getContextPath()
项目路径
- request.getServletPath()
获取Servlet的url-pattern
获取资源路径
2 获取请求头信息
Host: localhost:8080
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,en-GB;q=0.6
相关API
-
【重点】String getHeader(String headName)
指定请求头中键,得到相应的值
-
Enumeration getHeaderNames()
得到请求头中所有的键
Enumeration接口
Enumeration是枚举类型的集合,类似于迭代器
Iterator | Enumeration |
---|---|
hasNext() | hasMoreElements() |
next() | nextElement() |
-
boolean hasMoreElements()
判断是否还有下一个元素,如果有返回true
-
E nextElement()
得到当前元素,并且向下移动一个元素
案例1
需求
- 获取请求头信息并显示在终端上
实现
-
RequestHeaderServlet.java
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; import java.util.Enumeration; @WebServlet("/request_header") public class RequestHeaderServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); Enumeration<String> headerNames = request.getHeaderNames(); while (headerNames.hasMoreElements()) { String headerName = headerNames.nextElement(); System.out.println(headerName + ": " + request.getHeader(headerName)); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
输出
host: localhost:8080
connection: keep-alive
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
accept-encoding: gzip, deflate, br
accept-language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,en-GB;q=0.6
cookie: JSESSIONID=7D790A7277BAFB203442AA8F084217F7
案例2
需求
-
获取浏览器版本并显示在命令行上
判断是Edge、Chrome、Safari、Firefox或IE浏览器
实现
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("/request_header")
public class RequestHeaderServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String userAgent = request.getHeader("User-Agent");
if (userAgent.contains("Edge")) {
System.out.println("Edge浏览器");
} else if (userAgent.contains("Chrome")) {
System.out.println("Chrome浏览器");
} else if (userAgent.contains("Safari")) {
System.out.println("Safari浏览器");
} else if (userAgent.contains("Firefox")) {
System.out.println("Firefox浏览器");
} else {
System.out.println("IE浏览器");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
输出
Chrome
Firefox
Safari
小结
-
请求行
- getContextPath
获取项目路径
- getServletPath
获取servlet的url-pattern
-
请求头
String getHeader(String key)
3 获取请求参数[重点]
-
POST
username=user&password=pass
-
GET
GET /http_request/login?username=user&password=pass HTTP/1.1
相关API
-
String getParameter(String name)
通过参数名得到参数的值
-
String[] getParameterValues(String name)
通过参数名得到一组参数值,返回是字符串的数组
-
【非重点】Enumeration getParameterNames()
得到所有参数的名字,返回是枚举的类型
-
Map<String, String[]> getParameterMap()
得到表单提交的所有参数名和参数值,封装成一个Map集合
案例
- 获取注册表单提交的数据并输出到页面上
实现
-
index.html
<html> <head> <meta charset="utf-8"> <title></title> </head> <body> <form action="request_body" method="get"> <input type="text" name="username" placeholder="用户名"/><br/> <input type="password" name="password" placeholder="密码"/><br/> 爱好: <input type="checkbox" name="hobby" value="eat"/>吃饭 <input type="checkbox" name="hobby" value="sleep"/>睡觉 <input type="checkbox" name="hobby" value="hit dodo"/>打豆豆 <input type="submit" value="登录"/> </form> </body> </html>
-
RequestBodyServlet.java
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; import java.util.Arrays; import java.util.Enumeration; import java.util.Map; import java.util.Set; @WebServlet("/request_body") public class RequestBodyServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); System.out.println("username: " + request.getParameter("username")); System.out.println("password: " + request.getParameter("password")); System.out.println("hobby: " + Arrays.toString(request.getParameterValues("hobby"))); System.out.println("----"); Enumeration<String> names = request.getParameterNames(); while(names.hasMoreElements()) { String pname = names.nextElement(); System.out.println(pname + ": " + request.getParameter(pname)); } System.out.println("----"); Map<String, String[]> map = request.getParameterMap(); Set<Map.Entry<String, String[]>> entries = map.entrySet(); for (Map.Entry<String, String[]> entry : entries) { System.out.println(entry.getKey() + ": " + Arrays.toString(entry.getValue())); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
输出
namename: user
password: pass
hobby: [eat, sleep]
----
namename: user
password: pass
hobby: eat
----
username: [user]
password: [pass]
hobby: [eat, sleep]
小结
-
String getParameter(String name)
传进去一个参数名,返回一个参数值
-
String[] getParameterValues(String name)
传进去一个参数名,返回多个参数值
-
Map<String, String[]> getParameterMap()
不需要任何参数,返回所有的键和值
4 参数乱码问题
-
GET方式的乱码解决方案
Tomcat 8.5,GET方式无乱码问题
-
POST方式的乱码解决方案
request.setCharacterEncoding("utf-8");
5 小结
http://localhost:8080/JavaWeb_day02_Request_war_exploded/request_body
-
获取请求行信息
getContextPath获取项目路径
getServletPath获取servlet url-pattern
-
获取请求头信息
String getHeader(String name)
-
获取请求参数信息
String getParameter(String key)
-
参数乱码问题
setCharacterEncoding(“utf-8”)
-
注意
编码和解码要一致
第四部分 Request - 深入
1 转发
定义
用于资源跳转,从一个资源跳转到另一个资源
相关API
request.getRequestDispatcher("/resourceB").forward(request, response);
方法 | 说明 |
---|---|
RequestDispatcher getRequestDispatcher(String path) | 获取请求转发器(request对象方法) |
void forward(ServletRequest request, ServletResponse response) | 将请求转发到另一个资源(Servlet)上 |
特点
- 地址不变
- 服务器内部跳转
- 一次请求
案例
- 浏览器请求AServlet,转发至BServlet
实现
package com.itheima.request;
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("/resourceA")
public class AServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("AServlet接收到了用户的请求");
//... 处理自己所负责的业务
// 通过getRequestDispatcher,获得一个请求调度器
// 让调度器,转发到"/resourceB"
// 并且通过forward进行转发
// 转发时,需要两个参数,一个是request,一个是response
request.getRequestDispatcher("/resourceB").forward(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
2 请求域【重点】
问题
相关API
- Object getAttribute(String key)
从作用域中取出值
- void setAttribute(String key, Object obj)
向作用域中添加键和值,如果之前没有这个键则是添加,如果有就是修改
- void removeAttribute(String key)
删除指定的键和值
作用
服务器内存区域,用于数据存储
一个盒子,在盒子里面可以存储物品(Object)
小结
- setAttribute(String key, Object value)
- Object getAttribute(String key)
- removeAttribute(String key)
3 Request 对象生命周期
一个对象从创建到销毁的全过程
-
什么时候创建
每一次服务器接收到请求时
-
什么时候销毁
响应结束时销毁
-
由谁创建
Tomcat
-
由谁销毁
Tomcat
4 小结
-
转发的特点
1次
地址不变
服务器内部跳转 -
转发
request.getRequestDispatcher(“资源地址”).forward(request, response)
-
请求域
setAttribute(String name, Object obj);
Object getAttribute(String name);
removeAttribute(String name) -
Request的生命周期
-
创建
浏览器发送请求时,由Tomcat创建
-
销毁
响应结束时,由Tomcat销毁
-
第五部分 案例
1 需求
- 静态资源-HTML登录页面(帐号框、密码框、登录按钮)
- 登录表单提交至LoginServlet
- 若登录成功,转发至登录成功(LoginSuccessServlet)
- 若登录失败,转发至登录失败(LoginFailureServlet)
2 ver 0.1 原生方式
实现
-
index.html
<html> <head> <meta charset="utf-8"> <title></title> </head> <body> <form action="login" method="post"> <input type="text" name="username" placeholder="用户名"/><br/> <input type="password" name="password" placeholder="密码"/><br/> 爱好: <input type="checkbox" name="hobby" value="吃饭"/>吃饭 <input type="checkbox" name="hobby" value="睡觉"/>睡觉 <input type="checkbox" name="hobby" value="打豆豆"/>打豆豆 <input type="submit" value="登录"/> </form> </body> </html>
-
LoginServlet.java
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; import java.io.PrintWriter; @WebServlet("/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"); if (username.equals("user") && password.equals("pass")) { request.getRequestDispatcher("/login_success").forward(request, response); } else { request.getRequestDispatcher("/login_failure").forward(request, response); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
-
LoginSuccessServlet.java
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("/login_success") public class LoginSuccessServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); System.out.println(request.getParameter("username") + " login success!"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
-
LoginFailureServlet.java
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("/login_failure") public class LoginFailureServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); System.out.println(request.getParameter("username") + " login failure!"); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
3 ver 0.2 面向对象,JavaBean
什么是JavaBean
-
类必须用public修饰
-
提供publi无参数的构造器
-
提供getter和setter方法访问属性
JavaBean的两个概念
- 字段
就是成员变量,字段名就是成员变量名
- 属性
- 通过setter或getter方法获得
- 属性名: setter/getter方法去掉set/get前缀,首字母小写
- 比如: setName() -> Name -> name
- 一般情况下,字段名称和属性名称是一致的
实现
-
index.html
<html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <form action="login" method="post"> <input type="text" name="username" placeholder="用户名"/><br/> <input type="password" name="password" placeholder="密码"/><br/> <input type="submit" value="登录"/> </form> </body> </html>
-
UserInfo.java
public class UserInfo { private String username; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public UserInfo() { } public UserInfo(String username, String password) { this.username = username; this.password = password; } }
-
LoginServlet.java
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; import java.io.PrintWriter; @WebServlet("/login") public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); UserInfo userInfo = new UserInfo(); userInfo.setUsername(request.getParameter("username")); userInfo.setPassword(request.getParameter("password")); if (userInfo.getUsername().equals("user") && userInfo.getPassword().equals("pass")) { request.getRequestDispatcher("/login_success").forward(request, response); } else { request.getRequestDispatcher("/login_failure").forward(request, response); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
4 ver 1.0 BeanUtil方式
问题
- LoginServlet.java
UserInfo userInfo = new UserInfo();
userInfo.setUsername(request.getParameter("username"));
userInfo.setPassword(request.getParameter("password"));
- RegisterServlet.java
UserProfile userProfile = new UserProfile();
userProfile.setUsername(request.getParameter("username"));
userProfile.setPassword(request.getParameter("password"));
userProfile.setGender(request.getParameter("gender"));
userProfile.setMobile(request.getParameter("mobile"));
userProfile.setAvatar(request.getParameter("avatar"));
BeanUtils 工具包
-
commons-beanutils-1.9.3.jar
核心工具包
-
commons-logging-1.2.jar
日志记录包
-
commons-collection-3.2.2.jar
增强集合包
BeanUtils常用方法
-
setProperty(Object obj, String name, Object value)
给指定对象obj的指定属性name附值指定的值value 如果属性不存在,则什么也不发生
-
getProperty(Object obj, String name)
获取指定对象obj指定属性name的值 如果属性不存在,则会抛出异常
-
copyProperties(Object dest, Object orig)
将一个对象的值赋值给另一个对象 只有相同属性名才会赋值 简单记忆: "后付钱" -> 即将后一个对象的值赋值给前一个对象
-
populate(Object bean, Map<String, String[]> properties)[重点]
将Map集合中的数据封装到JavaBean对象中
实现
-
LoginServlet.java
import org.apache.commons.beanutils.BeanUtils; 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; import java.lang.reflect.InvocationTargetException; import java.util.Map; @WebServlet("/login") public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); Map<String, String[]> parameterMap = request.getParameterMap(); UserInfo userInfo = new UserInfo(); try { BeanUtils.populate(userInfo, parameterMap); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } if (userInfo.getUsername().equals("user") && userInfo.getPassword().equals("pass")) { request.getRequestDispatcher("/login_success").forward(request, response); } else { request.getRequestDispatcher("/login_failure").forward(request, response); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } }
第六部分 学习目标总结
-
能够理解HTTP协议概述
超文本传输协议
请求:request响应:response
-
能够理解HTTP协议的请求部分
行
头
体
POST请求有请求体,get请求没有请求体
-
能够应用Request对象的方法
getContextPath() 项目路径
getServletPath() 资源路径
getHeader()
getParameter()
-
能够理解Request请求头信息
User-Agent能够获取用户的浏览器和操作系统
-
能够应用Request对象解决获取请求参数中文乱码问题
setCharacterEncoding(“utf-8”)
注意:编码和解码要一致 -
能够应用BeanUtils工具类对请求参数数据进行封装
request.getParameterMap()
BeanUtils.populate(对象,map)
-
能够独立运用Servlet技术完成登录功能