Servlet 简介

Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。


Servlet 基本使用

  1. 创建Maven Web项目后,导入Servlet依赖坐标和Tomcat插件:

    <dependencies>
        <!-- Servlet依赖 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.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>
           </plugin>
       </plugins>
    </build>
    

    使用<scope>provided</scope>的原因: provided指的是在编译和测试过程中有效,最后生成的war包时不会加入。 因为Tomcat的lib目录中已经有servlet-api这个jar包,如果在生成war包的时候生效就会和Tomcat中的jar包冲突,导致报错。

  2. 创建Servlet类,实现Servlet接口,并重写接口中所有方法:

    package com.linner.web;
    
    import javax.servlet.*;
    import javax.servlet.annotation.WebServlet;
    import java.io.IOException;
    
    @WebServlet("/demo")
    public class ServletDemo implements Servlet {
    
        @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() {
    
        }
    
        @Override
        public void init(ServletConfig servletConfig) throws ServletException {
    
        }
    
        @Override
        public ServletConfig getServletConfig() {
            return null;
        }
    }
    
    • 使用@WebServlet注解配置该Servlet的访问路径:@WebServlet("/demo")
  3. 启动Tomcat,根据自己项目和Tomcat的配置访问,如:http://localhost:8080/web-demo/demo

    访问成功后可以看到在控制台输出service()方法中的内容。


Servlet 执行流程

运行Tomcat时并没有显式创建Servlet对象,也没有显式调用其中的方法。可控制台依然输出了ServletDemo.service()中的内容。

访问该Tomcat项目时,浏览器发出http://localhost:8080/web-demo/demo请求,从请求中可以解析出三部分内容:

  • 根据localhost:8080可以找到要访问的Tomcat Web服务器
  • 根据web-demo可以找到部署在Tomcat服务器上的web-demo项目
  • 根据demo可以找到要访问的是项目中的哪个Servlet类,根据@WebServlet后面的值进行匹配

找到ServletDemo这个类后,Tomcat Web服务器就会为ServletDemo这个类创建一个对象,然后调用对象中的service()方法。

而Tomcat则是根据@WebServlet注解或web.xml配置文件等信息来创建对应的Servlet对象。


Servlet 生命周期

生命周期是指对象的生命周期指一个对象从被创建到被销毁的整个过程。

Servlet运行在Servlet容器(web服务器)中,其生命周期由容器来管理,分为4个阶段:

  1. 加载和实例化:默认情况下,Servlet会在第一次访问时被容器创建

  2. 初始化:在Servlet实例化之后,容器将调用Servlet的init()方法初始化这个对象,完成一些如加载配置文件、创建连接等初始化的工作

    init()方法仅会被调用一次

  3. 请求处理:每次请求Servlet时,Servlet容器都会调用Servlet的service()方法对请求进行处理

  4. 服务终止:当需要释放内存或者容器关闭时,容器就会调用Servlet实例的destroy()方法完成资源的释放

    destroy()方法调用之后,容器会释放这个Servlet实例,该实例随后会被Java的垃圾收集器所回收

可以把Servlet的创建放到服务器启动的时候来创建(修改@WebServlet注解):

@WebServlet(urlPatterns = "/demo1", loadOnStartup = 1)

loadOnstartup的取值有两类情况:

  1. 负整数:第一次访问时创建Servlet对象
  2. 非负整数:服务器启动时创建Servlet对象,数字越小优先级越高(0的优先级最高)

Example:

package com.linner.web;
  
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;

@WebServlet(urlPatterns = "/demo", loadOnStartup = 1)
public class ServletDemo implements Servlet {
    /**
     * 初始化方法
     * - 在Servlet被第一次访问或者服务器启动时被调用一次
     */
    public void init(ServletConfig config) throws ServletException {
        System.out.println("init...");
    }

