Servlet的基本使用

在开发 Java 浏览器和服务器的 B/S 架构程序中,最开始用来接收浏览器发给服务器端请求的就是 Servlet 了,它最主要的作用就是用来接收用户请求,然后处理完相关的业务逻辑之后,再返回相应的信息给浏览器端。

1.Servlet是什么?

首先先看一下 API 文档中对它的定义:

`A servlet is a small Java program that runs within a Web server. Servlets receive and respond to requests from Web clients, usually across HTTP, the HyperText Transfer Protocol. `

Servlet 是一种必须运行在 Web 服务器中的 Java 小程序,通常通过 HTTP(超文本传输协议) 来接受并响应来自 Web 客户端的请求。

2.新建一个Servlet

如何才能新建一个 Servlet 呢?首先想到的就是实现 javax.servlet.Servlet 接口,然后再对实现接口的类进行配置。当然在实现 Servlet 这个接口的时候,也会需要重写它的很多方法。

首先声明一个类来实现 Servlet 接口:

import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class ServletUrl  implements Servlet{

    @Override
    public void init(ServletConfig config) throws ServletException {

    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    @Override
    public void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException {
        System.out.println("ServletUrl被访问了...");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}

然后再到 web.xml 文件中对这个 Servlet 进行配置

<servlet>
    <servlet-name>ServletUrl</servlet-name>
    <servlet-class>party.laucloud.ServletUrl</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>ServletUrl</servlet-name>
    <url-pattern>/servletUrl</url-pattern>
</servlet-mapping>

这样配置好了之后,当用户请求 /servletUrl 路径的时候就可以访问的到我们刚才编写的这个 Servlet 类了,而响应用户请求的则是 Service() 方法,因此可以在这个方法中添加打印语句进行测试。 `

3.Servlet的执行流程

对于 Servlet 的执行流程,当用户在浏览器中输入地址对服务器进行访问的时候,首先就会根据访问路径到 web.xmlServlet 配置中查找对应的 <url-pattern>,找到 <url-pattern> 之后就可以确定对应的 <servlet-name>,然后也就能确定到对应的 <servlet-class> 了,也就是具体的 Servlet 类了,而这个类中就会运行 service() 方法来响应用户的请求。这也就是 Servlet 的运行流程。

4.Servlet的实现关系

首先先看一段官方 API 中对于如何创建 Servlet 的描述:

`To implement this interface, you can write a generic servlet that extends javax.servlet.GenericServlet or an HTTP servlet that extends javax.servlet.http.HttpServlet.`

上面的说法是说要想创建一个 Servlet 有三种方式:

1、实现javax.servlet.Servlet这个接口
2、继承javax.servlet.GenericServlet这个类
3、继承javax.servlet.http.HttpServlet这个类

Servlet 的实现关系也就是上面三者之间的关系,也就是 GenericServlet 这个类实现了 Servlet 这个接口,而 HttpServlet 又继承了 GenericServlet 这个类。HttpServlet 是一个与协议有关的类,即它是用来处理 HTTP 协议的请求的,而我们浏览器与服务器之间通信就是基于 HTTP 请求啊,为什么还需要 GenericServlet 这个类呢?这样设计完全就是为了应对以后的发展,虽然现在都是基于 HTTP 协议的,但是不代表以后也一直是基于这个协议,事物总是会有发展的嘛,所以就设定了 GenericServlet 这个与任何协议都无关的类,以应对以后的发展。

我们开发的时候一般都是继承 HttpServlet 这个类,然后再重写它的 service() 方法来处理用户的请求,在查看 HttpServlet 类中的 service() 方法的源码时发现,在处理用户发送过来的请求时,它是根据用户的请求方式分类来进行处理的,如果用户使用的是 GET 请求方式,那么就会运行 doGet() 方法来处理用户的请求,如果是 POST 方式的话,那就调用 doPost() 方法来处理用户的请求,当然还有很多其它的请求方式,也都预定了它们对应的处理方法,因为 GET 方式和 POST 方式是使用的最多的两种方式,因此我们在重写 HttpServlet 中方法的时候,就可以不重写 service() 方法,而是重写 doGet()doPost() 方法。由于这两个方法要处理的业务逻辑往往是一样的,因此可以让其中一个方法调用另一个方法。

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    doPost(request,response);
}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    response.getWriter().print("hello servlet ...");
}

5.在Eclipse中使用Servlet的模板

也许你会觉得上面创建 Servlet 的方式太过繁琐了,想用简单一点的方式,但是最好还是在完全掌握上面这种方式之后再使用其它的方法,也就是下面要介绍的,基于 Eclipse 模板生成的这种,这种方式在创建 Servlet 的过程中,完全是可视化图形界面的方式,创建好类之后还会自动在 web.xml 文件中加入 Servlet 的配置,但是可能使用这种方式多了以后,就会忘记最原始怎么创建 Servlet 了。

其实方式也十分简单,就是在一个包中创建 Servlet 类的时候,单击右键,选择 new,然后再选择 Servlet,输入要创建的名称和实现的父类,点击下一步就可以修改 URL mapping,也就是我们之前手动设置时设置的 <url-pattern>,最后点击下一步选择需要重写的父类方法,点击完成 Eclipse 就会自动为我们生成一个 Servlet 了,而且还会在 web.xml 中跟我们配置好。

采用这种自动生成的方式的话,最好在生成之后都检查一下,生成的类和 web.xml 配置文件都应该检查一下。

6.Servlet的生命周期

关于 Servlet 的生命周期,API 中也给出了非常详细的介绍:

`This interface defines methods to initialize a servlet, to service requests, and to remove a servlet from the server. These are known as life-cycle methods and are called in the following sequence:

1.The servlet is constructed, then initialized with the init method. 
2.Any calls from clients to the service method are handled. 
3.The servlet is taken out of service, then destroyed with the destroy method, then garbage collected and finalized. `

上面就是说关于 Servlet 的生命周期,其实和三个方法有关,那就是 init()service()以及 destroy() 方法,当一个 Servlet 第一次被访问的时候,这时 Servlet 对象就会被创建,被调用 init() 方法来进行一些初始化操作,而且 init() 只会执行一次,然后当有用户请求访问这个 Servlet 的时候,就会调用其中的 service() 方法进行响应,最后在将服务器关闭的时候,就会调用 destroy() 方法将这个 Servlet 进行销毁。这就是 Servlet 的生命周期了,要是想测试的话也可以分别在一个 Servletinit()service() 以及 destroy() 方法中加上打印语句进行测试。

7.Servlet启动时加载配置

Servlet 是什么时候被创建呢?是被第一次访问的时候,那么这样说来,在 Servlet 第一次被访问的时候响应速度应该是最慢的,因为需要做很多初始化的操作,那如何解决这个问题呢?就是可以将 Servlet 创建的时间从第一次被访问移到服务器启动的时候,这样虽然服务器启动时间会偏长一点,但是以后使用 Servlet 响应用户请求的时候,每次的响应时间就都是一样的了。

要想实现让 Servlet 在服务器启动时创建,就需要在 Servlet 的配置文件中加入 load-on-startup 属性,该属性对应的属性值就是启动优先级,值越小说明优先级越高,Tomcat 中有一个默认的 Servlet 设置的优先级为 1,所以我们一般将自己创建的 Servlet 优先级设置为 2,可以如下设置:

<servlet>
    <servlet-name>ServletDemo1</servlet-name>
    <servlet-class>party.laucloud.ServletDemo1</servlet-class>
    <load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>ServletDemo1</servlet-name>
    <url-pattern>/ServletDemo1</url-pattern>
</servlet-mapping>

Tomcat 中一个默认的 Servlet 的配置是在 conf/web.xml

<servlet>
    <servlet-name>default</servlet-name>
    <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
    <init-param>
        <param-name>debug</param-name>
        <param-value>0</param-value>
    </init-param>
    <init-param>
        <param-name>listings</param-name>
        <param-value>false</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

8.Servlet访问路径的配置

Servlet 访问路径的设置,其实就是在 web.xml 中配置 Servlet 时其中的 url-pattern 属性,访问路径可以分为三种情况:全路径匹配、目录匹配和扩展名匹配。

全路径匹配:以/开头,例如:/ServletDemo、/abc/ServletDemo
目录匹配:以/开头,*结尾。例如:/*、/aaa/*(*代表任意字符)
扩展名匹配:以*开头,.xxx结尾。例如:*.action、*.do

有一种情况就是有一个路径请求匹配了多种路径设置,比如 /abc/servlet.action 可能既会满足全路径匹配 (/abc/servlet.action),又满足扩展名匹配 (*.action),那这样情况应该如何匹配呢?

上面就是要涉及到优先级了,其中的规则就是越精确优先级越高,也就是全路径匹配>目录匹配>扩展名匹配,也就是如果一个 Servlet 在在进行全路径匹配之后,就不会再匹配目录匹配和扩展名匹配了。

9.总结

关于 Servlet 的掌握的话重点还是应该在多使用上面,使用的多了也就会非常熟练了,最好是能做一些小案例,这样解决一些问题之后就会理解的更透彻,至于一些相关理论知识,可以通过查询文档来学习得知。

坚持原创技术分享,您的支持将鼓励我继续创作!