Servlet-学习笔记

Servlet-授课

一、 Servlet

1.1 Servlet概述

Servlet是SUN公司提供的一套规范,名称就叫Servlet规范,它也是JavaEE规范之一。我们可以像学习Java基础一样,通过API来学习Servlet。这里需要注意的是,在我们之前JDK的API中是没有Servlet规范的相关内容,需要使用JavaEE的API。目前在Oracle官网中的最新版本是JavaEE8,该网址中介绍了JavaEE8的一些新特性。当然,我们可以通过访问官方API,学习和查阅里面的内容。

打开官方API网址,在左上部分找到javax.servlet包,在左下部分找到Servlet,如下图显示:
Servlet-学习笔记_第1张图片

Servlet的API官网
通过阅读API,我们得到如下信息:
第一:Servlet是一个运行在web服务端的java小程序
第二:它可以用于接收和响应客户端的请求
第三:要想实现Servlet功能,可以实现javax.servlet.Servlet接口,继承GenericServlet或者HttpServlet
第四:核心方法:service(), 每次请求都会执行service方法
第五:Servlet还支持配置
具体请看下图:
Servlet-学习笔记_第2张图片

1.2 Servlet入门

1.2.1 Servlet使用步骤

搭建web环境流程

一、新建项目-选择Maven-Next
Servlet-学习笔记_第3张图片
Servlet-学习笔记_第4张图片
点击Finish
Servlet-学习笔记_第5张图片

Servlet-学习笔记_第6张图片
如果上面未出现WebApplication,则说明你未完全添加web支持,但是系统认定你有web支持,所以就不会显示出来,只需要把web相关的都删除即可。
操作步骤: File->Project Structure->(然后分别选择Facets和Atifacts)- 删除web相关即可。下面以Facets为例。
Servlet-学习笔记_第7张图片

结构目录如下:

Servlet-学习笔记_第8张图片
配置本地服务器

Servlet-学习笔记_第9张图片
Servlet-学习笔记_第10张图片
Servlet-学习笔记_第11张图片
点 Fix
Servlet-学习笔记_第12张图片
点击运行,就可以运行index.jsp文件。
Servlet-学习笔记_第13张图片
如果想修改默认的index.jsp页面可以在web.xml中添加

<welcome-file-list>
        <welcome-file>/admin.jspwelcome-file>
 welcome-file-list>

基本框架搭建完成,要需要Servlet,需要我们导入依赖包
1、在pom.xml中加入

<dependencies>
        <dependency>
            <groupId>javax.servletgroupId>
            <artifactId>servlet-apiartifactId>
            <version>2.5version>
        dependency>
    dependencies>

2、使用Servlet有三种方法:
1、实现Servlet接口,2、继承HttpServlet(经常使用), 3、继承GenericServlet(三者的关系如下)
Servlet-学习笔记_第14张图片

第一种方法:实现Servlet接口

** 我们先使用实现Servlet接口的方法:需要重写的方法很多,其余都不管,我们只注重service方法即可。**
Servlet-学习笔记_第15张图片
3、在web.xml加入配置
每个servlet都需要在web.xml进行声明和映射。否则无法使用。


    <servlet>
		
        <servlet-name>sutdentservlet-name>
		
        <servlet-class>com.lvmanba.servlet.StudentServletservlet-class>
    servlet>

    <servlet-mapping>
		
        <servlet-name>sutdentservlet-name>
		
        <url-pattern>/sutdenturl-pattern>
    servlet-mapping>

启动Tomcat,访问设置的路径
Servlet-学习笔记_第16张图片
运行流程分析:
Servlet-学习笔记_第17张图片

第二种方法:继承GenericServlet

如果是要使用GenericServlet,新增一个servlet,只要继承GenericServlet即可,重写方法只有一个。要想访问,同样也在web.xml配置一组声明和映射即可。
Servlet-学习笔记_第18张图片

第三种方法:继承HttpServlet

继承的时候没有提示需要重写方法, 我们可以通过alt+insert来选择 OverrideMethods来选择doGet和doPost方法。
如果不重写任何方法,出现了访问错误,状态码是405。提示信息是:方法不允许。需要重写里面的doGet和doPost方法来接收get方式和post方式的请求
Servlet-学习笔记_第19张图片
最后在xml加入一组配置:既声明和映射。

