【 JavaWeb 】- 3 Servlet

    科技2025-04-25  22

    1 Servlet 的入门程序

    1.1 创建 Maven 项目

    补全目录结构为下面的 Maven 项目的目录结构:

    pom.xml:

    <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.snow</groupId> <artifactId>servlet1</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <!-- 配置Tomcat插件 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <path>/</path> <port>8080</port> </configuration> </plugin> </plugins> </build> </project>

    web.xml:

    <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> </web-app>

    1.2 定义一个类,实现 Servlet 接口

    public class ServletDemo1 implements Servlet { }

    注意: 但在实际开发中,我们不会直接去实现 Servlet 接口,因为那样需要覆盖的方法太多,我们一般创建类继承 HttpServlet。

    实现步骤:

    创建类继承 HttpServlet 类覆盖 doGet 和 doPost在 web.xml 中进行 servlet 的配置

    1.3 实现接口中的抽象方法

    package com.snow.servlet; import javax.servlet.*; import java.io.IOException; public class ServletDemo1 implements Servlet { @Override public void init(ServletConfig servletConfig) throws ServletException { } @Override public ServletConfig getServletConfig() { return null; } /** * 提供服务的方法 * * @param servletRequest * @param servletResponse * @throws ServletException * @throws IOException */ @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("Hello Servlet..."); } @Override public String getServletInfo() { return null; } @Override public void destroy() { } }

    1.4 配置 Servlet

    在 web.xml 中配置: <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <!-- 配置Servlet --> <servlet> <!-- 注册Servlet --> <servlet-name>demo1</servlet-name> <!-- Servlet名称,当前 xml 中唯一 --> <servlet-class>com.snow.servlet.ServletDemo1</servlet-class> <!-- Servlet 实现类的全限定类名 --> </servlet> <servlet-mapping> <!-- 给注册的 Servlet 添加映射路径 --> <servlet-name>demo1</servlet-name> <!-- 已经注册的 Servlet 名称。注意:必须与注册的名称一致 --> <url-pattern>/demo1</url-pattern> <!-- 访问路径。要求:必须以 / 开头 --> </servlet-mapping> </web-app>

    测试:

    启动 Tomcat,浏览器输入:http://localhost:8080/demo1

    每访问一次,控制台就打印一次 Hello Servlet

    1.5 执行原理

    当服务器接受到客户端浏览器的请求后,会解析请求 URL 路径,获取访问的 Servlet 的资源路径查找 web.xml 文件,是否有对应的 <url-pattern> 标签体内容。如果有,则在找到对应的 <servlet-class> 全类名tomcat 会将字节码文件加载进内存,并且创建其对象调用其方法

    2 Servlet 生命周期

    2.1 Servlet 生命周期(API)

    Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:

    Servlet 通过调用 init() 方法进行初始化。Servlet 调用 service() 方法来处理客户端的请求。Servlet 通过调用 destroy() 方法终止(结束)。最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。

    pom.xml:

    <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.snow</groupId> <artifactId>servlet1</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <!-- 配置Tomcat插件 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <path>/</path> <port>8080</port> </configuration> </plugin> </plugins> </build> </project>

    web.xml:

    <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <!-- 配置Servlet --> <servlet> <!-- 注册Servlet --> <servlet-name>demo1</servlet-name> <!-- Servlet名称,当前 xml 中唯一 --> <servlet-class>com.snow.servlet.ServletDemo1</servlet-class> <!-- Servlet 实现类的全限定类名 --> <!-- 指定Servlet的创建时机 1.第一次被访问时,创建 * <load-on-startup>的值为负数 2.在服务器启动时,创建 * <load-on-startup>的值为0或正整数 --> <load-on-startup>-5</load-on-startup> </servlet> <servlet-mapping> <!-- 给注册的 Servlet 添加映射路径 --> <servlet-name>demo1</servlet-name> <!-- 已经注册的 Servlet 名称。注意:必须与注册的名称一致 --> <url-pattern>/demo1</url-pattern> <!-- 访问路径。要求:必须以 / 开头 --> </servlet-mapping> </web-app>

    ServletDemo1:

    package com.snow.servlet; import javax.servlet.*; import java.io.IOException; public class ServletDemo1 implements Servlet { /** * 初始化方法 * 再Servlet被创建时执行,只执行一次 * @param servletConfig * @throws ServletException */ @Override public void init(ServletConfig servletConfig) throws ServletException { System.out.println("初始化方法执行......"); } /** * 获取ServletConfig对象 * ServletConfig:Servlet的配置对象 * @return */ @Override public ServletConfig getServletConfig() { return null; } /** * 提供服务的方法 * 每一次Servlet被访问时,都会执行,执行多次 * @param servletRequest * @param servletResponse * @throws ServletException * @throws IOException */ @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("Hello Servlet......"); } /** * 获取Servlet的一些信息,版本,作者等等。。 * @return */ @Override public String getServletInfo() { return null; } /** * 销毁方法 * 再服务器正常关闭时,执行,只执行一次 */ @Override public void destroy() { System.out.println("销毁方法执行......"); } }

    启动程序,浏览器访问:http://localhost:8080/demo1 ,控制台打印:

    初始化方法执行...... Hello Servlet......

    2.2 init() 方法

    init 方法被设计成 只调用一次,说明一个 Servlet 在内存中只存在一个对象,Servlet 是单例的。

    注意: 多个用户同时访问时,可能存在线程安全问题。 解决:尽量不要在Servlet中定义成员变量。即使定义了成员变量,也不要对修改值

    默认情况下,第一次被访问时,Servlet 被创建。

    init 方法调用时间:在 第一次创建 Servlet 时被调用,在后续每次用户请求时不再调用。因此,它是用于一次性初始化。

    Servlet 创建时间:用户第一次调用对应于该 Servlet 的 URL 时,但是您也可以指定 Servlet 在服务器第一次启动时被加载。

    当用户调用一个 Servlet 时,就会创建一个 Servlet 实例,每一个用户请求都会产生一个新的线程,适当的时候移交给 doGet 或 doPost 方法。init() 方法简单地创建或加载一些数据,这些数据将被用于 Servlet 的整个生命周期。

    注意: 可以配置执行 Servlet 的创建时机 —— 在<servlet>标签下配置

    第一次被访问时,创建:<load-on-startup>的值为负数在服务器启动时,创建:<load-on-startup>的值为0或正整数

    2.3 service() 方法(提供服务,可执行多次)

    service() 方法是执行实际任务的主要方法。Servlet 容器(即 Web 服务器)调用 service() 方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端。

    每次访问 Servlet 时,Service方法都会被调用一次。

    每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut,doDelete 等方法。

    下面是该方法的特征:

    service() 方法由容器调用,service 方法在适当的时候调用 doGet、doPost、doPut、doDelete 等方法。所以,您不用对 service() 方法做任何动作,您只需要根据来自客户端的请求类型来重载 doGet() 或 doPost() 即可。

    doGet() 和 doPost() 方法是每次服务请求中最常用的方法。下面是这两种方法的特征。

    2.4 doGet() 方法

    GET 请求来自于一个 URL 的正常请求,或者来自于一个未指定 METHOD 的 HTML 表单,它由 doGet() 方法处理。

    2.5 doPost() 方法

    POST 请求来自于一个特别指定了 METHOD 为 POST 的 HTML 表单,它由 doPost() 方法处理。

    2.6 destroy() 方法

    destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用。destroy() 方法可以让您的 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。

    只有 服务器正常关闭时,才会执行destroy方法,destroy方法在Servlet被销毁之前执行,一般用于释放资源。

    在调用 destroy() 方法之后,servlet 对象被标记为垃圾回收。

    2.7 架构图

    下图显示了一个典型的 Servlet 生命周期方案。

    第一个到达服务器的 HTTP 请求被委派到 Servlet 容器。Servlet 容器在调用 service() 方法之前加载 Servlet。然后 Servlet 容器处理由多个线程产生的多个请求,每个线程执行一个单一的 Servlet 实例的 service() 方法。


    3 Servlet 3.0

    3.1 Servlet 3.0:注解配置

    3.1.1 好处:

    支持注解配置。可以不需要 web.xml 了。

    依赖:

    <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <!-- 配置Tomcat插件 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <path>/</path> <port>8082</port> </configuration> </plugin> </plugins> </build>

    3.1.2 步骤:

    创建 JavaEE 项目,选择 Servlet 的版本 3.0 以上,可以不创建 web.xml定义一个类,实现 Servlet 接口复写方法在类上使用 @WebServlet 注解,进行配置 - @WebServlet("资源路径") package cn.ys.servlet; import javax.servlet.*; import javax.servlet.annotation.WebServlet; import java.io.IOException; @WebServlet("/demo") public class ServletDemo implements Servlet { @Override public void init(ServletConfig servletConfig) throws ServletException { } @Override public ServletConfig getServletConfig() { return null; } @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("Servlet3.0来了....."); } @Override public String getServletInfo() { return null; } @Override public void destroy() { } }

    测试: 启动 Tomcat,浏览器访问:http://localhost:8082/demo

    3.1.3 @WebServlet 注解

    // // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package javax.servlet.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface WebServlet { String name() default ""; // 相当于<Servlet-name> String[] value() default {}; // 代表urlPatterns()属性配置 String[] urlPatterns() default {}; // 相当于<url-pattern> int loadOnStartup() default -1; // 相当于<load-on-startup> WebInitParam[] initParams() default {}; boolean asyncSupported() default false; String smallIcon() default ""; String largeIcon() default ""; String description() default ""; String displayName() default ""; }

    3.2 Servlet的体系结构

    Servlet -- 接口 | GenericServlet -- 抽象类 | HttpServlet -- 抽象类

    GenericServlet:将 Servlet 接口中其他的方法做了默认空实现,只将 service() 方法作为抽象

    将来定义 Servlet 类时,可以继承 GenericServlet,实现 service() 方法即可

    HttpServlet:对http协议的一种封装,简化操作。(强烈推荐使用) 1. 定义类继承 HttpServlet 2. 复写 doGet/doPost 方法

    3.3 Servlet 相关配置

    3.3.1 urlpartten :Servlet 访问路径

    一个Servlet可以定义多个访问路径 : @WebServlet({"/d4","/dd4","/ddd4"})路径定义规则: /xxx:路径匹配/xxx/xxx:多层路径,目录结构*.do:扩展名匹配/:缺省路径

    注: web 应用中所有的资源的响应都是 servlet 负责,包括静态资源。 通常情况访问 html 页面时,首先从当前 web 项目的 web.xml 文件寻找匹配路径,如果都没有找到,再从 tomcat 默认的 web.xml 匹配,将使用缺省 servlet。 优先级为:1>2>3>4

    package cn.itcast.web.servlet; 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; /** * Servlet路径配置 */ //@WebServlet({"/d4","/dd4","/ddd4"}) //@WebServlet("/user/demo4") //@WebServlet("/user/*") //@WebServlet("/*") @WebServlet("*.do") public class ServletDemo4 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("demo4..."); System.out.println(req); } }

    3.3.2 欢迎页面

    <welcome-file-list> <welcome-file>index.jsp</welcome-file> <welcome-file>index.html</welcome-file> </welcome-file-list>
    Processed: 0.011, SQL: 8