在Servlet中,我们是重写doGet方法来处理浏览器的Get请求。
但是如果重写的是doPost方法,那么服务器就只能处理Post方法,如果此时浏览器发送Get方法,会出现405(方法不允许)错误。
eg:

常见的浏览器发送GET请求的情况:
- 通过URL向服务器请求
- 通过a标签跳转
- 通过img、link、script标签跳转
- 通过from表单,method指定为GET
- 通过ajax,type指定为GET
常见的浏览器发送POST请求的情况:
- 通过from表单,method指定为POST方法
- 通过ajax,type指定为POST
在编写服务器时,需要让请求方式和重写函数进行对应。
文章目录
1. Tomcat运行原理
首先,Tomcat的定位如下图:

Tomcat在处理请求的时候调用了servlet接口。
Tomcat是一个工作在用户态的普通Java进程,工作在JVM之上。
用户通过Servlet接口将自定义方法交给Tomcat,Toncat进而通过封装分用的方式交给浏览器。
Tomcat工作流程
- Tomcat先从指定的目录中(webapps文件夹)找到所有要加载的Servlet类。
- 根据加载的类,给这些类创建Servlet实例
- 调用Servlet实例的初始化方法(init方法)
- 创建TCP 套接字,监听端口,循环等待客户端连接。每次有客户端连接时accept方法返回,tomcat将其插入到线程池中。
- 线程池中的线程执行Tomcat中处理HTTP请求方法.(doHttpRequest方法)
- 当循环获取链接结束后,Tomcat会循坏调用每一个Servlet的destory方法,这个方法在对象的生命周期中只会调用一次。
需要注意,这里的Tomcat正常流程会这样退出,如果Tomcat异常退出(进程被销毁),可能来不及调用destory方法。
Tomcat处理请求流程(doHttpRequest方法)
- 构造HTTP请求,响应对象。
请求req是通过读取socket中的数据,按照HTTP协议的请求解析,构造出一个对象。
响应resp实际上是空对象,需要服务器构造。 - 判断当前请求是否是静态文件,如果是静态方法,读取文件内容,将内容填充到resp对象中,返回给客户端。
- 如果是动态文件,首先根据请求的URL,来获取到使用那个Servlet类来处理这个请求。如果没有找到对应的类,返回404.
- 根据找到的Servlet对象,调用这个对象的service方法。
在这个service方法内部,又会进一步的调用doGet/doPost方法。
如果在这个过程中出现了未捕捉的异常,客户端提示500错误。这个异常被Tomcat处理。
Servlet对象service方法流程
- 根据当前请求的类型,使用条件判断来调用不同的方法eg:(doGet、doPost)
总结:
上述流程关于Servlet方法主要有三个,这就是Servlet的生命周期
- init:初始化阶段,对象创建好后,就会执行到,用户可以重写这个方法,来执行一些初始化逻辑。
- service:循环处理请求时,每个请求都要调用一次service。
- destory:退出接受循环,Tomcat准备结束前,调用这个方法来释放资源。

2. Servlet主要API(HttpServlet HttpServletRequest HttpServletResponse)
HttpServlet类
核心方法:
| 方法名称 | 调用时机 |
|---|---|
| init | HttpServlet实例化之后调用 |
| destroy | HttpServlet对象销毁时调用 |
| service | 收到HTTP请求时调用 |
| doGet | 收到GET请求时由service调用 |
| doPost | 收到POST请求时由service调用 |
| doPut/doDelete/… | 收到其他请求时由service调用 |
| eg: |
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 ServletPost extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// super.doPost(req, resp);
resp.setContentType("POST/html; charset=utf8");
resp.getWriter().write("POST 响应");
}
}
HttpServletRequest类
| 方法 | 描述 |
|---|---|
| String getProtocol() | 返回请求协议的名称和版本 |
| String getMethod() | 返回HTTP请求方法(GET、POST等) |
| String getRequestURI() | 从协议名称到HTTP请求第一行的查询字符串中,返回请求URL的一部分 |
| String getContextPath() | 返回请求上下文的请求URI部分 |
| String getQureryString() | 返回包含在路径后的请求URL中的查询字符串 |
| Enumeration getParammeterNames() | 请求中包含的参数名称的枚举 |
| String getParameter(String name) | 以字符串的形式返回请求参数的值,不存在为null |
| String[] getParameterValues(String name) | 返回一个字符串数组,包含了所有给定的请求参数的值 |
| Enumeration getHeaderNames() | 返回请求中包含的所有头名 |
| String getHeader(String name) | 返回指定请求头的值 |
| String getCharacterEncoding() | 返回请求主体使用的字符编码的名称 |
| String getContnetType() | 返回主题的MIME类型,不知道类型返回null |
| int getContentLength() | 以字节为单位返回请求主体的长度,并提供输出流,长度未知返回-1 |
| InputStream getInputStream() | 读取请求body内容,返回一个InputStream对象 |
eg:打印请求信息
import java.io.IOException;
import java.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/showRequest")
public class ShowRequest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
// super.doGet(req, resp);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("<h3> 首行部分 </h3>");
stringBuilder.append(req.getProtocol() + "<br>"); //协议的名称和版本
stringBuilder.append(req.getMethod() + "<br>"); //请求使用的方法
stringBuilder.append(req.getRequestURI() + "<br>"); //获取请求uri
stringBuilder.append(req.getContextPath() + "<br>"); //返回请求上下文的请求URI部分
stringBuilder.append(req.getQueryString() + "<br>"); //返回包含在路径后的请求URL中的查询字符串
stringBuilder.append("<h3> header 部分 </h3>");
Enumeration<String> headerNames = req.getHeaderNames(); //获取报头所有项名称
while (headerNames.hasMoreElements()) {
//迭代器遍历枚举元素
String name = headerNames.nextElement();
String value = req.getHeader(name); //获取HTTP报头对应名称的值
stringBuilder.append(name + ":" + value + "<br>");
}
// 将数据写到响应中
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write(stringBuilder.toString());
}
}

