Servlet获取请求数据HttpServletRequest
Posted 一朵花花
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Servlet获取请求数据HttpServletRequest相关的知识,希望对你有一定的参考价值。
HttpServletRequest
当 Tomcat 通过 Socket API 读取 HTTP 请求(字符串),并且按照 HTTP 协议的格式把字符串解析成
HttpServletRequest 对象
方法了解
部分方法:
方法 | 描述 |
---|---|
String getProtocol() | 返回请求协议的名称和版本 |
String getMethod() | 返回请求的 HTTP 方法的名称,例如,GET、POST 或 PUT |
String getRequestURI() | 从协议名称直到 HTTP 请求的第一行的查询字符串中,返回该请求的 URL 的一部分 |
String getContextPath() | 返回指示请求上下文的请求 URI 部分 |
String getQueryString() | 返回包含在路径后的请求 URL 中的查询字符串 |
String getParameter(Stringname) | 以字符串形式返回请求参数的值,或者如果参数不存在则返回null |
String[] getParameterValues(Stringname) | 返回一个字符串对象的数组,包含所有给定的请求参数的值,如果参数不存在则返回 null |
注意: 请求对象是服务器收到的内容,不应该修改;因此上面的方法也都只是 “读” 方法, 而不是 “写” 方法
通过上述方法可以获取到一个请求中的各个方面的信息
举例:
@WebServlet("/request")
public class RequestServletStudy extends HttpServlet
// 访问路径: request?username=hh&password=123
@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("资源路径/ServletPath:" + req.getServletPath());
System.out.println("请求头中键为Host的值:" + req.getHeader("Host"));
//响应给客户端的内容
resp.getWriter().println("请求信息已获取,在idea后端控制台查看");
运行后:
点击链接跳转,此时弹出 404,需在 url 后补充 /request.html
点击 get 跳转:
重点方法介绍
1.getParamter 方法
1).获取url QueryString中的数据
@WebServlet("/request")
public class RequestServletStudy extends HttpServlet
// 访问路径: request?username=hh&password=123
@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("资源路径/ServletPath:" + req.getServletPath());
System.out.println("请求头中键为Host的值:" + req.getHeader("Host"));
//重点
//通过键获取值: 1.queryString;
// 访问路径: request?username=hh&password=123
System.out.println("username: " + req.getParameter("username"));
System.out.println("password: " + req.getParameter("password"));
//响应给客户端的内容
resp.getWriter().println("请求信息已获取,在idea后端控制台查看");
可以在后端查看打印内容:
通过 fiddler 抓包查看:
注意: http 请求时,url 会进行编码,获取 queryString 中的中文,空格,特殊字符,就需要进行解码
举例 form 表单提交,没有设置请求方法,默认为 GET,会把 form 中的控件以name为键,用户输入/选择 的内容为值,设置到 queryString 中
<body>
<h3>get with query string</h3>
<form action="request">
<input type="text" name="username" placeholder="请输入用户名">
</br>
<input type="password" name="password" placeholder="请输入密码">
</br>
<input type="submit" value="提交">
</form>
</body>
其他与上述例子保持一致
由于前端代码可以立即生效,所以不需要进行重启,直接对页面进行刷新即可:
查看后端打印内容:
2).获取body中表单格式
表单格式: body中的数据,格式和 queryString 是一样的
修改前端代码:
<h3>表单提交</h3>
<form action="request" method="post">
<input type="text" name="username" placeholder="请输入用户名">
</br>
<input type="password" name="password" placeholder="请输入密码">
</br>
<input type="submit" value="提交">
</form>
刷新页面,提交表单:
提交后会发现方法不允许,出现405错误
后端代码,是 GET 方法,而我们前端代码写的是 post
思考: 如何在不改 doGet方法的前提下,使其同时支持 post 方法??
// 既支持 get, 也支持 post
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
doGet(req, resp);
重新启动,然后输入用户名和密码:
查看后端输出:
观察上图,会发现,出现了乱码的情况
注意: body 中的内容也是有编码格式的,需要设置一下才能正常显示:
req.setCharacterEncoding("utf-8"); //设置body解析的编码格式
System.out.println("username: " + req.getParameter("username"));
System.out.println("password: " + req.getParameter("password"));
重新启动,刷新页面查看:
此时不再出现乱码情况:
3).获取form-data中的简单数据类型的数据
修改前端代码:
<h3>fomr-data格式</h3>
<form action="request" 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>
刷新页面:
查看后端输出:
通过抓包查看:
添加后端代码:
@WebServlet("/form-data")
@MultipartConfig //form-data 格式需要使用这个注解
public class FormDataServlet extends HttpServlet
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
// request.getParameter 也可以获取 form-data 中的简单类型数据
req.setCharacterEncoding("utf-8"); // 设置body解析的编码格式
System.out.println("username: " + req.getParameter("username"));
System.out.println("password: " + req.getParameter("password"));
重新启动,刷新页面:
重点: http请求数据,存放的位置
- url queryString
- body(多种类型)
2.getPart 方法
获取form-data格式中,上传的文件
上传文件,若直接采用getParameter()来获取,是获取不到的
举例:
<h3>fomr-data格式 上传文件</h3>
<form action="form-data" enctype="multipart/form-data" method="post">
<input type="text" name="username" placeholder="请输入用户名">
</br>
<input type="password" name="password" placeholder="请输入密码">
</br>
选择头像: <input type="file" name="head" accept="image/*">
<input type="submit" value="提交">
</form>
@WebServlet("/form-data")
@MultipartConfig //form-data 格式需要使用这个注解
public class FormDataServlet extends HttpServlet
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
// request.getParameter 也可以获取 form-data 中的简单类型数据
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"));
通过 fiddler 抓包:
form-data 中上传的文件必须需要通过 getPart 来获取,getParameter 无法获取到
简单类型的数据其实也可以使用getPart获取,但还需要调用 part 对象api来获取内容,比较复杂
- 获取上传文件的二进制数据,转换为字符串打印
(通过 part 对象的输入流读取)
Part head = req.getPart("head");
// 获取上传文件的二进制数据,转换为字符串打印
InputStream is = head.getInputStream(); // 获取输入流(里边包含了数据)
// 输入流.available 返回包含的数据长度
byte[] bytes = new byte[is.available()];
// 从输入流中把数据读取到 byte[]中,字节数组对象就有了这些数据
is.read(bytes);
System.out.println(new String(bytes,"utf-8"));
后台打印出来的二进制数据,部分截图:
- 直接将客户端上传的文件,保存在服务端本地 (不读取,直接保存)
注意要将上述代码注释掉,否则不能用
// 直接把客户端上传的文件,保存在服务器本地
head.write("D://"+head.getSubmittedFileName());
注意: 若这个路径已经有这个文件,那么就会报错
重新启动,刷新页面,输入用户名和密码,选择图片,进行提交,成功之后就会在对应的目录下找到刚才保存的图片
3.getInputStream 方法
获取请求正文body的数据(输入流中包含了这些数据),不管什么格式,只要是在body中,都可以获取到;只是表单格式没有必要使用这个方式来获取(比较麻烦,还要自己解析里边的多组键值对)
常用的场景:json格式
前端代码:
<body>
<h3>ajax提交json格式</h3>
<input type="text" id="ajax_username" placeholder="请输入用户名">
</br>
<input type="password" id="ajax_password" placeholder="请输入密码">
</br>
<button onclick="ajax_submit()">提交</button>
</body>
<script>
function ajax_submit()
let username = document.querySelector("#ajax_username");
let password = document.querySelector("#ajax_password");
let json =
username: username.value, // 键为username,值为对象的value属性
password: password.value,
;
ajax(
url: "ajax-json-servlet",
method: "post",
//body上为 json格式的字符串
contentType: "application/json",
// JSON.stringify(json) 是将一个json对象序列化成一个字符串,格式是json格式
body: JSON.stringify(json),
callback: function(status,resp)
alert("后端返回的内容: " + resp)
);
function ajax(args)//var ajax = function()
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>
后端代码:
@WebServlet("/ajax-json-servlet")
public class AjaxJsonServlet extends HttpServlet
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
req.setCharacterEncoding("utf-8"); //获取请求body数据,先设置编码
// request.getInputStream 获取请求正文的数据 (不管Content-Type是什么类型,都可以获取)
// 表单格式也可以使用此 API 获取,比较复杂
// json是使用这个 api 比较典型的场景
InputStream is = req.getInputStream();
//先定义一个 byte 数组
int len = req.getContentLength(); //也可以通过getHeader("Content-Length")获取,只是返回的是字符串相对麻烦一点
byte[] bytes = new byte[len];
is.read(bytes);
System.out.println("获取的json数据:" + new String(bytes,"utf-8"));
重新启动,刷新页面:
输入用户名密码,提交:
后端打印内容:
可以抓包检查:
其实,拿到整个 json 字符串也不方便使用,如: 要判断账号密码是否正确
即:到目前为止,服务器拿到的 JSON 数据仍然是一个整体的 String 类型,若要想获取到 username 和 password 的具体值,还需要搭配 JSON 库进一步解析
常用的方式:使用第三方库
可以把 json字符串,转换为一个java对象;
还可以把一个java对象,转换为json字符串(响应的时候就有用)
引入 Jackson 这个库,进行 JSON 解析
- 在中央仓库中搜索 JackSon Databind
- 把中央仓库中的依赖配置添加到 pom.xml 中
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.3</version>
</dependency>
修改后端代码:
@WebServlet("/ajax-json-servlet")
public class AjaxJsonServlet extends HttpServlet
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
req.setCharacterEncoding("utf-8"); //获取请求body数据,先设置编码
InputStream is = req.getInputStream();
ObjectMapper mapper = new ObjectMapper();
// 简单暴力 直接转换为 map对象
Map json = mapper.readValue(is, Map.class);
System.out.println("获取的json字符串转换的map:" + json);
重新启动,刷新页面,提交数据,查看打印结果:
Map 使用其实也不太方便,若要使用指定的字符串键来获取值,再修改后端代码:
@WebServlet("/ajax-json-servlet")
public class AjaxJsonServlet extends HttpServlet
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
req.setCharacterEncoding("utf-8"); //获取请求body数据,先设置编码
InputStream is = req.getInputStream();
ObjectMapper mapper = new ObjectMapper();
User user = mapper.readValue(is,User.class)在Myeclipse buildpath 加server lib (server runtime)/项目导入时报错:The import javax.servlet.http.HttpServletR