使用 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: 驱动器中,和/或 /conf/catalina/localhost/ec.xml 的 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() 部分?) 嗨 Abhishek 我开始工作了..下面是我的代码 prop.load(new FileInputStream("./WEB-INF/temp.properties"));【参考方案4】:

今天我在同样的要求上苦苦挣扎,没有找到任何完整的源样本,所以我在这里用我可以组合的最小的独立测试:

@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 文件夹中的文件?的主要内容,如果未能解决你的问题,请参考以下文章

Openliberty arquillian 测试

使用 Postgres DB 的 Arquillian 的 Tomee 用户缺少权限或找不到对象

将所有 Maven 依赖项添加到 Arquillian

Arquillian,Runclient测试为远程

使用arquillian测试远程客户端jndi查找

在 Equinox 中运行 Arquillian