Servlet Request
- 用户通过浏览器访问服务器时,Tomcat 将 HTTP 请求中所有的信息都封装在 Request 对象中。
- 开发人员可以通过 Request 对象方法,来获取浏览器发送的所有信息。
1. Request 的体系结构
ServletRequest
|
HttpServletRequest
|
org.apache.catalina.connector.RequestFacade(由 Tomcat 厂商提供实现类)
- JavaEE 的编程即是面向接口编程。
- 面向接口编程就是先把客户的业务提取出来,作为接口。业务具体实现通过该接口的实现类来完成。当客户需求变化时,只需编来写该业务逻辑的新的实现类,通过更改配置文件(例如 Spring 框架)中该接口的实现类就可以完成需求,不需要改写现有代码,减少对系统的源影响。
- 采用基于接口编程的项目,业务逻辑清晰,代码易懂,方便扩展,可维护性强。理论上度当需求变化的时候只需要修改接口实现。
2. Request 获取 HTTP 请求信息
a. 获取请求行信息
- 请求行是 HTTP 请求内容的第一行。例如:
GET /webappPractice2/requestDemo HTTP/1.1
- 相关 API:
- 获取请求方式,如
GET
:
String getMethod()
- 获取项目虚拟路径项目名,如
/webappPractice2
:
String getContextPath()
- 获取 URI 统一资源标识符,如
/webappPractice2/requestDemo
:
String getRequestURI()
- 获取 URL 统一资源定位符,如
http://localhost:8080/webappPractice2/requestDemo
:
StringBuffer getRequestURL()
- 获取协议和版本号,如
HTTP/1.1
String getProtocol()
- 获取客户端 IP
String getRemoteAddr()
- 代码示例:
@WebServlet("/requestDemo")
public class RequestDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(req);
System.out.println("请求方式:" + req.getMethod());
System.out.println("虚拟路径:" + req.getContextPath());
System.out.println("URI:" + req.getRequestURI());
System.out.println("URL:" + req.getRequestURL());
System.out.println("协议和版本:" + req.getProtocol());
System.out.println("客户端ip:" + req.getRemoteAddr());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
b. 获取请求头信息
- 请求头信息很多,例如
Host: localhost:8080
- 相关 API:
- 获取知道请求头名称对应的值,注:名称不区分大小写
String getHeader(String name)
- 获取所有请求头的名称,注:Enumeration 是 Iterator 的前身
Enumeration<String> getHeaderNames()
i. 获取所有请求头
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("/requestDemo")
public class RequestDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Enumeration<String> enumeration = req.getHeaderNames();
while(enumeration.hasMoreElements()){
String name = enumeration.nextElement();
String value = req.getHeader(name);
System.out.println(name +" : "+ value);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
ii. 获取指定请求头
案例 1:视频防盗链
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("/requestDemo")
public class RequestDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=UTF-8");
String referer = req.getHeader("referer");
if (referer != null && referer.startsWith("http://localhost:8080")) {
resp.getWriter().write("正常播放视频...");
}else{
resp.getWriter().write("需要到优酷官网才能播放视频....");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
案例 2:浏览器兼容性
user-agen
:浏览器版本信息。- 现在后端处理兼容性问题的需求越来越少,基本都是前端工程师完成的。
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("/requestDemo")
public class RequestDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
String userAgent = req.getHeader("user-agent");
if (userAgent.contains("Chrome")) {
resp.getWriter().write("浏览器:谷歌");
} else if (userAgent.contains("Firefox")) {
resp.getWriter().write("浏览器:火狐");
} else {
resp.getWriter().write("浏览器:其他");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
c. 获取请求参数(请求体信息)
- 不论是 GET 还是 POST 的请求方式,它们的业务逻辑都是一样的,都可以使用下列方法来获取请求参数。
- 请求参数,例如:
username=Regino&password=123&hobby=drink&hobby=perm
- 相关 API:
- 获取指定参数名的值,如
username=jack
:
String getParameter(String name)
- 获取指定参数名的值数组,如
hobby=drink&hobby=perm
:
String[] getParameterValues(String name)
- 获取所有参数名和对应值的数组,封装为 map 集合,key 是参数名 name,value 是值数组:
Map<String,String[]> getParameterMap()
- 解决中文乱码问题:
- get:在 Tomcat8 及以上版本,内部 URL 编码(UTF-8),不用处理;
- post:编码解码不一致,造成乱码现象:
客户端(浏览器)编码:UTF-8
服务器默认解码:ISO-8859-1(拉丁文)
指定解码方法:void setCharacterEncoding(String env)
,注:该方法必须在方法内的行首
- 测试网页 demo.html:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>form</title>
</head>
<body>
<h3>get方式:</h3>
<form action="/webappPractice2/requestDemo" method="get">
用户:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
爱好:
<input type="checkbox" name="hobby" value="somke"/>抽烟
<input type="checkbox" name="hobby" value="drink"/>喝酒
<input type="checkbox" name="hobby" value="perm"/>烫头
<input type="submit" value="get提交...">
</form>
<h3>post方式:</h3>
<form action="/webappPractice2/requestDemo" method="post">
用户:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
爱好:
<input type="checkbox" name="hobby" value="somke"/>抽烟
<input type="checkbox" name="hobby" value="drink"/>喝酒
<input type="checkbox" name="hobby" value="perm"/>烫头
<input type="submit" value="post提交...">
</form>
</body>
</html>
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.Map;
@WebServlet("/requestDemo")
public class RequestDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("1.getParameter指定参数名的值或值数组的获取");
String username = req.getParameter("username");
System.out.println("用户:" + username);
String password = req.getParameter("password");
System.out.println("密码:" + password);
System.out.println("2.getParameterValues指定参数名的值数组的获取");
String[] hobby = req.getParameterValues("hobby");
System.out.println("爱好:" + Arrays.toString(hobby));
System.out.println("3.getParameterMap一并获取");
Map<String, String[]> parameterMap = req.getParameterMap();
parameterMap.forEach((k, v) -> {
System.out.println(k + " = " + Arrays.toString(v));
});
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
this.doGet(req, resp);
}
}
3. Request 的其他功能
a. 请求转发
- 请求转发是一种在服务器内部的资源跳转方式。
- 相关 API:
- 通过 Reqeust 对象,获得转发器对象:
RequestDispatcher getRequestDispatcher(String path)
- 通过转发器对象,实现转发功能:
void forward(ServletRequest request, ServletResponse response)
- 推荐写链式编程:
request.getRequestDispatcher("/requestDemo2").forward(request,response);
- 请求转发特点:浏览器发了一次请求,虽然地址栏没有发生改变,但是转发到了服务器的内部资源(引用地址栏只用写相对地址)。
- RequestDemo.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("/requestDemo")
public class RequestDemo extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("RequestDemo is working.");
request.getRequestDispatcher("/requestDemo2").forward(request,response);
}
}
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("/requestDemo2")
public class RequestDemo2 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("RequestDemo2 is working.");
}
}
b. 共享数据(Request 域对象)
- 域对象:一个有作用范围的对象,可以在范围内实现 Servlet 与 Servlet 之间的共享数据。
- Request 域:代表一次请求的范围,一般用于一次请求中 Servlet 与 Servlet 之间转发的多个资源的数据共享。
- 相关 API:
- 存储数据
void setAttribute(String name, Object o)
- 获取数据
Object getAttribute(String name)
- 删除数据
void removeAttribute(String name)
- 生命周期:
- 何时创建?
用户发送请求时,创建 Request 域对象。 - 何时销毁
服务器返回响应时,销毁 Request 域对象。 - 作用范围?
一次请求,包含多次转发。
- RequestDemo:
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("/requestDemo")
public class RequestDemo extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("RequestDemo is working.");
request.setAttribute("receipt", "hamburger");
request.getRequestDispatcher("/requestDemo2").forward(request,response);
}
}
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("/requestDemo2")
public class RequestDemo2 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("RequestDemo2 is working.");
String received = (String) request.getAttribute("receipt");
System.out.println("receipt:" + received);
}
}
- 请求转发中之所以可以用 Request 域对象共享数据是因为使用不同的 Servlet 使用了同一个 Request 对象。
- Tomcat 服务器收到请求转发的时候,不会创建新的 Request 与 Response 对象,而是直接利用 RequestDemo 的 Request 与 Response 对象调用 RequestDemo2 的 doPost 方法。
c. 获取 ServletContext 对象
- ServletContext 的中文直译:应用上下文对象。
- ServletContext 可以应用在一个 web 项目中:
- 通过reuqest,可以获得 ServletContext 对象:
public ServletContext getServletContext();
4. 综合案例:用户登录
a. 主要需求
- 实现用户的登录功能;
- 登录成功跳转到 SuccessServlet 展示:
登录成功!xxx,欢迎您
; - 登录失败跳转到 FailServlet 展示:
登录失败,用户名或密码错误
。
b. 需求分析
- Request 获取请求参数
- Request 请求转发
- Request 域共享数据
c. 代码实现
i. 创建 web 项目,并导入 BeanUtils 工具类
ii. index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<h4>用户登录</h4>
<form action="/webappPractice2/loginServlet" method="post">
用户:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
iii. User 实体类
public class User {
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;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
iv. LoginServlet
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("/loginServlet")
public class LoginServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
Map<String, String[]> parameterMap = request.getParameterMap();
User user = new User();
try {
BeanUtils.populate(user, parameterMap);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
if ("Regino".equals(user.getUsername()) && "123".equals(user.getPassword())) {
request.setAttribute("user", user);
request.getRequestDispatcher("/successServlet").forward(request, response);
} else {
request.getRequestDispatcher("/failServlet").forward(request, response);
}
}
}
v. SuccessServlet
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("/successServlet")
public class SuccessServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
User user = (User) request.getAttribute("user");
response.setContentType("text/html;charset=utf-8");
response.getWriter().write(user.getUsername() + ",登录成功!");
}
}
vi. FailServlet
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("/failServlet")
public class FailServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("用户名或密码错误。");
}
}
d. 测试
原文链接:https://qwert.blog.csdn.net/article/details/105509803