HttpServlet
init:当 tomcat 收到了 /hello 这样的路径是请求后就会调用 HelloServlet,于是就需要对 HelloServlet 进行实例化(只实例一次,后续再有请求也不实例了)。
destory:如果是通过 smart tomcat 的停止按钮,这个操作本质上是通过 tomcat 的 8005 端口主动停止,能够触发 destory。但如果是直接杀进程,此时很可能来不及执行 destory(这种情况比较常见)。
service:每次收到请求都会先执行 service,然后再根据请求的类型调用对应的 doxxx。
因此:Servlet 的生命周期就可以理解为:1. 一开始的时候,执行 init;2. 每次收到请求,执行 service;3. 销毁之前,执行 destory。
处理请求
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 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");
}
}
这里默认是 get 请求,为了构造别的方法请求可以使用 postman 来构造,也可以通过 Ajax 写代码来进行构造
postman
Ajax
首先得在 webapp 目录下创建一个 .html 的文件
<!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.7.1/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
当 Tomcat 通过 Socket API 读取 HTTP 请求(字符串), 并且按照 HTTP 协议的格式把字符串解析成 HttpServletRequest 对象.
:因为 query string 是键值对形式(form 表单构造的 body 也是),所以就可以通过 getParameter 放法来根据 key 获取到 value。
获取 GET 请求中的参数
GET 请求中的参数一般都是通过 query string 传递给服务器的. 形如:/getParameter?studentId=10&classId=20
此时浏览器通过 query string 给服务器传递了两个参数, studentId 和 classId, 值分别是 10 和 11,此时在服务器端就可以通过 getParameter 来获取到参数的值.
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("/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");
resp.getWriter().write("studentId = " + studentId + " classId = " + classId);
}
}
getParameter 的返回值类型为 String. 必要的时候需要手动把 String 转成 int 。当没有 query string的时候, getParameter 获取的值为 null.
获取 POST 请求中的参数
POST 请求的参数一般通过 body 传递给服务器. body 中的数据格式有很多种. 如果是采用 form 表单的形式, 仍然可以通过 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;
@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");
resp.getWriter().write("studentId = " + studentId + " classId = " + classId);
}
}
创建 testPost.html, 放到 webapp 目录中:
<form action="postParameter" method="POST">
<input type="text" name="userId">
<input type="text" name="classId">
<input type="submit" value="提交">
</form>
form 表单点击 提交 一定会发生页面跳转的
获取 POST 请求中的参数(2)
如果 POST 请求中的 body 是按照 JSON 的格式来传递, 那么获取参数的代码就要发生调整。因为通过 json 传递数据,服务器这边默认是把整个 body 都读过来,即没有按照键值对的方式来处理,也就不能根据 key 获取 value。
因此,要使用第三方库 “Jackson” 来解析 json 格式。在 maven 仓库里搜 Jackson,然后选一个版本点进去把 xml 片段粘贴到 pom.xml 的 <dependencies> 中即可。
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;
class Student {
// 把属性设为 public 的原因是能让 外面的Jackson 获取到这里有什么属性
public int studentId;
public int classId;
}
@WebServlet("/postParameter2")
public class PostParameter2Servlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 这段注释的代码是没有时候第三方库 Jackson 的,得到的是没有被处理过的 json
// 通过这个方法来处理 body 为 json 格式的数据.
// 直接把 req 对象里 body 完整的读取出来.
// getInputStream
// 在流对象中读多少个字节? 取决于 Content-Length
// int length = req.getContentLength();
// byte[] buffer = new byte[length];
//
// InputStream inputStream = req.getInputStream();
// inputStream.read(buffer);
//
// // 把这个字节数组构造成 String, 打印出来.
// String body = new String(buffer, 0, length, "utf8");
// System.out.println("body = " + body);
// resp.getWriter().write(body);
// 使用 jackson 涉及到的核心对象.
ObjectMapper objectMapper = new ObjectMapper();
// readValue 就是把一个 json 格式的字符串转成 Java 对象.
// writeValue 把一个 java 对象转成 json 格式字符串
Student student = objectMapper.readValue(req.getInputStream(), Student.class);
System.out.println(student.studentId + ", " + student.classId);
}
}
HttpServletResponse
Servlet 中的 doXXX 方法的目的就是根据请求计算得到相应, 然后把响应的数据设置到
HttpServletResponse 对象中. 然后 Tomcat 就会把这个 HttpServletResponse 对象按照 HTTP 协议的格式, 转成一个字符串, 并通过 Socket 写回给浏览器.
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("/redirect")
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// resp.sendRedirect("https://www.bilibili.com"); // 这是直接构造了重定向响应
// 上面的一行代码也可以分成下面两行:先设置状态码,然后再设置需要跳转到哪里
resp.setStatus(302);
resp.setHeader("Location", "https://www.bilibili.com");
}
}