Servlet与HttpServlet详解
一、Servlet概述
Servlet(Server Applet)是Java Servlet API中定义的一个接口,用于扩展Web服务器的功能。Servlet是一个运行在Web服务器或应用服务器上的Java程序,它可以动态地生成Web页面或其他类型的响应。
二、HttpServlet类
HttpServlet
类是Java Servlet API中的一个核心类,它继承自GenericServlet
类,实现了Servlet
接口,并为HTTP协议提供了特定的实现。HttpServlet
类的主要职责是处理HTTP请求和构建HTTP响应。
HttpServlet的主要方法
-
service(ServletRequest req, ServletResponse res)
这是Servlet接口中的核心方法,所有来自客户端的请求首先都会调用此方法。
HttpServlet
为这个方法提供了默认实现,它会根据请求的类型(GET、POST等)调用对应的doXXX
方法。 -
doGet(HttpServletRequest request, HttpServletResponse response)
用于处理HTTP GET请求。
-
doPost(HttpServletRequest request, HttpServletResponse response)
用于处理HTTP POST请求。
-
doPut , doDelete , doOptions , doHead , doTrace 等
这些方法用于处理其他类型的HTTP请求,但在常见的Web应用中很少直接使用。
-
init(ServletConfig config)
Servlet的初始化方法,当Servlet实例被加载到内存并准备使用时,容器会调用此方法。
-
destroy()
Servlet的销毁方法,当Servlet实例不再需要并被容器卸载时,容器会调用此方法。
HttpServlet处理流程
-
部署Servlet
- 开发者编写Servlet类,继承自
HttpServlet
并覆盖相应的方法。 - 在Web应用的
web.xml
文件中配置Servlet的映射路径和初始化参数等信息。 - 将Web应用打包成WAR文件并部署到Servlet容器中(如Tomcat)。
- 开发者编写Servlet类,继承自
-
客户端请求
- 客户端(如Web浏览器)发送HTTP请求到Servlet容器。
- 请求中包含URL、HTTP方法(GET、POST等)、请求头、请求体等信息。
-
容器调度
- Servlet容器接收到请求后,解析URL路径,找到与之匹配的Servlet实例。
- 如果Servlet实例不存在,容器会创建一个。
-
调用service方法
- Servlet容器调用Servlet实例的
service
方法,并传入HttpServletRequest
和HttpServletResponse
对象。 HttpServletRequest
对象包含了请求的所有信息,如参数、头信息等。HttpServletResponse
对象用于构建并发送HTTP响应。
- Servlet容器调用Servlet实例的
-
处理请求
- 根据请求的类型(如GET、POST),
service
方法会调用相应的doXXX
方法。 - 开发者在
doXXX
方法中实现业务逻辑,如访问数据库、处理数据等。
- 根据请求的类型(如GET、POST),
-
构建响应
- 开发者使用
HttpServletResponse
对象设置响应的状态码、响应头、响应体等。 - 可以向响应体写入HTML、JSON、XML等格式的数据。
- 开发者使用
-
发送响应
- Servlet容器将
HttpServletResponse
对象封装成HTTP响应,并通过网络发送给客户端。 - 客户端接收到响应后,会显示在Web浏览器上或进行其他处理。
- Servlet容器将
-
Servlet生命周期结束
- 当Servlet实例不再需要时(如Web应用被卸载),容器会调用
destroy
方法,允许开发者进行资源清理工作。
在Servlet API中,service
方法是Servlet容器(如Tomcat)用来调用特定HTTP方法处理程序的入口点。当客户端发送一个HTTP请求到Servlet容器时,容器会解析请求,确定它是哪种类型的HTTP方法(如GET、POST、PUT、DELETE等),然后调用相应的doXXX
方法。
- 当Servlet实例不再需要时(如Web应用被卸载),容器会调用
service
方法是一个重要的方法,它根据客户端发送的HTTP请求类型(如GET、POST等)调用相应的doXXX
方法。以下是HttpServlet
类中service
方法的实现:
java
@Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
// 将ServletRequest和ServletResponse强制转换为HttpServletRequest和HttpServletResponse
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
} catch (ClassCastException e) {
throw new ServletException("Cannot cast to HttpServletRequest/HttpServletResponse");
}
// 获取HTTP请求方法
String method = request.getMethod();
if (method.equalsIgnoreCase("GET")) {
// 如果是GET请求,调用doGet方法
long lastModified = getLastModified(request);
if (lastModified == -1) {
// 标记响应不被缓存
response.setDateHeader("Expires", -1);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
} else {
// 检查If-Modified-Since头以判断是否发送304 Not Modified响应
long ifModifiedSince = request.getDateHeader("If-Modified-Since");
if (ifModifiedSince < (lastModified / 1000 * 1000)) {
// 资源已修改,发送新内容
maybeSetLastModified(response, lastModified);
} else {
// 资源未修改,发送304 Not Modified响应
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
return;
}
}
doGet(request, response);
} else if (method.equalsIgnoreCase("HEAD")) {
// 如果是HEAD请求,调用doHead方法
long lastModified = getLastModified(request);
maybeSetLastModified(response, lastModified);
doHead(request, response);
} else if (method.equalsIgnoreCase("POST")) {
// 如果是POST请求,调用doPost方法
doPost(request, response);
} else if (method.equalsIgnoreCase("PUT")) {
// 如果是PUT请求,调用doPut方法
doPut(request, response);
} else if (method.equalsIgnoreCase("DELETE")) {
// 如果是DELETE请求,调用doDelete方法
doDelete(request, response);
} else if (method.equalsIgnoreCase("OPTIONS")) {
// 如果是OPTIONS请求,调用doOptions方法
doOptions(request, response);
} else if (method.equalsIgnoreCase("TRACE")) {
// 如果是TRACE请求,调用doTrace方法
doTrace(request, response);
} else {
// 对于不支持的HTTP方法,抛出ServletException
throw new ServletException("HTTP method " + method + " is not supported");
}
}
这个service
方法首先检查传入的ServletRequest
和ServletResponse
是否可以安全地强制转换为HttpServletRequest
和HttpServletResponse
。接着,它获取HTTP请求的方法(如GET、POST等),并根据这个方法调用相应的doXXX
方法。如果请求方法是GET,它还会检查If-Modified-Since
头以判断是否发送304 Not Modified响应。
对于不支持的HTTP方法,service
方法会抛出一个ServletException
。通常,开发者会覆盖doGet
、doPost
等方法来提供具体的业务逻辑,而service
方法则负责调度这些方法。
三、示例代码
下面是一个简单的HttpServlet
示例,展示了如何处理GET请求:
java
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 设置响应内容类型
response.setContentType("text/html;charset=UTF-8");
// 实际的逻辑是在这里
String message = "<html><body><h1>Hello, World!</h1></body></html>";
// 将响应体写入到response对象中
response.getWriter().write(message);
}
}
在这个示例中,MyServlet
类继承了HttpServlet
类,并重写了doGet()
方法。当容器接收到一个GET请求时,它会调用doGet()
方法来处理请求。在doGet()
方法中,我们设置了响应的内容类型为HTML,并构建了一个简单的HTML消息作为响应体。