【问题标题】:Accessing files/directories in webapp folder in Spring在 Spring 中访问 webapp 文件夹中的文件/目录
【发布时间】:2012-02-06 18:07:34
【问题描述】:

我对 Spring 缺乏经验,我现在需要做的就是访问并获取对 webapp 文件夹中文件和文件夹的引用。这是我的相关项目层次结构:

-src
--main
---java (marked as source root)
----my
-----package
------controller
-------Home.java
---webapp
----images
-----avatars

我在 Home.java 中的代码:

@Controller
@RequestMapping("/")
public class Home
{
    @RequestMapping(method = RequestMethod.GET)
    public String index(Model model,
                        HttpServletRequest request) throws Exception
    {
        String test1 = request.getSession().getServletContext().getRealPath("");
        String test2 = request.getSession().getServletContext().getRealPath("/");
        String test3 = request.getRealPath("");
        String test4 = request.getRealPath("/");
        String test5 = request.getSession().getServletContext().getRealPath(request.getServletPath());

        return "index";
    }
}

所有 5 个请求都返回 null。我是不是做错了什么?

web.xml:

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
         http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">

    <display-name>Test</display-name>

    <servlet>
        <servlet-name>test</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>test</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <session-config>
        <session-timeout>10</session-timeout>
    </session-config>
</web-app>

我想要实现的(未在此示例中显示)是编写一个负责图像缩放的控制器。因此,我需要访问 src/main/webapp/_images 文件夹。

谢谢!

更新:简化了示例以便更好地理解。

Update2:感谢@gigadot 的建议,我将应用程序部署为爆炸WAR,问题得到部分解决。有人能告诉我将 WAR 部署为爆炸式有什么区别吗?不建议在生产服务器上执行此操作吗?优点/缺点?

我认为值得用一个例子来解释这种情况。假设我正在编写一个社交网络,我必须上传我的个人资料图片。这张图片将上传到src/main/webapp/_images/avatars/[myid].jpg 文件夹。 是否建议将图片上传到webapp 文件夹?还是有更好的解决方案? 我希望能够在访问 URL /images/[width]x[height]/[userid].jpg 时返回图像的缩放实例。

将 WAR 部署为爆炸并实现 ResourceLoaderAware(感谢 @KevinSchmidt),我可以使用它使其工作:

resourceLoader.getResource("file:" + request.getSession().getServletContext().getRealPath("/") + "_images/avatars/");

对我来说它看起来很脏,对于生产服务器来说这是个好主意吗?有没有更好的解决方案?

【问题讨论】:

  • 我关心目录是否存在
  • 你想对这些文件做什么,只是将它们返回给客户端,或者处理它的内容?
  • 我已经尝试过您的代码并且它有效。你能告诉我们你是如何测试它的吗?您是使用 Maven 生成战争并将其放入 Tomcat 中还是直接从 Eclipse 中执行?

标签: java spring spring-mvc


【解决方案1】:

您究竟是如何部署应用程序的?

ServletContext().getRealPath("/") 如果未部署为展开式,则可能返回 null。阅读下面的链接以获取更多信息。但是,您的 servlet 容器的配置方法可能不一样。

http://ananthkannan.blogspot.com/2009/12/servletcontextgetrealpath-returns-null.html

更新

谁能告诉我将 WAR 部署为 爆炸了?

当您将 war 文件部署为分解时,servlet 容器,例如Tomcat,会将war文件的内容提取到一个临时文件夹并运行该文件夹中的所有内容,因此{WEB_ROOT]/_images/avatars/[myid].jpg实际上存在于文件系统(硬盘)上。因此,您实际上可以获得真正的路径(正如它在方法名称中已经说过的那样)。但是,如果您的 servlet 容器未提取 war 文件,则您要查找的文件夹位于 war 文件中,并且没有真正的路径,因此它将返回 null

这是不建议在生产服务器上执行的操作吗? 优点/缺点?

您不应在源文件夹或 webroot 文件夹 (webapp) 下存储动态内容,因为 servlet 容器会在您重新部署 Web 应用程序时临时使用并删除它或更改为新文件夹。您可能会丢失放入这些文件夹的动态数据。 Web 根文件夹通常用于存储静态内容,这意味着您不想更改的内容 - 例如,您的 Web 组件的图形图像,如背景图像、css 等。

存储用户数据的常用方法是以某种方式在用户空间中创建一个文件夹并将您的动态数据放入其中。但是,您将无法在 webroot 之外提供文件夹的内容。您将需要编写自己的静态 servlet 以在请求数据时通过管道传输数据。这对于初学者来说相当复杂。

实现您自己的静态 servlet 以提供动态内容的最简单方法是扩展您的 servlet 容器的静态 servlet。但是,您的代码将高度依赖于您要部署到的 servlet 容器。

由于您将提供一个 REST 接口来调整图像大小,您可以创建一个控制器,从动态内容文件夹中读取原始图像,调整大小,将其保存为临时文件或刷新 @ 的内容987654326@.

