zoukankan      html  css  js  c++  java
  • Servlet第二篇【Servlet调用图、Servlet细节、ServletConfig、ServletContext】

    Servlet的调用图

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

    Servlet的细节

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

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

    
    	    <servlet>
    	        <servlet-name>Demo1</servlet-name>
    	        <servlet-class>zhongfucheng.web.Demo1</servlet-class>
    	    </servlet>
    	    <servlet-mapping>
    	        <servlet-name>Demo1</servlet-name>
    	        <url-pattern>/Demo1</url-pattern>
    	    </servlet-mapping>
    	    <servlet-mapping>
    	        <servlet-name>Demo1</servlet-name>
    	        <url-pattern>/ouzicheng</url-pattern>
    	    </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. 用特定的后缀声明版权【公司缩写】
    
    		 <servlet>
    	        <servlet-name>Demo1</servlet-name>
    	        <servlet-class>zhongfucheng.web.Demo1</servlet-class>
    	    </servlet>
    	    <servlet-mapping>
    	        <servlet-name>Demo1</servlet-name>
    	        <url-pattern>*.jsp</url-pattern>
    	    </servlet-mapping>
    	    <servlet-mapping>
    	        <servlet-name>Demo1</servlet-name>
    	        <url-pattern>*.net</url-pattern>
    	    </servlet-mapping>
    	    <servlet-mapping>
    	        <servlet-name>Demo1</servlet-name>
    	        <url-pattern>*.asp</url-pattern>
    	    </servlet-mapping>
    	    <servlet-mapping>
    	        <servlet-name>Demo1</servlet-name>
    	        <url-pattern>*.php</url-pattern>
    	    </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
    
        <servlet>
            <servlet-name>default</servlet-name>
            <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
            <init-param>
                <param-name>debug</param-name>
                <param-value>0</param-value>
            </init-param>
            <init-param>
                <param-name>listings</param-name>
                <param-value>false</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
    
    
        <servlet-mapping>
            <servlet-name>default</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    
    
    
    • 什么叫做缺省Servlet?凡是在web.xml文件中找不到匹配的元素的URL,它们的访问请求都将交给缺省Servlet处理,也就是说,缺省Servlet用于处理所有其他Servlet都不处理的访问请求
    • 既然我说了在web访问任何资源都是在访问Servlet,那么我访问静态资源【本地图片,本地HTML文件】也是在访问这个缺省Servlet【DefaultServlet】
    • 证实一下:当我没有手工配置缺省Servlet的时候,访问本地图片是可以访问得到的

    • 现在我自己配置一个缺省Servlet,Demo1就是我手工配置的缺省Servlet,覆盖掉web.xml配置的缺省Servlet
    
        <servlet>
            <servlet-name>Demo1</servlet-name>
            <servlet-class>zhongfucheng.web.Demo1</servlet-class>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>Demo1</servlet-name>
            <url-pattern>/</url-pattern>
        </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
    
        <servlet>
            <servlet-name>Demo1</servlet-name>
            <servlet-class>zhongfucheng.web.Demo1</servlet-class>
            <init-param>
                <param-name>name</param-name>
                <param-value>zhongfucheng</param-value>
            </init-param>
        </servlet>
        <servlet-mapping>
            <servlet-name>Demo1</servlet-name>
            <url-pattern>/Demo1</url-pattern>
        </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的代码
    
            //获取到ServletContext对象
            ServletContext servletContext = this.getServletContext();
    
            String value = "zhongfucheng";
    
            //MyName作为关键字,value作为值存进   域对象【类型于Map集合】
            servletContext.setAttribute("MyName", value);
    
    
    
    • 这是Demo3的代码
    
            //获取ServletContext对象
            ServletContext servletContext = this.getServletContext();
    
            //通过关键字获取存储在域对象的值
            String value = (String) servletContext.getAttribute("MyName");
    
            System.out.println(value);
    
    
    • 访问Demo3可以获取Demo2存储的信息,从而实现多个Servlet之间通讯


    获取web站点配置的信息

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

    • web.xml文件支持对整个站点进行配置参数信息所有Servlet都可以取到该参数信息
    
        <context-param>
            <param-name>name</param-name>
            <param-value>zhongfucheng</param-value>
        </context-param>
    
    
    • Demo4代码
    
            //获取到ServletContext对象
            ServletContext servletContext = this.getServletContext();
    
            //通过名称获取值
            String value = servletContext.getInitParameter("name");
            System.out.println(value);
    
    
    

    • 试一下Demo3是否能拿到,相同的代码
    
            //获取到ServletContext对象
            ServletContext servletContext = this.getServletContext();
    
            //通过名称获取值
            String value = servletContext.getInitParameter("name");
            System.out.println(value);
    
    


    读取资源文件

    第一种方式:

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

    • 按我们以前的方式,代码应该是这样的。
    
            FileInputStream fileInputStream = new FileInputStream("1.png");
            System.out.println(fileInputStream);
    
    
    • 当我们访问的时候,却出错了!说找不到1.png文件

    • 这是为什么呢?我们以前读取文件的时候,如果程序和文件在同一包名,可以直接通过文件名称获取得到的!,原因很简单,以前我们写的程序都是通过JVM来运行的,而现在,我们是通过Tomcat来运行的
    • 根据web的目录规范,Servlet编译后的class文件是存放在WEB-INFclasses文件夹中的

    • 看到这里,我们知道了要进入classes目录中读取文件,所以我们将代码改成以下方式
    
    
            FileInputStream fileInputStream = new FileInputStream("D:\zhongfucheng\web\WEB-INF\classes\zhongfucheng\web\1.png");
            System.out.println(fileInputStream);
    
    
    
    • 再去读取时,就发现可以获取到文件了。
    • 但是现在问题又来了,我读取文件的时候都要写上绝对路径,这样太不灵活了。试想一下,如果我将该读取文件的模块移到其他的web站点上我的代码就又要修改了【因为web站点的名字不一样】
    • 我们通过ServletContext读取就可以避免修改代码的情况,因为ServletContext对象是根据当前web站点而生成的
    • 代码如下所示:
    
            //获取到ServletContext对象
            ServletContext servletContext = this.getServletContext();
    
            //调用ServletContext方法获取到读取文件的流
            InputStream inputStream = servletContext.getResourceAsStream("/WEB-INF/classes/zhongfucheng/web/1.png");
    
    


    第二种方式:

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

    • 代码如下所示
    
    
            //获取到ServletContext对象
            ServletContext servletContext = this.getServletContext();
    
            //调用ServletContext方法获取到读取文件的流
            InputStream inputStream = servletContext.getResourceAsStream("2.png");
    
    


    第三种方式:

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

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

    • 代码如下所示
    
            //获取到类装载器
            ClassLoader classLoader = Servlet111.class.getClassLoader();
    
            //通过类装载器获取到读取文件流
            InputStream inputStream = classLoader.getResourceAsStream("3.png");
    
    
    
    

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

    • 代码如下,添加包名路径即可。
    
            //获取到类装载器
            ClassLoader classLoader = Servlet111.class.getClassLoader();
    
            //通过类装载器获取到读取文件流
            InputStream inputStream = classLoader.getResourceAsStream("/zhongfucheng/web/1.png");
    
    
    
    

    原则:如果文件太大,就不能用类装载器的方式去读取,会导致内存溢出


    如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章的同学,可以关注微信公众号:Java3y

  • 相关阅读:
    C/C++多文件之间的变量定义
    PKU POJ 2186 Popular Cows 强连通分量
    重载函数
    ZOJ 2763 Prison Break
    201357 训练赛总结
    hdu 4467 Graph 构造
    201356 训练赛总结
    201353 NEERC 2012, Eastern subregional contest
    2013512 CF 183 总结
    一道动态规划
  • 原文地址:https://www.cnblogs.com/Java3y/p/8412710.html
Copyright © 2011-2022 走看看