WebDay08 Servlet入门

一 Servlet概述

  • servlet= server+applet 运行在服务器端的java程序。
  • Servlet是一个接口(规范),一个类要想通过浏览器被访问到,那么这个类就必须直接或间接的实现Servlet接口

作用

接收请求,处理业务,响应结果
在这里插入图片描述

二 Servlet快速入门

目标:编写一个普通的java类,通过浏览器可以访问

#编写步骤
	1. 定义一个类,实现Servlet接口,重写所有的抽象方法(特别是service方法)
	2. 配置web.xml
	

2.1 代码编写

① 创建web项目
在这里插入图片描述
② 编写普通java类,实现servlet接口
重写抽象方法(service方法)

package com.itheima01.servlet;

import javax.servlet.*;
import java.io.IOException;

/*
*  ctrl+i(implements) : 提示重写所有抽象方法
*   ctrl+ enter: 万能提示
* */
public class MyServlet implements Servlet {

    /*
    * servletRequest : 请求
    * servletResponse : 响应
    * */
    @Override
    public void service(ServletRequest servletRequest,
                        ServletResponse servletResponse) throws ServletException, IOException {

        System.out.println("接收到请求"); //控制台打印
        servletResponse.getWriter().print("hello servlet");//响应给浏览器
    }

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

    }

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

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

    @Override
    public void destroy() {

    }
}

③ 配置web.xml

配置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_3_1.xsd"
         version="3.1">

    <!--
        1. servlet和servlet-mapping标签里都有servlet-name子标签
            内部文本可以随意命名,但是必须一致
        2.  servlet-class标签: 写Servlet实现类的全限定名(包名+类名)
        3. url-pattern : 指定的是该Servlet的虚拟路径
    -->
    <servlet>
        <servlet-name>MyServlet01</servlet-name>
        <servlet-class>com.itheima01.servlet.MyServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MyServlet01</servlet-name>
        <url-pattern>/myServlet</url-pattern>
    </servlet-mapping>
</web-app>

④ 部署web项目
在这里插入图片描述
⑤ 启动测试
在这里插入图片描述

2.2 执行原理

在这里插入图片描述

三 Servlet相关API

3.1 生命周期方法

3.1.1 思想介绍

  • 生命周期:指的是一个对象从生(创建)到死(销毁)的一个过程
// 1. servlet对象创建时,调用此方法
public void init(ServletConfig servletConfig);
// 2. 用户访问servlet时,调用此方法
public void service(ServletRequest servletRequest, ServletResponse servletResponse);
// 3. servlet对象销毁时,调用此方法
public void destroy();

在这里插入图片描述

* 创建
	1)默认情况下
		用户第一次访问时,创建servlet,执行init方法
	2)修改创建时机
		<load-on-startup></load-onstartup>
			正数:4-N  【服务器启动时,创建】
				补充:Tomcat的web.xml里有1,3 所以推荐4-n 
			负数(默认值):-1 【用户第一次访问时,创建】
	
* 运行(提供服务)
		用户每次访问时,都执行service方法

* 销毁
		服务器正常关闭时,销毁servlet,执行destroy方法

3.1.2 代码演示

① LifeServlet

package com.itheima02.lifecycle;

import javax.servlet.*;
import java.io.IOException;
/*
*   1. servlet的api(方法) -> 生命周期方法
*   2. 生命周期(lifecycle) : 从创建到销毁的整个过程
*   3. servlet的重要三个方法
*       1). init : 初始化
*           a. 此方法默认Servlet第一次被访问的时候调用
*           b. 适合做一些数据初始化工作
*
*       2). service : 活动  (最重要)
*           a. 此方法Servlet每次被访问,都会执行一次
*           b. 这是servlet的核心方法(接收请求,业务处理,响应数据)
*
*       3). destroy : 销毁
*           a. 此方法是tomcat关闭的时候调用一次
*           b. 这个方法适合资源释放,数据保存
*
*   注意: 每新增一个Servlet,由于tomcat要重新读取配置信息,所以必须重启tomcat
*
*   测试:
*       浏览器第一次访问: 执行一次 init, service
*       浏览器再次访问 : 每访问一次,执行一次service
*       关闭tomcat的时候: 执行一次 destroy
* */
public class LifeServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("init");
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("service");
    }

    @Override
    public void destroy() {
        System.out.println("destroy");
    }

    // 了解: 这两个方法是servlet配置相关(一般不怎么用了)
    @Override
    public ServletConfig getServletConfig() {
        System.out.println("getServletConfig");
        return null;
    }

    @Override
    public String getServletInfo() {
        System.out.println("getServletInfo");
        return null;
    }

}

