目录
1. Request和Response的概述
request是请求对象,response是响应对象:
- request对象是用来封装请求数据的对象。
- response对象是用来封装响应数据的对象。
2. Request对象
2.1 Request继承体系
实现类RequestFacade:
- 该类实现了HttpServletRequest接口,也间接实现了ServletRequest接口。
- Servlet类中的service方法、doGet方法或者是doPost方法最终都是由Web服务器[Tomcat]来调用的,所以Tomcat提供了方法参数接口的具体实现类,并完成了对象的创建。
- 要想了解RequestFacade中都提供了哪些方法,我们可以直接查看JavaEE的API文档中关于 ServletRequest和HttpServletRequest的接口文档,因为RequestFacade实现了其接口就需要重写接口中的方法。
2.2 Request获取请求数据
2.2.1 获取请求行数据
方法 | 说明 |
getMethod() | 获取请求方式 |
getContextPath() | 获取项目访问路径 |
getRequestURL | 获取请求URL |
getRequestURI | 获取请求URI |
getQueryString | 获取get方式的请求参数 |
2.2.2 获取请求头数据
方法 | 说明 |
getHeader(String name) | 根据请求头名称获取对应的值 |
2.2.3 获取请求体数据(post方式的请求参数)
方法 | 说明 |
getReader() | 获取字符输入流(字符数据如纯文本数据) |
getInputStream() | 获取字节输入流(字节数据如文件数据) |
/**
* request获取请求数据
*/
@WebServlet("/req1")
public class RequestDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*
获取请求行数据
*/
//1.获取请求方式
String method = req.getMethod();
//GET
System.out.println(method);
//2.获取虚拟目录(项目访问路径)
String contextPath = req.getContextPath();
// /request-demo
System.out.println(contextPath);
//3.获取URL(统一资源定位符)
StringBuffer requestURL = req.getRequestURL();
//http://localhost:8080/request-demo/req1
System.out.println(requestURL.toString());
//4.获取URI(统一资源标识符)
String requestURI = req.getRequestURI();
// /request-demo/req1
System.out.println(requestURI);
//5.获取get方式的请求参数
String queryString = req.getQueryString();
//username=ydh&password=123
System.out.println(queryString);
/*
获取请求头数据
*/
//根据请求头的键获取对应的值
String agent = req.getHeader("user-agent");
//Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36
System.out.println(agent);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/*
获取请求体数据(post方式的请求参数)
*/
//1.获取字符输入流
BufferedReader br = req.getReader();
//2.读取数据
String line = br.readLine();
//username=ydh&password=123
System.out.println(line);
}
}
2.2.4 获取请求参数的通用方式
request对象已经将上述获取请求参数的方法进行了封装,并把获取到的内容进行分割,存入到一个Map<String,String[]>集合中。
基于上述理论,request对象为我们提供了如下方法:
方法 | 说明 |
getParameterMap()
|
获取所有参数
Map
集合
|
getParameterValues(String name)
|
根据名称获取参数值(数组)
|
getParameter(String name)
|
根据名称获取参数值
(
单个值
)
|
/**
* request获取请求参数的通用方式
*/
@WebServlet("/req2")
public class RequestDemo2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("get...");
//1.获取所有参数的Map集合
Map<String, String[]> map = req.getParameterMap();
//增强for循环遍历键
for (String key : map.keySet()) {
System.out.print(key+":");
//根据键获取参数值(数组)
String[] values = map.get(key);
//增强for循环遍历值
for (String value : values) {
System.out.print(value+" ");
}
//换行
System.out.println();
}
//2.根据名称获取参数值(数组)
String[] hobbies = req.getParameterValues("hobby");
for (String hobby : hobbies) {
System.out.println(hobby);
}
//3.根据名称获取参数值(单个值)
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(username);
System.out.println(password);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//采用通用方式获取请求参数,直接调用doGet方法
this.doGet(req,resp);
}
}
2.3 请求参数中文乱码问题
2.3.1 post请求解决方案
产生中文乱码的原因:
- POST的请求参数是通过request的getReader()来获取流中的数据。
- TOMCAT在获取流的时候采用的编码是ISO-8859-1。
- ISO-8859-1编码是不支持中文的,所以会出现乱码。
解决方案:
- 页面设置的编码格式为UTF-8。
- 把TOMCAT在获取流数据之前的编码设置为UTF-8。
- 通过request.setCharacterEncoding("UTF-8")设置编码,UTF-8也可以写成小写。
方法 | 说明 |
setCharacterEncoding("UTF-8")
| 设置字符输入流的编码 |
//1.设置字符输入流的编码(设置的字符集要和页面的字符集一致)
request.setCharacterEncoding("UTF-8");
//2.获取username
String username = request.getParameter("username");
System.out.println(username);
2.3.2 GET请求解决方案
POST
请求的中文乱码解决方案为什么不适用
GET
请求?
- GET请求获取请求参数的方式是getQueryString() ,POST请求获取请求参数的方式getReader()。
- setCharacterEncoding("utf-8")是设置request处理流的编码,getQueryString方法并没有通过流的方式获取数据。
GET
请求出现乱码的原因:
URL编码的编码过程
- 将字符串按照编码方式转为二进制
- 每个字节转为2个16进制数并在前边加上%
String username = "张三";
//1.URL编码
String encode = URLEncoder.encode(username, "utf-8");
System.out.println(encode);//%E5%BC%A0%E4%B8%89
//2.URL解码
//String decode = URLDecoder.decode(encode, "utf-8");
//System.out.println(decode);//张三
String decode = URLDecoder.decode(encode, "ISO-8859-1");
System.out.println(decode);//å¼ ä¸
GET请求解决中文乱码方案:
方案 | 说明 |
username = new String(username.getBytes("ISO-8859-1"),"uft-8"); | 先编码,再解码(也适用于post方式) |
//1.获取username
String username = request.getParameter("username");
// //2.编码,字符串转为字节数据
// byte[] bytes = username.getBytes("ISO-8859-1");
// //3.解码,字节数据转为字符串
// username = new String(bytes,"utf-8");
// System.out.println(username);
username = new String(username.getBytes("ISO-8859-1"), "utf-8");
System.out.println(username);
注意
- Tomcat8.0之后,已将GET请求乱码问题解决,设置默认的解码方式为UTF-8。
2.4 Request请求转发
请求转发(forward):一种在服务器内部的资源跳转方式。
请求转发
方法 | 说明 |
getRequestDispatcher("
资源
B
路径
").forward(req,resp)
| 资源A请求转发到资源B |
请求转发资源间共享
方法 | 说明 |
void setAttribute(String name,Object o)
| 存储数据到request对象中 |
Object getAttribute(String name)
| 根据键获取值 |
void removeAttribute(String name)
| 根据键删除该键值对 |
RequestDemo5.java
@WebServlet("/req5")
public class RequestDemo5 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("demo5...");
//1.存储数据
request.setAttribute("msg","hello");
//2.请求转发
request.getRequestDispatcher("/req6").forward(request,response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
RequestDemo6.java
@WebServlet("/req6")
public class RequestDemo6 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("demo6...");
//3.获取数据
Object msg = request.getAttribute("msg");
System.out.println(msg);//hello
//4.删除数据
request.removeAttribute("msg");
System.out.println(request.getAttribute("msg"));//null
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
请求转发的特点
- 浏览器地址栏路径不发生变化。
- 只能转发到当前服务器的内部资源。
- 一次请求,可以在转发资源间使用request共享数据。
3. Response对象
3.1 Response继承体系
Reponse的继承体系和Request的继承体系非常相似。
3.2 Response设置响应数据
3.2.1 设置响应行
方法 | 说明 |
setStatus(int sc) | 设置响应状态码 |
3.2.2 设置响应头
方法 | 说明 |
setHeader(String name,String value) | 设置响应头键值对 |
3.2.3 设置响应体
对于响应体,是通过字符或者字节输出流的方式往浏览器写。
方法 | 说明 |
getWriter()
| 获取字符输出流 |
getOutputStream()
| 获取字节输出流 |
3.3 Response请求重定向
Response重定向(redirect):一种资源跳转方式。
方法 | 说明 |
sendRedirect(String s) | 重定向 |
ResponseDemo1.java
@WebServlet("/resp1")
public class ResponseDemo1 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("resp1...");
/*
重定向
*/
// //1.设置响应状态码 302
// response.setStatus(302);
// //2.设置响应头
// response.setHeader("Location","/request-demo/resp2");
//简单写法,一步搞定
response.sendRedirect("/request-demo/resp2");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
ResponseDemo2.java
@WebServlet("/resp2")
public class ResponseDemo2 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("resp2...");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
重定向的特点
- 浏览器地址栏路径会发生变化。
- 可以重定向到任何位置的资源(服务器内部、外部均可)。
- 两次请求,不可以在多个资源间使用request共享数据。
3.4 路径问题
虚拟目录(项目的根目录):
- 浏览器使用:需要加虚拟目录(项目访问路径)。
- 服务端使用:不需要加虚拟目录。
以下路径中,是否需要加虚拟目录?
<a href="路径"> 需要
<form action="路径"> 需要
req.getRequestDispatcher("路径") 不需要
resp.sendRediect("路径") 需要
如果虚拟目录变了,那么项目中所有重定向的路径都应该变,代码耦合度太高,因此采取下面这种方式解决。
//动态获取虚拟目录
String contextPath = request.getContextPath();
response.sendRedirect(contextPath + "/resp2");
3.5 Response响应字符数据
方法 | 说明 |
setContentType("text/html;charset=utf-8") | 设置的响应数据及数据的编码 |
getWriter() | 获取字符输出流 |
write() | 通过字符输出流写数据 |
//设置的响应数据及数据的编码
response.setContentType("text/html;charset=utf-8");
//1.获取字符输出流
PrintWriter writer = response.getWriter();
// //2.设置响应头的content-type的值,告诉浏览器返回的数据类型是html类型数据,这样浏览器才会解析html标签
// response.setHeader("content-type","text/html");
//3.写数据到浏览器上
//简单字符串
writer.write("aaa");
//html字符串
writer.write("<h1>bbb</h1>");
//中文字符串
writer.write("你好");
注意
- 设置响应头的content-type的值与调用setContentType的效果是等效的。
-
一次请求响应结束后, response 对象就会被销毁掉,所以不要手动关闭字符输出流。
3.6 Response响应字节数据
传统方式:
/*
返回一张图片文件给浏览器
*/
//1.读取文件
FileInputStream fileInputStream = new FileInputStream("d://Desert.jpg");
//2.获取response字节输出流
ServletOutputStream outputStream = response.getOutputStream();
//3.完成流的copy
//在内存中开辟1KB的字节数组(缓存区)
byte[] buff = new byte[1024];
int len = 0;
//读取文件数据并将其存放到字节数组中,返回读取的字节数。(-1表示文件末尾)
while((len = fileInputStream.read(buff))!= -1){
//将字节数组中的数据写到浏览器上
outputStream.write(buff,0,len);
}
fileInputStream.close();
对于流的
copy
的代码还是比较复杂的,所以我们可以使用别人提供好的方法来简化代码
的开发:
pom.xml中导入依赖坐标:
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
调用工具类方法:
方法 | 说明 |
IOUtils.copy(fileInputStream,outputStream) | 流的copy |
/*
返回一张图片文件给浏览器
*/
//1.读取文件
FileInputStream fileInputStream = new FileInputStream("d://Desert.jpg");
//2.获取response字节输出流
ServletOutputStream outputStream = response.getOutputStream();
//3.完成流的copy
IOUtils.copy(fileInputStream,outputStream);
fileInputStream.close();