WildFly - 从 WAR 中获取资源

Posted

技术标签:

【中文标题】WildFly - 从 WAR 中获取资源【英文标题】:WildFly - getting resource from WAR 【发布时间】:2014-07-13 17:54:26 【问题描述】:

我在 WildFly 中使用以下方法从 WAR 文件中获取资源:

this.getClass().getResource(relativePath)

当应用程序部署为分解的 WAR 时,它可以工作。 它过去也可以与压缩 WAR 一起工作。昨天,我在 Eclipse 中对项目进行了清理和重建,但它刚刚停止工作。

当我检查资源根目录时:

logger.info(this.getClass().getResource("/").toExternalForm());

我明白了:

file:/C:/JBoss/wildfly8.1.0.CR1/modules/system/layers/base/org/jboss/as/ejb3/main/timers/

所以,难怪它不起作用。它可能与 JBoss 模块加载有关,但我不知道这是一个错误还是正常行为。

我在 *** 上发现了各种类似的问题,但没有适用的解决方案。建议之一是像这样使用 ServletContext:

@Resource
private WebServiceContext wsContext;
...
ServletContext servletContext = (ServletContext)this.wsContext.getMessageContext()
        .get(MessageContext.SERVLET_CONTEXT);
servletContext.getResource(resourcePath);

但是,当我尝试以这种方式获取 MessageContext 时,我得到了 IllegalStateException。所以我基本上被卡住了。有什么想法吗?

【问题讨论】:

您试图从哪里访问此代码? 来自 JAX-RS Web 服务中的 @GET 方法。 更具体地说,来自 stateless JAX-RS Web 服务中的 @GET 方法。 【参考方案1】:

我遇到了同样的问题,我没有将资源定义为共享模块,而是通过在我的 WAR 中使用 ServletContextListener 来解决这个问题。

在 contextInitialized 方法中,我从 ServletContextEvent 中获取了 ServletContext,并使用它的 getResource("/WEB-INF/myResource") 来获取我的 WAR 文件中资源的 URL。似乎在 ServletContextListener 中, .getResource() 方法按预期解析,而不是“/modules/system/layers/base/org/jboss/as/ejb3/main/timers/” url。然后,该 URL 可以存储在 ServletContext 中,供您的 servlet 或注入的 ApplicationScoped CDI bean 中使用。

@WebListener
public class ServletInitializer implements ServletContextListener 

    @Override
    public void contextInitialized(ServletContextEvent sce) 
        try 
            final ServletContext context = sce.getServletContext();
            final URL resourceUrl = context.getResource("/WEB-INF/myResource");
            context.setAttribute("myResourceURL", resourceUrl);
         catch (final MalformedURLException e) 
            throw new AssertionError("Resource not available in WAR file", e);
        
    

    @Override
    public void contextDestroyed(ServletContextEvent sce) 

@WebListener
public class ServletInitializer implements ServletContextListener 

    @Inject
    private SomeApplicationScopedBean myBean;

    @Override
    public void contextInitialized(ServletContextEvent sce) 
        try 
            final ServletContext context = sce.getServletContext();
            final URL resourceUrl = context.getResource("/WEB-INF/myResource");
            myBean.setResourceUrl(resourceUrl);
         catch (final MalformedURLException e) 
            throw new AssertionError("Resource not available in WAR file", e);
          
    

    @Override
    public void contextDestroyed(ServletContextEvent sce) 

【讨论】:

【参考方案2】:

我们遇到了类似的问题,我们的错误是我们试图通过原始路径而不是使用资源提供的输入流来访问静态资源 - 即使在部署非爆炸的 .war 时,以下代码也适用于我们-文件。

final URL resource = this.getClass().getResource(FILE);

try (final InputStream inputStream = resource.openStream();
     final InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
     final BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) 
    // Use bufferedReader to read the content
 catch (IOException e) 
    // ...

【讨论】:

谢谢。我现在没有时间检查它,但也许它会帮助其他人。【参考方案3】:

我终于放弃了,把我的资源文件放到了一个新的 JBoss 模块中,正如这个链接中描述的那样。

https://community.jboss.org/wiki/HowToPutAnExternalFileInTheClasspath

它可以工作,但缺点是有两个部署目标,所以事情更复杂。从好的方面来说,WAR 文件的大小减小了,如果只是部分资源发生了变化,我不必重新部署应用程序。

【讨论】:

【参考方案4】:

我最近试图弄清楚如何在我自己的 Java 战争中访问文件。以下是java类和资源在war文件中的打包方式:

WAR
 `-- WEB-INF
        `-- classes (where all the java classes are)
        `-- resourcefiles
                   `-- resourceFile1

我的目标文件是resourceFile1。要获取该文件,我只是在代码中执行了以下操作:

InputStream inStream = this.class.getClassLoader().getResourceAsStream("resourcefiles/resourceFile1");

在这种情况下,资源文件需要与包含 java 类的类文件夹位于同一文件夹中。希望其他人觉得这很有帮助。

【讨论】:

【参考方案5】:

此示例代码适用于在 openshift 上部署和测试的 Wildfly。 我认为这是一个野蝇问题,我降落野蝇并在本地尝试过,我也得到了错误。

Check sample project on github

import org.springframework.web.bind.annotation.RequestMethod;    
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLConnection;

@Controller
@RequestMapping
public class FileDownloadController 

    private static final Logger logger = LoggerFactory.getLogger(FileDownloadController.class);

    private static final String DOC_FILE = "file/ibrahim-karayel.docx";
    private static final String PDF_FILE = "file/ibrahim-karayel.pdf";


    @RequestMapping(value = "/download/type", method = RequestMethod.GET)
    public void downloadFile(HttpServletRequest request, HttpServletResponse response,
                             @PathVariable("type") String type) throws IOException 

        File file = null;
        InputStream inputStream;
        if (type.equalsIgnoreCase("doc")) 
            inputStream = getClass().getClassLoader().getResourceAsStream(DOC_FILE);
            file = new File(Thread.currentThread().getContextClassLoader().getResource(DOC_FILE).getFile());
         else if (type.equalsIgnoreCase("pdf")) 
            inputStream = getClass().getClassLoader().getResourceAsStream(PDF_FILE);
            file = new File(Thread.currentThread().getContextClassLoader().getResource(PDF_FILE).getFile());
         else
            throw new FileNotFoundException();
        
        if (file == null && file.getName() == null) 
            logger.error("File Not Found -> " + file);
            throw new FileNotFoundException();
        

        String mimeType = URLConnection.guessContentTypeFromName(file.getName());
        if (mimeType == null) 
            System.out.println("mimetype is not detectable, will take default");
            mimeType = "application/octet-stream";
        

        System.out.println("mimetype : " + mimeType);
        response.setContentType(mimeType);
        /* "Content-Disposition : inline" will show viewable types [like images/text/pdf/anything viewable by browser] right on browser
            while others(zip e.g) will be directly downloaded [may provide save as popup, based on your browser setting.]*/
        response.setHeader("Content-Disposition", String.format("inline; filename=\"" + file.getName() + "\""));

        /* "Content-Disposition : attachment" will be directly download, may provide save as popup, based on your browser setting*/
        //response.setHeader("Content-Disposition", String.format("attachment; filename=\"%s\"", file.getName()));

        response.setContentLength(inputStream.available());
        IOUtils.copy(inputStream, response.getOutputStream());
        response.flushBuffer();
        inputStream.close();
    

【讨论】:

【参考方案6】:

与 Wildfly 和未爆炸的 WAR 有同样的问题,使用 Spring 和 ServletContextResource 我已经解决了这个问题:

[org.springframework.core.io.]Resource resource = new ServletContextResource(servletContext, "WEB-INF/classes/resource.png");

在同一个 @Service 类中我也有:

@Inject
private ServletContext servletContext;

【讨论】:

【参考方案7】:

我决定了:

@Autowired
private final ApplicationContext ctx;
private final Path path = Paths.get("testfiles/load")

ctx.getRosource("classpath:" + path);

【讨论】:

【参考方案8】:

我阅读了 this 解决方案,这导致我们在 Wildfly 中使用 getResourceAsStream(...) 而不是 getResource()。我只是在 Wildfly 19 上使用从控制台部署的 myApp.ear 对其进行测试。

【讨论】:

以上是关于WildFly - 从 WAR 中获取资源的主要内容,如果未能解决你的问题,请参考以下文章

如何在wildfly服务器中以编程方式热重载静态资源(如xhtml)以获取爆炸战争中存在的库

Undertow:WAR 文件之外的静态根内容(wildfly)

在 Jboss 8 Wildfly 中设置默认地址

如何将 root(/) 上下文中的 war 文件部署到 Wildfly 9.0.1 版

在WildFly 中配置MySql

在 Wildfly 9 上部署 EAR 具有原始 WAR 和复制 WAR