1.2.2 Servlet执行过程分析

我们通过浏览器发送请求,请求首先到达Tomcat服务器,由服务器解析请求URL,然后在部署的应用列表中找到我们的应用。接下来,在我们的应用中找应用里的web.xml配置文件,在web.xml中找到FirstServlet的配置,找到后执行service方法,最后由FirstServlet响应客户浏览器。整个过程如下图所示:
Servlet-学习笔记_第20张图片
一句话总结执行过程:
浏览器——>Tomcat服务器——>我们的应用——>应用中的web.xml——>FirstServlet——>响应浏览器

1.2.3 Servlet实现三种方法分析

我们在实现Servlet功能时,可以选择以下三种方式:
第一种:实现Servlet接口,接口中的方法必须全部实现。
​ 使用此种方式,表示接口中的所有方法在需求方面都有重写的必要。此种方式支持最大程度的自定义。
第二种:继承GenericServlet,service方法必须重写,其他方可根据需求,选择性重写。
​ 使用此种方式,表示只在接收和响应客户端请求这方面有重写的需求,而其他方法可根据实际需求选择性重写,使我们的开发Servlet变得简单。但是,此种方式是和HTTP协议无关的。
第三种:继承HttpServlet,它是javax.servlet.http包下的一个抽象类,是GenericServlet的子类。如果我们选择继承HttpServlet时,只需要重写doGet和doPost方法,不要覆盖service方法。
​ 使用此种方式,表示我们的请求和响应需要和HTTP协议相关。也就是说,我们是通过HTTP协议来访问的。那么每次请求和响应都符合HTTP协议的规范。请求的方式就是HTTP协议所支持的方式(目前我们只知道GET和POST,而实际HTTP协议支持7种请求方式,GET POST PUT DELETE TRACE OPTIONS HEAD )。
Servlet-学习笔记_第21张图片

1.3 Servlet使用细节

1.3.1 Servlet的生命周期

对象的生命周期,就是对象从生到死的过程,即:出生——活着——死亡。既是对象创建到销毁的过程。
出生:请求第一次到达Servlet时,对象就创建出来,并且初始化成功。只出生一次,就放到内存中
活着:服务器提供服务的整个过程中,该对象一直存在,每次只是执行service方法。
死亡:当服务停止时,或者服务器宕机时,对象消亡。
Servlet对象只会创建一次,销毁一次。所以,Servlet对象只有一个实例。如果一个对象实例在应用中是唯一的存在,那么我们就说它是单实例的,即运用了单例模式。