【讨论】:

  • 谢谢,这解决了问题。您能告诉我将 WAR 部署为爆炸式有什么区别吗?不建议在生产服务器上执行此操作吗?优点/缺点?
  • 谢谢你,@gigadot。我搜索了您建议的解决方案,但找不到任何示例。正如我所说,我是一个初学者,所以如果你能提供一个链接或一个小例子,那就太好了。在谷歌搜索时,我发现人们通常将这种图像存储在数据库(blob)中。我可以想象这在集群时有很大的优势(我将来需要的东西)而且我看不到任何劣势。这是你建议的吗?谢谢!
  • @satoshi 对于这个特殊问题,我认为您需要静态 servlet,除非您想在不进行任何处理的情况下提供动态内容,并且在这里,您想先调整图像大小,以便您可以只需将调整大小的图像流写入 HttpResponse。使用 BLOB 是解决问题的一种方法。限制是 BLOB 的大小不大于 2GB。我暂时想不出任何其他问题。
  • 如果您想了解静态 servlet(我认为您不需要),请阅读此处stackoverflow.com/questions/132052/…
  • 非常感谢@gigadot。我想我会选择 Blob 解决方案。我编写的缩放功能是对缩放后的图像进行调整,您认为将它们存储在哪里更好(考虑到如果它们被删除,这不是问题)?我猜webapp 文件夹在这种情况下适合吗?谢谢。
【解决方案2】:

这是我的代码,它可以工作 我没有得到空值。

我正在运行 JDK 1.7_02 雄猫 7.0.25 春季 3.1.1

而且我没有得到空值

    @Controller
    public class IndexController {

        @RequestMapping("/index")
        public String go(HttpServletRequest request, HttpServletResponse response) {
            HttpSession session = request.getSession();
            ServletContext sc = session.getServletContext();
            String x = sc.getRealPath("/");
            System.out.println(x);
            return "index";
        }
    }

【讨论】:

  • 如果我有一个 RestController,但没有会话怎么办?
【解决方案3】:

考虑到文件的位置,你应该看看Spring ResourceLoader,像这样:

public class ArbitraryResourceLoader implements ResourceLoaderAware {
    private ResourceLoader resourceLoader;

    public void test() {
        Resource resource = resourceLoader.getResource("file:webapp/images/avatars/avatar.jpg");
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }
}

请注意,您的容器需要有权访问该文件。

【讨论】:

    【解决方案4】:

    ClassPathResource 可能会有所帮助。如果完全错误,您访问类路径中资源的方式。

    关于web资源的位置,存储在src/main/resources中的会部署在WEB-INF/classes文件夹中,显然是不行的。改为用户 webapp。

    更新:现在我知道你来自哪里了。我认为映射没有任何问题,尽管非常奇特。 DispatcherServlet 映射可能没有覆盖images 文件夹(即它不是/*)。

    关于文件打开的问题,webapp 目录在类加载器中是不可见的,唯一的例外是 WEB-INF 文件夹。因此,您需要调用HttpServletRequest.getRealPath() 方法以获取图像的真实路径。

    请注意,虽然不太可能是您的情况,但强化的 Java JVM(即具有安全策略的 JVM)可能需要额外的授权才能让 servlet 从任意位置打开文件。

    【讨论】:

    • 感谢您的回答。我现在将所有 CSS/JS/images 文件和文件夹移动到 webapp 文件夹。现在图像文件夹位于 src/main/webapp/images,如何从我的代码中引用它?它不在类路径中,对吧?
    • 你能透露更多关于你到底想要完成什么吗?
    • @AlessandroSantini 次要注意:HttpServletRequest.getRealPath() 已弃用。应该使用ServletContext.getRealPath()
    • 谢谢两位。不幸的是 request.getSession().getServletContext().getRealPath("images") 返回一个空对象。我也尝试在“图像”之前和之后添加斜线......
    • 如果您可以发布解决方案以造福其他用户,那就太好了。
    【解决方案5】:

    查看 Spring Reference 中 16.14.5 Configuring Serving of Resources 部分中的 &lt;mvc:resources&gt; 使用方法。我将这种方法用于我的 JavaScript/CSS/图像,效果很好——我只需在我的 application-context.xml 文件中添加一行。文档指出:

    这提供了一种方便的方式来提供静态资源 Web 应用程序根目录以外的位置,包括 类路径。

    【讨论】:

      【解决方案6】:

      你可以试试这个:

      @Controller
      @RequestMapping("/")
      public class Home implements ServletContextAware
      {
          private ServletContext servletContext;
          public void setServletContext(ServletContext servletCtx){
             this.servletContext=servletCtx;
          }
      
          @RequestMapping(method=RequestMethod.GET)
          public String index(Model model,HttpServletRequest) throws Exception{
             String rootPath = servletContext.getRealPath("/");
             //...
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-28
        • 2018-05-28
        • 2014-07-18
        • 2015-12-11
        • 1970-01-01
        相关资源
        最近更新 更多