Request&Response
Request是请求对象,Response是响应对象。这两个对象在我们使用Servlet的时候有看到
- request:==获取==请求数据
- 浏览器会发送HTTP请求到后台服务器[Tomcat]
- HTTP的请求中会包含很多请求数据[请求行+请求头+请求体]
- 后台服务器[Tomcat]会对HTTP请求中的数据进行解析并把解析结果存入到一个对象中
- 所存入的对象即为request对象,所以我们可以从request对象中获取请求的相关参数
- 获取到数据后就可以继续后续的业务,比如获取用户名和密码就可以实现登录操作的相关业务
- response:==设置==响应数据
- 业务处理完后,后台就需要给前端返回业务处理的结果即响应数据
- 把响应数据封装到response对象中
- 后台服务器[Tomcat]会解析response对象,按照[响应行+响应头+响应体]格式拼接结果
- 浏览器最终解析结果,把内容展示在浏览器给用户浏览
1. Request
HTTP请求数据总共分为三部分内容,分别是==请求行、请求头、请求体==,对于这三部分内容的数据,分别该如何获取,首先我们先来学习请求行数据如何获取?
1.1 获取请求行数据
请求行包含三块内容,分别是请求方式、请求资源路径、HTTP协议及版本

对于这三部分内容,request对象都提供了对应的API方法来获取,具体如下:
- 获取请求方式:
GET
String getMethod()
- 获取虚拟目录(项目访问路径):
/request-demo
String getContextPath()
- 获取URL(统一资源定位符):
http://localhost:8080/request-demo/req1
StringBuffer getRequestURL()
- 获取URI(统一资源标识符):
/request-demo/req1
String getRequestURI()
- 获取请求参数(GET方式):
username=zhangsan&password=123
String getQueryString()
介绍完上述方法后,咱们通过代码把上述方法都使用下:
案例
@WebServlet("/request01")
public class Request01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
response.setHeader("content-type","text/html;charset=utf-8");
response.getWriter().write("<h1>"+username+",欢迎您!</h1>");
// 通过request 获取请求体信息
//获取请求方式:
String method = request.getMethod();
System.out.println("method = " + method);
//获取虚拟目录(项目访问路径):当前项目
String contextPath = request.getContextPath();
System.out.println("contextPath = " + contextPath);
//获取URL(统一资源定位符): 全路径
StringBuffer requestURL = request.getRequestURL();
System.out.println("requestURL = " + requestURL.toString());
//获取URI(统一资源标识符):不带域名的项目路径和目录路径
String requestURI = request.getRequestURI();
System.out.println("requestURI = " + requestURI);
//获取请求参数(GET方式):
String getParams = request.getQueryString();
System.out.println("getParams = " + getParams);
/**
* 执行结果如下:
* method = GET
* contextPath = /07RequestResponse
* requestURL = http://localhost:8080/07RequestResponse/request01
* requestURI = /07RequestResponse/request01
* getParams = username=Hades
*/
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
1.2 获取请求头数据
请求头信息包括像Cookie、User-Agent浏览器信息等。
获取请求头信息
String getHeader(String name)
案例
Enumeration<String> headerNames = request.getHeaderNames();
System.out.println("请求头信息——————start");
while (headerNames.hasMoreElements()){
System.out.println(headerNames.nextElement()+":"+request.getHeader(headerNames.nextElement()));
}
System.out.println("请求头信息——————end");
/**
* 执行结果如下:
* 请求头信息——————start
* host:keep-alive
* upgrade-insecure-requests:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_16_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
* sec-fetch-user:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng;
* sec-fetch-site:navigate
* referer:gzip, deflate, br
* accept-language:Idea-8efd91f8=448175f3-de4a-4bb9-8c6e-25bab5b3328a
* 请求头信息——————end
*/
1.3 获取请求参数
浏览器默认是发出get请求,所以需要更改一下html中的from、 method= post
对于请求参数的获取,常用的有以下两种:
- GET方式:
String getQueryString()
- POST方式:
BufferedReader getReader();
post请求体是以键值对&键值对的方式传递
username=zhangsan&password=1234
注意:因为参数的值可能是一个,也可能有多个,所以Map的值的类型为String数组。
基于上述理论,request对象为我们提供了如下方法:
- 获取所有参数Map集合
Map<String,String[]> getParameterMap()
- 根据名称获取参数值(数组)
String[] getParameterValues(String name)
- 根据名称获取参数值(单个值)
String getParameter(String name)
案例
html
<form action="/07RequestResponse/request01" method="post">
用户名<input name="username" type="text"></br>
密 码<input name="password" type="password"></br>
<input type="submit">
</form>
//获取请求参数
Map<String, String[]> map = request.getParameterMap();
for (String key : map.keySet()) {
System.out.print(key+":");
//获取值
String[] values = map.get(key);
for (String value : values) {
System.out.print(value + " ");
}
System.out.println();
}
/**
* 所有参数结果:
* username:zhangsan
* password:12344
*/
1.4请求参数中文乱码问题
分析出现中文乱码的原因:
- POST的请求参数是通过request的getReader()来获取流中的数据
- TOMCAT 7.x在获取流的时候采用的编码是ISO-8859-1
- ISO-8859-1编码是不支持中文的,所以会出现乱码
Post解决方案:
- 页面设置的编码格式为UTF-8
- 把TOMCAT在获取流数据之前的编码设置为UTF-8
- 通过request.setCharacterEncoding("UTF-8")设置编码,UTF-8也可以写成小写
request.setCharacterEncoding("utf-8");//post 解决乱码问题
get的解决方案
- GET请求获取请求参数的方式是
request.getQueryString() - POST请求获取请求参数的方式是
request.getReader() - request.setCharacterEncoding("utf-8")是设置request处理流的编码
- getQueryString方法并没有通过流的方式获取数据
所以GET请求不能用设置编码的方式来解决中文乱码问题,只能在获取数据后,对数据进行字节转换处理。
String username = request.getParameter("username"); //get 解决乱码,相对麻烦一点,不过也适用于post,在tomcat8.*,默认编码是utf-8,所以不需要处理编码问题 username = new String(username.getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8);注意
- 把
request.setCharacterEncoding("UTF-8")代码注释掉后,会发现GET请求参数乱码解决方案同时也可也把POST请求参数乱码的问题也解决了 - 只不过对于POST请求参数一般都会比较多,采用这种方式解决乱码起来比较麻烦,所以对于POST请求还是建议使用设置编码的方式进行。
另外需要说明一点的是
Tomcat8.0之后,已将GET请求乱码问题解决,设置默认的解码方式为UTF-8。总结
- 中文乱码解决方案
POST请求和GET请求的参数中如果有中文,后台接收数据就会出现中文乱码问题
GET请求在Tomcat8.0以后的版本就不会出现了
POST请求解决方案是:设置输入流的编码
request.setCharacterEncoding("UTF-8"); 注意:设置的字符集要和页面保持一致通用方式(GET/POST):需要先解码,再编码
new String(username.getBytes("ISO-8859-1"),"UTF-8");
- URL编码实现方式:
编码:
URLEncoder.encode(str,"UTF-8");解码:
URLDecoder.decode(s,"ISO-8859-1");
- GET请求获取请求参数的方式是
1.5 Request请求转发
请求转发(forward):一种在服务器内部的资源跳转方式。

