Servlet学习总结(一)

本文深入探讨Servlet的基础知识,包括其实现方式、执行流程、生命周期管理及线程安全性问题,并介绍了HttpServlet的使用优势和配置细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近学到了JavaWeb阶段,随手进行总结:

一、Servlet介绍

1.Servlet概述

    Servlet是JavaEE规范之一,是一个运行在web服务端的java小程序,它可以用于接收和响应客户端的请求。

2.Servlet的实现方法

    1.实现Servlet接口
        需要重写Servlet接口中所有的抽象方法
    2.继承GenericServlet
        只需要重写Service()方法
    3.继承HttpServlet
        只需要重写doGet()和doPost()方法

3.Servlet的执行过程

浏览器输入url,敲回车访问服务器,整个资源的查找过程:
    通过浏览器发送请求,请求首先到达Tomcat服务器,然后Tomcat服务器会解析请求url,然后根据url中的虚拟目录在部署的应用列表 找到相应的web应用。接下来,找到web.xml配置文件,在web.xml中,根据<servlet-mapping>中的<servlet-name>找到<servlet>中的<servlet-name>,根据<servlet-name>找到<servlet-class>具体的Servlet文件,找到后执行service方法或者doGet()/doPost()方法,最后由Servlet响应给客户端浏览器。
     总结:浏览器——>Tomcat服务器——>我们的应用——>应用中的web.xml——>FirstServlet——>响应浏览器

4.Servlet的细节

Servlet:接口
		--GenericServlet:抽象的实现类
			--HttpServlet:抽象的子类

二、Servlet-HttpServlet

    这里着重讲HttpServlet,因为在用的最多的就是继承HttpServlet

1.HttpServlet的优势

HttpServlet做了Http协议相关的细节封装,可以简化程序员的开发,并且继承了HttpServlet后,只需要重写doGet/doPost方法,这里先做一下简单介绍,后面会详细讲解

2.Servlet的生命周期

 Servlet的生命周期分为三个阶段,分别是init、service、destroy
    init:在Servlet对象创建的时候(浏览器第一次访问的时候)执行,只会执行一次;一般用来做加载资源等初始化动作
	service:每次浏览器访问资源,都会执行一次,提供服务。 执行多次
	destroy:在Servlet对象销毁(tomcat正常关闭)之前执行,只会执行一次;一般用来做释放资源等动作

3.Servlet的线程安全问题

3.1 Servlet产生线程安全问题的原因

 回顾多线程安全问题产生原因:
    1.多线程程序
    2.多个线程共享资源
    3.多个线程同时对共享资源进行增删改的操作

 而tomcat提供的Servlet:
    	1.tomcat是一个多线程程序,每一次用户请求,tomcat都会使用一个子线程来提供服务
		2.多次请求,访问同一个Servlet类(一个Servlet类,在内存中只有一个对象),使用的都是同一个Servlet对象,成员变量也是同一份;
		3.多个请求都会修改同一份成员变量

示例:

/**
 * 演示Servlet的线程安全问题:
 *    示例需求:
 *       模拟网上看书的翻页功能。
 *       (类似的有浏览商品的翻页,浏览论坛帖子的翻页)
 * @author 
 * @Company 
 */
public class ServletDemo4 extends HttpServlet {

    /**
     * 我们讨论的是类成员的线程安全问题,所以要定义一个类成员
     */
    //定义浏览书籍的页码,都是从第一页开始的
    private int currentPage = 1;

