Request&Response
- Request:获取请求数据
- Response:设置响应数据
Request
Request 继承体系
- Tomcat需要解析请求数据,封装为request对象,并且创建request对象传递到service方法中
- 使用request对象,查阅JavaEE API文档的HttpServletRequest接口
Request获取请求数据
- 请求数据分为3部分:
- 请求行:
GET /request-demo/req1?username=zhangsan HTTP/1.1
String getMethod()
:获取请求方式:GETString getContextPath()
:获取虚拟目录(项目访问路径): /request-demoStringBuffer getRequestURL()
:获取URL(统一资源定位符): http://localhost:8080/request-demo/req1String getRequestURI()
:获取URI(统一资源标识符): /request-demo/req1String getQueryString()
:获取请求参数(GET方式): username=zhangsan&password=123
- 请求头:
User-Agent: Mozilla/5.0 Chrome/91.0.4472.106
String getHeader(String name)
:根据请求头名称,获取值
- 请求体:
username=superbaby&password=123
ServletlnputStream getInputStream()
:获取字节输入流BufferedReader getReader()
:获取字符输入流
- 请求行:
Request通用方式获取请求参数
-
请求参数获取方式:
GET方式:
String getQueryString()
POST方式
BufferedReader getReader()
思考:
GET请求方式和POST请求方式区别主要在于获取请求参数的方式不一样,是否可以提供一种统一获取请求参数的方式,从而统一doGet和doPost方法内的代码?
Map<String, String[ ]> getParameterMap()
:获取所有参数Map集合String[ ] getParameterValues(String name)
︰根据名称获取参数值(数组)String getParameter(String name)
:根据名称获取参数值(单个值)
示例:
//前端文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="GBK">
<title>requestDemo</title>
</head>
<body>
<form action="/webdemo/request" method="post">
<input type="text" name="username"> <br>
<input type="password" name="password"> <br>
<input type="checkbox" name="hobby" value="1"> 游泳
<input type="checkbox" name="hobby" value="2"> 跳绳 <br>
<input type="submit">
</form>
</body>
</html>
//RequestDemo后端文件
package com.jihua.webdemo;
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.Map;
@WebServlet("/request")
public class RequestDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1. 获取所有参数的Map集合
Map<String, String[]> parameterMap = req.getParameterMap();
for (String key : parameterMap.keySet()) {
System.out.print(key + ":");
//获取值
String[] values = parameterMap.get(key);
for (String value : values) {
System.out.print(value + " ");
}
System.out.println();
}
System.out.println("------");
//2. 根据key获取参数值,数组
String[] hobbies = req.getParameterValues("hobby");
System.out.println("hobby: ");
for (String hobby : hobbies) {
System.out.print(hobby + " ");
}
System.out.println();
System.out.println("------");
//3.根据key获取单个参数值
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 {
this.doGet(req, resp);
}
}
//控制台输出
username:zhangsan
password:123123
hobby:1 2
------
hobby:
1 2
------
zhangsan
123123
-
使用通用方式获取请求参数后,屏蔽了GET和POST的请求方式代码的不同,则代码可以定义为如下格式:
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ······ } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doGet(req, resp); }
-
可以使用Servlet模板创建Servlet更高效
右键新建文件时选择Servlet,如果没有就打开项目结构选择Facet下方根源勾选相应目录
可在设置-编辑器-文件和代码模板-其他-Web-Java代码模板-Servlet Annotated Class.java修改每次创建的模板
请求参数中文乱码处理
-
请求参数如果存在中文数据,则会乱码
-
解决乱码:
-
POST:getReader()
request.setcharacterEncoding("UTF-8");//设置字符输入流的编码
-
GET:获取参数的方式: getQueryString
乱码原因:浏览器在传输中文请求时,将中文使用相应的字符编码方式进行URL转换,将中文转为十六进制数并用%隔开,数据传到Tomcat后再进行URL解码,Tomcat使用lSO-8859-1解码,不可更改,而浏览器一般选择UTF-8编码,编解码使用的字符集不一致,所以造成了乱码
Java自带一个处理URL编解码的类
package com.jihua.webdemo; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder; public class URLDemo { public static void main(String[] args) throws UnsupportedEncodingException { String username = "张三"; //1. URL编码 String encode = URLEncoder.encode(username, "utf-8"); System.out.println(encode); //2. URL解码 String decode = URLDecoder.decode(encode, "utf-8"); System.out.println(decode); } }
//输出 %E5%BC%A0%E4%B8%89 张三 进程已结束,退出代码0
解决方法:
//3.1先对乱码数据进行编码:转为字节数组 byte[] bytes = username.getBytes(StandardCharsets.ISO_8859_1); //3.2字节数组解码 username = new String(bytes,StandardCharsets.UTF_8); System.out.println(username);
-
通用解决方式:
username = new String(username.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
Tomcat 8.0之后,已将GET请求乱码问题解决,设置默认的解码方式为UTF-8
Request请求转发
请求转发
-
请求转发(forward):一种在服务器内部的资源跳转方式
-
实现方式:
req.getRequestDispatcher("资源B路径").forward(req,resp);
-
请求转发资源间共享数据:使用Request对象
- void setAttribute(String name, Object o):存储数据到request域中Object
- getAttribute(String name):根据key,获取值
- void removeAttribute(String name):根据key,删除该键值对
例如:
//在demo1中: req.setAttribute("msg","hello"); req.getRequestDispatcher("/demo2").forward(req,resp); //在demo2中: Object msg = req.getAttribute("msg"); System.out.println(msg);
-
请求转发特点:
- 浏览器地址栏路径不发生变化
- 只能转发到当前服务器的内部资源
- 一次请求,可以在转发的资源间使用request共享数据
Response
Response设置响应数据功能介绍
- 响应数据分为3部分:
- 响应行:
HTTP/1.1 200 OK
void setStatus(int sc)
︰设置响应状态码
- 响应头:
Content-Type: text/html
void setHeader(String name, String value)
︰设置响应头键值对
- 响应体:
<html><head>head><body></body></html>
PrintWriter getWriter()
:获取字符输出流ServletOutputStream getOutputStream()
:获取字节输出流
- 响应行:
Response完成重定向
-
重定向(Redirect):一种资源跳转方式
-
实现方式:
//1. 设置响应状态码 resp.setStatus(302); //2. 设置重定向路径 resp.setHeader("location","“资源B的路径"); //简化方式完成重定向 response. sendRedirect( location: "/request-demo/resp2");
-
重定向特点:
- 浏览器地址栏路径发生变化
- 可以重定向到任意位置的资源(服务器内部、外部均可)
- 两次请求,不能在多个资源使用request共享数据
路径问题
-
明确路径谁使用?
- 浏览器使用:需要加虚拟目录(项目访问路径)
- 服务端使用:不需要加虚拟目录
-
举例
<a href='路径'>
加虚拟目录<form action='路径'>
加虚拟目录req.getRequestDispatcher("路径")
不加虚拟目录(转发)resp.sendRedirect("路径")
加虚拟目录(重定向)
-
动态获取虚拟目录
String contextPath = request.getcontextPath();
Response响应字符数据
-
使用:
-
通过Response对象获取字符输出流
PrintWriter writer = resp.getWriter();
-
写数据
writer.write("aaa");
-
-
示例:
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取字符输出流 PrintWriter writer = resp.getWriter(); // content-type resp.setHeader("content-type" ,"text/html"); writer.write("aa"); writer.write("<h1>aaa</h1>"); }
-
简化content-type书写以及解决中文乱码问题
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // content-type resp.setContentType("text/html;charset=utf-8"); // 获取字符输出流 PrintWriter writer = resp.getWriter(); writer.write("你好"); writer.write("<h1>aaa</h1>"); }
-
注意:
-
该流不需要关闭,随着响应结束,response对象销毁,由服务器关闭
-
中文数据乱码:原因通过Response获取的字符输出流默认编码:ISO-8859-1
resp.setContentType("text/html;charset=utf-8");
-
Response响应字节数据
-
使用:
-
通过Response对象获取字符输出流
ServletOutputStream outputStream = resp.getOutputStream();
-
写数据
outputStream.write(字节数据);
-
-
示例:
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获取字节输出流 ServletOutputStream os = resp.getOutputStream(); // 读取文件 FileInputStream fis = new FileInputStream("D:/图片/work.png"); //拷贝 byte[] ch = new byte[1024]; int len = 0; while ((len=fis.read(ch))!=-1) { os.write(ch,0,len); } }
-
可以使用lOUtils工具类简化流的复制
首先用maven导入
<dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency>
然后导包使用
import org.apache.commons.io.IOUtils; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获取字节输出流 ServletOutputStream os = resp.getOutputStream(); // 读取文件 FileInputStream fis = new FileInputStream("D:/图片/work.png"); //拷贝 IOUtils.copy(fis,os); }