`

servletContextResource (ServletContext.getResourceAsStream)

阅读更多
/*
 * Copyright 2002-2005 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.web.context.support;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

import javax.servlet.ServletContext;

import org.springframework.core.io.AbstractResource;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.util.WebUtils;

/**
 * Resource implementation for ServletContext resources,
 * interpreting relative paths within the web application root directory.
 *
 * <p>Always supports stream access and URL access, but only allows
 * <code>java.io.File</code> access when the web application archive
 * is expanded.
 *
 * @author Juergen Hoeller
 * @since 28.12.2003
 * @see javax.servlet.ServletContext#getResourceAsStream
 * @see javax.servlet.ServletContext#getResource
 * @see javax.servlet.ServletContext#getRealPath
 */
public class ServletContextResource extends AbstractResource {

	private final ServletContext servletContext;

	private final String path;


	/**
	 * Create a new ServletContextResource.
	 * <p>The Servlet spec requires that resource paths start with a slash,
	 * even if many containers accept paths without leading slash too.
	 * Consequently, the given path will be prepended with a slash if it
	 * doesn't already start with one.
	 * @param servletContext the ServletContext to load from
	 * @param path the path of the resource
	 */
	public ServletContextResource(ServletContext servletContext, String path) {
		// check ServletContext
		Assert.notNull(servletContext, "Cannot resolve ServletContextResource without ServletContext");
		this.servletContext = servletContext;

		// check path
		Assert.notNull(path, "path is required");
		if (!path.startsWith("/")) {
			path = "/" + path;
		}
		this.path = StringUtils.cleanPath(path);
	}

	/**
	 * Return the ServletContext for this resource.
	 */
	public final ServletContext getServletContext() {
		return servletContext;
	}

	/**
	 * Return the path for this resource.
	 */
	public final String getPath() {
		return path;
	}


	/**
	 * This implementation delegates to <code>ServletContext.getResourceAsStream</code>,
	 * but throws a FileNotFoundException if no resource found.
	 * @see javax.servlet.ServletContext#getResourceAsStream(String)
	 */
	public InputStream getInputStream() throws IOException {
		InputStream is = this.servletContext.getResourceAsStream(this.path);
		if (is == null) {
			throw new FileNotFoundException("Could not open " + getDescription());
		}
		return is;
	}

	/**
	 * This implementation delegates to <code>ServletContext.getResource</code>,
	 * but throws a FileNotFoundException if no resource found.
	 * @see javax.servlet.ServletContext#getResource(String)
	 */
	public URL getURL() throws IOException {
		URL url = this.servletContext.getResource(this.path);
		if (url == null) {
			throw new FileNotFoundException(
					getDescription() + " cannot be resolved to URL because it does not exist");
		}
		return url;
	}

	/**
	 * This implementation delegates to <code>ServletContext.getRealPath</code>,
	 * but throws a FileNotFoundException if not found or not resolvable.
	 * @see javax.servlet.ServletContext#getRealPath(String)
	 */
	public File getFile() throws IOException {
		String realPath = WebUtils.getRealPath(this.servletContext, this.path);
		return new File(realPath);
	}

	/**
	 * This implementation creates a ServletContextResource, applying the given path
	 * relative to the path of the underlying file of this resource descriptor.
	 * @see org.springframework.util.StringUtils#applyRelativePath(String, String)
	 */
	public Resource createRelative(String relativePath) throws IOException {
		String pathToUse = StringUtils.applyRelativePath(this.path, relativePath);
		return new ServletContextResource(this.servletContext, pathToUse);
	}

	/**
	 * This implementation returns the name of the file that this ServletContext
	 * resource refers to.
	 * @see org.springframework.util.StringUtils#getFilename(String)
	 */
	public String getFilename() {
		return StringUtils.getFilename(this.path);
	}

	/**
	 * This implementation returns a description that includes the ServletContext
	 * resource location.
	 */
	public String getDescription() {
		return "ServletContext resource [" + this.path + "]";
	}


	/**
	 * This implementation compares the underlying ServletContext resource locations.
	 */
	public boolean equals(Object obj) {
		if (obj == this) {
			return true;
		}
		if (obj instanceof ServletContextResource) {
			ServletContextResource otherRes = (ServletContextResource) obj;
			return (this.servletContext.equals(otherRes.servletContext) && this.path.equals(otherRes.path));
		}
		return false;
	}

	/**
	 * This implementation returns the hash code of the underlying
	 * ServletContext resource location.
	 */
	public int hashCode() {
		return this.path.hashCode();
	}

}

 

其中使用到了Log4J作为日志输出工具,Log4J的配置文件log4j.propertes放在DefaultWebApp\WEB-INF目录下。Log4J通过一个自动加载的Servlet进行初始化,初始化代码如下:

ServletContext context = getServletContext(); 
org.apache.log4j.PropertyConfigurator.
configure(context.getRealPath("/")
+ "/WEB-INF/log4j.properties");


其中,context.getRealPath("/")得到当前Web应用的真实根目录,比如,如果你的WebLogic安装在D:\bea下,在Windows下context.getRealPath("/")通常会返回:

D:\bea\wlserver6.1\config\mydomain
\applications\DefaultWebApp



在UNIX下类似:

/bea/wlserver6.1/config/mydomain
/applications/DefaultWebApp



这样,和 "/ WEB-INF /log4j.properties"

拼接后,就得到了log4j.properties文件的真实路径


现在一切正常!测试通过后,将DefaultWebApp下的所有文件打为一个.war包,进行部署时,发现系统报告找不到“D:\bea\wlserver6.1\null\ WEB-INF \log4j.properties”文件!如果你的应用中还需要读取其它已经被打包到war包中的文件,都会报告找不到文件。并且,系统并不会到D:\bea\wlserver6.1\config\mydomain\applications\DefaultWebApp目录下寻找,而会到D:\bea\wlserver6.1\null下寻找。这是因为context.getRealPath("/")返回了null。

查看ServletContext的API文档,原来,对一个打包的应用来说,是没有RealPath的概念的,调用getRealPath只会简单地返回null。其实,也很好理解,一个文件被打包入了.war文件,就不存在目录结构了(虽然包中仍然存在目录结构,但这不等同于文件系统中的目录结构)。

所以,对war包中的资源是无法得到RealPath的。这样也就无从通过文件IO进行读取了。那么,如何读取war包中的资源呢?答案是使用ServletContext.getResourceAsStream(String)方法

对于org.apache.log4j.PropertyConfigurator,有如下几种配置方法:

static void configure(Properties properties); 
static void configure(String configFilename); 
static void configure(URL configURL);



既然,现在不能得到war包中的Log4J的配置文件,那么可以通过读入InputStream,构造一个Properties,通过configure(Properties properties)方法同样可以完成配置。示例代码如下:

InputStream is = getServletContext(). 
getResourceAsStream("/WEB-INF/log4j.properties"); 
Properties props = new Properties(); 
try
{ 
props.load(is); 
}
catch (IOException e)
{ 
System.err.println("Load log4j 
configuration failed"); 
        } 
        PropertyConfigurator.configure(props);



那么,现在对于war应用可以成功运行,但如果现在不通过war部署,直接通过目录结构部署应用会不会又出现找不到资源的错误呢?请来看看ServletContext.getResourceAsStream的API文档,

Returns a URL to the resource that is 
mapped to a specified path. The path 
must begin with a "/" and is interpreted
as relative to the current context root. 
This method allows the servlet container 
to make a resource available to servlets
from any source. Resources can be located 
on a local or remote file system,
in a database, or in a .war file.



可见,通过getResourceAsStream可以获取包括本地文件系统、远程文件系统、war包等资源。不会出现上面担心的问题。

结论:在开发J2EE Web应用时,如果需要读取本应用中的文件,尽量使用ServletContext.getResourceAsStream进行,而不要使用文件IO

 

System.out.println(this.getServletContext().getResourceAsStream("/WEB-INF/classes/log4j.properties"));

 

1.关于request.getRealPath
问题:
String filename=request.getRealPath(filename)
-------------------
信息:
warning: [deprecation] getRealPath(java.lang.String) in javax.servlet.ServletRequest has been deprecated

解决:
这个getRealPath方法已经不建议使用了

参看request.getRealPath的java doc:
Deprecated. As of Version 2.1 of the Java Servlet API, use ServletContext.getRealPath(java.lang.String) instead. 


而在servlet中使用getServletContext.getRealPath()这个方法受到war 和non-war的影响,以及不同app server实现的影响,运气好的话,你常常会得到null,嘿嘿,比如你在weblogic上部署war文件,又调用这个方法..

推荐ServletContext.getResourceAsStream


2.关于serveletContext.getRealPath返回NULL和不同的app server返回不同的结果

问题:

有几个配置文本配置文件(是一些报表的模板),放在WEB-INF下面的config目录下,程序中是这样得到这个config的实际路径的:
先用 serveletContext.getRealPath得到根路径,tomcat中比如是
c:\tomcat\webapp\test

然后我加上 "/WEB-INF/config/aa.config",这样得到文件的path然后进行读入,应用在tomcat上跑是ok的,后来将war放到weblogic上,出错,原因是:
在weblogic上用getRealPath得到的是像
myserver\stage\_appsdir_test_war\test.war!\WEB-INF\config....
这样的路径,于是一直报FileNotFoundException

解决:

serveletContext.getRealPath
这个方法在不同的服务器上所获得的实现是不一样的,建议是通过classloader来获得你配置的资源文件

context.getRealPath("/")可能返回了null,你可以输入来看看,
对一个打包的应用来说,是没有RealPath的概念的,调用getRealPath只会简单地返回null。其实,也很

好理解,一个文件被打包入了.war文件,就不存在目录结构了(虽然包中仍然存在目录结构,但这不等同于文件系统中的目录结构)。所以,对war包中的资源是无法得到RealPath的。这样也就无从通过文件IO进行读取了。

那么,如何读取war包中的资源呢?答案是使用:
ServletContext.getResourceAsStream("/WEB-INF/config/aa.config")方法。


原则:基本上就是尽量使用j2ee规范中的各层次classloader来获取资源,而不是试图去找文件的绝对路
径
方法:调用this.getClass().getClassLoader().getResource("/").getPath(); 获取到classes目录的全路径

使用:在得到classes目录的全路径后再根据字符串的截取与拼装达到你的要求即可。




   绝对不要使用ServletContext的getRealPath方法获取Web应用的路径!应该使用ServletContext的getResource()方法,直接使用相对于Web应用根目录的相对路径来获取资源。


ServletContext接口中定位资源的方法
getResource
java.net.URL getResource(java.lang.String path)
throws java.net.MalformedURLException
Returns a URL to the resource that is mapped to a specified path. The path must begin with a "/" and is interpreted as relative to the current context root. 
This method allows the servlet container to make a resource available to servlets from any source. Resources can be located on a local or remote file system, in a database, or in a .war file. 
The servlet container must implement the URL handlers and URLConnection objects that are necessary to access the resource. 
This method returns null if no resource is mapped to the pathname. 
Some containers may allow writing to the URL returned by this method using the methods of the URL class. 
The resource content is returned directly, so be aware that requesting a .jsp page returns the JSP source code. Use a RequestDispatcher instead to include results of an execution. 
This method has a different purpose than java.lang.Class.getResource, which looks up resources based on a class loader. This method does not use class loaders. 
Parameters:
path - a String specifying the path to the resource 
Returns:
the resource located at the named path, or null if there is no resource at that path 
Throws:
java.net.MalformedURLException - if the pathname is not given in the correct form

--------------------------------------------------------------------------------

getResourceAsStream
java.io.InputStream getResourceAsStream(java.lang.String  path)
Returns the resource located at the named path as an InputStream object. 
The data in the InputStream can be of any type or length. The path must be specified according to the rules given in getResource. This method returns null if no resource exists at the specified path. 
Meta-information such as content length and content type that is available via getResource method is lost when using this method. 
The servlet container must implement the URL handlers and URLConnection objects necessary to access the resource. 
This method is different from java.lang.Class.getResourceAsStream, which uses a class loader. This method allows servlet containers to make a resource available to a servlet from any location, without using a class loader. 
Parameters:
path - a String specifying the path to the resource 
Returns:
the InputStream returned to the servlet, or null if no resource exists at the specified path

getRealPath
java.lang.String getRealPath(java.lang.String path)
Returns a String containing the real path for a given virtual path. For example, the path "/index.html" returns the absolute file path on the server's filesystem would be served by a request for "http://host/contextPath/index.html", where contextPath is the context path of this ServletContext.. 
The real path returned will be in a form appropriate to the computer and operating system on which the servlet container is running, including the proper path separators. This method returns null if the servlet container cannot translate the virtual path to a real path for any reason (such as when the content is being made available from a .war archive). 
Parameters:
path - a String specifying a virtual path 
Returns:
a String specifying the real path, or null if the translation cannot be performed

说明
可以看到,ServletContext接口中的getResource()等方法,可以找到任何从应用程序的根目录开始的资源。包括在.war包这样的压缩文件中。参数必须以/开头。
而我们常用的getRealPath(“/”)方法,在.war包发布时,就会失效。会返回null。
因此,我们应该避免使用getRealPath(“/”)这样的方法来获取应用程序的绝对路径。

 

分享到:
评论

相关推荐

    ServletContext与application异同.docx

    ServletContext与application异同.docx

    ServletContext介绍及用法.docx

    ServletContext官方叫servlet上下文。服务器会为每一个工程创建一个对象,这个对象就是ServletContext对象。这个对象全局唯一,而且工程内部的所有servlet都共享这个对象。所以叫全局应用程序共享对象。

    访问或添加三个范围的属性与获取Request-Session-ServletContext-Response对象.rar

    NULL 博文链接:https://llxhna.iteye.com/blog/1067851

    JavaWeb新版教程Servlet-1vlet-ServletContext对象的介绍.avi

    JavaWeb新版教程Servlet-1vlet-ServletContext对象的介绍.avi

    sevlet生命周期,request web.xml 及ServletContext总结

    Servlet生命周期,及servlet相关知识点的总结。

    Application对象(ServletContext对象).pptx

    Application对象(ServletContext对象).pptx

    Java文件路径详解

    String realpath = servletContext.getRealPath("/"); 该方法可以获取到 Web 项目的根目录。 Java 文件路径详解是 Java 中获取文件路径的方式,包括 Class.getResourceAsStream() 和 ClassLoader....

    ViewBaseServlet代码模板,使用了thymeleaf视图模板技术,是处理视图模板文件的Servlet基类

    处理视图模板文件的servlet基类; 继承:HttpServlet类 重写了init()方法: 1.获取ServletContext对象 ... ServletContext servletContext = this.getServletContext(); // 2.创建Thymeleaf解析器 }

    ServLetContext基础

    ServLetContext 解决的问题:不同的用户使用相同的数据 就是不同的用户,访问网页的时候能看到某一个相同的数据,例如该网站被访问的次数 其他特征: 特点:服务器创建;用户共享 作用域:整个项目 生命周期:服务器...

    Servlet知识点和示例

    ServletContext对象 (1)WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web 应用。 (2)ServletContext对象被包含在ServletConfig对象中,开发人员在编写servlet时,...

    Spring实战之ServletContextResource访问资源文件示例

    主要介绍了Spring实战之ServletContextResource访问资源文件,结合实例形式分析了spring使用ServletContextResource读取与遍历资源文件相关操作技巧,需要的朋友可以参考下

    Spring-for -servletcontext1.0.jar

    Ssh获取ServletContext 只需要更改struts-config action中的type就可以了ru :type="com.uo.spring.SpringDelegatingActionProxy" 大家有什么疑问可以直接去我的blog查看...《[正解]Ssh获取ServletContext》

    java编写根据模板导出excel

    String path = servletContext.getRealPath("\\ExcelFile"); String srcFilePath = path + "\\template\\" + templateFile; String destFilePath = path + "\\download\\" + filename; Map beanParams =...

    org.springframework.web.servlet-3.0.1.RELEASE-A.jar

    Error creating bean with name 'org.springframework.web.servlet.handler.SimpleUrlHandlerMapping#0' defined in ServletContext resource [/WEB-INF/springMVC-servlet.xml]: Initialization of bean failed;...

    servlet-api-2.4.jar.zip

    javax.servlet.ServletContext javax.servlet.ServletRequest javax.servlet.http.HttpUtils javax.servlet.ServletResponse javax.servlet.ServletException javax.servlet.http.HttpServlet javax.servlet....

    在action以外的地方获取dao

    这是在action以外的地方拿ApplicationContext的方法,需要的参数是:ServletContext,在request.getServletContext里能拿到,所以只要有request就能拿到spring配置文件里的bean. 这种方法通常在写组件时用,比如写...

    ServletConfig与ServletContext.docx

    注意:每个servlet有一个ServletConfig,每个Web应用有一个ServletContext.要把初始化参数认为是部署时常量,可用在运行时得到这些初始化参数,但不能设置初始化参数,根本没有setInitParameter().如果修改XML来改变...

    servlet小型项目

    servlet小项目 public class BookListener implements ServletContextListener { public void ... ServletContext context = event.getServletContext(); context.setAttribute("bookmap",map); } }

    Java连接数据库代码

    in = MyTask.class.getClassLoader().getResourceAsStream("db.properties"); prop.load(in); this.sql_ip=prop.getProperty("DB_IP").trim(); this.sql_db_name=prop.getProperty("DB_NAME").trim(); this.sql...

    ServletContext与ServletConfig关系

    ServletConfig 与 ServletContext 的关系 在 Servlet 编程中,ServletConfig 和 ServletContext 两个对象经常被混淆,然而它们有着截然不同的作用域和用途。 首先, lets 看看 ServletConfig 对象。ServletConfig ...

Global site tag (gtag.js) - Google Analytics