Java Servlet简介

2025/04/07

1. 概述

在本文中,我们将了解Java Web开发的一个核心方面-Servlet。

2. Servlet和容器

简单地说,Servlet是一个处理请求、处理请求并返回响应的类。

例如,我们可以使用Servlet通过HTML表单收集用户的输入、从数据库查询记录以及动态创建网页。

Servlet受另一个Java应用程序(称为Servlet容器)的控制,当Web服务器中运行的应用程序收到请求时,服务器会将请求传递给Servlet容器,后者再将其传递给目标Servlet。

3. Maven依赖

为了在我们的Web应用中添加Servlet支持,需要jakarta.servlet-api依赖:

<dependency>
    <groupId>jakarta.servlet</groupId>
    <artifactId>jakarta.servlet-api</artifactId>
    <version>6.1.0</version>
</dependency>

最新的maven依赖可以在这里找到。

当然,我们还必须配置一个Servlet容器来部署我们的应用程序;这是在Tomcat上部署WAR的一个好起点

4. Servlet生命周期

让我们来看看定义Servlet生命周期的一组方法。

4.1 init()

init方法设计为仅调用一次,如果不存在Servlet实例,则Web容器:

  1. 加载Servlet类
  2. 创建Servlet类的实例
  3. 通过调用init方法进行初始化

init方法必须成功完成,Servlet才能接收任何请求。如果init方法抛出ServletException或未在Web服务器定义的时间段内返回,Servlet容器将无法将Servlet投入使用。

public void init() throws ServletException {
    // Initialization code like set up database etc....
}

4.2 service()

仅当Servlet的init()方法成功完成后才会调用此方法。

容器调用service()方法来处理来自客户端的请求,解释HTTP请求类型(GET、POST、PUT、DELETE等)并根据需要调用doGet、doPost、doPut、doDelete等方法。

public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
    // ...
}

4.3 destroy()

由Servlet容器调用以使Servlet停止服务。

该方法仅在Servlet的service方法中的所有线程都退出或超时后才会调用,容器调用此方法后,将不会在Servlet上再次调用服务方法。

public void destroy() {
    // 
}

5. 示例Servlet

首先,将上下文根从jakarta-servlets-1.0-SNAPSHOT更改为/:

<Context path="/" docBase="jakarta-servlets-1.0-SNAPSHOT"></Context>

在$CATALINA_HOME\conf\server.xml中的Host标签下。

现在让我们构建一个使用表单处理信息的完整示例。

首先,让我们定义一个带有映射/calculateServlet的Servlet,它将捕获表单POST的信息并使用RequestDispatcher返回结果:

@WebServlet(name = "FormServlet", urlPatterns = "/calculateServlet")
public class FormServlet extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String height = request.getParameter("height");
        String weight = request.getParameter("weight");

        try {
            double bmi = calculateBMI(
                    Double.parseDouble(weight),
                    Double.parseDouble(height));

            request.setAttribute("bmi", bmi);
            response.setHeader("Test", "Success");
            response.setHeader("BMI", String.valueOf(bmi));

            request.getRequestDispatcher("/WEB-INF/jsp/index.jsp").forward(request, response);
        } catch (Exception e) {
            request.getRequestDispatcher("/WEB-INF/jsp/index.jsp").forward(request, response);
        }
    }

    private Double calculateBMI(Double weight, Double height) {
        return weight / (height * height);
    }
}

如上所示,使用@WebServlet标注的类必须扩展jakarta.servlet.http.HttpServlet类。需要注意的是,@WebServlet注解仅在Java EE 6及更高版本中可用。

@WebServlet注解由容器在部署时处理,并在指定的URL模式中提供相应的Servlet。值得注意的是,通过使用注解来定义URL模式,我们可以避免使用名为web.xml的XML部署描述符进行Servlet映射。

如果我们希望映射不使用注解的Servlet,我们可以使用传统的web.xml:

<web-app ...>
    <servlet>
       <servlet-name>FormServlet</servlet-name>
       <servlet-class>com.root.FormServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>FormServlet</servlet-name>
        <url-pattern>/calculateServlet</url-pattern>
    </servlet-mapping>
</web-app>

接下来,让我们创建一个基本的HTML表单:

<form name="bmiForm" action="calculateServlet" method="POST">
    <table>
        <tr>
            <td>Your Weight (kg) :</td>
            <td><input type="text" name="weight"/></td>
        </tr>
        <tr>
            <td>Your Height (m) :</td>
            <td><input type="text" name="height"/></td>
        </tr>
        <th><input type="submit" value="Submit" name="find"/></th>
        <th><input type="reset" value="Reset" name="reset" /></th>
    </table>
    <h2>${bmi}</h2>
</form>

最后- 为了确保一切按预期进行,我们来编写一个快速测试:

public class FormServletLiveTest {

    @Test
    public void whenPostRequestUsingHttpClient_thenCorrect() throws Exception {
        HttpClient client = new DefaultHttpClient();
        HttpPost method = new HttpPost(
                "http://localhost:8080/calculateServlet");

        List<BasicNameValuePair> nvps = new ArrayList<>();
        nvps.add(new BasicNameValuePair("height", String.valueOf(2)));
        nvps.add(new BasicNameValuePair("weight", String.valueOf(80)));

        method.setEntity(new UrlEncodedFormEntity(nvps));
        HttpResponse httpResponse = client.execute(method);

        assertEquals("Success", httpResponse
                .getHeaders("Test")[0].getValue());
        assertEquals("20.0", httpResponse
                .getHeaders("BMI")[0].getValue());
    }
}

6. Servlet、HttpServlet和JSP

重要的是要理解Servlet技术不仅限于HTTP协议

实际上几乎总是如此,但Servlet是一个通用接口,而HttpServlet是该接口的扩展-添加HTTP特定支持,例如doGet和doPost等。

最后,Servlet技术也是许多其他Web技术(如JSP–JavaServer Pages、Spring MVC等)的主要驱动力。

7. 总结

在这篇简短的文章中,我们介绍了Java Web应用程序中Servlet的基础知识。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章