使用 Arquillian 时如何引用放置在 WEB-INF 文件夹中的文件?
Posted
技术标签:
【中文标题】使用 Arquillian 时如何引用放置在 WEB-INF 文件夹中的文件?【英文标题】:How do I reference a file that is placed in the WEB-INF folder when using Arquillian? 【发布时间】:2012-10-18 06:06:21 【问题描述】:我正在使用 Maven 和标准目录布局。所以我在src/test/resources文件夹下添加了一个testdata.xml文件,我也添加为:
.addAsWebInfResource("testdata.xml", "testdata.xml")
在部署方法中,我已经确认它在那里。这将使文件出现在/WEB-INF/testdata.xml
中。现在我需要在我的代码中引用这个文件,我尝试了几个不同的 getClass().getResourceAsStream(...)
并且一次又一次地失败,所以我现在需要一些建议。
我的 DBUnit 集成测试需要它。这不可能吗?
【问题讨论】:
应该在类路径中做Class.getResourseAsStream()
。并非 WEB-INF 中的所有内容都放在类路径中。只有 WEB-INF 中的类文件夹的内容被添加到类路径中。您可以获取上下文路径的路径并将其余位置附加到它。
或者如果你可以访问ServletContext
,你可以访问servletContext.getRealPath("/WEB-INF/testdata.xml")
。
@Dude,这个 XML 文件是包含要在测试中使用的数据的 DbUnit 平面 XML 文件吗?
【参考方案1】:
访问WEB-INF
下的文件的方式是通过ServletContext
的三种方式:
getResource("/WEB-INF/testdata.xml")
给你一个网址
getResourceAsStream
给你一个输入流
getRealPath
为您提供相关文件在磁盘上的路径。
前两个应该始终有效,如果资源路径和磁盘上的文件之间没有直接对应关系,第三个可能会失败,例如,如果您的 Web 应用程序直接从 WAR 文件而不是解压缩的目录结构运行。
【讨论】:
使用 Arquillian 时如何获取 servlet 上下文对象?【参考方案2】:选项 A)使用 ServletContext.getResourceXXX()
你应该有一个 Aquillarian MockHttpSession 和一个 MockServletContext。例如:
@Test
public void myTest()
HttpSession session = new MockHttpSession(new MockServletContext());
ServletLifecycle.beginSession(session);
..testCode..
// You can obtain a ServletContext (will actually be a MockServletContext
// implementation):
ServletContext sc = session.getServletContext();
URL url = sc.getResource("/WEB-INF/testdata.xml")
Path resPath = new Path(url);
File resFile = new File(url);
FileReader resRdr = new FileReader(resFile);
etc...
..testCode..
ServletLifecycle.endSession(session);
您可以在以下位置创建资源文件和子目录:
-
Web 模块文档根目录 - 可以从浏览器和类访问资源
WEB-INF/classes/ - 资源可供类访问
WEB-INF/lib/*.jar 源 jar - 类可访问
WEB-INF/lib/*.jar 专用的仅资源 jar - 可供类访问
WEB-INF/ 直接在目录中 - 类可访问。这就是您所要求的。
在所有情况下,资源都可以通过以下方式访问:
URL url = sc.getResource("/<path from web doc root>/<resourceFileName>");
OR
InputStream resIS = sc.getResourceAsStream("/<path from web doc root>/<resourceFileName>");
>
这些将被打包到 WAR 文件中,并且可能会分解到已部署的应用服务器上的目录中,或者它们可能会保留在应用服务器上的 WAR 文件中。无论哪种方式 - 访问资源的行为相同:使用 ServletContext.getResourceXXX()。
请注意,作为一般原则,(5) *** WEB-INF 目录本身是供服务器使用的。不将您的网络资源直接放在这里或直接在这里创建您自己的目录是“礼貌的”。相反,最好使用上面的 (2)。
JEE5 tutorial web modules JEE6 tutorial web modules
选项 B):使用 Class.getResourceXXX()
首先将资源从 WEB-INF 文件夹中移出到 WEB-INF/classes 中(或在 jar WEB-INF/lib/*.jar 中)。
如果你的测试类是:
com.abc.pkg.test.MyTest 在文件 WEB-INF/classes/com/abc/pkg/test/MyTest.class 中你的资源文件是
WEB-INF/classes/com/abc/pkg/test/resources/testdata.xml(或 jar 文件中的等效项)使用相对文件位置访问文件,通过 Java 类加载器 - 查找相对于类路径的文件夹/罐子:
java.net.URL resFileURL = MyTest.class.getResource("resources/testdata.xml");
File resFile = new File(fileURL);
OR
InputStream resFileIS =
MyTedy.class.getResourceAsStream("resources/testdata.xml");
使用完整的类包限定访问文件,使用 Java 类加载器 - 查找相对于类路径的文件夹/罐子:
java.net.URL resFileURL = MyTest.class.getResource("/com/abc/pkg/test/resources/testdata.xml");
File resFile = new File(fileURL);
OR
InputStream resFileIS =
MyTest.class.getResourceAsStream("/com/abc/pkg/test/resources/testdata.xml");
OR
java.net.URL resFileURL = MyTest.class.getClassLoader().getResource("com/abc/pkg/test/resources/testdata.xml");
File resFile = new File(fileURL);
OR
InputStream resFileIS =
MyTest.class.getClassLoader().getResourceAsStream("com/abc/pkg/test/resources/testdata.xml");
希望一切顺利! @B)
【讨论】:
谢谢。这对我也有帮助。 java.io.File 没有 java.net.URL 的构造函数,因此您的 File resFile = new File(url);转换甚至不会编译 正如@JanM 所说,java.io.File 没有 java.net.URL 构造函数。 File 从 Java 1.4 开始就有一个构造函数 File(URI)。 URL 扩展了 URI。 糟糕。 URL 实际上并没有扩展 URI,并且 URL.toURI() 声明了一个已检查的异常。真烦人。【参考方案3】:将此类添加到您的项目中:
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
public class Init
private static final String WEB_INF_DIR_NAME="WEB-INF";
private static String web_inf_path;
public static String getWebInfPath() throws UnsupportedEncodingException
if (web_inf_path == null)
web_inf_path = URLDecoder.decode(Init.class.getProtectionDomain().getCodeSource().getLocation().getPath(), "UTF8");
web_inf_path=web_inf_path.substring(0,web_inf_path.lastIndexOf(WEB_INF_DIR_NAME)+WEB_INF_DIR_NAME.length());
return web_inf_path;
现在无论您想要获取文件"testdata.xml"
的完整路径,都可以使用以下代码或类似代码:
String testdata_file_location = Init.getWebInfPath() + "/testdata.xml";
【讨论】:
HI Abhishek:我尝试了你的代码..我将 .properties 文件保存在 WEB-INF 中..当我打印 testdata_file_location 时,它的打印方式类似于 E:\ec\temp.properties ..所以我不知道它为什么这样做。那么如何从中读取属性 @sree 您是否正在使用某个 IDE 运行您的项目?你能告诉我们Tomcat或Glassfish的版本或你使用的任何东西吗?看起来 ec.war 已部署在 E: 驱动器中,和/或Context
元素中的 docBase
属性指向该位置。还要检查您是否使用上面代码中的web_inf_path.lastIndexOf(WEB_INF_DIR_NAME)+WEB_INF_DIR_NAME.length()
或web_inf_path.lastIndexOf(WEB_INF_DIR_NAME)
(即您是否不小心留下了该代码的+WEB_INF_DIR_NAME.length()
部分?)今天我在同样的要求上苦苦挣扎,没有找到任何完整的源样本,所以我在这里用我可以组合的最小的独立测试:
@RunWith(Arquillian.class)
public class AttachResourceTest
@Deployment
public static WebArchive createDeployment()
WebArchive archive = ShrinkWrap.create(WebArchive.class).addPackages(true, "org.apache.commons.io")
.addAsWebInfResource("hello-kitty.png", "classes/hello-kitty.png");
System.out.println(archive.toString(true));
return archive;
@Test
public void attachCatTest()
InputStream stream = getClass().getResourceAsStream("/hello-kitty.png");
byte[] bytes = null;
try
bytes = IOUtils.toByteArray(stream);
catch (IOException e)
e.printStackTrace();
Assert.assertNotNull(bytes);
在您的项目中,hello-kitty.png 文件转到 src/test/resources。在测试存档中,它被打包到类路径上的 /WEB-INF/classes 文件夹中,因此您可以使用与用于测试场景的容器相同的类加载器来加载它。
IOUtils 来自 apache commons-io。
补充说明: 让我摸不着头脑的一件事与我的服务器路径中的空格以及 getResourceAsStream() 转义这些特殊字符的方式有关:sysLoader.getResource() problem in java
【讨论】:
为什么不使用 Java 7 文件 API?以上是关于使用 Arquillian 时如何引用放置在 WEB-INF 文件夹中的文件?的主要内容,如果未能解决你的问题,请参考以下文章