HttpServlet详解

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的主要方法

  1. service(ServletRequest req, ServletResponse res)

    这是Servlet接口中的核心方法,所有来自客户端的请求首先都会调用此方法。HttpServlet为这个方法提供了默认实现,它会根据请求的类型(GET、POST等)调用对应的doXXX方法。

  2. doGet(HttpServletRequest request, HttpServletResponse response)

    用于处理HTTP GET请求。

  3. doPost(HttpServletRequest request, HttpServletResponse response)

    用于处理HTTP POST请求。

  4. doPut , doDelete , doOptions , doHead , doTrace

    这些方法用于处理其他类型的HTTP请求,但在常见的Web应用中很少直接使用。

  5. init(ServletConfig config)

    Servlet的初始化方法,当Servlet实例被加载到内存并准备使用时,容器会调用此方法。

  6. destroy()

    Servlet的销毁方法,当Servlet实例不再需要并被容器卸载时,容器会调用此方法。

HttpServlet处理流程

  1. 部署Servlet

    • 开发者编写Servlet类,继承自HttpServlet并覆盖相应的方法。
    • 在Web应用的web.xml文件中配置Servlet的映射路径和初始化参数等信息。
    • 将Web应用打包成WAR文件并部署到Servlet容器中(如Tomcat)。
  2. 客户端请求

    • 客户端(如Web浏览器)发送HTTP请求到Servlet容器。
    • 请求中包含URL、HTTP方法(GET、POST等)、请求头、请求体等信息。
  3. 容器调度

    • Servlet容器接收到请求后,解析URL路径,找到与之匹配的Servlet实例。
    • 如果Servlet实例不存在,容器会创建一个。
  4. 调用service方法

    • Servlet容器调用Servlet实例的service方法,并传入HttpServletRequestHttpServletResponse对象。
    • HttpServletRequest对象包含了请求的所有信息,如参数、头信息等。
    • HttpServletResponse对象用于构建并发送HTTP响应。
  5. 处理请求

    • 根据请求的类型(如GET、POST),service方法会调用相应的doXXX方法。
    • 开发者在doXXX方法中实现业务逻辑,如访问数据库、处理数据等。
  6. 构建响应

    • 开发者使用HttpServletResponse对象设置响应的状态码、响应头、响应体等。
    • 可以向响应体写入HTML、JSON、XML等格式的数据。
  7. 发送响应

    • Servlet容器将HttpServletResponse对象封装成HTTP响应,并通过网络发送给客户端。
    • 客户端接收到响应后,会显示在Web浏览器上或进行其他处理。
  8. Servlet生命周期结束

    • 当Servlet实例不再需要时(如Web应用被卸载),容器会调用destroy方法,允许开发者进行资源清理工作。
      在Servlet API中,service 方法是Servlet容器(如Tomcat)用来调用特定HTTP方法处理程序的入口点。当客户端发送一个HTTP请求到Servlet容器时,容器会解析请求,确定它是哪种类型的HTTP方法(如GET、POST、PUT、DELETE等),然后调用相应的doXXX方法。

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方法首先检查传入的ServletRequestServletResponse是否可以安全地强制转换为HttpServletRequestHttpServletResponse。接着,它获取HTTP请求的方法(如GET、POST等),并根据这个方法调用相应的doXXX方法。如果请求方法是GET,它还会检查If-Modified-Since头以判断是否发送304 Not Modified响应。

对于不支持的HTTP方法,service方法会抛出一个ServletException。通常,开发者会覆盖doGetdoPost等方法来提供具体的业务逻辑,而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消息作为响应体。

相关推荐
HBryce243 分钟前
缓存-基础概念
java·缓存
一只爱打拳的程序猿18 分钟前
【Spring】更加简单的将对象存入Spring中并使用
java·后端·spring
杨荧19 分钟前
【JAVA毕业设计】基于Vue和SpringBoot的服装商城系统学科竞赛管理系统
java·开发语言·vue.js·spring boot·spring cloud·java-ee·kafka
minDuck21 分钟前
ruoyi-vue集成tianai-captcha验证码
java·前端·vue.js
为将者,自当识天晓地。40 分钟前
c++多线程
java·开发语言
daqinzl1 小时前
java获取机器ip、mac
java·mac·ip
激流丶1 小时前
【Kafka 实战】如何解决Kafka Topic数量过多带来的性能问题?
java·大数据·kafka·topic
Themberfue1 小时前
Java多线程详解⑤(全程干货!!!)线程安全问题 || 锁 || synchronized
java·开发语言·线程·多线程·synchronized·
让学习成为一种生活方式1 小时前
R包下载太慢安装中止的解决策略-R语言003
java·数据库·r语言
晨曦_子画1 小时前
编程语言之战:AI 之后的 Kotlin 与 Java
android·java·开发语言·人工智能·kotlin