请求转发的实现方式:
req.getRequestDispatcher("资源B路径").forward(req,resp);
- 转发存储数据到request域[范围,数据是存储在request对象]中
void setAttribute(String name,Object o);
- 根据key获取值
Object getAttribute(String name);
- 根据key删除该键值对
void removeAttribute(String name);
只能转发到当前服务器的内部资源
不能从一个服务器通过转发访问另一台服务器
一次请求,可以在转发资源间使用request共享数据
代码演示
request.setAttribute("username",username);
request.getRequestDispatcher("/request02").forward(request,response);
@WebServlet("/request02")
public class Request02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = (String) request.getAttribute("username");
System.out.println("资源转发:"+username);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
2. Response
HTTP响应数据总共分为三部分内容,分别是响应行、响应头、响应体,对于这三部分内容的数据,respone对象都提供了哪些方法来进行设置

对于响应头,比较常用的就是设置响应状态码:
void setStatus(int sc);//200响应头
void setHeader(String name,String value); response.setHeader("content-type","text/html;charset=utf-8");响应体
<html><head></head><body></body></html> response.getWriter().write("<h1>"+username+",欢迎您!</h1>");对于响应体,是通过字符、字节输出流的方式往浏览器写,
获取字符输出流:
PrintWriter getWriter();获取字节输出流
ServletOutputStream getOutputStream();
2.1 Respones请求重定向
Response重定向(redirect):一种资源跳转方式。

