• HeadFirst Jsp 05 (属性和监听)


    活用DD, 比如, 我想设置一个email地址, 但是不像在servlet中硬编码, 如果能再web.xml中设置一个参数, 直接拿到这个参数就更好一点.

    容器建立一个servlet时, 它会读DD(web.xml), 并为ServletConfig创建名/值对, 容器不会再读初始化参数了, 一旦参数放在ServletConfig中,就不会再读了. 除非你重新部署 servlet.

    可见web.xml只读取一次, 所以如果你想修改点web.xml内容时, 就需要重新部署整个内容, 但是这比将内容写在servlet或Jsp中强一点,后者不仅要重新部署, 还要重新编译.

    例如我想把email地址作为servlet 来响应的内容, 把它写在 web.xml 比在servlet中强, 因为不需要编译.

    web.xml 中的初始化参数如下:

    <servlet>

      <init-param>

        <param-name>abc</param-name>

        <param-value>abc@123.com</param-value>

      </init-param>

    </servlet>

    以上内容, 会作为一个参数名和值传给ServletConfig, 然后init()方法执行时, 会将这些内容读取, 只读取这一次

    getServletConfig().getInitParameter("abc")  // 可以获得参数 abc的值 abc@123.com

    另外, init 初始化参数只能针对某个特定的servlet, 即 <init-param> 要在 <servlet>内部

    以上的 init 初始化参数, 只能 servlet 使用, jsp 不能使用, jsp如果想使用, 可以通过增加jsp属性的方法, 上一章有提过来增加, 但是这样做也不好, 解决办法是上下文初始化参数.

    上下文初始化参数, 对整个Web应用而不只是对servlet可用. 并且, 上下文参数不在 <servlet>内部, 不是针对特定的 servlet.

    <context-param>

      <param-name>aaa</param-name>

      <param-value>aaa@123</param-value>

    </context-param>

    在servlet中使用代码, getServletContext().getInitParameter(“aaa”);

    上下文参数, 与普通 parameter 参数区别

    image

    容器在创建servlet时, 会读取DD, 并为ServletConfig创建 名/值对, 容器不会再读初始化参数了. 除非重新部署

    成熟的 容器可以提供动态部署, 即不用关闭, 重启就可以部署.

    每个 servlet 一个 servletConfig, 每个 Web应用一个 ServletContext

    如果你希望应用初始化参数是一个数据库 datasource ? 不可能还利用xml来初始化数据库, 另外也不能把对象放到XML文件中来进行初始化啊?

    如果 xml 能够激活一个对象或一个函数, 而这个对象或函数能够初始化对象和数据库(比如数据库连接, 关闭等), 所以就由了xml监听类.

    xml中设置监听类

    我们需要一个单独的对象, 它能做到:

    上下文初始化时得到通知( 应用得到部署 )

    • 从ServletContext得到上下文的初始化参数
    • 使用初始化参数查找名建立一个数据库连接
    • 把数据库连接存储为一个属性, 使得web应用的各个部分都能访问

    上下文撤销时得到通知 ( 应用取消部署或结束 )

    • 关闭数据库连接

    容器通过web.xml 发现和使用监听者

    用来初始化的对象

    import javax.servlet.*;
    
    public class MyServletContextListener implements ServletContextListener {
        
        public void contextInitialized(ServletContextEvent event) {
            // 初始化数据库连接代码
            // 并且保存这段连接代码为一个 context attribute
        }
    
        public void contextDestoryed(ServletContextEvent event) {
            // 关闭数据库连接的代码
        }
    }
    View Code

    <listener></listener>

    process

    image

    image

    image

    image

    例子:我们把String初始化参数转换为一个真正的对象, 一个 Dog

    0. 首先创建一个监听者类 , 把它放在 WEB-INF/classes目录中, 并在部署描述文件中放一个<listener>元素来告诉容器.

    package com.example;
    
    import javax.servlet.*;
    
    public class MyServletContextListener implements ServletContextListener {
    
        public void contextInitialized(ServletContextEvent event) {
            // 由事件得到 ServletContext
            servletContext sc = event.getServletContext();
            // 使用上下文的到初始化参数
            String dogBreed = sc.getInitParameter("breed");
            // 根据参数建立对象
            Dog d = new Dog(dogBreed);
            // 使用上下文, 增加了属性
            sc.setAttribute("dog", d);    
        }
    
        public void contextDestroyed(ServletContextEvent event) {
        }
    }

    1. web.xml


    2. Dog class 只是一个比方, 连接数据库的内容类似


    3. Listener 主要用来实例化 Dog

    4. Servlet, testlistener

    5. 测试时, 只需要执行 http://localhost:8080/listenerTest/ListenTest.do

    总结:首先, 容器在启动的时候, 会去读取 web.xml, 并实例化其中的<Listener> 类和servlet类,  并且将所有的上下文参数<context-param> 做成了 (key-value 对的形式交给servletContext), 注意:实例化<Listener>类时会调用contextInitialized()这个方法, 这个方法的实际意义是用来连接数据库的, 这个方法具体做什么事情, 你可以自己编写, 只不过这个方法可以访问到ServletContext所有的key和value对, 通过这些可以访问到得key和value, 来初始化数据库或者创建对象等等, 并将结果以 key, value的形式添加到 ServletContext的atribute中, 此时这个方法可以通过 getServletContext()获得<context-param>中的参数来进行一些处理, 例如连接数据库, 然后再将数据库连接的内容设置成servletContext的一个属性, 供所有人调用, 这个时候如果有别人需要请求时, 其他的servlet就可以调用这个属性来确认连接数据库. 由此可见, <Listener>会在容器启动时先运行并实例化完毕, 在哪里等待, 等待别的servlet调用 (本例中就是 ListenerTester).

    这样也就实现了, 属性可以通过编程设置. 另外可以用很多类型的监听者, 不单单是监听上下文参数的.

    另外要注意, 上下文属性是大家都能访问的, 换句话说, 它不是线程安全的.

    其他的监听者

    image

    image

    属性和参数的区别


    image

    上下文, 请求, 会话

    image

    image

    image

    多线程访问时, 属性也并非是安全的, 比如 A线程修改了一个属性的值, 而后B线程也修改了属性的值, 但是A不知道, A还以为属性是刚刚他修改的内容. 类似之前说的实例变量不安全, 一样.

    RequestDispatcher 只有两个方法, forward() 和 include()

    image

  • 相关阅读:
    File类
    Java运算符
    JAVA语法
    数据库-子查询
    爬取笔趣阁_完本书籍
    爬取动物图片源码
    爬取电影天堂上最新电影的下载链接的源码
    pyinstaller的安装、使用、出错解决办法
    Emmet插件使用方法总结
    Markdown基本语法
  • 原文地址:https://www.cnblogs.com/moveofgod/p/3389773.html
Copyright © 2020-2023  润新知