• 2020年11月11日Java学习日记


    Servlet第二篇【Servlet细节、ServletConfig、ServletContext】

     

    Servlet的调用图

    前面我们已经学过了Servlet的生命周期了,我们根据Servlet的生命周期画出Servlet的调用图加深理解

    Servlet的细节

    一个已经注册的Servlet可以被多次映射

    同一个Servlet可以被映射到多个URL上。

    1.        <servlet>

    2.            <servlet-name>Demo1</servlet-name>

    3.            <servlet-class>zhongfucheng.web.Demo1</servlet-class>

    4.        </servlet>

    5.        <servlet-mapping>

    6.            <servlet-name>Demo1</servlet-name>

    7.            <url-pattern>/Demo1</url-pattern>

    8.        </servlet-mapping>

    9.        <servlet-mapping>

    10.            <servlet-name>Demo1</servlet-name>

    11.            <url-pattern>/ouzicheng</url-pattern>

    12.        </servlet-mapping>

    无论我访问的是http://localhost:8080/Demo1还http://localhost:8080/ouzicheng。我访问的都是Demo1。

    Servlet映射的URL可以使用通配符

    通配符有两种格式:

    1. *.扩展名

    2. 正斜杠(/)开头并以“/*”结尾。

    匹配所有

    匹配扩展名为.jsp的

    如果.扩展名和正斜杠(/)开头并以“/”结尾两种通配符同时出现,匹配的是哪一个呢?

    1. 看谁的匹配度高,谁就被选择

    2. *.扩展名的优先级最低

    Servlet映射的URL可以使用通配符和Servlet可以被映射到多个URL上的作用:

    1. 隐藏网站是用什么编程语言写的【.php,.net,.asp实际上访问的都是同一个资源】

    2. 用特定的后缀声明版权【公司缩写】

    1.         <servlet>

    2.            <servlet-name>Demo1</servlet-name>

    3.            <servlet-class>zhongfucheng.web.Demo1</servlet-class>

    4.        </servlet>

    5.        <servlet-mapping>

    6.            <servlet-name>Demo1</servlet-name>

    7.            <url-pattern>*.jsp</url-pattern>

    8.        </servlet-mapping>

    9.        <servlet-mapping>

    10.            <servlet-name>Demo1</servlet-name>

    11.            <url-pattern>*.net</url-pattern>

    12.        </servlet-mapping>

    13.        <servlet-mapping>

    14.            <servlet-name>Demo1</servlet-name>

    15.            <url-pattern>*.asp</url-pattern>

    16.        </servlet-mapping>

    17.        <servlet-mapping>

    18.            <servlet-name>Demo1</servlet-name>

    19.            <url-pattern>*.php</url-pattern>

    20.        </servlet-mapping>


    Servlet是单例的

    为什么Servlet是单例的

    浏览器多次对Servlet的请求,一般情况下,服务器只创建一个Servlet对象,也就是说,Servlet对象一旦创建了,就会驻留在内存中,为后续的请求做服务,直到服务器关闭

    每次访问请求对象和响应对象都是新的

    对于每次访问请求,Servlet引擎都会创建一个新的HttpServletRequest请求对象和一个新的HttpServletResponse响应对象,然后将这两个对象作为参数传递给它调用的Servlet的service()方法service方法再根据请求方式分别调用doXXX方法

    线程安全问题

    当多个用户访问Servlet的时候,服务器会为每个用户创建一个线程当多个用户并发访问Servlet共享资源的时候就会出现线程安全问题

    原则:

    1. 如果一个变量需要多个用户共享,则应当在访问该变量的时候,加同步机制synchronized (对象){}

    2. 如果一个变量不需要共享,则直接在 doGet() 或者 doPost()定义.这样不会存在线程安全问题


    load-on-startup

    如果在元素中配置了一个元素,那么WEB应用程序在启动时,就会装载并创建Servlet的实例对象、以及调用Servlet实例对象的init()方法

     

    作用:

    1. 为web应用写一个InitServlet,这个servlet配置为启动时装载,为整个web应用创建必要的数据库表和数据

    2. 完成一些定时的任务【定时写日志,定时备份数据】


    在web访问任何资源都是在访问Servlet

    当你启动Tomcat,你在网址上输入http://localhost:8080。为什么会出现Tomcat小猫的页面?

    这是由缺省Servlet为你服务的

    • 我们先看一下web.xml文件中的配置,web.xml文件配置了一个缺省Servlet

    1.    <servlet>

    2.        <servlet-name>default</servlet-name>

    3.        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>

    4.        <init-param>

    5.            <param-name>debug</param-name>

    6.            <param-value>0</param-value>

    7.        </init-param>

    8.        <init-param>

    9.            <param-name>listings</param-name>

    10.            <param-value>false</param-value>

    11.        </init-param>

    12.        <load-on-startup>1</load-on-startup>

    13.    </servlet>

    14.    <servlet-mapping>

    15.        <servlet-name>default</servlet-name>

    16.        <url-pattern>/</url-pattern>

    17.    </servlet-mapping>

    • 什么叫做缺省Servlet?凡是在web.xml文件中找不到匹配的元素的URL,它们的访问请求都将交给缺省Servlet处理,也就是说,缺省Servlet用于处理所有其他Servlet都不处理的访问请求

    • 既然我说了在web访问任何资源都是在访问Servlet,那么我访问静态资源【本地图片,本地HTML文件】也是在访问这个缺省Servlet【DefaultServlet】

    • 证实一下:当我没有手工配置缺省Servlet的时候,访问本地图片是可以访问得到的

    • 现在我自己配置一个缺省Servlet,Demo1就是我手工配置的缺省Servlet,覆盖掉web.xml配置的缺省Servlet

    1.    <servlet>

    2.        <servlet-name>Demo1</servlet-name>

    3.        <servlet-class>zhongfucheng.web.Demo1</servlet-class>

    4.    </servlet>

    5.    <servlet-mapping>

    6.        <servlet-name>Demo1</servlet-name>

    7.        <url-pattern>/</url-pattern>

    8.    </servlet-mapping>

    • 下面我继续访问一下刚才的图片,此时输出的是Demo1这个Servlet写上的内容了

    • 总结:无论在web中访问什么资源【包括JSP】,都是在访问Servlet。没有手工配置缺省Servlet的时候,你访问静态图片,静态网页,缺省Servlet会在你web站点中寻找该图片或网页,如果有就返回给浏览器,没有就报404错误


    ServletConfig对象

    ServletConfig对象有什么用?

    通过此对象可以读取web.xml中配置的初始化参数。

    现在问题来了,为什么我们要把参数信息放到web.xml文件中呢?我们可以直接在程序中都可以定义参数信息,搞到web.xml文件中又有什么好处呢

    好处就是:能够让你的程序更加灵活【更换需求,更改配置文件web.xml即可,程序代码不用改】

    获取web.xml文件配置的参数信息

    • 为Demo1这个Servlet配置一个参数,参数名是name,值是zhongfucheng

    1.    <servlet>

    2.        <servlet-name>Demo1</servlet-name>

    3.        <servlet-class>zhongfucheng.web.Demo1</servlet-class>

    4.        <init-param>

    5.            <param-name>name</param-name>

    6.            <param-value>zhongfucheng</param-value>

    7.        </init-param>

    8.    </servlet>

    9.    <servlet-mapping>

    10.        <servlet-name>Demo1</servlet-name>

    11.        <url-pattern>/Demo1</url-pattern>

    12.    </servlet-mapping>

    • 在Servlet中获取ServletConfig对象,通过ServletConfig对象获取在web.xml文件配置的参数 


    ServletContext对象

    什么是ServletContext对象?

    当Tomcat启动的时候,就会创建一个ServletContext对象。它代表着当前web站点

    ServletContext有什么用?

    1. ServletContext既然代表着当前web站点,那么所有Servlet都共享着一个ServletContext对象,所以Servlet之间可以通过ServletContext实现通讯

    2. ServletConfig获取的是配置的是单个Servlet的参数信息,ServletContext可以获取的是配置整个web站点的参数信息

    3. 利用ServletContext读取web站点的资源文件

    4. 实现Servlet的转发【用ServletContext转发不多,主要用request转发】

    Servlet之间实现通讯

    ServletContext对象可以被称之为域对象

    到这里可能有一个疑问,域对象是什么呢?其实域对象可以简单理解成一个容器【类似于Map集合】

    实现Servlet之间通讯就要用到ServletContext的setAttribute(String name,Object obj)方法, 第一个参数是关键字,第二个参数是你要存储的对象

    • 这是Demo2的代码

    1.        //获取到ServletContext对象

    2.        ServletContext servletContext = this.getServletContext();

    3.        String value = "zhongfucheng";

    4.        //MyName作为关键字,value作为值存进   域对象【类型于Map集合】

    5.        servletContext.setAttribute("MyName", value);

    • 这是Demo3的代码

    1.        //获取ServletContext对象

    2.        ServletContext servletContext = this.getServletContext();

    3.        //通过关键字获取存储在域对象的值

    4.        String value = (String) servletContext.getAttribute("MyName");

    5.        System.out.println(value);

    • 访问Demo3可以获取Demo2存储的信息,从而实现多个Servlet之间通讯


    获取web站点配置的信息

    如果我想要让所有的Servlet都能够获取到连接数据库的信息,不可能在web.xml文件中每个Servlet中都配置一下,这样代码量太大了!并且会显得非常啰嗦冗余。

    • web.xml文件支持对整个站点进行配置参数信息所有Servlet都可以取到该参数信息

    1.    <context-param>

    2.        <param-name>name</param-name>

    3.        <param-value>zhongfucheng</param-value>

    4.    </context-param>

    • Demo4代码

    1.        //获取到ServletContext对象

    2.        ServletContext servletContext = this.getServletContext();

    3.        //通过名称获取值

    4.        String value = servletContext.getInitParameter("name");

    5.        System.out.println(value);
    • 试一下Demo3是否能拿到,相同的代码

    1.        //获取到ServletContext对象

    2.        ServletContext servletContext = this.getServletContext();

    3.        //通过名称获取值

    4.        String value = servletContext.getInitParameter("name");

    5.        System.out.println(value);


    读取资源文件

    第一种方式:

    • 现在我要通过Servlet111读取1.png图片

    • 按我们以前的方式,代码应该是这样的。

    1.        FileInputStream fileInputStream = new FileInputStream("1.png");

    2.        System.out.println(fileInputStream);

    • 当我们访问的时候,却出错了!说找不到1.png文件

    • 这是为什么呢?我们以前读取文件的时候,如果程序和文件在同一包名,可以直接通过文件名称获取得到的!,原因很简单,以前我们写的程序都是通过JVM来运行的,而现在,我们是通过Tomcat来运行的

    • 根据web的目录规范,Servlet编译后的class文件是存放在WEB-INF\classes文件夹中的

    • 看到这里,我们知道了要进入classes目录中读取文件,所以我们将代码改成以下方式

    1.        FileInputStream fileInputStream = new FileInputStream("D:\\zhongfucheng\\web\\WEB-INF\\classes\\zhongfucheng\\web\\1.png");

    2.        System.out.println(fileInputStream);

    • 再去读取时,就发现可以获取到文件了。

    • 但是现在问题又来了,我读取文件的时候都要写上绝对路径,这样太不灵活了。试想一下,如果我将该读取文件的模块移到其他的web站点上我的代码就又要修改了【因为web站点的名字不一样】

    • 我们通过ServletContext读取就可以避免修改代码的情况,因为ServletContext对象是根据当前web站点而生成的

    • 代码如下所示:

    1.        //获取到ServletContext对象

    2.        ServletContext servletContext = this.getServletContext();

    3.        //调用ServletContext方法获取到读取文件的流

    4.        InputStream inputStream = servletContext.getResourceAsStream("/WEB-INF/classes/zhongfucheng/web/1.png");


    第二种方式:

    • 如果我的文件放在web目录下,那么就简单得多了!,直接通过文件名称就能获取

    • 代码如下所示

    1.        //获取到ServletContext对象

    2.        ServletContext servletContext = this.getServletContext();

    3.        //调用ServletContext方法获取到读取文件的流

    4.        InputStream inputStream = servletContext.getResourceAsStream("2.png");


    第三种方式:

    通过类装载器读取资源文件

    • 我的文件放在了src目录下【也叫做类目录】

    • 代码如下所示

    1.        //获取到类装载器

    2.        ClassLoader classLoader = Servlet111.class.getClassLoader();

    3.        //通过类装载器获取到读取文件流

    4.        InputStream inputStream = classLoader.getResourceAsStream("3.png");

    • 我的文件放在了src目录下的包下

  • 相关阅读:
    Spring Data JPA条件查询
    Cannot add foreign key constraint
    项目运行慢的原因剖析
    文本摘要的一些研究概念
    datatables表格设置序号自增
    记录一次没有报错的错误
    final、static、this、super关键字总结
    datatables条件搜索后表格内出现重复字符串
    linux上重装redis,设置密码
    datatables render出现重复的字符
  • 原文地址:https://www.cnblogs.com/9635741zly/p/14176471.html
Copyright © 2020-2023  润新知