Reading a file from within App Engine module

2019-07-23 05:08发布

I am trying to read a static file from within App Engine module that is placed inside WEB-INF directory.

...
File file = new File("WEB-INF/somestaticfile.ext);
...

It perfectly works in cloud environment, however, in development server it ends up with FileNotFoundException.

I build and run the app with the aid of maven and it seems that it is also needed to prepend a directory representing the module inside the project's EAR hierarchy so that the file would be found.

...
File file = new File("modulename.war/WEB-INF/somestaticfile.ext);
...

This works in local development server but not in cloud environment.

I believe that there is a way how to read a file that would work in both cloud and local environment. Any advice would be appreciated.

2条回答
beautiful°
2楼-- · 2019-07-23 05:47

I have spent some time to figure it out and here are solutions I have found. If you have your resources placed on classpath then you can access them as follows from both cloud and local dev server.

getClass().getClassLoader().getResource("resourceName");

or

getClass().getClassLoader().getResourceAsStream("resourceName");

However, if your resources are place somewhere else (e.g. WEB-INF), the only way I have found is by means of javax.servlet.ServletContext#getResource(String) or javax.servlet.ServletContext#getResourceAsStream(String) that also work in both environments. This solution is perfectly OK if you access resources from web layer of your app but if you need to access them from other layers (e.g. service layer), it is not probably a good idea to introduce a dependency to Java Servlet API to that layer.

Since I am using Spring, I decided to load resources via org.springframework.core.io.ResourceLoader#getResource(String) that returns a resource abstraction whose concrete implementation depends on the application context type and a resource path prefix. For applications running in a web container, the actual implementation uses ServletContext methods under the hood but you are shielded from it.

If you do not use Spring, it should not be a big deal to implement your own resource abstraction based on ServletContext.

If anyone could provide other solutions, feel free to do so.

查看更多
成全新的幸福
3楼-- · 2019-07-23 06:01

An excellent resource, as always, are the Google developer documents:

That said, to help others in future, I will summarize some relevant points that I think generally relate to the question (since I can't see what is happening your specific environment).

App Engine serves static files from dedicated servers and caches that are separate from the application servers. Files that are accessible by the application code using the file system are called resource files. These files are stored on the application servers with the app.

By default, all files in the WAR are treated as both static files and resource files, except for JSP files, which are compiled into servlet classes and mapped to URL paths, and files in the WEB-INF/ directory, which are never served as static files and always available to the app as resource files. You can adjust which files are considered static files and which are considered resource files using elements in the appengine-web.xml file. The element specifies patterns that match file paths to include and exclude from the list of static files, overriding or amending the default behavior. Similarly, the element specifies which files are considered resource files.

You mentioned that there seemed to be a disconnect between the development server and deployment. Without diving into Maven, my first thought was to look at path patterns. As they note on the Google Developers documentation, path patterns are specified using zero or more and elements. In a pattern, * represents zero or more of any character in a file or directory name, and ** represents zero or more directories in a path. Files and directories matching patterns will not be uploaded when you deploy your app to App Engine. However, these files and directories will still be accessible to your application when running on the local Development Server. An element overrides the default behavior of including all files. An element applies after all patterns (as well as the default if no explicit is provided).

Hope that helps provide a general perspective. If you find a specific solution to the issue and can share it here, please do!

查看更多
登录 后发表回答