public class OtherServlet extends HttpServlet {
    @Override
    public void init() throws ServletException { 
        System.out.println("对象出生了");  //只执行一次,常驻内存
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("我是HttpSerlet...");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
    @Override
    public void destroy() {
        System.out.println("对象销毁了!"); //tomcat停止的时候才执行
    }
}

1.3.2 Servlet的线程安全

由于Servlet运用了单例模式,即整个应用中只有一个实例对象,所以我们需要分析这个唯一的实例中的类成员是否线程安全。接下来,我们来看下面的的示例:

/*
    Servlet线程安全
 */
public class ServletDemo04 extends HttpServlet{
    //1.定义用户名成员变量
    //private String username = null;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = null;
        //synchronized (this) {
            //2.获取用户名
            username = req.getParameter("username");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //3.获取输出流对象
            PrintWriter pw = resp.getWriter();
            //4.响应给客户端浏览器
            pw.print("welcome:" + username);
            //5.关闭
            pw.close();
        //}
    }

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

启动两个浏览器,输入不同的参数,访问之后发现输出的结果都是一样,所以出现线程安全问题。
Servlet-学习笔记_第22张图片
通过上面的测试我们发现,在Servlet中定义了类成员之后,多个浏览器都会共享类成员的数据。其实每一个浏览器端发送请求,就代表是一个线程,那么多个浏览器就是多个线程,所以测试的结果说明了多个线程会共享Servlet类成员中的数据,其中任何一个线程修改了数据,都会影响其他线程。因此,我们可以认为Servlet它不是线程安全的。

分析产生这个问题的根本原因,其实就是因为Servlet是单例,单例对象的类成员只会随类实例化时初始化一次,之后的操作都是改变,而不会重新初始化。

解决这个问题也非常简单,就是在Servlet中定义类成员要慎重。如果类成员是共用的,并且只会在初始化时赋值,其余时间都是获取的话,那么是没问题。如果类成员并非共用,或者每次使用都有可能对其赋值,那么就要考虑线程安全问题了,把变量定义到doGet或者doPost方法里面去就可以了,或者加上同步。

解决的方法1:

//private String username=null;
@Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username=null;  //将变量放在方法中
        //接收浏览器的参数
        username = req.getParameter("username");
        try {
            Thread.sleep(30000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //将用户名响应给浏览器
        PrintWriter pw = resp.getWriter();
        pw.println("welcome:"+username);
        pw.close();
    }

解决的方法2:

private String username = null;
        @Override
        protected void doGet (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            synchronized (this){  
                //接收浏览器的参数
                username = req.getParameter("username");
                try {
                    Thread.sleep(30000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //将用户名响应给浏览器
                PrintWriter pw = resp.getWriter();
                pw.println("welcome:" + username);
                pw.close();
            }
        }

1.3.3 Servlet的映射的三种方式

Servlet支持三种映射方式,以达到灵活配置的目的。

第一种:指名道姓的方式

​ 此种方式,只有和映射配置一模一样时,Servlet才会接收和响应来自客户端的请求。
​ 例如:映射为:/servletDemo5
​ 访问URL:http://localhost:8585/servlet_demo/servletDemo5
Servlet-学习笔记_第23张图片

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

​ 此种方式,只要符合目录结构即可,不用考虑结尾是什么。
​ 例如:映射为:/servlet/*
​ 访问URL:http://localhost:8585/servlet/itheima
​ http://localhost:8585/servlet/itcast.do
​ 这两个URL都可以。因为用的*,表示/servlet/后面的内容是什么都可以。
Servlet-学习笔记_第24张图片

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

​ 此种方式,只要符合固定结尾格式即可,其前面的访问URI无须关心(注意协议,主机和端口必须正确)
​ 例如:映射为:.do
​ 访问URL:http://localhost:8585/servlet/itcast.do
​ http://localhost:8585/itheima.do
​ 这两个URL都可以方法。因为都是以.do作为结尾,而前面用
号通配符配置的映射,所有无须关心。
Servlet-学习笔记_第25张图片
通过测试我们发现,Servlet支持多种配置方式,但是由此也引出了一个问题,当有两个及以上的Servlet映射都符合请求URL时,由谁来响应呢?注意:HTTP协议的特征是一请求一响应的规则。那么有一个请求,必然有且只有一个响应。所以,我们接下来明确一下,多种映射规则的优先级。
先说结论:指名道姓的方式优先级最高,带有通配符的映射方式,有/的比没/的优先级高
所以,我们前面讲解的三种映射方式的优先级为:第一种>第二种>第三种。
演示代码如下:

public class ServletDemo6 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("ServletDemo6接收到了请求");
    }
   
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}

<servlet>
    <servlet-name>servletDemo6servlet-name>
    <servlet-class>com.itheima.web.servlet.ServletDemo6servlet-class>
servlet>
<servlet-mapping>
    <servlet-name>servletDemo6servlet-name>
    <url-pattern>/*url-pattern>
servlet-mapping>

运行结果如下:
Servlet-学习笔记_第26张图片

多路径映射Servlet

给一个Servlet配置多个访问映射,也可以配置一个/开头+通配符配置一个映射,然后获取URL,根据参数来实现不同的功能。

首先,创建一个Servlet:

public class MultpleServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //定义商品的价格
        int price = 1000;
        //获取为war包(在tomcat中定义的虚拟路径后面的参数)  //http://localhost:8080/lvmanba/a
        String path = req.getRequestURI();  //  获取后为 /lvmanba/a
        int i = path.lastIndexOf("/");      //  查找/出现的最后位置  8
        String s = path.substring(i+1);     //  从第几个开始(包括开始)截去到最后
        if(s.equals("vip")){
            System.out.println(price*0.9);
        }else if(s.equals("vvip")){
            System.out.println(price*0.8);
        }else{
            System.out.println(price);
        }
    }

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

接下来,在web.xml配置Servlet:用第二种方式配置: 为以 /lvmanba/ 开始,后面随意

    <servlet>  
        <servlet-name>multipleservlet-name>
        <servlet-class>com.lvmanba.servlet.MultpleServletservlet-class>
    servlet>
    <servlet-mapping>
        <servlet-name>multipleservlet-name>
        <url-pattern>/lvmanba/*url-pattern>
    servlet-mapping>

获取给multiple配置多个映射

	
	<servlet>
        <servlet-name>multipleservlet-name>
        <servlet-class>com.lvmanba.servlet.MultpleServletservlet-class>
    servlet>
    
    <servlet-mapping>
        <servlet-name>multipleservlet-name>
        <url-pattern>/lvmanba/vipurl-pattern>
    servlet-mapping>
    <servlet-mapping>
        <servlet-name>multipleservlet-name>
        <url-pattern>/lvmanba/vvipurl-pattern>
    servlet-mapping>
    <servlet-mapping>
        <servlet-name>multipleservlet-name>
        <url-pattern>/lvmanba/userurl-pattern>
    servlet-mapping>

最后,启动服务测试运行结果:
Servlet-学习笔记_第27张图片

启动时创建Servlet

了解Servlet的生命周期,Servlet的创建默认情况下是请求第一次到达Servlet时创建的。但是我们都知道,Servlet是单例的,也就是说在应用中只有唯一的一个实例,所以在Tomcat启动加载应用的时候就创建也是一个很好的选择。那么两者有什么区别呢?

  • 第一种:应用加载时创建Servlet,它的优势是在服务器启动时,就把需要的对象都创建完成了,从而在使用的时候减少了创建对象的时间,提高了首次执行的效率。它的弊端也同样明显,因为在应用加载时就创建了Servlet对象,因此,导致内存中充斥着大量用不上的Servlet对象,造成了内存的浪费。
  • 第二种:请求第一次访问是创建Servlet,它的优势就是减少了对服务器内存的浪费,因为那些一直没有被访问过的Servlet对象都没有创建,因此也提高了服务器的启动时间。而它的弊端就是,如果有一些要在应用加载时就做的初始化操作,它都没法完成,从而要考虑其他技术实现。

当有很多Servlet的使用时机并不确定是,就选择第二种方式。

在web.xml中是支持对Servlet的创建时机进行配置的,配置的方式如下:我们就以ServletDemo3为例。


<servlet>
    <servlet-name>servletDemo3servlet-name>
    <servlet-class>com.lvmanba.web.servlet.ServletDemo3servlet-class>
    
    <load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
    <servlet-name>servletDemo3servlet-name>
    <url-pattern>/servletDemo3url-pattern>
servlet-mapping>

Servlet-学习笔记_第28张图片

默认Servlet

默认Servlet是由服务器提供的一个Servlet,它配置在Tomcat的conf目录下的web.xml中。如下图所示:
Servlet-学习笔记_第29张图片
它的映射路径是/,我们在发送请求时,首先会在我们应用中的web.xml中查找映射配置,找到就执行,这块没有问题。但是当找不到对应的Servlet路径时,就去找默认的Servlet,由默认Servlet处理。所以,一切都是Servlet。

1.4 Servlet关系总图

Servlet-学习笔记_第30张图片

二、 ServletConfig

2.1 ServletConfig概述

2.1.1 基本概念

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

使用格式:包含在init-param标签中,隶属于servlet标签,可以设置多组。

encoding UTF-8

Servlet-学习笔记_第31张图片

2.1.2 ServletConfig的生命周期

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

2.2 ServletConfig的使用

设置ServletConfig配置

ServletConfig是每个servlet的自己的配置,配置是在web.xml的对应的servlet的配置中进行的。使用init-param标签进行配置,可以配置多个,。要放置在load-on-startup前,否则会报错>如:

<servlet>
    <servlet-name>multipleservlet-name>
    <servlet-class>com.lvmanba.servlet.MultpleServletservlet-class>
    
    
    <init-param>
        
        <param-name>encodingparam-name>
        
        <param-value>UTF-8param-value>
    init-param>
    
    <init-param>
        <param-name>desparam-name>
        <param-value>this is ServletConfigparam-value>
    init-param>
    <load-on-startup>1load-on-startup>
servlet>

获取ServletConfig配置

Servlet-学习笔记_第32张图片

public class MultpleServlet extends HttpServlet {
    //1、声明ServletConfig
    private ServletConfig config;
    //2、通过init方法,对上面定义的ServletConfig进行赋值
    @Override
    public void init(ServletConfig config) throws ServletException {
        this.config = config;
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //3、ServletConfig常用的方法使用
        //3.1 根据key获取value
        String encoding = config.getInitParameter("encoding");
        System.out.println(encoding);
        //3.2 获取所有的key值
        Enumeration keys = config.getInitParameterNames();
        while (keys.hasMoreElements()){
            //读取key值
            String key = (String) keys.nextElement();
            //根据kay获取value
            String value = config.getInitParameter(key);
            System.out.println(key+":"+value);
        }
        //3.3 获取所在Servlet的名称 既servlet-name标签内的值
        String servletName = config.getServletName();
        System.out.println(servletName);
        //3.4 获取ServletContext对象
        ServletContext servletContext = config.getServletContext();
        System.out.println(servletContext);


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

三、 ServletContext

3.1 ServletContext 概述

3.1.1、ServletContext介绍

ServletContext对象: 它是应用上下文对象。每一个应用有且只有一个ServletContext对象。

作用:它可以实现让应用中所有Servlet间的数据共享,可以配置和获取应用的全局初始化参数。

生命周期:应用一加载该对象就被创建出来了(出生)。只要应用一直提供服务,该对象就一直存在。应用被卸载(或者服务器挂了),该对象消亡。

一个应用只有一个实例对象。(Servlet和ServletContext都是单例的)

3.1.2 域对象概念

域对象:它指的是对象有作用域,即有作用范围。
域对象的作用:域对象可以实现数据共享。不同作用范围的域对象,共享数据的能力不一样。

在Servlet规范中,一共有4个域对象。今天我们讲解的ServletContext就是其中一个、它是web应用中最大的作用域,也叫application域。每个应用只有一个application域。它可以实现整个应用间的数据共享功能。
Servlet-学习笔记_第33张图片

3.2 ServletContext的使用

3.2.1 ServletContext配置

ServletContext既然被称之为应用上下文对象,所以它的配置是针对整个应用的配置,而非某个特定Servlet的配置。它的配置被称为应用的初始化参数配置。配置的方式,需要在标签中使用来配置初始化参数。具体代码如下:

Servlet-学习笔记_第34张图片


<context-param>
    
    <param-name>servletContextInfoparam-name>
    
    <param-value>This is application scopeparam-value>
context-param>

<context-param>
    <param-name>globalEncodingparam-name>
    <param-value>UTF-8param-value>
context-param>

3.2.2 ServletContext常用方法

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取ServletContext
        ServletContext sc = getServletContext();
        //获取自定义全局配置
        String globalEncoding = sc.getInitParameter("globalEncoding");
        System.out.println(globalEncoding);
        //获取tomcat中定义的虚拟目录  就是tomcat中设置的deployment-Application Content
        String contextPath = sc.getContextPath();
        System.out.println(contextPath);
        //获取当前路径的绝对路径
        String realPath1 = sc.getRealPath("/");
        System.out.println(realPath1);
        //获取文件在磁盘中的绝对路径
        String realPath = sc.getRealPath("/WEB-INF/web.xml");
        System.out.println(realPath);
        //向对象域中添加数据
        sc.setAttribute("username","zhangsan");
        //获取对象域中的数据
        String username = (String) sc.getAttribute("username");
        System.out.println(username);
        //移除对象域中的数据
        //sc.removeAttribute("username");
    }

Servlet-学习笔记_第35张图片
Servlet-学习笔记_第36张图片

四、 注解开发Servlet

4.1 Servlet3.0规范

使用注解: 上面我们每创建一个servlet,就需要在web.xml中配置进行一组:声明和映射。如果servlet多了,配置起来就很麻烦,如果使用注解就不需要进行配置,提高了开发的效率。

我们使用的是Tomcat9,JavaEE规范要求是8,对应的Servlet规范规范应该是JavaEE8包含的4.x版本。而Servlet3.0以后的版本,才开始支持注解开发,而3.0版本既保留了2.5版的web.xml配置方法,又支持注解,同时还有一些其他的新特征,所以建议使用3.0版本。而且3.0以后,servlet的依赖artifactId名称由servlet-api 修改为 javax.servlet-api。

采坑历程:使用 jave1.8 + servlet4.0.1 + tomcat9
1、如果使用servlet3.0, 提示要添加 Add Java Jre6… 更换为了4.0.1 版本
2、访问出现了404, 将tomcat10 更换为 tomcat9 正常。

4.2 注解开发入门案例

4.2.1 自动注解配置

项目搭建详见1.21:
搭建完以后,直接删除掉web.xml,也可以将web目录移至src下面。但是主要要进行配置。
Servlet-学习笔记_第37张图片
依赖的引入:

<dependencies>
    
    
    <dependency>
        <groupId>javax.servletgroupId>
        <artifactId>javax.servlet-apiartifactId>
        <version>4.0.1version>
    dependency>
dependencies>

第二步:编写Servlet

public class ServletDemo1 extends HttpServlet {

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

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Servlet Demo1 Annotation");
    }
}

第三步:使用注解配置Servlet
在类上面加@WebServlet(“/访问的路径”)
Servlet-学习笔记_第38张图片
第四步:测试
Servlet-学习笔记_第39张图片

2)WebServlet注解代码解读
/**
 * WebServlet注解
 * @since Servlet 3.0 (Section 8.1.1)
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebServlet {

    //1、指定Servlet的名称。 相当于xml配置中标签下的
    String name() default "";
    
    //2、用于映射Servlet访问的url映射: 相当于xml配置时的
    String[] value() default {};

    //3、相当于xml配置时的
    String[] urlPatterns() default {};

    //4、用于配置Servlet的启动时机:相当于xml配置的
    int loadOnStartup() default -1;

    //5、用于配置Servlet的初始化参数:相当于xml配置的
    WebInitParam[] initParams() default {};

    //6、用于配置Servlet是否支持异步:相当于xml配置的
    boolean asyncSupported() default false;

    //7、用于指定Servlet的小图标
    String smallIcon() default "";

    //8、用于指定Servlet的大图标
    String largeIcon() default "";

    //9、用于指定Servlet的描述信息
    String description() default "";

    //10、用于指定Servlet的显示名称
    String displayName() default "";
}

4.2.2 手动创建容器

1)前置说明

在使用Servlet3.1版本的规范时,脱离了web.xml进行注解开发,它除了支持使用注解的配置方式外,还支持纯手动创建Servlet容器的方式。要想使用的话,必须遵循它的编写规范。它是从Servlet3.0规范才开始引入的,加入了一个新的接口:

package javax.servlet;

import java.util.Set;

/**
 * 初始化Servlet容器必须实现此接口
 * 它是Servlet3.0规范提供的标准接口
 * @since Servlet 3.0
 */
public interface ServletContainerInitializer {
     /**
     * 启动容器时做一些初始化操作,例如注册Servlet,Filter,Listener等等。
 	 * @since Servlet 3.0
     */
    void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException;
}

同时可以利用@HandlesTypes注解,把要加载到onStartup方法中的类字节码传入进来,@HandlesTypes源码如下:

/**
 * 用于指定要加载到ServletContainerInitializer接口实现了中的字节码
 * @see javax.servlet.ServletContainerInitializer
 * @since Servlet 3.0
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface HandlesTypes {

    /**
     * 指定要加载到ServletContainerInitializer实现类的onStartUp方法中类的字节码。
     * 字节码可以是接口,抽象类或者普通类。
     */
    Class[] value();
}
2)编写步骤

第一步:创建工程,并移除web.xml

第二步:编写Servlet

/**
 * 注解开发Servlet 之 手动初始化容器
 * @author 黑马程序员
 * @Company http://www.itheima.com
 */
public class ServletDemo1 extends HttpServlet {

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

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Servlet Demo1 Annotation manual");
    }
}

第三步:创建初始化容器的类,并按照要求配置

/**
 * 初始化容器操作
 */
public class MyServletContainerInitializer implements ServletContainerInitializer {

    @Override
    public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
       
    }
}

在脱离web.xml时,要求在src目录下包含一个META-INF目录,位置和及字母都不能改变,且严格区分大小写。在目录中创建一个名称为javax.servlet.ServletContainerInitializer的文件,里面写实现了ServletContainerInitializer接口的全限定类名。如下图所示:
Servlet-学习笔记_第40张图片
第四步:编写注册Servlet的代码
Servlet-学习笔记_第41张图片
第五步:测试

Servlet-学习笔记_第42张图片

你可能感兴趣的:(java-ee,java,tomcat)