Servlet

1. 介绍

Servlet运行在服务器端的小程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。

  • Servlet就是一个接口,定义了java类被浏览器访问到(Tomcat识别)的规则。
  • 将来我们自定义一个类,实现Servlet接口,复写方法。

**运行在服务器端的程序:**即运行在Tomcat这类web容器的程序。

Servlet: 是指所有实现了 Servlet 接口的类,是编写的程序。

**作用:**Servlet 主要用于处理客户端传来的 HTTP 请求,并返回一个响应,它能够处理的请求有 doGet() 和 doPost() 等。

**来源:**Servlet 由 Servlet 容器提供,Servlet 容器是指提供了 Servlet 功能的服务器(如 Tomcat)。Servlet 容器会将 Servlet 动态加载到服务器上,然后通过 HTTP 请求和 HTTP 应与客户端进行交互。

image-20211216092703238

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m4xSIM7K-1652970457898)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20211218200119946.png)]

综合以上:

  1. Servlet是我们编写的程序,这个程序是运行在服务器上的。
  2. Servlet容器就是我们的服务器。Tomcat就是一种容器。

image-20211214140349809

Servlet 的请求首先会被 HTTP 服务器(如 Apache)接收,HTTP 服务器只负责静态 HTML 页面的解析,而 Servlet 的请求会转交给 Servlet 容器,Servlet 容器会根据 web.xml 文件中的映射关系,调用相应的 Servlet,Servlet 再将处理的结果返回给 Servlet 容器,并通过 HTTP 服务器将响应传输给客户端。

最主流的三个Web服务器(HTTP服务器)是Apache、 Nginx 、IIS。

Servlet 技术具有如下特点。

  1. 方便

    Servlet 提供了大量的实用工具例程,如处理很难完成的 HTML 表单数据、读取和设置 HTTP 头,以及处理 Cookie 和跟踪会话等。

  2. 跨平台

    Servlet 使用 Java 类编写,可以在不同的操作系统平台和不同的应用服务器平台运行。

  3. 灵活性和可扩展性强

    采用 Servlet 开发的 Web 应用程序,由于 Java 类的继承性及构造函数等特点,使得应用灵活,可随意扩展。

2. 快速入门

使用Servlet

  1. 创建JavaEE项目(参考上一章节Tomcat服务器中的创建步骤)

  2. 创建一个Servlet类,实现Servlet接口

  3. 实现类中的抽象方法

public class ServletDemo1 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("hello servlet");
    }
    @Override
    public String getServletInfo() {
        return null;
    }
    @Override
    public void destroy() {
    }
}
  1. 配置Servlet

在xml中添加实现接口类的路径以及定义url地址

配置之后,我们通过浏览器访问对应的路径时,即可跳转到我们相应的接口中

<?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_3_1.xsd"
         version="3.1">
<!--    配置servlet类的路径-->
    <servlet>
        <servlet-name>demo1</servlet-name>
        <servlet-class>cn.itcast.web.servlet.ServletDemo1</servlet-class>
    </servlet>
<!--       配置访问的url路经-->
    <servlet-mapping>
        <servlet-name>demo1</servlet-name>
         <url-pattern>/demo1</url-pattern>
    </servlet-mapping>
</web-app>
  1. 运行结果:

  2. Jsp页面

    1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
        <head>
          <title>$Title$</title>
        </head>s
        <body>
        <h1>Hello servlet</h1>
        <a href="/servlet/demo1">please enter</a>
        </body>
      </html>
      

浏览器访问:

image-20211216094409657

控制台打印:image-20211216094446697

设置请求路径

  1. image-20211216094632083

  2. image-20211216104337242

  3. image-20211216104316683

  4. 重启服务器,再次请求

3. 执行原理

  1. 当服务器接受到客户端浏览器的请求后,会解析请求URL路径,获取访问的Servlet的资源路径

  2. 查找web. xml文件,是否有对应的标签体内容。

  3. 如果有,则在找到对应的全类名

  4. tomcat会将字节码文件加载进内存,并且创建其对象

  5. 调用其方法

image-20211217155127565

通过反射机制,创建类的实例对象,之后调用对象的service方法。

Servlet方法(生命周期)解析