    /**
     * 真正翻页看书的功能
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.获取当前要看的书名(此处我们今天先来用以下,明天来着重讲解请求和响应对象)
        String bookName = req.getParameter("bookName");
        //2.输出书名和当前页码
        System.out.println("您看的是:"+bookName+",当前页码是:"+currentPage);
        //3.执行翻页
        currentPage++;
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

     理想状态下,用户每次请求都来看自己该看的页码,但是结果并不是,所以它是线程不安全的。

3.2解决Servlet线程安全问题

    1.不声明成员变量(推荐);
	2.加同步代码块

4.Servlet不同映射方式

     第一种:指名道姓的方式

          此种方式,只有和映射配置一模一样时,Servlet才会接收和响应来自客户端的请求。

     第二种:/开头+通配符的方式

          此种方式,只要符合目录结构即可,不用考虑结尾是什么。

     第三种:通配符+固定格式结尾

          此种方式,只要符合固定结尾格式即可,其前面的访问URI无须关心(注意协议,主机和端口必须正确)

     拓展:多路径映射Servlet

          在web.xml配置Servlet,可以配置多个不同的路径,实现同一个Servlet来执行不同的代码


public class ServletDemo7 extends HttpServlet {

    /**
     * 根据不同的请求URL,做不同的处理规则
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.获取当前请求的URI
        String uri = req.getRequestURI();
        uri = uri.substring(uri.lastIndexOf("/"),uri.length());
        //2.判断是1号请求还是2号请求
        if("/servletDemo7".equals(uri)){
            System.out.println("ServletDemo7执行1号请求的业务逻辑:商品单价7折显示");
        }else if("/demo7".equals(uri)){
            System.out.println("ServletDemo7执行2号请求的业务逻辑:商品单价8折显示");
        }else {
            System.out.println("ServletDemo7执行基本业务逻辑:商品单价原价显示");
        }
    }

    /**
     * 调用doGet方法
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

在web.xml中配置Servlet

<!--配置ServletDemo7-->
<servlet>
    <servlet-name>servletDemo7</servlet-name>
    <servlet-class>com.itheima.web.servlet.ServletDemo7</servlet-class>
</servlet>
<!--映射路径1-->
<servlet-mapping>
    <servlet-name>servletDemo7</servlet-name>
    <url-pattern>/demo7</url-pattern>
</servlet-mapping>
<!--映射路径2-->
<servlet-mapping>
    <servlet-name>servletDemo7</servlet-name>
    <url-pattern>/servletDemo7</url-pattern>
</servlet-mapping>
<!--映射路径3-->
<servlet-mapping>
    <servlet-name>servletDemo7</servlet-name>
    <url-pattern>/servlet/*</url-pattern>
</servlet-mapping>

5.Servlet的创建时机

Servlet默认创建时机:浏览器第一次访问创建
可以设置Servlet在服务器启动加载时就创建:
    在web.xml中的servlet标签中:
		<load-on-startup>正整数</load-on-startup>即可
<!--配置ServletDemo3-->
<servlet>
    <servlet-name>servletDemo3</servlet-name>
    <servlet-class>com.itheima.web.servlet.ServletDemo3</servlet-class>
    <!--配置Servlet的创建顺序,当配置此标签时,Servlet就会改为应用加载时创建
        配置项的取值只能是正整数(包括0),数值越小,表明创建的优先级越高
    -->
    <load-on-startup>1</load-on-startup>
</servlet>

6.默认Servlet

    默认Servlet是由服务器提供的一个Servlet,它配置在Tomcat的conf目录下的web.xml中,它的映射路径是<url-pattern>/<url-pattern>,我们在发送请求时,首先会在我们应用中的web.xml中查找映射配置,找到就执行,这块没有问题。但是当找不到对应的Servlet路径时,就去找默认的Servlet,由默认Servlet处理。所以,一切都是Servle。

三、ServletConfig

    1.ServletConfig概述

           1.1基本概念

                它是Servlet的配置参数对象,在Servlet规范中,允许为每个Servlet都提供一些初始化配置。所以,每个Servlet都一个自己的ServletConfig。它的作用是在Servlet初始化期间,把一些配置信息传递给Servlet。

           1.2生命周期

                由于它是在初始化阶段读取了web.xml中为Servlet准备的初始化配置,并把配置信息传递给Servlet,所以生命周期与Servlet相同。这里需要注意的是,如果Servlet配置了<load-on-startup>1</load-on-startup>,那么ServletConfig也会在应用加载时创建

           1.3配置ServletConfig

                使用<servlet>标签中的<init-param>标签来配置。Servlet的初始化参数都是配置在Servlet的声明部分的。并且每个Servlet都支持有多个初始化参数,并且初始化参数都是以键值对的形式存在的

<!--配置ServletDemo8-->
<servlet>
    <servlet-name>servletDemo8</servlet-name>
    <servlet-class>com.itheima.web.servlet.ServletDemo8</servlet-class>
    <!--配置初始化参数-->
    <init-param>
        <!--用于获取初始化参数的key-->
        <param-name>encoding</param-name>
        <!--初始化参数的值-->
        <param-value>UTF-8</param-value>
    </init-param>
    <!--每个初始化参数都需要用到init-param标签-->
    <init-param>
        <param-name>servletInfo</param-name>
        <param-value>This is Demo8</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>servletDemo8</servlet-name>
    <url-pattern>/servletDemo8</url-pattern>
</servlet-mapping>

           1.4常用方法

/**
 * 演示Servlet的初始化参数对象
 * @author 黑马程序员
 * @Company http://www.itheima.com
 */
public class ServletDemo8 extends HttpServlet {

