目录
- 一. 构造HTTP请求的方式
- 1.1 使用 Postman 来构造请求
- 1.2 使用ajax 来构造请求
- 二 . HttpServletRequest API
- 使用api实现前后端交互
- 1 . 通过 GET 请求 query string 进行传参
- 2 . POST请求 form 表单传参 (body)
- 3 . Post 请求的 json 格式的数据传参(body)
一. 构造HTTP请求的方式
1.1 使用 Postman 来构造请求
import javax.jws.WebService;
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.net.HttpCookie;
/**
* Created with IntelliJ IDEA.
* Description:
* User: snutyx
* Date: 2023-03-19
* Time: 17:07
*/
@WebServlet("/method")
public class MethodServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doGet()");
resp.getWriter().write("doGet()");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doPost");
resp.getWriter().write("doPost()");
}
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doPut()");
resp.getWriter().write("doPut()");
}
@Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doDelete()");
resp.getWriter().write("doDelete()");
}
}
- 启动tomcat服务器
- 启动成功 , 构造请求
- 构造 get 请求
返回响应
postman 是我们在后端开发过程中非常好用的工具 ,后端在公司中主要就是实现一些 http 接口 , 前端发送对应的请求 , 后端就通过 postman 进行验证和测试 。
1.2 使用ajax 来构造请求
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!-- 使用这个页面来构造 ajax 请求 -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script>
$.ajax({
type:'get',
//相对路径的写法 : url : 'method',
//绝对路径的写法 :
url: '/hello_servlet/method',
success:function(body,status){
console.log(body);
}
});
</script>
</body>
</html>
同理 , 构造post请求, 只需要修改对应的 type即可 。
编写 tomcat 代码时 , 每次修改都需要重新启动服务器
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!-- 使用这个页面来构造 ajax 请求 -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script>
$.ajax({
type:'post',
//相对路径的写法 : url : 'method',
//绝对路径的写法 :
url: '/hello_servlet/method',
success:function(body,status){
console.log(body);
}
});
</script>
</body>
</html>
二 . HttpServletRequest API
- 常用方法
方法 | 描述 |
---|---|
String getProtocol() | 返回请求协议的名称和版本。 |
String getMethod() | 返回请求的 HTTP 方法的名称,例如,GET、POST 或 PUT。 |
String getRequestURI() | 从协议名称直到 HTTP 请求的第一行的查询字符串中,返回该请求的 URL 的一部分。 |
String getContextPath() | 返回指示请求上下文的请求 URI 部分。 |
String getQueryString() | 返回包含在路径后的请求 URL 中的查询字符串。 |
Enumeration getParameterNames() | 返回一个 String 对象的枚举,包含在该请求中包含的参数的名称。 |
String getParameter(String name) | 以字符串形式返回请求参数的值,或者如果参数不存在则返回 null。 |
String[] getParameterValues(String name) | 返回一个字符串对象的数组,包含所有给定的请求参数的值,如果参数不存在则返回 null。 |
Enumeration getHeaderNames() | 返回一个枚举,包含在该请求中包含的所有的头名。 |
String getHeader(String name) | 以字符串形式返回指定的请求头的值。 |
String getCharacterEncoding() | 返回请求主体中使用的字符编码的名称。 |
String getContentType() | 返回请求主体的 MIME 类型,如果不知道类型则返回 null。 |
int getContentLength() | 以字节为单位返回请求主体的长度,并提供输入流,或者如果长度未知则返回 -1。 |
InputStream getInputStream() | 用于读取请求的 body 内容。返回一个 InputStream 对象。 |
使用 HttpServletRequest API 来简单获取一个HTTP 请求的内容
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.Enumeration;
/**
* 测试 HttpServlet 中的相关 api
*/
@WebServlet("/showRequest")
public class ShowRequestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 这里是设置响应的 content-type. 告诉浏览器, 响应 body 里的数据格式是啥样的.
resp.setContentType("text/html");
// 搞个 StringBuilder, 把这些 api 的结果拼起来, 统一写回到响应中.
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(req.getProtocol());
stringBuilder.append("<br>");
stringBuilder.append(req.getMethod());
stringBuilder.append("<br>");
stringBuilder.append(req.getRequestURI());
stringBuilder.append("<br>");
stringBuilder.append(req.getContextPath());
stringBuilder.append("<br>");
stringBuilder.append(req.getQueryString());
stringBuilder.append("<br>");
stringBuilder.append("<br>");
stringBuilder.append("<br>");
stringBuilder.append("<br>");
// 获取到 header 中所有的键值对
Enumeration<String> headerNames = req.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
stringBuilder.append(headerName + ": " + req.getHeader(headerName));
stringBuilder.append("<br>");
}
resp.getWriter().write(stringBuilder.toString());
}
}
响应结果 :
使用api实现前后端交互
使用 getParameter() 方法 , 既可以获取 GET 请求中 query string 中的键值对 , 也可以获取 POST 请求中的 form 表单构造的 body 中的键值对
1 . 通过 GET 请求 query string 进行传参
通过前端给后端传入数据 , studentId 和 classId
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;
/**
* Created with IntelliJ IDEA.
* Description:
* User: snutyx
* Date: 2023-03-19
* Time: 18:43
*/
@WebServlet("/getParameter")
public class GetParameterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 预期浏览器会发一个形如 /getParameter?studentId=10&classId=20 请求.
// 借助 req 里的 getParameter 方法就能拿到 query string 中的键值对内容了.
// getParameter 得到的是 String 类型的结果.
String studentId = req.getParameter("studentId");
String classId = req.getParameter("classId");
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("学生ID = "+studentId+"班级ID = "+ classId);
}
}
当设置的 url 的querystring 为空时 :
query string 不为空时
这里的query string 键值对 ,会自动被tomcat处理成 Map这样的结构 , 后续就可以随时通过 key 获取 value , 如果key 在query string 中不存在 ,返回 null .
2 . POST请求 form 表单传参 (body)
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!-- 这里的 action 指的是路径,规定当提交表单时向何处发送表单数据。
method 规定用于发送 form-data 的 HTTP 方法 -->
<form action="postParameter" method="post">
<input type="text" name="studentId">
<input type="text" name="classId">
<input type="submit" value="提交">
</form>
</body>
</html>
此时点击提交之后就构造出了一个 post 请求 , post请求的 body就是form表单中的内容 , 此时通过 Fiddler 抓包就可以完整的显示出请求报文
因为此时我们还未编写 postParameter , 所以此时的页面显示 404
form 表单中的 action 决定了路径 , method 决定了 http请求的类型, input中的name 决定了body中的键值对 中key , 提交的内容决定了 body中的键值对 中value;
Content-type决定了这是由 form 表单构成的请求 。
后端 PostParameter 代码:
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;
/**
* Created with IntelliJ IDEA.
* Description:
* User: snutyx
* Date: 2023-03-19
* Time: 19:29
*/
@WebServlet("/postParameter")
public class PostParameterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String studentId = req.getParameter("studentId");
String classId = req.getParameter("classId");
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("学生Id = "+ studentId+"班级Id = "+ classId);
}
}
3 . Post 请求的 json 格式的数据传参(body)
json 是一种非常主流的数据格式 , 也是键值对结构 , 通过使用 getInputStream() 来获取 请求的流对象 , 再将流对象存入字节数组当中,最后构造成字符串之后打印出来 。
import sun.awt.windows.WBufferStrategy;
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("/postparameter2")
public class PostParameter2Servlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 此方法用来处理 body 为 json 格式的数据。
// 直接把 req 对象里的 body 完整的读取出来
// 使用 getInputStream 来获取 body 的内容并返回一个流对象
// 流对象中的字节数目取决于 content-length
int length = req.getContentLength();
byte[] buffer = new byte[length];
// 读取操作
InputStream inputStream = req.getInputStream();
// 读取到的字节传入 buffer 数组当中
inputStream.read(buffer);
// 把字节数组构造成 string 打印出来
String body = new String(buffer,0,length,"utf8");
System.out.println("body = "+body);
resp.getWriter().write(body);
}
}
此处我们可以使用 ajax 来构造请求 , 同时也可以使用 postman 来构造请求 ,进行处理 post 请求中的 body 中 json 格式 , 最后返回响应 。
- 使用 postman 构造 指定post 请求 , body 就是 json 数据
使用 fiddler 进行抓包 , 得到的请求报文的格式如下
请求到达 tomcat , tomcat 解析成 req 对象 , 在servlet 代码当中 req. getInputStream() 读取 body 的内容 , 将 body 的内容转化为 字符串 写入响应 的body 并返回给客户端,显示在浏览器当中 。
控制台打印 body 的内容 , 并返回响应给客户端(postman)
使用 json 格式的数据与 form 表单传参有一定的区别 , 但是三种方式基本是等价的 。
//form 表单传参
studentId=20 && classId=10
//json 格式的传参
{
"studentId" : 20,
"classId" : 10
}
但是通过 json 进行传递数据,服务器这边只是把整个 body 读出来, 没有按照键值对的方式进行处理,还不能够通过 key 获取 value , form 表单可以通过 key 来获取value , 此时就需要引入第三库来解析 json 格式 ,比如 jackson ,gson 等
- 引入 jackson 来解析json格式
通过 maven 来引入第三方库 ,中央仓库中搜索 jackson ,找到Jackson DataBind
选择合适的版本,此处我们选择 2.14.1
将 一下内容复制到 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.14.1</version>
</dependency>
配置完成之后 , 重新编写服务器的相关代码 ,
import com.fasterxml.jackson.databind.ObjectMapper;
import sun.awt.windows.WBufferStrategy;
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;
// 创建一个 student 类 , 属性名字需要和 json 中的key 一致
// 也可以写为 private ,但是需要提供 getter and setter 方法
class Student{
public int studentId;
public int classId;
}
@WebServlet("/postparameter2")
public class PostParameter2Servlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
y);
// 使用 jackson 涉及到的核心对象 。
ObjectMapper objectMapper = new ObjectMapper();
// readvalue 就是把一个json 格式的字符串转化为 Java 对象
Student student = objectMapper.readValue(req.getInputStream(),Student.class);
System.out.println(student.studentId+ "," + student.classId);
// 返回响应
resp.getWriter().write("studentId: "+student.studentId+","+"classId: "+student.classId);
}
}
上述代码的核心代码就是将 一个 json 格式的字符串 转化为一个 java 对象 ,并赋予其相关属性 。
- 使用 req.getInputStream ()获取到的 json 格式的字符串
- 根据第二个参数对象创建 student 实例 。
- 通过这个类对象, 在 readValue 的内部就可以借助反射机制来构造出 Student 对象, 并将上树的字符串处理成 map 键值对结构。
- 遍历所有键值对,并且根据键值对中key 的名字, 把对应的 value 赋值给 student 的对应字段
- 返回该 student 实例
使用 postman 构造 指定post 请求
控制台打印 student 相关属性
响应成功 ,通过 key 获取到 value 的值
如果 json 格式中的属性在实现的类中不包含会出现什么情况 ?
响应如下 : 因为存在为定义的属性, 所以服务器端解析错误 。