三种状态
  1. 被创建时:执行init(),只执行一次。加载资源

    1. servlet什么时候被创建

    2. 默认情况下,第一次访问时被创建

      1. 可以指定Servlet的创建时机(在xml中配置)

        <servlet>
            <servlet-name>demo1</servlet-name>
            <servlet-class>cn.itcast.web.servlet.ServletDemo1</servlet-class>
            <!--指定servlet的创建时机-->
            <!-- 1.第一次访问时创建-->访问的是所在页面
            <!-- <load-on-startup>的值为负数-->
            <!-- 2.在服务器启动时创建-->Tomcat服务器启动时
            <!-- <load-on-startup>的值为0或正整数-->
            <load-on-startup>5</load-on-startup>
        </servlet>
        
      2. 初始化参数init

      @WebServlet(urlPatterns = "/demo3",initParams = {
            @WebInitParam(name = "username",value = "tom"),
            @WebInitParam(name = "password",value = "123456")
      })
      public class ServletDemo3 extends HttpServlet {
        public void doGet(HttpServletRequest request, HttpServletResponse response){
            System.out.println(this.getInitParameter("username"));
            System.out.println(this.getInitParameter("password"));
        }
      
      }
      
  2. 提供服务时:执行 service(),执行多次

  3. 每次访问Servlet时执行(刷新页面)

  4. 被销毁:执行destory(),只执行一次。释放资源

    1. Servlet被销毁时执行。服务器关闭时,Servlet被销毁
    2. 只有服务器被正常关闭时,而不是只关闭页面
    3. 是在Servlet在Servlet执行之前执行(死前遗言)
public class ServletDemo1 implements Servlet {
    @Override
    /*
    1.初始化方法
    在Servlet创建时执行,只执行一次
     */
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("init............");
    }

    @Override
/***
 *2. 获得severlet的一些配置信息
 */
    public ServletConfig getServletConfig() {

        return null;
    }
//提供服务的方法
    @Override
        /*
   3. 提供服务方法
    每一次Servlet被访问时执行。执行多次
     */
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("service...............");
    }

/*
  4.获得servlet的一些信息,版本,作者等。
* */
    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    /*
   5. 销毁方法
    在服务器正常关闭时执行,执行一次。
     */
    public void destroy() {
        System.out.println("destory......");

    }
}
架构图

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

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

Servlet 生命周期

注解配置Servlet

@WebServlet注解(Servlet注解) (biancheng.net)

从快速入门中我们看到,当我们想访问servlet时,需要在xml中对servlet路径进行配置,但是配置很麻烦,如果有多个servlet,那么就很繁琐。

Servlet3.0之后,引入了注释配置,就不需要在xml中配置了。

创建项目时,也不需要勾选create.web.xml了

image-20211216095858953

语法

@WebServlet(urlPatterns = "/demo1")或者
@WebServlet("/demo1")

使用

@WebServlet(urlPatterns = "/demo1")
public class ServletDemo1 implements Servlet {
    @Override
    /*
    1.初始化方法
    在Servlet创建时执行,只执行一次
     */
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("init............");
    }

    @Override
/***
 *2. 获得severlet的一些配置信息
 */
    public ServletConfig getServletConfig() {

        return null;
    }
    //提供服务的方法
    @Override
        /*
   3. 提供服务方法
    每一次Servlet被访问时执行。执行多次
     */
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("service...............");
    }

    /*
      4.获得servlet的一些信息,版本,作者等。
    * */
    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    /*
   5. 销毁方法
    在服务器正常关闭时执行,执行一次。
     */
    public void destroy() {
        System.out.println("destory......");

    }
}

urlPatterns()配置

通过看注解的原码得知,urlPatterns()是一个数组,可以配置多个路径。img

路径配置

  1. 配置多个路径之后,我们就可以在多个路径访问Servlet

    1. @WebServlet({“/demo4”,“/ddemo4”,“/dddemo4”})
  2. 路径配置规则

    1. “/XXXX” 单层路径

    2. “/XXXX/XXXX” 多层路径 ,目录结构

    3. “/XXXX/*” *表示任意,即/XXXX/随意

    4. “/*” 表示什么样的路径(除了其他已经配置的路径文件),都能访问到此文件

    5. “*.do” 除了其他已经配置的路径文件,任意语录加上.do,即可访问到此文件

      1. @WebServlet("*.do")
        
  3. “/servlet” 虚拟路径开始http://localhost:8800/sevlet

    1. 虚拟路径,tomcat配置的路径。即/servlet开始
  4. “/source/begin” 当前路径开始http://localhost:8800/sevlet/source/begin

    1. 当前接口路径,即/source/begin开始
以下两个方法时httpservlet
//serlvet 是tomcat配置的路径
        String contextPath = req.getContextPath();
        System.out.println(contextPath);
// /source/begin 是当前接口配置的路径
        String servletPath = req.getServletPath();
        System.out.println(servletPath);

@WebServlet注解

属性名类型描述
nameString指定Servlet 的 name 属性,等价于 <servlet-name>。如果没有显式指定,则该 Servlet 的取值即为类的全限定名。
valueString[]该属性等价于 urlPatterns 属性。两个属性不能同时使用。
urlPatternsString[]指定一组 Servlet 的 URL 匹配模式。等价于<url-pattern>标签。
loadOnStartupint指定 Servlet 的加载顺序,等价于 <load-on-startup>标签。
initParamsWebInitParam[]指定一组 Servlet 初始化参数,等价于<init-param>标签。
asyncSupportedboolean声明 Servlet 是否支持异步操作模式,等价于<async-supported> 标签。
descriptionString该 Servlet 的描述信息,等价于 <description>标签。
displayNameString该 Servlet 的显示名,通常配合工具使用,等价于 <display-name>标签。

4. Servlet体系结构

image-20211216103216060

GenericServlet:

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

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

public class ServletDemo extends GenericServlet {
    /*
    通过继承GenericServlet就可以单独实现service方法
    但是不推荐使用这个
     */
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("GenericServlet.....");
    }
}

HttpServlet:

对http协议的一种封装,简化操作

  1. 定义类继承HttpServlet

  2. 重写doGet/doPost及其它几种Http请求方法

当用户请求数据时,需要判断用户是以何种方式请求。判断这个请求方式是一个麻烦的过程。

HttpServlet中封装了对请求方式的判断,我们使用时只需要重写doGet()和doPost()以及其它我们需要的方法即可。

HttpServlet的service方法

通过请求方法的不同去执行对应的方法。

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();
        long lastModified;
        if (method.equals("GET")) {
            lastModified = this.getLastModified(req);
            if (lastModified == -1L) {
                this.doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader("If-Modified-Since");
                if (ifModifiedSince < lastModified) {
                    this.maybeSetLastModified(resp, lastModified);
                    this.doGet(req, resp);
                } else {
                    resp.setStatus(304);
                }
            }
        } else if (method.equals("HEAD")) {
            lastModified = this.getLastModified(req);
            this.maybeSetLastModified(resp, lastModified);
            this.doHead(req, resp);
        } else if (method.equals("POST")) {
            this.doPost(req, resp);
        } else if (method.equals("PUT")) {
            this.doPut(req, resp);
        } else if (method.equals("DELETE")) {
            this.doDelete(req, resp);
        } else if (method.equals("OPTIONS")) {
            this.doOptions(req, resp);
        } else if (method.equals("TRACE")) {
            this.doTrace(req, resp);
        } else {
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[]{method};
            errMsg = MessageFormat.format(errMsg, errArgs);
            resp.sendError(501, errMsg);
        }

    }
重写doGet()方法

例如:浏览器直接访问

@WebServlet("/demo2")
public class ServletDemo2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("get请求");
        System.out.println(req.getParameter("username"));
        System.out.println(req.getParameter("password"));
    }

}
重写doPost()方法

例如:通过表单向后台发送数据。

@WebServlet("/demo2")
public class ServletDemo2 extends HttpServlet {

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("post请求");
        System.out.println(req.getParameter("username"));
        System.out.println(req.getParameter("password"));
    }


}

在webapp包下创建index.jsp。启动tomcat服务器,会默认访问该路径下的index文件。

image-20211217164501181

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>$Title$</title>
</head>
<body>
<h1>Hello servlet</h1>
<a href="/servlet/demo1">please enter</a>

<div>
    <a href="/servlet/blog/add">添加blog</a>
    <br>
    <a href="http://localhost:8899/servlet/blog/delete">删除blog</a>
    <br>
    <a href="/servlet/blog/update">修改blog</a>
    <br>
    <a href="/servlet/blog/query">查询blog</a>
</div>

<div>
    <h1>post请求</h1>
    <form action="/servlet/demo2" method="post">
        <input name="username">
        <input name="password">
        <input type="submit" value="提交">
    </form>
    <h1>get请求</h1>
    <form action="/servlet/demo2" method="get">
        <input name="username">
        <input name="password">
        <input type="submit" value="提交">
    </form>
</div>
</body>
</html>

创建servlet接口

运行:

image-20211217164614014

控制台打印:

image-20211217164632070

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