补全目录结构为下面的 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>注意: 但在实际开发中,我们不会直接去实现 Servlet 接口,因为那样需要覆盖的方法太多,我们一般创建类继承 HttpServlet。
实现步骤:
创建类继承 HttpServlet 类覆盖 doGet 和 doPost在 web.xml 中进行 servlet 的配置测试:
启动 Tomcat,浏览器输入:http://localhost:8080/demo1
每访问一次,控制台就打印一次 Hello Servlet
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......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或正整数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() 方法是每次服务请求中最常用的方法。下面是这两种方法的特征。
GET 请求来自于一个 URL 的正常请求,或者来自于一个未指定 METHOD 的 HTML 表单,它由 doGet() 方法处理。
POST 请求来自于一个特别指定了 METHOD 为 POST 的 HTML 表单,它由 doPost() 方法处理。
destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用。destroy() 方法可以让您的 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。
只有 服务器正常关闭时,才会执行destroy方法,destroy方法在Servlet被销毁之前执行,一般用于释放资源。
在调用 destroy() 方法之后,servlet 对象被标记为垃圾回收。
下图显示了一个典型的 Servlet 生命周期方案。
第一个到达服务器的 HTTP 请求被委派到 Servlet 容器。Servlet 容器在调用 service() 方法之前加载 Servlet。然后 Servlet 容器处理由多个线程产生的多个请求,每个线程执行一个单一的 Servlet 实例的 service() 方法。支持注解配置。可以不需要 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>测试: 启动 Tomcat,浏览器访问:http://localhost:8082/demo
GenericServlet:将 Servlet 接口中其他的方法做了默认空实现,只将 service() 方法作为抽象
将来定义 Servlet 类时,可以继承 GenericServlet,实现 service() 方法即可HttpServlet:对http协议的一种封装,简化操作。(强烈推荐使用) 1. 定义类继承 HttpServlet 2. 复写 doGet/doPost 方法
注: 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); } }