详解 HttpServletRequest 请求类型API
HttpServletRequest
:是客户端浏览器发出的请求被封装的一个HttpServletRequest
对象,该对象中包含了请求的地址、请求的参数、提交的数据以及上传的数据;
1. 获取请求信息的方法
获取一个请求中各方面信息的方法有:
方法 | 描述信息 |
---|---|
String getProtocol() | 返回请求协议的名称 |
String getMethod() | 返回请求的 HTTP 方法的名称:GET、POST … |
String getContextPath() | 返回请求上下文的请求 URl 部分 |
String getQueryString() | 返回请求 URL 中的查询字符串 |
String getParameter(String name) | 以字符串形式返回请求参数的值,参数不存在返回 null |
String getHeader(String name) | 以字符串形式返回指定的请求头的值 |
String getCharacterEncoding() | 返回请求主体中使用的字符编码名称 |
String getContentType() | 返回请求主体的 MIME 类型,不知道返回 null |
int getContentLength() | 以字节为单位返回请求主体的长度,并提供输入流 |
InputStream getInputStream() | 用于读取请求的 body 内容,返回一个 InputStream 对象 |
Enumeration getHeaderNames() | 返回一个枚举,包含在该请求中包含的所有的头名 |
String[] getParameterValues(String name) | 返回一个字符串对象的数组 |
Enumeration getParameterNames() | 返回一个 String 对象的枚举,包含在该请求中包含的参数的名称 |
代码示例:
package request;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
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")
public class requestStudyServlet extends HttpServlet {
//重写 doGet 方法
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//通过打印来学习获取请求的方法
System.out.println("请求协议名:"+req.getProtocol());
System.out.println("请求方法名:"+req.getMethod());
System.out.println("请求上下文路径:"+req.getContextPath());
System.out.println("请求资源路径:"+req.getServletPath());
System.out.println("请求头中,键为Host的值:"+ req.getHeader("Host"));
}
}
启动服务器,运行结果:
2. 前端发送请求数据的格式
(1)请求数据为 queryString
前端代码使用链接标签并规定好访问路径:request?username=abc&password=123
后端通过 getParameter(String name)
函数 ,通过键来获取值;
前端 HTML 代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h3>QueryString:/request</h3>
<!-- 当前页面访问的路径:/[contextPath应用上下文路径]/request.html,
需要跳转到/[contextPath]/request -->
<!-- 也可以直接在url输入链接跳转后相同的url绝对路径来访问 -->
<a href="request?username=abc&password=123">get</a>
</body>
</html>
后端代码:
package request;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
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")
public class requestStudyServlet extends HttpServlet {
//重写 doGet 方法
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 注意:http请求时,url会进行编码,获取queryString中的中文,空格,特殊字符,就需要解码
// 社区版中文正常显示,但我们写代码要注意可能有乱码的情况
// queryString 访问路径 request?username=abc&password=123
req.setCharacterEncoding("utf-8");//设置body解析的编码格式
System.out.println("username: "+ req.getParameter("username"));
System.out.println("password: "+ req.getParameter("password"));
//响应给客户端的内容
resp.getWriter().println("请求信息已获取,在idea控制台查看");
}
}
访问路径
:
点击 get
链接查看运行结果:
(2)请求数据为表单格式
与上面点击链接达到相同的效果,也可以通过表单来实现:
前端代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h3>表单格式</h3>
<!-- 表单格式,没有设置请求方法默认为get方法,将form表单中的控件以name为键,
选择输入的内容为值设置到querystring中-->
<form action="request">
<input type="text" name="username" placeholder="请输入用户名">
<br>
<input type="password" name="password" placeholder="请输入密码">
<br>
<input type="submit" value="提交">
</form>
</body>
</html>
后端代码与上面相同~
浏览器显示:
后端运行结果:
(3)请求数据为 form-data 格式
- form-data 格式的简单类型时:
getParameter()
获取;
前端代码:
<body>
<h3>form-data格式</h3>
<form action="form-data-servlet" enctype="multipart/form-data" method="post">
<input type="text" name="username" placeholder="请输入用户名">
<br>
<input type="password" name="password" placeholder="请输入密码">
<br>
<input type="submit" value="提交">
</form>
</body>
由于请求方法为 post
方法,因此,后端需要重写 doPost
方法;
后端代码:
package request;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.IOException;
@WebServlet("/form-data-servlet")
//form-data格式,需要添加这个注解
@MultipartConfig
public class FormDataServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//getParameter()也可以获取form-data中的简单类型数据
req.setCharacterEncoding("utf-8");//设置body解析的编码格式
System.out.println("username: "+ req.getParameter("username"));
System.out.println("password: "+ req.getParameter("password"));
}
}
通过http://localhost:8080/servlet-study/request.html
访问网页显示:
网页点击提交后,后端运行结果:
- form-data 复杂类型格式时:
getPart()
获取;
复杂类型:如文件类型
前端代码:
<h3>form-data格式</h3>
<form action="form-data-servlet" enctype="multipart/form-data" method="post">
<input type="text" name="username" placeholder="请输入用户名">
<br>
<input type="password" name="password" placeholder="请输入密码">
<br>
<!-- 设置图片类型 accept="image/* -->
选择头像:<input type="file" name="head" accept="image/*">
<br>
<input type="submit" value="提交">
</form>
后端代码:
package request;
import javax.servlet.annotation.WebServlet;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.http.HttpServlet;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
@WebServlet("/form-data-servlet")
//form-data格式,需要添加这个注解
@MultipartConfig
public class FormDataServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//getParameter()也可以获取form-data中的简单类型数据:字符串、boolean
req.setCharacterEncoding("utf-8");//设置body解析的编码格式
System.out.println("username: "+ req.getParameter("username"));
System.out.println("password: "+ req.getParameter("password"));
System.out.println("head[文件类型的格式无法通过getParameter获取]:"+req.getParameter("head"));
//form-data 中上传的文件,需要通过 getPart获取,getParameter无法获取
Part head = req.getPart("head");
//获取上传文件的二进制数据,转换为字符串打印
// InputStream is = head.getInputStream();//获取输入流
// //输入流转换为字节数组
// byte[] bytes = new byte[is.available()];
// //从输入流中把数据读取到byte[]中,字节数组对象就有了这些数据
// is.read(bytes);
// //转换为字符串
// System.out.println(new String(bytes,"utf-8"));
//也可以将客户端上传的图片保存到服务端本地
//保存与读取操作只能存在一个
head.write("E://"+head.getSubmittedFileName());
}
}
二进制数据流转为字符串打印结果:
保存到本地:
以上操作也可以使用抓包工具查看结果:
(4)请求数据为 json 格式
前端代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>ajax提交json格式</h3>
<input type="text" id="ajax_username" placeholder="请输入用户名">
<br>
<input type="password" id="ajax_password" placeholder="请输入密码">
<br>
<button onclick="ajaxSubmit()">提交</button>
</body>
<script>
function ajaxSubmit() {
let username = document.querySelector("#ajax_username");
let password = document.querySelector("#ajax_password");
let json = {
// 键为username,值为对象的value属性
username: username.value,
password: password.value,
};
ajax({
url: "ajax-json-servlet",
method: "post",
// body 上为json格式的字符串
contentType: "application/json",
//JSON.stringify 是将一个json对象序列化为一个字符串,格式为json格式
body: JSON.stringify(json),
callback: function (status, resp) {
alert("后端返回的内容:" + resp);
}
});
}
function ajax(args) {
let xhr = new XMLHttpRequest();
// 设置回调函数
xhr.onreadystatechange = function () {
// 4: 客户端接收到响应后回调
if (xhr.readyState == 4) {
// 回调函数可能需要使用响应的内容,作为传入参数
args.callback(xhr.status, xhr.responseText);
}
}
xhr.open(args.method, args.url);
//如果args中,contentType属性有内容,就设置Content-Type请求头
if (args.contentType) {//js中,if判断,除了判断boolean值,还可以判断字符串,对象等,有值就为true
xhr.setRequestHeader("Content-Type", args.contentType);
}
//如果args中,设置了body请求正文,调用send(body)
if (args.body) {
xhr.send(args.body);
} else {//如果没有设置,调用send()
xhr.send();
}
}
</script>
</html>
后端代码:
package 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.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@WebServlet("/ajax-json-servlet")
public class ajaxJsonServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取请求body数据并设置编码
req.setCharacterEncoding("utf-8");
//request.getInputStream获取请求正文的数据(不管Content-Type是什么类型,都可以获取)
//json是使用这个api比较典型的场景: {"username":"张三","password":"111"}
InputStream is =req.getInputStream();
//了解:涉及IO流
// InputStreamReader isr = new InputStreamReader(is, "utf-8");
// BufferedReader br = new BufferedReader(isr);
// StringBuilder sb = new StringBuilder();
// String str;
// while((str=br.readLine())!=null){
// sb.append(str);
// }
// System.out.println("获取的json数据:"+sb);
//简单一点的操作方式
//body的长度,在请求头Content-Length已经标识
int len = req.getContentLength();
byte[] bytes = new byte[len];
is.read(bytes);
System.out.println("获取的json数据:"+new String(bytes, "utf-8"));
}
网页提交数据后,可以看到如下所示:
但实际上,如得到整个json
字符串也不方便使用,如:我们要判断账号密码是否正确?
常用的方式:使用第三方库,
- 可以把
json
字符串转换为一个Java
对象;- 还可以把
Java
对象转换为json
字符串
使用第三方库需要引入依赖包:
网址:此处需要人机校验
输入:jackson-databind
,如下所示:
选择 2.11.3
将方框中内容复制到 pom.xml
中并刷新:
后端代码:
//借助第三方库,可以将json字符串和java对象互相转换
//我们这里使用jackson库
ObjectMapper mapper = new ObjectMapper();
//简单暴力:直接转换为map对象,转换为map是万金油方法(任何json格式都可以转换为map)
Map json = mapper.readValue(is, Map.class);
System.out.println("获取的json字符串转换的map: "+json);
输出结果:
将Map
对象以 toString
方式转成字符串打印输出;
另一种方式:转换json
字符串为自定义类型:
前端代码不变,后端代码:
package request;
import com.fasterxml.jackson.databind.ObjectMapper;
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.InputStream;
@WebServlet("/ajax-json-servlet")
public class ajaxJsonServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取请求body数据并设置编码
req.setCharacterEncoding("utf-8");
//request.getInputStream获取请求正文的数据(不管Content-Type是什么类型,都可以获取)
//json是使用这个api比较典型的场景: {"username":"张三","password":"111"}
InputStream is =req.getInputStream();
ObjectMapper mapper = new ObjectMapper();
//map使用,也不方便:使用指定的字符串键,来获取值
//一般转换json字符串为自定义类型,但需要注意:json中的键在java类型必须有对应的成员变量名,否则会报错
User user = mapper.readValue(is, User.class);
System.out.println("获取的json字符串转换的user对象:"+user);
}
//静态内部类:包含再一个类{}内,使用和普通类一样
//把json字符串转换为java对象,需要某个键的名称和成员变量名一样(类型也是一样)
static class User {
private String username;
private String password;
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
//提供getter和setter方法
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;
}
}
}
输出结果:
小结:
重点 API:
- getParameter():
(1)获取
URL
queryString
中的内容;
(2)获取body
中,表单格式;
(3)获取form-data
简单类型数据;
- getPart(): 获取
form-data
上传的文件 - getInputStream():获取请求正文
body
的数据
常用场景:
json
格式