② 配置web.xml

 <!--
        书写规范:
            1. servlet-name虽然可以自定义,但是一般与类名相同(见名知意)
            2. servlet的虚拟路径: 必须/开头, 可以自定义,一般是类名的小驼峰写法
    -->
    <servlet>
        <servlet-name>LifeServlet</servlet-name>
        <servlet-class>com.itheima02.lifecycle.LifeServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LifeServlet</servlet-name>
        <url-pattern>/lifeServlet</url-pattern>
    </servlet-mapping>

3.1.3 启动加载

   # 启动加载
*       1)问题: 发现 init 默认第一次被访问的时候才调用,适合用来初始化项目数据
*           如果项目数据很多, 加载就需要一定的时候,这样就会给第一个用户的体验不好,因为要等比较久
*
*       2)解决: 服务器一启动,就执行init方法
*       
*       3) 实现: 要在web.xml配置
<servlet>
        <servlet-name>LifeServlet</servlet-name>
        <servlet-class>com.itheima02.lifecycle.LifeServlet</servlet-class>
        <!--
            启动加载:
                <load-on-startup> n </load-on-startup>
                    n取值必须是整数
                1) n < 0 , 表示第一次被访问的时候才加载(默认-1)
                2) n >= 0, tomcat 一启动就会加载这个servlet(创建对象,并调用init方法)
                       a. 数字越小,优先级越高
                       b. 我们一般取值n>=4, tomcat已经默认占用前几位
                        (tomcat/conf/web.xml 全局配置文件)
        -->
        <load-on-startup>4</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>LifeServlet</servlet-name>
        <url-pattern>/lifeServlet</url-pattern>
    </servlet-mapping>

四 Servlet体系结构

快捷键:
1. ctrl + alt + u : 查看一个类的继承结构图
2. ctrl + h : 这个类的简化版继承结构

在这里插入图片描述

4.1 GenericServlet

1. 问题: 
	Servlet中使用频率最高,最重要的方法是service方法(大部分场景)
	但是我们每次编写Servlet实现类,都是直接实现Servlet接口,重写5个抽象方法(太冗余了)

2. 需求: 如果我们以后编写Servlet实现类,只要重写service方法就好了
3. 解决:
		1) 定义一个类 GenericServlet implements Servlet
		2) 重写除service方法之外其他抽象方法 -> GenericServlet 只剩下一个service抽象方法
			-> GenericServlet就保存起来 (适配器设计模式)
		3) 以后,我们再编写	Servlet实现类,只要extends GenericServlet,重写service方法即可
			a. 我们的类依然是Servlet实现类(因为继承可以多重继承:  B继承A, C继承B)
			b. 我们的类依然可以重写其他方法(GenericServlet普通方法也可以被重写)
			
4. 发现: 好巧啊,GenericServlet不需要我们写,因为开发包已经提供了

① 编写普通java类,继承GenericServlet抽象类

public class GoodServlet extends GenericServlet {

    @Override
    public void init() throws ServletException {
        System.out.println("其他方法如果有需要,也可以重写");
    }

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("GoodServlet被访问了~~");
    }
}

② 配置web.xml

	<servlet>
        <servlet-name>GoodServlet</servlet-name>
        <servlet-class>com.itheima03.generic.GoodServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>GoodServlet</servlet-name>
        <url-pattern>/goodServlet</url-pattern>
    </servlet-mapping>

4.2 HttpServlet

1. 问题: 
	  我们在请求中,学习过有两种常用的请求方式(get/post)
	  我们现在的service方法是这样的: 用户发送请求,无论是什么请求方式,都会统一的执行service方法, 我们无法很好的区别是哪一种请求方式
2. 需求: 我们如果想确切的知道是哪一种请求方式,必须要先了解HttpServletRequest
3. 解决: 自己封装了一个MyHttpServlet  -> 开发包 HttpServlet
	  
// 拥有抽象方法的类必须是抽象类
// 抽象doGet和doPost的目的: 为了封装
// 以后,只要定义一个类继承MyHttpServlet,重写 doGet和doPost就可以了
    // 可以通过执行的方法就可以区分到底是哪一种请求
public abstract class MyHttpServlet extends GenericServlet {
    /*
    * ServletRequest : 这个对象包含了请求报文内容(兼容大部分协议)
    *       请求行: 里面有请求方式
    * */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
            //简单的来说, 父类类型调用不了子类特有方法,所以要强转
            // 因为我们的协议确实是http协议,强转是没有问题的
        HttpServletRequest request = (HttpServletRequest) servletRequest;
            // 获取请求方式
        String method = request.getMethod();
        if("post".equalsIgnoreCase(method)){
            //如果是post请求,执行doPost方法
            doPost((HttpServletRequest)servletRequest,(HttpServletResponse)servletResponse);
        }else if("get".equalsIgnoreCase(method)){
            //如果是get请求,执行doGet方法
            doGet((HttpServletRequest)servletRequest,(HttpServletResponse)servletResponse);
        }

    }
    //如果是get请求,执行doGet方法 -> 实际上就是只处理get请求的service方法
    public abstract void doGet(HttpServletRequest servletRequest, HttpServletResponse servletResponse);
    //如果是post请求,执行doPost方法 -> 实际上就是只处理post请求的service方法
    public abstract void doPost(HttpServletRequest servletRequest, HttpServletResponse servletResponse);
}

