zoukankan      html  css  js  c++  java
  • Servlet&jsp基础:第一部分

    使用Servlet激活器... 5

    缺省Servlet6

    Tomcat中的类装载器... 6

    Servlet8

    Servlet路径映射... 8

    ServletConfig接口... 9

    获取ServletContext对象(getServletContext... 9

    获取Servlet的注册名(getServletName... 9

    获取Servlet初始化参数(getInitParameter... 9

    GenericServletHttpServlet... 10

    init方法... 10

    service方法... 10

    getServletInfo方法... 11

    doXxx方法... 11

    浏览器缓存与getLastModified方法... 13

    ServletContext16

    获取web应用的初始化参数(getInitParameter... 16

    记录日志(log... 17

    访问资源文件(getResourcePaths... 17

    将虚拟路径转换成本地路径(getRealPath... 18

    Web应用程序之间的访问(getContext... 19

    其他方法(getMajorVersiongetMimeTypegetServerInfo... 19

    使用Servlet激活器

    配置一个Servlet时,一般要在自己项目中的web.xml配置<servlet><servlet-mapping>两个元素,但con/web.xml中为我们提供了一个名叫 invoker Servlet5.5.30中已被注释掉,我们需要去掉),如下:

        <servlet>

            <servlet-name>invoker</servlet-name>

            <servlet-class>

              org.apache.catalina.servlets.InvokerServlet

            </servlet-class>

            <init-param>

                <param-name>debug</param-name>

                <param-value>0</param-value>

            </init-param>

            <load-on-startup>2</load-on-startup>

        </servlet>

    它可以根据URL中提供的Servlet类信息而自动激活这个Servlet,而不需要我们再在自己的应用中的web.xmlj里另外配置一<servlet>,只需要配置 <servlet-mapping>即可,配置如下:

        <servlet-mapping>

            <servlet-name>invoker</servlet-name>

            <url-pattern>/servlet/*</url-pattern>

        </servlet-mapping>

    如现在有这样一个Servletmypak.HelloWorldServlet,则这样可以访问http://localhost:8080/myapp/servlet/mypak.HelloWorldServlet。注意,每个Web应用程序中为Servlet激活器所映射的访问路径可以各不相同,但必须以“/*”结尾(比如这里去掉前面的 /servlet 也可以)。经过这样的设置以后,即使某个Servlet程序没有在web.xml文件中进行注册,我们只需要将Servlet激活器所映射的访问路径中的通配符(*)替换为这个Servlet的完整类名,就可以通过Servlet激活器来调用这个Servlet程序。

    缺省Servlet

    如果某个Servlet的映射路径(<servlet-mapping>元素中的<url-pattern>元素的值)仅仅为一个正斜杠(/),那么这个Servlet就成为当前Web应用程序的缺省Servlete。凡是在web.xml文件中找不到匹配的<servlet-mapping>元索的URL,它们的访问请求都将交给缺省Servlet处理,也就是说,缺省Servlet用于处理所有其他Servlet都不处理的访问请求。在<tomcat的安装目录>confweb.xml文件中,注册了一个名称为org.apache.catalina.servlets.DefaultServletServlet,并将这个Servlet设置为缺省Servlet。由于<tomcat的安装目录>confweb.xml文件的设置信息对该服务器上的所有Web应用程序都起作用,所以,服务器上的所有Web应用程序的缺省Setvlet都是org.apacbe.catalina.servlets.DefaultServlet

        <servlet>

            <servlet-name>default</servlet-name>

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

               …

        </servlet>

     

    当访问Tomcat服务器中的某个静态HTML文件和图片时,实际上是在访问这个缺省Setvlet,而这个缺省Servlet的处理方式通常是把静态资源中的内容按字节原封不动地读出来,然后再按字节流原封不动传递给客户端,并且生成一些响应消息头字段,例如,根据静态资源的扩展名所映射的MIME类型生成Content-Type头字段,根据静态资源的大小生成Content-Length头字段。

     

    如果将conf/web.xml 下的默认Servlet注释掉,则非ServletJsp资源将不能访问:

        <!--servlet-mapping>

            <servlet-name>default</servlet-name>

            <url-pattern>/</url-pattern>

    </servlet-mapping-->

     

     

    注意,缺省Servlet在输出静态页面内容后,会将静态页面内容暂时在服务器上的缓存中保存5中,也就是在这5秒中内如果又来访问这个静态的页面(根据你请求的URL来分辨,如果与上次相同则认为是请求的同一资源),将会得到相同的静态页面内容,即使你立即修改了这个静态页面的内容。但这会有个问题:如果静态页面是在服务上动态生成的,虽然它是静态页面,但里面的内容却是动态的,这就会使浏览器在5秒内不会看到最新的内容。另外,当请求一个静态页面时,缺少Servlet会自动在响应头上加上 Last-Modified 头,如果静态页面不修改,缺少Servlet会回应 304 状态码,表示没有修改,浏览器可以从缓存中读取。

    Tomcat中的类装载器

     

    image002[6]

    1、  Bootstrap类装载器负责加载Java核心名中的类<java_home>jrelib t.jar

    2、  ExtClassLoader负责加载存在<JAVA_HOME>/jre/lib/ext上当下的Java名中的类。

    3、  AppClassLoader负责加载应用程序中的类,即CLASSPAH环境变量设置的目录中的类。但Tomcat的启动脚本catalina.bat 已将CLASSPATH环境变量原来的设置值完全清除,也就是说,Tomcat不会继承操作系统上原来设置好的CLASSPATH环境变量的内容,而是将CLASSPATH一半变量重新设置成了如下两个jar包:<CATALINA_HOME>/bin/bootstrap.jar<JAVA_HOME>/lib/tools.jar

    4、  Common类装载器负责从<CATALINA_HOME>/common/classes中的.class 类文件和<CATALINA_HOME>/common/lib中的jar包加载类。Common类装载器加载的类对Tomcat服务器内核和每个Web应用程序都可见,例如,servlet.jar中包含的类既要被Tomcat服务器内核使用,又要被每个Web应用程序便用,所以,它需耍放置在CATALINA_HOME/common/lib中。

    5、  Catalina类装载器负<CATALINA_HOME>/server/classes中的 .class 类文件和<CATALINA_HOME>/server/lib中的jar包加载类。Catalina类装载器加载的类只对Tomcat服务器内核可见,对每个Web应用程序完全不可见,所以,只想让Tomcat服务器内核使用而不想让Web应用程序便用的类应放置在Catalina类装载器的搜索目录中。对于运行Tomcat内核的线程,它的上下文类装载器就是Catalina类装载器。

    6、  Shared类装载器负责从<CATALINA_HOME>/share/claases中的 .class 类文件和<CATALINA_HOME>/share/lib中的jar包加载类。Catalina类装载器加载的类只对所有的Web应用程序可见,对Tomcat服务器内核完全不可见。

    7、  WebappX类装载器负责从当前Web应用程序的/WEB-INF/classes中的.class类文件/WEB-INF/lib中的Jar包加载类。WebappX类装载器加载的类只对当前Web应用程序可见,对其他wb应用程序不可见。对于运行每个节Web应用程序的线程,它们的上下文类装载器就是它们各自的WebappX类装载器。San公司在Servlet规范中建议WebappX类装载器不应按照标准委托模式来设计,而是应该由WebappX类装载器自己先加载某个类,只有自己加载不了时,才委托父级的类装载器进行加载,除了WebappX类装载器之外,Servlet引擎中的其他类装载器都遵循标准委托棋式。但是,许多Servlet引攀开发商认为这个建议没有什么意义,所以,他们并没有采纳Servlet规范的建议,而是仍然按照标准委托模式设计了他们的WebappX类装载器,例如,笔者通过实验发现Tomcat 4.中的WebappX类装载器采用的就是标准委托模式。

    Servlet

    image003[6]

    Servlet路径映射

        <servlet>

            <servlet-name>test.Forward</servlet-name>

            <servlet-class>test.Forward</servlet-class>

        </servlet>

        <servlet-mapping>

            <servlet-name>test.Forward</servlet-name>

            <url-pattern>/demo/hello.html</url-pattern>

    </servlet-mapping>

    上面Servleturl-pattern配置的是 /demo/hello.html ,注意,demo 不是应用目录(虚拟目录或Web站点),现假设应用目录为myapp,则访问的路径为 http://localhost:8080/myapp/demo/hello.html。另外,如果在应用目录下真存在 /demo/hello.html这样一个静态页面,这里也不会去调用它,除非这里没有配这个Servlet

     

    Servlet映射到URL中也可以使用 * 通配符,但是只能有两种固定的格式:一种格式是“*.扩展名”,在 * 前面不能有目录分隔符“/”,例如“*.do”表示匹配以“.do”结尾的所有URL;另一种是以“/”开头,并以“/*”结尾,例如“/*”表示匹配当前Web应用程序下的所有URL,“/action/*”表示匹配当前Web应用程序下的“/action”子路径下的所有URL。另外,在匹配时,如果与多个路径都匹配,则优先使用最精确的那个Servlet

    ServletConfig接口

    Sevlet引擎将代表Servlet容器的对象和Servlet的配置参数信息(web.xml中所配置的)一并封装到一个称为ServletConfig的对象中,并在初始化Servlet实例对象时传递给该ServletServlet引擎装载并创建一个Servlet的实例对象后,接着调用该实例对象的init(ServletConfig config)方法将ServletConfig对象传递给Servlet

     

    GenericServlet实现了ServletConfig接口。这里我们不必要这样 getServletConfig().getServletName()来获取Servlet的名称,而是直接通过 getServletName() 方法即可获取。

    获取ServletContext对象(getServletContext

    getServletContext方法返回某个Web应用程序的ServletContext对象。

    获取Servlet的注册名(getServletName

    getServletName方法用于返回Servletweb.xml文件中的注册名称,如下面的的Servlet配置将返回“default”。对于没有在web.xml文件中注册的Servlet,将返回Servlet的类名。

    获取Servlet初始化参数(getInitParameter

    web.xml文件中可以为Servlet设置很多个初始化参数,getInitParameterNames()方法用于返回一个Enumeration的集合对象,该对象包含了在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>

     

    servletConfig.getInitParameter("debug") = "0"

    GenericServletHttpServlet

    GenericServlet是一个实现了Servlet的基本我笑和功能的基类,其完整的名称为javax.servlet.GenericServletHttpServletGenericServlet的子类。其完整名称为javax.servlet.http.HttpServlet,它提供了处理HTTP协议的基本架构。如果一个Servlet要充分利用HTTP协议的功能,就应该继承HttpServlet

    init方法

    Servlet接口中定义了一个带参的init方法:

    public void init(ServletConfig config) throws ServletException

     

    GenericServlet中还定义了一个无参数的init方法:

    public void init() throws ServletException

     

    GenericServlet类中带参数init与不带参数init的实现如下:

       public void init() throws ServletException {}

    public void init(ServletConfig config) throws ServletException {

            this.config = config;

            this.init();

    }

    所以我们在创建自己的Servlet时,一般只重写不带参数的init方法即可。如果重写带参数的init,你还得要在该方法的第一行调用一下super.init(config)语句,否则会有问题。

     

    只有带参数的init方法才是Servlet接口定义的标准方法,也是Servler引擎才会调用的方法。

    service方法

    Servlet接口中定义的 service 方法如下:

    public void service(ServletRequest req, ServletResponse res)throws ServletException, IOException;

    GenericServlet类没有对这个方法进行实现,HttpServlet类实现了这个方法,实现如下:

        public void service(ServletRequest req, ServletResponse res)

            throws ServletException, IOException {

            HttpServletRequest  request;

            HttpServletResponse response;      

            try {

                request = (HttpServletRequest) req;

                response = (HttpServletResponse) res;

            } catch (ClassCastException e) {

                throw new ServletException("non-HTTP request or response");

            }

            service(request, response);//调用了另外一重载形式的service方法

        }

    针对HttpServlet的实现,为了简化这一转换过程,HttpServlet类实现的service方法内部调用了另外一重载形式的service方法,重载的service方法的定义语法为:

    protected void service(HttpServletRequest req, HttpServletResponse resp)        throws ServletException, IOException

     

    注,Servlet引擎或容器只会去调用在Servlet接口中定义的 service方法,即service(ServletRequest req, ServletResponse res)方法,还不是在HttpServlet中重载的service(HttpServletRequest req, HttpServletResponse resp)方法。所以我们在创建自己的Servlet类时,我们可以去重写service(HttpServletRequest req, HttpServletResponse resp)方法,Servlet引擎会通过调用Servlet接口上中的那个service方法来调用我们重写过的service方法。

    getServletInfo方法

    返回Servlet的描述信息,GenericServlet实现返回的为空字符串,如有必要,可以重写这个方法,以便返回Servlet的作者、版本等信息

    doXxx方法

    不管客户端以哪种请求主方式访问ServletServlet引擎都将调用Servlet接口中定义的那个service方法,它是所有请求方式的总入口;然后再调用HttpServlet中重载的那个service方法;最后由重载的那个service方法分派到不同的doXxx方法。HttpServlet重载的service方法实现如下:

    protected void service(HttpServletRequest req, HttpServletResponse resp)

            throws ServletException, IOException {

            String method = req.getMethod();

            if (method.equals(METHOD_GET)) {

                long lastModified = getLastModified(req);//默认为-1,即不支持Last-Modified

                if (lastModified == -1) {//不支持Last-Modified

                    // servlet doesn't support if-modified-since, no reason

                    // to go through further expensive logic

                    doGet(req, resp);

                } else {//支持Last-Modified

                    long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);

                    if (ifModifiedSince < (lastModified / 1000 * 1000)) {//如果已更新

                        // If the servlet mod time is later, call doGet()

                        // Round down to the nearest second for a proper compare

                        // A ifModifiedSince of -1 will always be less

    //在响应头中设置文档最后更新时间头Last-Modified

                        maybeSetLastModified(resp, lastModified);

                        doGet(req, resp);

                    } else {

    //如果没有更改,则返回304状态码,表示GET请求的资源可用并且没有修改,

    //浏览器会从缓存中读取

                        resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);

                    }

                }

            } else if (method.equals(METHOD_HEAD)) {

    //doHead的目的就是看服务器是否已更新文档

                long lastModified = getLastModified(req);

                maybeSetLastModified(resp, lastModified);

                doHead(req, resp);

            } else if (method.equals(METHOD_POST)) {

                doPost(req, resp);

            } else if (method.equals(METHOD_PUT)) {

                doPut(req, resp);           

            } else if (method.equals(METHOD_DELETE)) {

                doDelete(req, resp);          

            } else if (method.equals(METHOD_OPTIONS)) {

                doOptions(req,resp);          

            } else if (method.equals(METHOD_TRACE)) {

                doTrace(req,resp);          

            } else {

                String errMsg = lStrings.getString("http.method_not_implemented");

                Object[] errArgs = new Object[1];

                errArgs[0] = method;

                errMsg = MessageFormat.format(errMsg, errArgs);

                resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);

            }

    }

    在一般情况下,Servlet只需处理GETPOST两种请求方式,也就是在继承HttpServlet时只需重写doGetdoPost这两个方法即可。

     

    如果自己编写的Servlet程序要对客户端的所有请求方式进行相同的处理,可以重写HttpServletservice方法。这时Servlet引擎将不会再调用父类HttpServlet中的service方法(除非在重写的service方法中使用super.service()进行显示的调用),所以,doXxx方法也将不再被调用。

     

    另外,虽然HttpServlet中的doXxx方法都有默认实现,但doGetdoPostdoPutdoDelete方法的实现都是违例实现,即它们在没有重写的情况下,就表示没有实现,再直接调用时会返回给浏览器相应错误状态码与信息,以下是doGetdoPostdoPutdoDelete各自默认实现所抛出的错误信息:

    http.method_get_not_supported=HTTP method GET is not supported by this URL

    http.method_post_not_supported=HTTP method POST is not supported by this URL

    http.method_put_not_supported=HTTP method PUT is not supported by this URL

    http.method_delete_not_supported=Http method DELETE is not supported by this URL

     

    当然,在重写doGetdoPost时,如果这两个方法实现都一样,我们也只需要实现其中一个,再实现另一个时去直接调用它即可。

    浏览器缓存与getLastModified方法

    image004[6]

     

    getLastModified()方法返回Servlet当前输出的响应内容的修改时间,单位为毫秒数。它由HttpServlet类的service方法调用,HttpServlet类的service方法可以根据这个返回值决定是否在响应消息中自动生成Last-Modified头。默认返回-1,表示不生成,则浏览器将页面缓存在本地时不会有

     

    注意,HttpServet中的doGet支持Last-Modified头缓存功能,但doPost不支持。如果我们要实现Last-Modified头与If-Modified-Since头的功能,对于doGet,我们只需要实现HttpServlet中的getLastModified方法;但如果是doPost,则还要自己让doPost支持缓存功能。

     

     

    public class CacheServlet  extends HttpServlet{

           @Override

           protected void doGet(HttpServletRequest req, HttpServletResponse resp)

                         throws ServletException, IOException {

                  PrintWriter out = resp.getWriter();

                  out.println(new Date());

           }

         

    //     @Override

    //     protected long getLastModified(HttpServletRequest req) {

    //            //返回当前毫秒数,默认返回为-1

    //            return System.currentTimeMillis();

    //     }

    }

     

    http://localhost:8080/myapp/cacheservlet

    image005[6]

     

    去掉getLastModified的注释再访问

    image006[6]

     

    如果将getLastModified方法返回值改成很小的毫秒数,如1,则刷新页面时,页中的时间内容不会再变化。

     

    如果getLastModified方法返回的不是-1,则响应头会有Last-Modified字段:

    linux-7qez /home/fpcsmp> telnet 192.168.1.94 8080

    Trying 192.168.1.94...

    Connected to 192.168.1.94.

    Escape character is '^]'.

    GET /myapp/cacheservlet HTTP/1.1

    Host:

     

    HTTP/1.1 200 OK

    Server: Apache-Coyote/1.1

    Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT

    Content-Length: 30

    Date: Mon, 12 Jul 2010 08:34:52 GMT

     

    Mon Jul 12 16:34:52 CST 2010

     

    如果请求头的 if-modified-since 头字段值比服务器新或等时,返回304状态码:

    linux-7qez /home/fpcsmp> telnet 192.168.1.94 8080

    Trying 192.168.1.94...

    Connected to 192.168.1.94.

    Escape character is '^]'.

    GET /myapp/cacheservlet HTTP/1.1

    if-modified-since: Thu, 01 Jan 1970 00:00:00 GMT

    Host:

     

    HTTP/1.1 304 Not Modified

    Server: Apache-Coyote/1.1

    Date: Mon, 12 Jul 2010 08:38:12 GMT

    ServletContext

    Servlet引擎为每个Web应用程序都创建一个对应的ServletContext对象,ServletContext对像被包含在ServletConfig对象中。调用ServletConfig.getServletcontext法可以返回ServletContext对象的引用。在Servlet容器初始化Servlet对象时,ServletContext对象随着ServletConfig对象提供给Servlet。与Servlet API中的其他接口一样,ServletContext接口的实现类也是由Servlet引擎提供的。

    获取web应用的初始化参数(getInitParameter

    如果要在server.xml文件中为某个web应用程序设置初始化参数,需要在该web应用所对应的<Context>元素增加<Parameter>子元素,更改confCatalinalocalhostmyapp.xml 文件,添加 <Parameter>

    <Context path= "/myapp" docBase="Z:eclipse_workspaceservlet_jsp_exercisemyapp" debug="0" reloadable="true">

           <Parameter name="companyName1" value="XX" override="false"/>

    <Parameter name="companyName2" value="YY" override="true"/>

    </Context>

    其中voerride属性用于指定在web应用程序的web.xml文件中设置的同名初始化参数是否覆盖这里的设置,当该属性值为false时表示不允许覆盖,默认值为true,即允许覆盖。

     

    如果要在web应用程序中web.xml文件设置初始化参数,则需要在根元素的<Web-app>中增加<context-param>子元素,如下:

        <context-param>

           <param-name>companyName1</param-name>

           <param-value>XXX</param-value>

        </context-param> 

        <context-param>

           <param-name>companyName2</param-name>

           <param-value>YYY</param-value>

        </context-param>

     

    public class ContextParmServlet extends HttpServlet {

           private static final long serialVersionUID = 1L;

           protected void doGet(HttpServletRequest request,

                         HttpServletResponse response) throws ServletException, IOException {

                  ServletContext servletContext = this.getServletContext();

                  System.out.println(servletContext.getInitParameterNames().nextElement());

                  //companyName1 = XX

                  System.out.println("companyName1 = " + servletContext.getInitParameter("companyName1"));

                  //companyName2 = YYY

                  System.out.println("companyName2 = " + servletContext.getInitParameter("companyName2"));

           }

    }

    记录日志(log

    ServletContext类中定义了以下两个记录日志方法:

    log(java.lang.String msg)

    log(java.lang.String message, java.lang.Throwable throwable)

     

    GenericServlet类中也定义了两个log方法,不过它们是通过调用ServletContext相应的方法来实现的:

        public void log(String msg) {

                  getServletContext().log(getServletName() + ": "+ msg);

    }

    public void log(String message, Throwable t) {

           getServletContext().log(getServletName() + ": " + message, t);

    }

     

    log方法记录的日志文件名称和存储路径因Web服务器不同而不同。Tomcat中的日志文件的存储路径和名称是在servlet.xml文件中进行设置的。每个Web应用程序都可以设置其单独的日志文件。在server.xml文件中,使用<logger>元素来设置日志文件的相关信息,如下所示:

    <Logger className="org.apache.catalina.logger.FileLogger" directory="logs" prefix="catalina_log." suffix=".txt" timestamp="true"/>

     

    directory如果是相对路径,则是相对于 $CATALINA_HOME 环境变量所设置的目录,directory的默认值为相对目录“logs”。

     

    以上是针对 Tomcat 4.X的配置,Tomcat 5.x不一样了。

     

    <logger>元素可以嵌套在<Engine> <Host> <Context>元素之中,如果里层元素中没有单独的设置<logger>元素,它将继承外层元素中的日志设置。

    访问资源文件(getResourcePaths

    ServletContext接口中还定义了一些用于访问Web应用程序的内部资源文件的方法,比如WEB-INF目录中不能被外界访问的文件。

     

    getResourcePaths(java.lang.String path):返回一个Set集合,包含某个资源目录中所有子目录和文件的路径名称,每个路径名名称相对于web应用程序的根目录(web应用目录或虚拟目录)的形式表示,如果是目录,则还以“/”结尾。如有某个应用目录下有以下这些资源:

    /welcome.html

    /catalog/index.html

    /catalog/products.html

    /catalog/offers/books.html

    /catalog/offers/music.html

    /customer/login.jsp

    /WEB-INF/web.xml

    /WEB-INF/classes/com.acme.OrderServlet.class,

    getResourcePaths("/") returns {"/welcome.html", "/catalog/", "/customer/", "/WEB-INF/"}

    getResourcePaths("/catalog/") returns {"/catalog/index.html", "/catalog/products.html", "/catalog/offers/"}

    注,参数path一定要以“/”开头,且是相对于应用目录。

     

    java.net.URL getResource(java.lang.String path):返回指定的某个资源的URL对象,path参数也必须以“/”开头,并且也是相对于应用根目录的。

     

    java.io.InputStream getResourceAsStream(java.lang.String path):返回连接到某个资源上的InputStream对象,实际上是打开了getResource方法返回的URL对象上的输入流,它的参数传递规则与getResource方法完全一样

     

    一个Web应用程序在本地文件系统中的安装位里是可以变化的,不同的公司或个人可能将它安装在不同的位置上,所以ServIet程序不应使用绝对路径的形式来访问Web应用程序中的某个文件。

    在某个java类中使用的相对路径是相对于当前的工作目录(比如在eclipse里运行一个Java类时,目录为项目所在的根目录;如果Tomcat是通过startup.bat启动的,那就是相对于startup.bat所在的目录而言的)而言的,这个工作目录通常是执行java命令的目录,而不是当前正在执行的java类所在的目录,这一特性导致在Java程序中很难直接使用相对目录。

    针对在Java程序中使用FileInputStream类和相对路径访问资源文件时会出现的问题,JDK中的ClassLoader类专门提供了getResource等方法去装载资源文件,它们使用与查找Java类文件同样的方式去查找资源文件,即在类装载器所搜索的目录中查找。为了简化程序的编写,Class类中也定义了几个访问资源文件的方法,这些方法内部调用了ClassLoader类中的同名方法去完成相应的功能。为了防止外部使用浏览器访问到资源文件,Web应用程序中的资源文件通常应放置在WEB-INF目录或其子目录中。由于Web应用程序的类装载器会搜索WEB-INF/classes目录,所以,ClassLoader.getResourceAsStream方法也可以访问该目录中的资源文件,但是,ClassLoader.getResourceAsStream方法不能访问Web应用程序内的其他目录(比如应用目录或虚拟目录下的文件,或者是WEB-INF中的资源,而不是WEB-INF/classesWEB-INF/lib下的资源)中的资源。ServletContext类中的访问资源的方法是通过Servlet容器来获得资源文件的,它使得Servlet程序可以访问Web应用程序内部的任意位置的文件。

    将虚拟路径转换成本地路径(getRealPath

    ServletContext接口的getRealPath方法,用于返回某个虚拟路径所映射的本地文件系统路径。不管传递的路径参数是否以“/”开头,它们都应该是相对于应用目录的,因为在转换后它们前面都会带上应用目录。具体的细微差别请看:

    // Z:eclipse_workspaceservlet_jsp_exercisemyapp

    System.out.println(servletContext.getRealPath(""));

    // Z:eclipse_workspaceservlet_jsp_exercisemyapp

    System.out.println(servletContext.getRealPath("/"));

    // Z:eclipse_workspaceservlet_jsp_exercisemyappWEB-INF

    System.out.println(servletContext.getRealPath("WEB-INF"));

    // Z:eclipse_workspaceservlet_jsp_exercisemyappWEB-INF

    System.out.println(servletContext.getRealPath("/WEB-INF"));

    Web应用程序之间的访问(getContext

    ServletContext.getRealPath只能获取当前应用下的资源路径,因为传给它的路径永远是相对于当前应用目录的。如果要获取其他Web应用的资源,怎么办?那就得先要获取到其他Web应用的ServletContext对象。

     

    ServletContext接口中定义了一个getContext方法来获得某个URL所对应的ServletContext对象,传递给geContext方法的路径字符串必须以“/”作为起始字符,这个“/”代表的是整个Web服务器的根目录,而不是某个Web应用程序的根目录,这说明在一个Web应用程序中可以获得代表其他Web应用程序的ServletContext对象,如果要让某个Web应用程序内部能够使用ServletContext.getContext方法返回代表其他Web应用程序的ServletContext对象,必须将conf/server.xml文件中与该Web应用程序对应的<Context>元素的crossContext属性设置为true,只有为true时,它所对应的Web应用程序内部才能使用ServletContext.getContext方法返回代表其他Web应用程序的ServletContext对象。例如,如果想/myapp这个Web应用程序能够访问其他的Web应用程序,应将对应的<Context>元素的起始标签修改成如下形式:

    <Context path= "/myapp" docBase="Z:eclipse_workspaceservlet_jsp_exercisemyapp" crossContext="true" debug="0" reloadable="true">

     

    //获取同一主机中Web应用目录为 / Web应用

    ServletContext sc = servletContext.getContext("/");

    // Z: omcat-5.5.30webappsROOT

    System.out.println(sc.getRealPath(""));

    //获取同一主机中Web应用目录为 /myapp2 Web应用

    sc = servletContext.getContext("/myapp2");

    // Z:eclipse_workspacemyapp2myapp2

    System.out.println(sc.getRealPath(""));

     

    crossContext的默认值为false

    其他方法(getMajorVersiongetMimeTypegetServerInfo

    //获取Servlet容器所支持的Servlet API的主次版本号

    System.out.println(servletContext.getMajorVersion() + "."

                  + servletContext.getMinorVersion());//2.4

    //获取某个文件的MIME类型,这个类型是在conf/web.xml中配置的

    System.out.println(servletContext.getMimeType("xx.html"));//text/html

    //获取容器的名称和版本信息

    System.out.println(servletContext.getServerInfo());//Apache Tomcat/5.5.30

  • 相关阅读:
    [BZOJ3223] [Tyvj1729] 文艺平衡树 (splay)
    [BZOJ3098] Hash Killer II
    [BZOJ3000] Big Number (Stirling公式)
    [BZOJ2048] [2009国家集训队] 书堆
    [BZOJ1707] [Usaco2007 Nov] tanning分配防晒霜 (贪心)
    BZOJ2482: [Spoj1557] Can you answer these queries II
    BZOJ2157: 旅游
    BZOJ2795: [Poi2012]A Horrible Poem
    BZOJ3681: Arietta
    BZOJ3218: a + b Problem
  • 原文地址:https://www.cnblogs.com/jiangzhengjun/p/4288968.html
Copyright © 2011-2022 走看看