servlet

1  servlet

1.1  servlet介绍

1.2   servlet入门

1.2.1  案例

(1)

(2)

 (3)

 (4)

1.2.2   servlet执行流程

 详解:

1、输入地址回车发起请求

2、解析请求地址

 3、找到对应的项目

 4、根据项目找到xml文件

 5、解析资源路径

 6、找到应用资源

 7、执行方法,进行响应

1.2.3   servlet关系视图

 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 )。

HttpServlet实现

1.3  servlet使用细节

1.3.1 Servlet的生命周期

对象的生命周期,就是对象从生到死的过程,即:出生——活着——死亡。用更偏向 于开发的官方说法就是对象创建到销毁的过程。

出生:请求第一次到达Servlet时,对象就创建出来,并且初始化成功。只出生一次,就放到内存中。

活着:服务器提供服务的整个过程中,该对象一直存在,每次只是执行service方法。

死亡:当服务停止时,或者服务器宕机时,对象消亡。

方式一:通过分析Servlet的生命周期我们发现,它的实例化和初始化只会在请求第一次到达Servlet时执行,而销毁只会在Tomcat服务器停止时执行,由此我们得出一个结论,Servlet对象只会创建一次,销毁一次。所以,Servlet对象只有一个实例。如果一个对象实例在应用中是唯一的存在,那么我们就说它是单实例的,即运用了单例模式。

方式二:一旦tomcat服务器启动的时候就会创建Servlet对象, 后面每次请求也不会再次创建Servlet对象,而是直接调用 doGet 或者 doPost方法来处理用户的请求, 服务器关闭

<servlet>
    <!--servlet的名字 必须和 mapping
        中的name一样-->
    <servlet-name>ServletDemo1</servlet-name>
    <!--servlet的全路径-->
    <servlet-class>com.itheima.servlet.ServletDemo1</servlet-class>
    <!--参数 可以是负数也可以是正数
        默认是负数
        负数: 第一次请求servlet的时候会创建对象,且调用init方法进行初始化
        正数:服务器一旦启动就会创建servlet对象,且数字越小优先级别越高-->
    <load-on-startup>1</load-on-startup>
</servlet>

1.3.2  Servlet的线程安全

代码

package com.itheima.servlet;
​
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
​
/*
    Servlet线程安全
 */
public class ServletDemo04 extends HttpServlet{
    //1.定义用户名成员变量
    private String username = null;
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        
        //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中定义了类成员之后,多个浏览器都会共享类成员的数据。其实每一个浏览器端发送请求,就代表是一个线程,那么多个浏览器就是多个线程,所以测试的结果说明了多个线程会共享Servlet类成员中的数据,其中任何一个线程修改了数据,都会影响其他线程。因此,我们可以认为Servlet它不是线程安全的。

图解

解决方式

  • 方式一:将成员变量定义为局部变量

    package com.itheima.servlet;
    ​
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    ​
    /*
        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;
            //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);
        }
    }
  • 方式二:加同步

    package com.itheima.servlet;
    ​
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    ​
    /*
        Servlet线程安全
     */
    public class ServletDemo04 extends HttpServlet{
        //1.定义用户名成员变量
        private String username = null;
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            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);
        }
    }
    ​

1.3.2  Servlet不同的映射方式

2  ServletConfig

2.1  介绍

基本概念

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

生命周期

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

2.2   ServletConfig使用

2.2.1  如何获取

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

/**
 * 演示Servlet的初始化参数对象
 */
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>

2.2.2  如何配置

在上一小节中,我们已经准备好了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>

2.2.3  常用方法

/**
 * 演示Servlet的初始化参数对象
 */
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);
    }
}

3  ServletContext

3.1  ServletContext概述

3.1.1  基本介绍

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

3.1.2 生命周期

出生——活着——死亡

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

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

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

3.1.3  域对象概念

域对象的概念,它指的是对象有作用域,即有作用范围。

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

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

 3.2  ServletContext使用

配置全局化初始参数

  常用方法

  获取该对象的方法有

1. 通过request对象获取
    request.getServletContext();
2. 通过HttpServlet获取
    this.getServletContext();
3. 通过ServletConfig对象
    ServletConfig对象.getServletContext()

 

 其它路径如何获取

//String getRealPath(String path): 获取文件的真实(服务器)路径
String b = context.getRealPath("/b.txt");//web目录下资源访问
System.out.println(b);

String c = context.getRealPath("/WEB-INF/c.txt");//WEB-INF目录下的资源访问
System.out.println(c);

String a = context.getRealPath("/WEB-INF/classes/a.txt");//src目录下的资源访问
System.out.println(a);

 设置的数据都是全局的,也就是说你在一个类里设置了数据,其它的类也是可以获取到这个数据

4  注解开发Servlet

4.1 Servlet3.0规范

 4.1 注解开发案例

 浏览器输入对应路径即可

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值