在这里插入图片描述
① 编写前端html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>login</title>

</head>
<body>
    <!--
            表单的提交按钮被点击, 提交数据到action地址(没有请求参数)
                前端中发送的请求,不指定默认get
        -->
        <h1>get请求</h1>
        <form action="http://localhost:8080/day08-servlet_xml/betterServlet" method="get">
          <input type="submit">
        </form>

        <h1>post请求</h1>
        <form action="http://localhost:8080/day08-servlet_xml/betterServlet" method="post">
          <input type="submit">
        </form>
</body>
</html>

② 编写普通java类,继承HttpServlet抽象类

/*
*   浏览器访问,如果不指定请求方式,默认是get
* */
public class BetterServlet extends HttpServlet {
    @Override
    public void doGet(HttpServletRequest servletRequest, HttpServletResponse servletResponse) {
        System.out.println("执行的get方法: 具体业务");
    }

    @Override
    public void doPost(HttpServletRequest servletRequest, HttpServletResponse servletResponse) {
        System.out.println("执行的post方法 : 具体业务");
    }
}

③ 配置web.xml

<servlet>
        <servlet-name>BetterServlet</servlet-name>
        <servlet-class>com.itheima04.http.BetterServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>BetterServlet</servlet-name>
        <url-pattern>/betterServlet</url-pattern>
    </servlet-mapping>

4.3 经验值分享

① 响应状态码405

请求方法没有重写…

	/*
        注意: 如果我们不重写doGet/doPost方法, 那么父类的doGet/doPost方法会执行(继承)
            给浏览器响应一个错误: 状态码405 (http1.1)
     */

在这里插入图片描述
** 响应状态码500**
java代码写错了…
在这里插入图片描述

五 Servlet路径

5.1 url-pattern

作用:将一个请求网络地址和servlet类建立一个映射关系
在这里插入图片描述

5.1.1 Servlet映射多个url

在这里插入图片描述

5.1.2 url映射模式【了解】

配置 <url-pattern> url地址取值可以是:

```markdown
1. 精确匹配(掌握) 
 		/servletDemo3  
2. 目录匹配 
		/aa/*
3. 后缀匹配 
		*.xxx	例如:*.do
<!--
        现在浏览器地址栏输入: (http://localhost:8080/day08-servlet_xml)
            通过 /urlServlet01 就可以访问到 UrlServlet

        1. 一个servlet的url可以设置多个
            <servlet-mapping>标签设置多个
            /urlServlet01 和 /urlServlet02 都可以访问UrlServlet

            作用: 其实没什么用,了解即可(为过滤器做铺垫)

        2. 路径匹配模式
            a. 精确匹配(掌握)
                    /urlServlet01
            b. 目录匹配
                    /aa/*  (* 符号匹配所有)
            c. 后缀匹配
                    *.xxx	例如:*.do (前面不要加/)
                    访问的url后缀名带do就可以访问到
    -->
    <servlet-mapping>
        <servlet-name>UrlServlet</servlet-name>
        <url-pattern>/urlServlet01</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>UrlServlet</servlet-name>
        <url-pattern>/aa/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>UrlServlet</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

5.2 相对/绝对路径

  • 现阶段我们访问资源的方式越来越多,请求路径在编写时难免出现混淆
  1. 浏览器的地址栏 (输入地址,敲回车会发送请求)
  2. a标签的href属性 (超链接被点击的时候会发送请求)
  3. form表单的action属性 (form中的submit按钮被点击的时候,发送请求)
  4. js的loation.href属性 (只要设置, 触发相应的)
  5. ajax请求地址
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="http://www.baidu.com">超链接</a> <br>

    <form action="http://www.baidu.com">
        <input type="text" name="username"> <br>
        <input type="submit">
    </form>

    <input type="button" value="按钮" id="myid">
    <script>
        //js
        document.getElementById("myid").onclick = function () {
            //bom对象: window,location地址栏
            location.href = "http://www.baidu.com"
        }
    </script>
</body>
</html>

这里我们复习下路径规则:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
        <!--
            1. 绝对路径
                a. 完整路径: http://localhost:8080/day08-servlet_xml/urlServlet01
                b. 简要写法: /day08-servlet_xml/urlServlet01  (只要在本项目内,省略三要素, 协议://ip:port)
                    (推荐)

            2. 相对路径 (不推荐)
                web/test下的url.html ->
                    http://localhost:8080/day08-servlet_xml/test/url.html
                发现:
                    http://localhost:8080/day08-servlet_xml/urlServlet01
                观察: /urlServlet01 是 /test/url.html
                相对: url.html 要找到urlServlet01, 先回到上一级,才能找到
                 符号:
                        ./  当前路径 可以省略
                        ../ 上一级

        -->
    <a href="http://localhost:8080/day08-servlet_xml/urlServlet01">访问/urlServlet01_完整路径</a> <br>
    <a href="/day08-servlet_xml/urlServlet01">访问/urlServlet01_简略路径</a> <br>
    <hr>
        <a href="../urlServlet01">访问/urlServlet01_相对路径</a> <br>

</body>
</html>

5.3 ServletConfig

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

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

首先,我们要清楚的认识到,它可以为每个Servlet都提供初始化参数,所以肯定可以在每个Servlet中都配置。那是配置在Servlet的声明部分,还是映射部分呢?我们接下来先准备一个Servlet,然后给同学们揭秘。

/**
 * 演示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;
    }

    /**
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //输出ServletConfig
        System.out.println(servletConfig);
    }

    /**
     * 调用doGet方法
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }
}
<!--配置ServletDemo8-->
<servlet>
    <servlet-name>servletDemo8</servlet-name>
    <servlet-class>com.itheima.web.servlet.ServletDemo8</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>servletDemo8</servlet-name>
    <url-pattern>/servletDemo8</url-pattern>
</servlet-mapping>

如何配置

在上一小节中,我们已经准备好了Servlet,同时也获取到了它的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>
/**
 * 演示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);
    }
}

5.4ServletContext

基本介绍 ServletContext对象,它是应用上下文对象。每一个应用有且只有一个ServletContext对象。它可以实现让应用中所有Servlet间的数据共享。
生命周期
出生——活着——死亡

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

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

死亡:应用被卸载(或者服务器挂了),该对象消亡。
域对象概念
域对象的概念,它指的是对象有作用域,即有作用范围。

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

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

在讲解ServletConfig对象时,我们已经看到了获取ServletContext对象的方式,它只需要调用ServletConfig对象的getServletContext()方法就可以了。具体代码如下:我们创建一个新的Servlet用于演示ServletContext。

/**
 * 用于演示ServletContext对象的使用
 * @author 黑马程序员
 * @Company http://www.itheima.com
 */
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);
    }
}
<!--配置ServletDemo9-->
    <servlet>
        <servlet-name>servletDemo9</servlet-name>
        <servlet-class>com.itheima.web.servlet.ServletDemo9</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>servletDemo9</servlet-name>
        <url-pattern>/servletDemo9</url-pattern>
    </servlet-mapping>

在实际开发中,如果我们每个Servlet对ServletContext都使用频繁的话,那么每个Servlet里定义ServletConfig,再获取ServletContext的代码将非常多,造成大量的重复代码。Servlet规范的定义中也为我们想到了这一点,所以它在GenericServlet中,已经为我们声明好了ServletContext获取的方法,如下图所示:

我们的Servlet都是继承自HttpServlet,而HttpServlet又是GenericServlet的子类,所以我们在获取ServletContext时,如果当前Servlet没有用到它自己的初始化参数时,就可以不用再定义初始化参数了,而是直接改成下图所示的代码即可:

如何配置

ServletContext既然被称之为应用上下文对象,所以它的配置是针对整个应用的配置,而非某个特定Servlet的配置。它的配置被称为应用的初始化参数配置。

配置的方式,需要在<web-app>标签中使用<context-param>来配置初始化参数。具体代码如下:

<!--配置应用初始化参数-->
<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>

六 Servlet3.0

  • 通过注解配置Servlet,简化web.xml配置Servlet复杂性,提高开发效率,几乎所有的框架都在使用注解

① 创建web工程【注解】
在这里插入图片描述
② 编写普通java类,继承HttpServlet

public class QuickServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("QuickServlet....3.0");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("QuickServlet....3.0");
    }
}

③ 配置@WebServlet
在这里插入图片描述

// @WebServlet(name = "QuickServlet",urlPatterns = "/quickServlet")
// @WebServlet(urlPatterns = "/quickServlet")
// @WebServlet(value = "/quickServlet")
@WebServlet("/quickServlet") // 注解中有且仅有一个属性,名为value时,属性名可以省略...
public class QuickServlet extends HttpServlet {
    
}

idea创建web模块的规律

在这里插入图片描述
tomcat可以同时运行多个web模块,但是现在一般只运行一个模块

注意: project structure中要设置这两项
在这里插入图片描述

手动创建容器

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");
    }
}

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

/**
 * 初始化容器操作
 * @author 黑马程序员
 * @Company http://www.itheima.com
 */
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的代码
在这里插入图片描述
第五步:测试
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值