    //定义Servlet配置对象ServletConfig
    private ServletConfig servletConfig;

    /**
     * 在初始化时为ServletConfig赋值
     * @param config
     * @throws ServletException
     */
    @Override
    public void init(ServletConfig config) throws ServletException {
        this.servletConfig = config;
    }

    /**
     * doGet方法输出一句话
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.输出ServletConfig
        System.out.println(servletConfig);
        //2.获取Servlet的名称
        String servletName= servletConfig.getServletName();
        System.out.println(servletName);
        //3.获取字符集编码
        String encoding = servletConfig.getInitParameter("encoding");
        System.out.println(encoding);
        //4.获取所有初始化参数名称的枚举
        Enumeration<String> names = servletConfig.getInitParameterNames();
        //遍历names
        while(names.hasMoreElements()){
            //取出每个name
            String name = names.nextElement();
            //根据key获取value
            String value = servletConfig.getInitParameter(name);
            System.out.println("name:"+name+",value:"+value);
        }
        //5.获取ServletContext对象
        ServletContext servletContext = servletConfig.getServletContext();
        System.out.println(servletContext);
    }

    /**
     * 调用doGet方法
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

四、ServletContext 

         1、ServletContext概述

                          ServletContext对象,它是应用上下文对象。每一个应用有且只有一个ServletContext对象。它可以实现让应用中所有Servlet间的数据共享。

         2、ServletContext生命周期

                        出生——活着——死亡

                       出生: 应用一加载,该对象就被创建出来了。一个应用只有一个实例对象。(Servlet和ServletContext都是单例的)

                       活着:只要应用一直提供服务,该对象就一直存在。

                       死亡:应用被卸载(或者服务器挂了),该对象消亡。

         3、域对象概念

                      域对象的概念,它指的是对象有作用域,即有作用范围。域对象的作用,域对象可以实现数据共享。不同作用范围的域对象,共享数据的能力不一样。在Servlet规范中,一共有4个域对象。今天我们讲解的ServletContext就是其中一个。它也是我们接触的第一个域对象。它是web应用中最大的作用域,叫application域。每个应用只有一个application域。它可以实现整个应用间的数据共享功能。

         4、获取ServletContext


public class ServletDemo9 extends HttpServlet {

    //定义Servlet配置对象ServletConfig
    private ServletConfig servletConfig;

    /**
     * 在初始化时为ServletConfig赋值
     * @param config
     * @throws ServletException
     */
    @Override
    public void init(ServletConfig config) throws ServletException {
        this.servletConfig = config;

    }

    /**
     *
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.获取ServletContext对象
        ServletContext servletContext = servletConfig.getServletContext();
        System.out.println(servletContext);
    }

    /**
     * 调用doGet方法
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

         4、配置ServletContext

<!--配置应用初始化参数-->
<context-param>
    <!--用于获取初始化参数的key-->
    <param-name>servletContextInfo</param-name>
    <!--初始化参数的值-->
    <param-value>This is application scope</param-value>
</context-param>
<!--每个应用初始化参数都需要用到context-param标签-->
<context-param>
    <param-name>globalEncoding</param-name>
    <param-value>UTF-8</param-value>
</context-param>

暂时只总结到这里,在后续学习还会继续总结,希望大家多多指导!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值