1)浏览器发送请求给服务器,服务器中对应的资源A接收到请求
(2)资源A现在无法处理该请求,就会给浏览器响应一个302的状态码+location的一个访问资源B的路径
(3)浏览器接收到响应状态码为302就会重新发送请求到location对应的访问地址去访问资源B
(4)资源B接收到请求后进行处理并最终给浏览器响应结果,这整个过程就叫重定向
重定向的实现方式:
resp.setStatus(302);
resp.setHeader("location","资源B的访问路径");
代码演示
- 访问Servlet
@WebServlet("/responseDemo1")
public class ResponseDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("ResponseDemo1");
// response.setStatus(302);
// response.setHeader("Location","https://www.baidu.com");
String route = request.getContextPath();
System.out.println("route = " + route);
// response.setHeader("Location",route+"/responseDemo2");
// 请求转发的简写方式
response.sendRedirect(request.getContextPath()+"/responseDemo2");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
但是从设置重定向的两行代码来看,会发现除了重定向的地址不一样,其他的内容都是一模一样,所以request对象给我们提供了简化的编写方式为:
resposne.sendRedirect("绝对路径")
- 重定向Servlet
@WebServlet("/responseDemo2")
public class ResponseDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("ResponseDemo2");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
2.1.1 重定向的特点
| 重定向 | 请求转发 |
|---|---|
| 地址栏发生变化 | 浏览器地址栏路径不发生变化 |
| 可以重定向到任意资源(服务器内部、外部) | 只能转发到当前服务器内部资源 |
两次请求,不能在多个资源使用request共享数据 | 一次请求,可以在资源转发间使用request共享数据 |
| response.sendRedirect("path") | request.getRequestDispatcher("/path").forward(request,response); |
2.2 Response响应字符数据
要想将字符数据写回到浏览器,我们需要两个步骤:
通过Response对象获取字符输出流: PrintWriter writer = resp.getWriter();
通过字符输出流写数据: writer.write("aaa");
示例代码
@WebServlet("/responseDemo2")
public class ResponseDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("ResponseDemo2");
//content-type,告诉浏览器返回的数据类型是HTML类型数据,这样浏览器才会解析HTML标签,否则原样显示
response.setContentType("text/html;charset = utf-8");
response.getWriter().write("abc");
response.getWriter().write("<h1>abc</h1>");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
**注意:**一次请求响应结束后,response对象就会被销毁掉,所以不要手动关闭流。
2.3 Response响应字节数据
要想将字节数据写回到浏览器,我们需要两个步骤:
通过Response对象获取字节输出流:ServletOutputStream outputStream = resp.getOutputStream();
通过字节输出流写数据: outputStream.write(字节数据);
示例代码
@WebServlet("/responseDemo3")
public class ResponseDemo3 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//Response响应字节数据
FileInputStream fis = new FileInputStream("/Users/hades/Desktop/单词/day01/1best.png");
ServletOutputStream os = response.getOutputStream();
//3. 完成流的copy
byte[] buff = new byte[1024];
int len = 0;
while ((len = fis.read(buff))!= -1){
os.write(buff,0,len);
}
fis.close();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
2.3.1 使用commons-io
om.xml添加依赖
<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency>调用工具类方法
//fis:输入流 //os:输出流 IOUtils.copy(fis,os);
3. 用户注册登录案例
学完Request和Response,来练习一个用户登陆注册案例巩固一下学习成果。
3.1 用户登陆