eg:获取GET请求中的参数
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/Parameter")
public class GetParameterServlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
// super.doGet(req, resp);
// /pParameter?userId=123&classId=450
String userid=req.getParameter("userId");
String classid=req.getParameter("classId");
resp.getWriter().write("userId="+userid+" classId="+classid);
}
}

需要注意的是如果是POST请求,数据在body上。body常见的格式为:
- x-www-form-urlencoded
- form-data
- json
如果是第一种body格式,服务器获取参数的方式和GET一样,使用getParameter
eg:
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/PostParameter")
public class PostParameter extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
// super.doPost(req, resp);
// userid=10&classid=20
String userid = req.getParameter("userId");
String classId = req.getParameter("classId");
resp.getWriter().write("userId:" + userid + " classId:" + classId + "Test");
}
}

如果是第三种body请求,即数据以json形式保存到body上。
这里借助第三方库来处理json格式数据,这里使用Jackson库
eg:首先通过JS构造jsion请求,之后在java后端上通过Jackson来解析。
import java.io.IOException;
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 com.fasterxml.jackson.databind.ObjectMapper;
//存放Json转化后的数据
class user {
public int userId;
public int classId;
}
@WebServlet("/postJson")
public class PostJson extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 创建jackson对象
ObjectMapper objectMapper = new ObjectMapper();
// 将字符串转化为Java对象,第一个参数是待转化的Json字符串,第二个参数是转化的类型
user msg = objectMapper.readValue(req.getInputStream(), user.class);
resp.getWriter().write("userId: " + msg.userId + " classId: " + msg.classId);
}
}
使用ajax构造json数据
<!doctype html>
<html lang="cn">
<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>测试Post响应</title>
</head>
<body>
<!-- ajax构造post请求 -->
<!-- 引入cdn -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<input type="text" id="userId"><br>
<input type="text" id="classId"><br>
<input type="submit" value="提交" id="submit">
<script>
let button = document.querySelector("#submit");
let userIdInput = document.querySelector("#userId");
let classIdInput = document.querySelector("#classId");
button.onclick = function () {
//获取输入框内容
$.ajax({
type: 'post',
url: 'postJson',
contentType: 'application/json',
// 将js对象转化为字符串
data: JSON.stringify({
userId: userIdInput.value,
classId: classIdInput.value
}),
success: function (body) {
console.log(body);
}
});
}
</script>
</body>
</html>

HttpServletResponse类
| 方法 | 描述 |
|---|---|
| void setStatus(int sc) | 为响应设置状态码 |
| void setHeader(String name,String value) | 设置一个带有给定的名称和值的 header.如果name 已经存在,则覆盖旧的值. |
| void addHeader(String name, String value) | 添加一个带有给定的名称和值的 header.如果name 已经存在,不覆盖旧的值,并列添加新的键值对 |
| void setContentType(String type) | 设置被发送到客户端的响应的内容类型。 |
| void setCharacterEncoding(String charset) | 设置被发送到客户端的响应的字符编码(MIME字符集)例如,UTF-8。 |
| void sendRedirect(String location) | 使用指定的重定向位置URL发送临时重定向响应到客户端。 |
| Printwriter getWriter() | 用于往body中写入文本格式数据. |
| OutputStream getOutputStream() | 用于往body中写入二进制格式数据. |
eg:实现网页自动刷新功能
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/states")
public class StatutsServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setStatus(200);
resp.getWriter().write("Hello");
resp.setHeader("Refresh", "1");
resp.getWriter().write("time: " + System.currentTimeMillis());
}
}

本文详细介绍了Servlet的工作原理,包括Tomcat如何处理请求及Servlet的生命周期。同时深入探讨了HTTPServlet类、HttpServletRequest类和HttpServletResponse类的主要方法及其应用。
)&spm=1001.2101.3001.5002&articleId=127275979&d=1&t=3&u=462c9c0c3b67479aa176dc2bc103aa8f)
1285

被折叠的 条评论
为什么被折叠?