    /**
     * 提供服务
     * - 每一次Servlet被访问时被调用
     * - 可被调用多次
     */
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        System.out.println("Hello Servlet!");
    }

    /**
     * 销毁方法
     * - 调用时机:内存释放或者服务器关闭的时候被调用一次
     */
    public void destroy() {
        System.out.println("destroy...");
    }

    public ServletConfig getServletConfig() {
        return null;
    }

    public String getServletInfo() {
        return null;
    }
}

注意:若要在关闭Tomcat时调用destroy(),需要在正常关闭Tomcat的情况下,destroy()才能被执行。


Servlet 方法

剩下两个Servlet方法的作用是:

  • 获取Servlet信息:

    public String getServletInfo() {
        return "";
    }
    
  • 获取ServletConfig对象:

    public String getServletInfo() {
        return "";
    }
    

    ServletConfig对象,Tomcat Web服务器在创建Servlet对象的时候会通过init()方法将其作为参数传入:

    void init(ServletConfig config) throws ServletException
    

    getServletInfo()中仅需将服务器传过来的ServletConfig进行返回即可:

    private ServletConfig servletConfig;
    
    public void init(ServletConfig config) throws ServletException {
        // 获取服务器传入的ServletConfig
        this.servletConfig = config;
        System.out.println("init...");
    }
    public ServletConfig getServletConfig() {
        // 将服务器传入的ServletConfig返回
        return servletConfig;
    }
    

urlPattern 配置

urlPatterns 多路径访问

一个Servlet,可以配置多个访问路径(urlPattern):

@WebServlet(urlPatterns = {"/path1", "/path2", ....})

精确匹配

目录匹配

精确匹配优先级要高于目录匹配

扩展名匹配

注意:

  1. 如果路径配置的不是扩展名,那么在路径的前面就必须要加/否则会报错
  2. 如果路径配置的是*.html,那么在*.html的前面不能加/,否则会报错

任意匹配

  • 配置路径:

    @WebServlet("/")
    

    @WebServlet("/*")
    
  • 访问路径:

    任何以 http://localhost:8080/web-demo/ 开头的路径

//*的区别:

  1. 当项目中的Servlet配置了@WebServlet("/"),会覆盖掉Tomcat中的DefaultServlet,当其他的urlPattern都匹配不上时都会走这个Servlet。
  2. 当项目中配置了@WebServlet("/"),意味着匹配任意访问路径。
  3. DefaultServlet是用来处理静态资源,如果使用@WebServlet("/")将其覆盖掉。当请求静态资源的时候则是使用了自定义的Servlet类,最终会导致静态资源不能被访问。

XML配置Servlet(不推荐)

Servlet从3.0版本后才开始支持注解配置,而3.0版本前只支持XML配置文件的配置方法。

  • 编写Servlet类:

    package com.linner.web;
    
    import javax.servlet.*;
    import javax.servlet.annotation.WebServlet;
    import java.io.IOException;
    
    public class ServletDemo implements Servlet {
        // ...
    }
    
  • web.xml中配置该Servlet:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
            version="4.0">
    
        <!-- Servlet 全类名 -->
        <servlet>
            <!-- Servlet的名称,名字任意 -->
            <servlet-name>demo</servlet-name>
            <!-- Servlet的类全名 -->
            <servlet-class>com.linner.web.ServletDemo</servlet-class>
        </servlet>
    
        <!-- Servlet 访问路径 -->
        <servlet-mapping>
            <!-- Servlet的名称,要和上面的名称一致 -->
            <servlet-name>demo</servlet-name>
            <!-- Servlet的访问路径 -->
            <url-pattern>/demo</url-pattern>
        </servlet-mapping>
    </web-app>
    

ServletRequest 和 ServletResponse

Servlet.service() 中有这样两个参数,它们的类型是 ServletRequestServletResponse。这两个参数就是Servlet的 RequestResponse 对象。

Request是请求对象,作用是将客户端的请求数据从客户端发送到服务端;Response是响应对象,作用是将服务端的响应数据从服务端发送到客户端。