🎉🎉🎉点进来你就是我的人了
博主主页:🙈🙈🙈戳一戳,欢迎大佬指点!欢迎志同道合的朋友一起加油喔🤺🤺🤺
目录
1. HttpServlet类
2. HttpServletRequest
2.1 前后端交互
1. 获取query String
2.获取body (数据格式与query String一致)
3. .获取body (json数据格式)
3. HttpServletResponse
3.1 设置状态码
3.2 ⾃动刷新
3.3 重定向
Servlet API中包含了很多的内容,但我们主要用到的是以下三个类,HttpServlet,HttpServletRequest,HttpServletResponse
1. HttpServlet类
在写Servlet代码的时候,第一步是创建一个类,继承HttpServlet,并重写其中的方法
方法 | 调用时机 |
---|---|
init | 在HttpServlet实例化之后被调用一次 |
destroy | 在HttpServelet实例不再使用时调用一次 |
service | 收到HTTP请求时调用 (由service调用) |
doGet | 收到GET请求时调用 (由service调用) |
doPost | 收到POST请求时调用 (由service调用) |
doPut / doDelete… | 收到对应请求时调用 (由service调用) |
init方法: 该方法是在tomcat首次收到了该类相关联(访问/hello路径的请求)的请求时,就会调用到HelloServlet,就需要先对HelloServlet进行实例化,后续在收到请求时,不必再实例化了,直接复用之前的HelloServlet实例即可,只执行一次
destroy方法: 当HttpServlet实例不再使用时调用该方法,啥时候该实例就不再使用了?服务器只要不停止,该实例就一直被使用,只有当服务器停止后了,才会调用该方法,只执行一次
这里的destroy能否被执行到,是存在争议的:
如果是通过停止按钮,这个本质操作是通过tomcat的8005端口,主动停止,才能触发destroy
如果是直接杀死进程,此时就来不及执行destroy
所以不建议在destroy内执行有效代码
service: 收到HTTP请求就会调用 (进到父类 HttpServlet 里面查看)
Service中根据请求的类型不同,调用不同的方法,doGet,doPost方法等等,会执行多次,每收到一次HTTP请求就执行一次
Servlet的生命周期:
- 开始的时候执行init
- 每次收到请求后,执行service
- 销毁之前执行destroy
处理GET请求
- 直接在浏览器中,通过URL就能构造(GET请求最常用用法)
- 通过postman构造GET请求 (最简单)
- 通过ajax构造GRT请求
- 下面演示ajax构造Get请求,首先创建MethodServlet.java类, 创建 doGet 方法
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;
@WebServlet("/method")
public class HelloServlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("这是一个 doGet");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("这是一个doPost");
}
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("这是一个doPut");
}
@Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("这是一个doDelete");
}
}
创建 TestMethod.html, 放到 webapp 目录中,与WEB-INF处于同级关系
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
$.ajax({
type: 'get',
url: 'method',
success: function (body, status) {
console.log(body);
}
});
</script>
</body>
</html>
启动smart Tomcat一键打包部署后结果如下:
注意路径匹配:
我们还需要注意是否加 / 的问题
我们想要处理其他方法也是同理,在html中将type类型修改,HelloServlet2方法中重写对应方法即可,我们每次修改完代码之后都需要重启服务器
2. 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 中的查询字符串 |
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() | 返回请求body的长度 |
InputStream getInputStream() | 用于读取请求的 body 内容. 返回一个 InputStream 对象 |
- query string 是键值对结构,我们可以通过getParameter根据key获取到value
- 接下来就使用这些方法来将请求信息返回到浏览器上
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;
@WebServlet("/showRequest")
public class ShowRequestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
// 此处返回一个 HTML, 在 HTML 里面显示刚才看到的这些 API 的接口
// 把这些 API 的返回结果往这个 StringBuilder 里面来拼
StringBuilder html = new StringBuilder();
html.append(req.getProtocol()); // HTTP版本号
html.append("<br>");
html.append(req.getMethod()); // 方法
html.append("<br>");
html.append(req.getRequestURI()); // 请求路径
html.append("<br>");
html.append(req.getContextPath()); // 上下文路径
html.append("<br>");
html.append(req.getQueryString()); // QueryString
html.append("<br>");
html.append("<br>");
html.append("<br>");
html.append("<br>");
// 获取到请求的 header 头
Enumeration<String> headers = req.getHeaderNames();
// 请求中的 header 是一组键值对结构,循环相当于拿到键值对中所有的 key
while (headers.hasMoreElements()) {
String headerName = headers.nextElement();
html.append(headerName);
html.append(":");
html.append((req.getHeader(headerName))); // 根据 key 来获取 value
html.append("<br>");
}
resp.getWriter().write(html.toString());
}
}
浏览器响应结果如下:
2.1 前后端交互
- GET请求传参通过query string
- POST请求传参通过form表单
- POST请求传参通过json
我们下来演示一下上述三种方法,前端给后端传参,我们后端获取请求中传来的参数
1. 获取query String
- 前端直接通过地址栏构造一个URL发送给后端
- 请求参数(useId = 10 & classId = 001)放在url的query string中
- 后端重新doGET()使用getParameter()方法获取key (used / classld)对应的value (10 / 001)
- 然后将数据返回给浏览器
@WebServlet("/getParameter")
public class GetParameterServelet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//使用getParameter获取前端query string的数据 useId = 10 & classId = 001
String userId = req.getParameter("useId");
String classId = req.getParameter("classId");
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write(userId +", " + classId);
}
}
浏览器响应结果如下:
这里请求中的query string键值对会被tomcat处理成形似map结构的数据,我们就可以通过key去获取value了,需要注意的是我们这里的value都是String类型的,如果我们getParameter的参数前端并没有传递,那么我们的value就是null
2.获取body (数据格式与query String一致)
- 通过form表单构造post请求
- 请求的参数(useId = 10 & classId = 001)放在body 中
- 后端重写doPost()使用getParameter()方法获取key (used / classld)对应的value (10 / 001)
- 然后将数据返回给浏览器
通过表单构造 get/post请求 详解可参考我上一篇博客(【HTTP协议】)
text.html里面使用form表单构造请求
<!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>使用form表单构建一个请求</title>
</head>
<body>
<form action="postParameter" method="post">
<input type="text" name="useId">
<input type="text" name="classId">
<input type="submit" value="提交">
</form>
</body>
</html>
后端接收请求并返回结果
@WebServlet("/postParameter")
public class PostParameterServelet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//使用getParameter获取前端body的数据 useId = 10 & classId = 001
String userId = req.getParameter("useId");
String classId = req.getParameter("classId");
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write(userId +", " + classId);
}
}
浏览器响应结果如下:
3. .获取body (json数据格式)
- postman构造出一个指定的post请求,body就是josn数据
- 请求到达tomcat,tomcat解析成req对象
- 在servlet代码中,req.getInputStream()读取body的内容
- 又把body内容构造成一个响应结果返回给浏览器(postman)
@WebServlet("/JsonParameter")
public class JsonParameterServelet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//通过这个方法处理body为json格式的数据
//直接把req对象里的body完整的读出来
// 1.先拿到body的长度,单位是字节
int length = req.getContentLength();
// 2.准备一个字节数组,来存放body的内容
byte[] buffer = new byte[length];
// 3.获取到InputStream对象
InputStream inputStream = req.getInputStream();
// 4. 读取数据,从InputStream对象中,读到数据,放到buffer这个数组中
inputStream.read(buffer);
//把这个数组构造成String,打印出来
String body = new String(buffer,0,length,"utf8");
System.out.println("body = "+body);
resp.getWriter().write(body);
}
}
通过postman构造请求(body为josn格式),服务器返回body给postman
当前通过 json 传递数据, 服务器这边只是把整个 body 读出来, 没有按照键值对的方式来处理.(还不能根据 key 获取 value),如果响应通过key获取value此时需要借助第三方库来处理。
引入依赖:Jackson这个库在在中央仓库中获取(Jackson地址)。
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.1</version>
</dependency>
将这段代码复制到pom.xml里面就可了。
JsonParameterServlet.java 文件
class Student {
public String userId;
public String classId;
@Override
public String toString() {
return "Student{" +
"userId='" + userId + '\'' +
", classId='" + classId + '\'' +
'}';
}
}
@WebServlet("/JsonParameter")
public class JsonParameterServelet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//通过这个方法处理body为json格式的数据
//直接把req对象里的body完整的读出来
// 1.先拿到body的长度,单位是字节
// int length = req.getContentLength();
// // 2.准备一个字节数组,来存放body的内容
// byte[] buffer = new byte[length];
// // 3.获取到InputStream对象
// InputStream inputStream = req.getInputStream();
// // 4. 读取数据,从InputStream对象中,读到数据,放到buffer这个数组中
// inputStream.read(buffer);
// //把这个数组构造成String,打印出来
// String body = new String(buffer,0,length,"utf8");
// System.out.println("body = "+body);
//使用json涉及到的核心对象
ObjectMapper objectMapper = new ObjectMapper();
//readValue 就是把一个 json 格式的字符串 转成java对象
Student student = objectMapper.readValue(req.getInputStream(),Student.class);
resp.getWriter().write(student.toString());
System.out.println(student.userId+", "+student.classId);;
}
}
注意:Jackson库的核心类为ObjectMapper。
3. HttpServletResponse
核心方法:
方法 | 描述 |
---|---|
void setStatus(int sc) | 给响应设置状态码 |
void setHeader(String name,String value) | 设置一个header,如果存在覆盖value |
void addHeader(String name,String value) | 添加一个带有给定的名称和值的 header. 如果 name 已经存在,不覆盖旧的值, 并列添加新的键值对 |
void setContentType(String type) | 设置被发送到客户端的响应的内容类型。 |
void setCharacterEncoding(String charset) | 设置被发送到客户端响应的字符编码 (例如utf-8) |
void sendRedirect(String location) | 使用重定向位置URL发送临时重定向给客户端 |
PrintWriter getWriter() | 往body中写入文本数据 |
OutputStream getOutputStream() | 往body写入二进制数据 |
3.1 设置状态码
@WebServlet("/state")
public class StateServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf8");
int status=404;
resp.setStatus(status);
//resp.getWriter().write("响应状态码是"+status);
//返回tomcat自带的错误页面
//resp.sendError(404);
}
}
3.2 ⾃动刷新
@WebServlet("/refresh")
public class RefreshServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//告诉浏览器1秒刷新一次
resp.setHeader("Refresh", "1");
resp.getWriter().println("" + LocalDateTime.now());
}
}
下面浏览器每秒钟会自动刷新一次:
3.3 重定向
实现一个程序, 返回一个重定向 HTTP 响应, 自动跳转到另外一个页面.
@WebServlet("/redirect")
public class RediractServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//实现重定向,让浏览器自动跳转到百度浏览器
resp.setStatus(302);
resp.setHeader("Location","https://www.baidu.com");
//另一种更简单的重定向写法
//resp.sendRedirect("https://www.baidu.com");
}
}
输入敲下回车之后,跳转到百度主页
fiddler抓包结果如下: