【Servlet教科书】Servlet到底是什么?有什么作用?(详细记录知识)

本文详细介绍了Servlet,包括Servlet的概念、核心作用、目录结构、开发步骤和IDEA创建流程。讲解了Servlet接口的实现、HttpServlet的使用以及Servlet的两种配置方式。还探讨了Servlet的生命周期、线程安全问题以及初始化参数配置。通过实例展示了Servlet与JDBC的集成、页面跳转、响应头操作和请求处理等,深入浅出地阐述了Servlet在JavaWeb开发中的重要性。
摘要由CSDN通过智能技术生成

文章目录

一、初识Servlet

1.1 Servlet概念

Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。 简单来说,Servlet是服务器端的一段程序(代码、功能实现),可交互式的处理客户端发送到服务器的请求,并完成操作响应。并支持动态网页技术。JavaWeb程序开发的基础,JavaEE规范(一套接口)的一个组成部分。它是由服务器厂商实现的。

1.2 Servlet的核心作用
  1. 接受客户端请求,完成操作任务
  2. 动态生成网页(页面数据可变)
  3. 将包含操作结果的动态网页响应给客户端
1.3 Servlet核心目录结构

web :存放需要部署的网站项目

——WEB-INF :核心内容,分别是以下内容

———classes :存放.class文件(XxxServlet.class)

———lib :储存所需jar包

———web.xml :web配置文件

——index.html/index.jsp.index.css/images等

见idea目录结构如下图: (因为idea会自动处理部署的文件并打包成war包的形式储存在out文件中,所以我们在使用IDEA时不用自己创建classes文件)

在这里插入图片描述

1.3 IDEA工具内创建核心目录结构

因为我们使用的是idea,如果去项目目录创建该Servlet目录结构过于繁琐,所以我们可以使用idea在工具内创建目录结构(可以在配置tomact时提前创建好都是OK的!)

在这里插入图片描述

1.4 Servlet的开发步骤
1.4.1 开发步骤
  1. 搭建开发环境,并创建Servlet核心目录结构
  2. 实现javax.serlvet.Servlet接口,覆盖5个方法(我在1.4.3里的每个方法上做了详细的注释)
  3. 在核心的servlet()方法中书写输出语句,验证访问结果
  4. 将编译后的.class文件放置在WEB-INF/classes中
  5. web.xml文件中添加配置信息

注意:

Java web工程下的web就是工程的发布文件夹,发布时会把该文件夹发布到idea项目下的out文件夹里artifacts。开发时classes文件存放路径为out文件夹下production文件夹下

鉴于我们使用的是IDEA集成开发工具,会自动处理文件放在idea并放在production文件夹内;而Eclipse不同,他会自动处理文件并放在tomact容器中的指定文件夹内,所以开发步骤作为了解,但是也可以自己动手试试!(后面我贴了一张图,可以去看一下!至于关于war包的情况不了解,可以去翻看tomact教科书系列文章)

在使用DOS命令行去编译执行Web项目时,我们需要将Servlet相关的jar包 完整路径\lib\servlet-api.jar 配置到CLASSPATH中。)

如果配置了环境还出现引用包的问题,那我们就可以选择带包编译或者不带包编译了。如下:

带包编译:javac -d . -classpath D:\tomcat\apache-tomcat-8.5.45\lib\servlet-api.jar MyServlet.java

不带包编译: javac -classpath D:\apache-tomcat-7.0.42\lib\servlet-api.jar MyServlet.java

在这里插入图片描述

1.4.2 web.xml配置文件添加配置信息

解释放在了配置信息中,你们看注释即可理解!

<?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">
	<!--下面两个标签,写在web-app标签内-->
	<!--Servlet配置-->
    <servlet>
        <!--Servlet的全称类名,通过名称找到对应的Servlet,因为的配置文件中可能存在很多Servlet,他需要一个可识别的名称标签-->
        <servlet-name>myservlet</servlet-name>
        <!--访问实际的类,这里需要写全限定名-->
        <servlet-class>com.mylifes1110.java.MyServlet</servlet-class>
    </servlet>
	<!--映射配置  -->
    <servlet-mapping>
        <!--同上,Servlet名称-->
        <servlet-name>myservlet</servlet-name>
        <!--URL路径访问名称,比如:localhost:8080/firstservlet/test(这里访问就需要在地址栏上假如test)-->
        <url-pattern>/test</url-pattern>
    </servlet-mapping>
</web-app>
1.4.3 我们的第一个Servlet(MyServlet代码)

实现javax.serlvet.Servlet接口,覆盖5个方法,标有详细注释

package com.mylifes1110.java;

import javax.servlet.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;

/**
 * Servlet
 * 实现Servlet接口中的所有方法
 */
public class MyServlet implements Servlet {
   
    
    /**
     * 实例化(调用构造器,可以省略,但是要知道)
     */
    public MyServlet() {
   
        //默认无参构造
    }
    
    /**
     * 初始化方法
     *
     * @param servletConfig 包含 servlet 的配置和初始化参数的 ServletConfig 对象
     * @throws ServletException 如果发生妨碍 servlet 正常操作的异常
     */
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
   
        //Servlet初始化工作
    }

    /**
     * 获取Servlet配置信息
     *
     * @return 返回 ServletConfig 对象,该对象包含此 servlet 的初始化和启动参数。返回的 ServletConfig 对象是传递给 init 方法的对象。
     */
    @Override
    public ServletConfig getServletConfig() {
   
        return null;
    }

    /**
     * 提供服务
     * <p>
     * 由 servlet 容器调用,以允许 servlet 响应某个请求。
     * 此方法仅在 servlet 的 init() 方法成功完成之后调用。
     * 应该为抛出或发送错误的 servlet 设置响应的状态代码。
     *
     * @param servletRequest  包含客户端请求的 ServletRequest 对象
     * @param servletResponse 包含 servlet 的响应的 ServletResponse 对象
     * @throws ServletException 如果发生妨碍 servlet 正常操作的异常
     * @throws IOException      果发生输入或输出异常
     */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
   
        //请求相关内容    ServletRequest  ;   相应相关内容  ServletResponse
        /**
         * 在控制台内打印输出
         */
        System.out.println("这是我的第一个Servlet!");

        /**
         * 利用输出流输出系统时间,在浏览器中显示
         */
        PrintWriter printWriter = servletResponse.getWriter();
        Date date = new Date();
        printWriter.println(date);
        printWriter.close();

        /**
         * 利用流输出信息在浏览器内显示
         * 解决浏览器显示乱码问题
         */
        servletResponse.setContentType("text/html;charset=utf-8");
        servletResponse.getWriter().println("这是我的第一个Servlet");

    }

    /**
     * 返回有关 servlet 的信息,比如作者、版本和版权。
     * <p>
     * 此方法返回的字符串应该是纯文本,不应该是任何种类的标记(比如 HTML、XML,等等)。
     *
     * @return 包含 servlet 信息的 String
     */
    @Override
    public String getServletInfo() {
   
        return null;
    }

    /**
     * 销毁(清除所有资源)
     * <p>
     * 由 servlet 容器调用,指示将从服务中取出该 servlet。
     * 此方法仅在 servlet 的 service 方法已退出或者在过了超时期之后调用一次。
     * 在调用此方法之后,servlet 容器不会再对此 servlet 调用 service 方法。
     * 此方法为 servlet 提供了一个清除持有的所有资源(比如内存、文件句柄和线程)的机会,并确保任何持久状态都与内存中该 servlet 的当前状态保持同步。
     */
    @Override
    public void destroy() {
   

    }
}

地址栏输入:http://localhost:8080/firstservlet/test (firstservlet是项目资源名称、test是Servlet名称)

1.4.4 解决浏览器输出显示乱码问题
		/**
         * 利用流输出信息在浏览器内显示
         * 解决浏览器显示乱码问题
         */
        servletResponse.setContentType("text/html;charset=utf-8");
        servletResponse.getWriter().println("这是我的第一个Servlet");
1.4.5 解决idea控制台乱码

如果还解决不了,参考文章有多种解决方法:https://blog.csdn.net/weixin_44170221/article/details/105478788

-Dfile.encoding=utf-8

在这里插入图片描述

1.5 Web中路径问题
1.5.1 路径分类

关于路径分类有这么几种:绝对路径相对路径根路径

1.5.2 路径分析

绝对路径 :用在不同网站之间跳转,比如:http://www.baidu.com.image/sky.png

相对路径 :用在同一网站中,比如:image/1.jpg,仅限静态资源,如果页面比较多,并且使用框架,会出现混乱

根路径 :根指定就是主机名(服务器)

比如:/servletdemo/loginservlet,如果在浏览器中,/ 表示主机名http://localhost:8080/

比如:/loginservlet,如果在服务器中,/ 表示项目路径/servletdemo

二、Servlet的使用

2.1 Servlet核心接口和类

关于使用Servlet有三种方法: 实现Servlet接口、继承GenericServlet 抽象类、继承HttpServlet抽象类

2.1.1 实现Servlet接口(繁琐)

关于实现Servlet接口覆盖其所有方法,其实在上面的1.4.3章节中已经写过了,但是我们现在再写一遍!

package com.mylifes1110.java;

import javax.servlet.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;

/**
 * Servlet
 * 实现Servlet接口中的所有方法
 */
public class MyServlet implements Servlet {
   
    /**
     * 初始化方法
     *
     * @param servletConfig 包含 servlet 的配置和初始化参数的 ServletConfig 对象
     * @throws ServletException 如果发生妨碍 servlet 正常操作的异常
     */
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
   
        //Servlet初始化工作
    }

    /**
     * 获取Servlet配置信息
     *
     * @return 返回 ServletConfig 对象,该对象包含此 servlet 的初始化和启动参数。返回的 ServletConfig 对象是传递给 init 方法的对象。
     */
    @Override
    public ServletConfig getServletConfig() {
   
        return null;
    }

    /**
     * 提供服务
     * <p>
     * 由 servlet 容器调用,以允许 servlet 响应某个请求。
     * 此方法仅在 servlet 的 init() 方法成功完成之后调用。
     * 应该为抛出或发送错误的 servlet 设置响应的状态代码。
     *
     * @param servletRequest  包含客户端请求的 ServletRequest 对象
     * @param servletResponse 包含 servlet 的响应的 ServletResponse 对象
     * @throws ServletException 如果发生妨碍 servlet 正常操作的异常
     * @throws IOException      果发生输入或输出异常
     */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
   
        //请求相关内容    ServletRequest  ;   相应相关内容  ServletResponse
        /**
         * 在控制台内打印输出
         */
        System.out.println("这是我的第一个Servlet!");

        /**
         * 利用输出流输出系统时间,在浏览器中显示
         */
        PrintWriter printWriter = servletResponse.getWriter();
        Date date = new Date();
        printWriter.println(date);
        printWriter.close();

        /**
         * 利用流输出信息在浏览器内显示
         * 解决浏览器显示乱码问题
         */
        servletResponse.setContentType("text/html;charset=utf-8");
        servletResponse.getWriter().println("这是我的第一个Servlet");

    }

    /**
     * 返回有关 servlet 的信息,比如作者、版本和版权。
     * <p>
     * 此方法返回的字符串应该是纯文本,不应该是任何种类的标记(比如 HTML、XML,等等)。
     *
     * @return 包含 servlet 信息的 String
     */
    @Override
    public String getServletInfo() {
   
        return null;
    }

    /**
     * 销毁(清除所有资源)
     * <p>
     * 由 servlet 容器调用,指示将从服务中取出该 servlet。
     * 此方法仅在 servlet 的 service 方法已退出或者在过了超时期之后调用一次。
     * 在调用此方法之后,servlet 容器不会再对此 servlet 调用 service 方法。
     * 此方法为 servlet 提供了一个清除持有的所有资源(比如内存、文件句柄和线程)的机会,并确保任何持久状态都与内存中该 servlet 的当前状态保持同步。
     */
    @Override
    public void destroy() {
   

    }
}

我们看到了实现Servlet接口的方法来使用Servlet。其中我们可以看到5个方法,分别是初始化、获取配置、提供服务、返回信息以及销毁。而我们有没有发现5个方法中有对我们来说有不是必须全部写在里面的方法呢?或者是可以优化,把某个方法封装来实现复用呢?其实有的,5个方法中初始化和销毁我们可以封装一下,实现多个Servlet之间复用。而获取配置、返回信息感觉是没有必要的。所以我们引入了GenericServlet抽象类。那么继承这个抽象类有什么好处呢?会比我们实现Servlet接口更简单化吗?继续向下看吧那就!

2.1.2 继承GenericServlet 抽象类(无协议)

GenericServlet的内部也实现了Servlet接口,并重写了初始化、获取配置、返回信息、销毁方法,有没有发现少了一个提供服务呢?它的做法很聪明,重写了我们想要简化的那四个方法并返回了默认没有的值(空值等),这就相当于我们实现了Servlet接口,并没有给他们编写方法体代码而已。那么少的那个提供服务,它做了什么呢?它的做法是把提供服务的方法用abstract修饰成了抽象类,所以我们继承这个类必须覆盖该抽象方法。

以上所述,GenericServlet 使编写 Servlet 变得更容易。它提供生命周期方法 init 和 destroy 的简单实现,要编写一般的 Servlet,只需重写抽象 service 方法提供服务即可。 (那么这个代码就简化了太多了,看代码吧!)

package com.mylifes1110.java;

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;

/**
 * 继承GenericServlet抽象类并重写service方法提供服务
 */
public class MyServlet2 extends GenericServlet {
   
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
   
        System.out.println("提供服务!");
    }
}

那么我说的你们不信的话,我给你们再贴一下源码,你们可以看看,或者觉得透着些。

在这里插入图片描述

destroy销毁方法

在这里插入图片描述

getServletConfig获取配置方法(this.config在最上面声明是这样声明空值的:private transient ServletConfig config;

在这里插入图片描述

getServletInfo返回信息方法

在这里插入图片描述

init初始化方法

在这里插入图片描述

然而主角一般都是最后登场,那就是service提供服务方法被写为抽象方法

在这里插入图片描述

这样来,我们不需要那4个方法时,就可以直接覆盖service方法去提供服务,假如需要某一个方法时,我们可以直接选择性的重写父类方法即可!然而小伙伴们有没有想过,GenericServlet只是定义了一般的、与协议无关的servlet,而编写基于Web上的HTTP协议下的servlet,所以GenericServlet与协议无关是不安全的,鉴于目前HTTP和HTTPS的广泛使用,市面上很少有Web不使用HTTP协议的。那么这个问题来的这么突然,我们怎么办呢?有没有更好的使用Servlet的方法又安全、又简单化呢?答案很明显,在上面我介绍了三种使用Servlet的方法,现在只介绍了两种,那么答案显而易见就是第三种方法了。于是,我们强大的HttpServlet抽象类登场了!(我发现主角总是最后登场的,哈哈!)

2.1.3 继承HttpServlet抽象类(有协议,推荐使用)

HttpServlet抽象类的内部继承了GenericServlet抽象类(证明HttpServlet有了上面我们说到的那四个方法),并扩展提供了适用于Web站点的HTTP协议的几个方法,也就是说HttpServlet的子类至少必须重写一个方法,该方法通常是如下这几个方法:

  • doGet,如果 servlet 支持 HTTP GET 请求
  • doPost,用于 HTTP POST 请求
  • doPut,用于 HTTP PUT 请求
  • doDelete,用于 HTTP DELETE 请求
  • initdestroy,用于管理 servlet 的生命周期内保存的资源
  • getServletInfo,servlet 使用它提供有关其自身的信息

注意:因为我们是继承了GenericServlet抽象类,所以没有理由再去重写 service 方法。service 通过将标准 HTTP 请求分发给每个 HTTP 请求类型的处理程序方法(上面列出的 doXXX 方法)来处理它们。(只需要使用扩展的Http的所需方法即可)

package com.mylifes1110.java;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 继承HttpServlet抽象类
 */
public class MyServlet3 extends HttpServlet {
   
    /**
     * doGet    HTTP中Get请求
     * doPost   HTTP中Post请求
     */

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   
//        super.doGet(req, resp);
        /**
         * 当接受参数时,我们不使用Get请求,就在内部调用doPost方法,这样传来参数后,就避免了使用Get请求方式(默认使用一个请求方式)
         */
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
   
       	resp.getWriter().println("这是我的第一个Servlet!");
    }
}

那我们也看一下源码是怎么实现的!

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

看到这里,我们上面说到,为什么没有理由去重写service方法呢,在这里我们去做解释!看源码!

在这里插入图片描述

你会发现这个service方法参数是父类请求、响应的参数。而传入参数后做了强转为子类参数进行使用(因为父类参数是不可以使用的,我们使用的是关于Http的参数),又调用了this.service方法,我们会想这不是自己调用自己陷进去一种死循环调用吗?然而源码内还提供了一个传入子类参数的service方法。如下:

在这里插入图片描述

在上面的那个service方法中this.service(request, response); 这里我们调用的是哪一个service方法呢?然后这里我们就会想到了JavaSE中的多态,一个传入父类参数的service,还有一个传入子类参数的service方法。至于选择哪一个,就看我们传入的参数了。它会精确匹配参数类型而选择传入哪一个service方法中。而这个传入子类参数的service方法内做了什么呢?看我标红的段落,传入请求参数后,调用Method方法,如果调用方法后得到的是GET,那就会调用doGet方法,而doGet方法就是上面我们说到的HTTP中的Get请求!举一反三,其他的Post、Delete等都是如此!

在这里插入图片描述

也许就有人会问Method方法是什么,那我正好就粘出来,你们就明白了!(返回一个字符串!)

2.2 Servlet的两种配置方式

Servlet的两种配置方式为web.xml配置方式和注解配置方式

2.2.1 web.xml配置方式(支持所有版本)

容器在进行url-pattern配置的时候是遵循一定的匹配原则的

url-pattern定义匹配规则,取值说明如下表:

url-pattern配置名称 配置说明 取值说明
/具体名称 精确匹配 只有url路径是具体名称的时候才会触发Servlet
*.xxx 后缀匹配 只要是以xxx结尾的就匹配成功并触发Servlet
/a/b/* 目录匹配 访问时必须书写/a/b/*路径,*的话随便输入(必须以"/“开头,以”*"结尾)
/* 通配符匹配 匹配所有请求,包含服务器的所有资源
/ 通配符匹配 匹配所有请求,包含服务器的所有资源,不包括 .jsp

load-on-startup

  1. 元素标记容器是否应该在web应用程序启动的时候就加载触发Servlet初始化
  2. 它的值必须是一个整数,表示Servlet被加载的先后顺序
  3. 如果该元素的值是负数或者没有设置,则容器会当Servlet被请求时在加载
  4. 如果值为正整数或者0时,表示容器在应用程序启动时就加载并触发了Servlet的初始化。(值越小,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>myservlet</servlet-name>
        <!--全限定名路径-->
        <servlet-class>com.mylifes1110.java.MyServlet</servlet-class>
        <!--启动时被加载并初始化-->
        <load-on-startup>0</load-on-startup>
    </servlet>
    <!--映射配置-->
    <servlet-mapping>
        <!--Servlet属性名称-->
        <servlet-name>myservlet</servlet-name>
        <!--精确匹配-->
        <url-pattern>/test</url-pattern>
        <!--后缀匹配-->
        <url-pattern>*.myservlet</url-pattern>
        <!--通配符匹配-->
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>
2.2.2 注解类WebServlet配置方式(支持3.0版本以后)

@WebServlet有4个属性我们目前可以使用分别是name、value、urlPatterns和loadOnStartup

注解属性 类型 属性说明
name String 指定Servlet 的 name 属性,等价于 <servlet-name>。如果没有显式指定,则该 Servlet 的取值即为类的全限定名
value String[] 配置url路径(idea为我们设置路径提供了两个属性,根据自己习惯去用)
urlPatterns String[] 配置url路径,与value作用相同,不能同时使用
loadOnStartup int 配置Servlet的创建的时机, 如果是0或者正数启动程序时,则创建,如果是负数,则访问时创建
initParams WebInitParam[] 指定一组 Servlet 初始化参数,等价于<init-param>标签。
asyncSupported boolean 声明 Servlet 是否支持异步操作模式,等价于<async-supported> 标签
description String 该 Servlet 的描述信息,等价于 <description>标签
displayName String 该 Servlet 的显示名,通常配合工具使用,等价于 <display-name>标签
package com.mylifes1110.java;

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;

/**
 * value定义了多个url路径:value = {"/hi", "/hello", "*.haha"}
 * Servlet的创建时机设置为:loadOnStartup = 0(启动程序时创建并初始化)
 */
@WebServlet(name = "HiServlet", value = {
   "/hi", "/hello", "*.haha"}, loadOnStartup = 0)
public class HiServlet extends HttpServlet {
   
    @Override
    public void init() throws ServletException {
   
        System.out.println("初始化方法");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
   
        System.out.println
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值