需求分析
- 用户在登录页面输入用户名和密码,提交请求给LoginServlet
- 在LoginServlet中接收请求和数据[用户名和密码]
- 在LoginServlt中通过Mybatis实现调用UserMapper来根据用户名和密码查询数据库表
- 将查询的结果封装到User对象中进行返回
- 在LoginServlet中判断返回的User对象是否为null
- 如果为nul,说明根据用户名和密码没有查询到用户,则登录失败,返回"登录失败"数据给前端
- 如果不为null,则说明用户存在并且密码正确,则登录成功,返回"登录成功"数据给前端
环境准备
导入依赖库
<dependencies> <dependency> <!-- 网络访问--> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <dependency> <!-- 数据库操作--> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.5</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.23</version> </dependency> </dependencies>
代码实现
LoginServlet
package com.example.web;
import com.example.mapper.UserMapper2;
import com.example.pojo.User;
import com.example.utils.SqlSessionUtil;
import org.apache.ibatis.ognl.security.UserMethod;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求参数
String username = request.getParameter("username");
String password = request.getParameter("password");
//防止中文乱码
if (username != null&&password!=null) {
username = new String(username.getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8);
password = new String(password.getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8);
System.out.println(username+":"+password);
//通过mysql数据查询用户名密码是否存在数据库中
SqlSessionFactory sqlSessionFactory = SqlSessionUtil.getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper2 mapper = sqlSession.getMapper(UserMapper2.class);
User user = mapper.findUser(username, password);
sqlSession.close();
response.setContentType("text/html;charset = utf-8");
if (user == null) {
response.getWriter().write("用户名密码错误!!");
}else {
response.getWriter().write("登陆成功");
}
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
<style>
</style>
</head>
<body>
<center>
<form action="/RegisterLoginDemo/loginServlet" method="post">
用户名:<input type="text" name="username"></br>
密 码:<input type="password" name="password"></br>
<input type="submit" value="登陆">
</form>
</center>
</body>
</html>
3.2 用户注册

- 用户在注册页面输入用户名和密码,提交请求给RegisterServlet
- 在RegisterServlet中接收请求和数据[用户名和密码]
- 在RegisterServlet中通过Mybatis实现调用UserMapper来根据用户名查询数据库表
- 将查询的结果封装到User对象中进行返回
- 在RegisterServlet中判断返回的User对象是否为null
- 如果为nul,说明根据用户名可用,则调用UserMapper来实现添加用户
- 如果不为null,则说明用户不可以,返回"用户名已存在"数据给前端
代码实现
RegisterServlet
package com.example.web;
import com.example.mapper.UserMapper2;
import com.example.pojo.User;
import com.example.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@WebServlet("/registerServlet")
public class RegisterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求参数
String username = request.getParameter("username");
String password = request.getParameter("password");
//防止中文乱码
if (username != null&&password!=null) {
username = new String(username.getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8);
password = new String(password.getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8);
System.out.println(username+":"+password);
//通过mysql数据查询用户名密码是否存在数据库中
SqlSessionFactory sqlSessionFactory = SqlSessionUtil.getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper2 mapper = sqlSession.getMapper(UserMapper2.class);
User user = mapper.findUserByName(username);
response.setContentType("text/html;charset = utf-8");// 响应中文
if (user == null) {
User userAdd = new User();
userAdd.setUsername(username);
userAdd.setPassword(password);
mapper.addUser(userAdd);
sqlSession.commit();
sqlSession.close();
response.getWriter().write("注册成功");
}else {
response.getWriter().write("用户名已存在!!");
}
}
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
register.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
<meta charset="UTF-8">
<title>注册</title>
</head>
<body>
<center>
<h1>注册用户</h1>
<form action="/RegisterLoginDemo/registerServlet" method="post">
用户名:<input type="text" name="username"></br>
密 码:<input type="password" name="password"></br>
<input type="submit" value="注册">
</form>
</center>
</body>
</html>
更多详细代码,查看07RequestResponse下的子模块RegisterLoginDemo。
