Java EE - Best way to get real path to uploaded files? [duplicate] - servlets

This question already has answers here:
Recommended way to save uploaded files in a servlet application
(2 answers)
Closed 6 years ago.
I have a web application with an upload form where users can upload files.
I'd like to store the files a folder 'files'. And i'd like this folder to be placed directly under the webapp-root.
Using struts2, in my uploadFileAction, i can easily set this path with String uploadDir = ServletActionContext.getServletContext().getRealPath("/files")+ "/";
But when i'm trying to retrieve the files, apparently my bean which tries to access the file does not have access to getServletContext() and thus throws a nullpointer on getRealPath
Now im trying to figure out how i should approach this. I've heard about spring resource is the way to go, but i cant find any relevant examples.
Is there an easy way to get my paths? I just want the rootpath to my webapp. Nothing more nothing less...

I'd like this folder to be placed directly under the webapp-root.
This isn't going to work. All those files will get lost whenever you redeploy the webapp or even when you restart the server. Those files are namely not contained as part of the original WAR.
You need to store them in a fixed path outside the webapp's context. E.g. /var/webapp/uploads. You can configure this path in a properties file or as a system property.

I've found that a few ways to accomplish this regardless of what OS platform you're using. I typically like to store my files in some way relative to my web application. This being said, the easiest way to do this is using your class file as a reference to get the real path. I use something similar to the following to store image uploads for a few web applications that I've built:
public class FileLocationTest {
public static void main(String[] args) {
String path = FileLocationTest.class.getProtectionDomain().getCodeSource().getLocation().getPath();
System.out.println(path);
}
}
This can be done using a static utility class in your web app, or any class for that matter to obtain the real path of your application regardless of OS. Alternatively in a servlet I've also used the request class to get the Tomcat location if my appbase is in a different area, something like this:
String location = request.getClass().getProtectionDomain().getClassLoader().getClass().getProtectionDomain().getCodeSource().getLocation().getPath();
String path = location.substring(0, location.indexOf("/tomcat")) + "/data/events/images/";

Related

Access static files on server from RCL

I've read dozens of questions but none seem to work for me. I'm not using IIS. I'm using ASP.Net Core 3.1 with Kestrel.
I have a Razor Class Library with a resources folder, in that I have folders like css, js, content, etc. I use this library so all of my common Web Api projects can share common files instead of duplicating them everywhere. To do this, I followed the guide from here. Please see there for how Startup is configured.
That works great, I can access those files by going to e.g. localhost/css/site.css. In my cshtml files, I can include that file by doing <link rel="stylesheet" href="~/css/site.css"/>
The problem arises when I try to access those files from a controller. I have a sister folder to css called content which contains json files. I can view that file by going to localhost/content/test.json, but I can't figure out how to access it from a controller.
What I'd like to do is make an HTTP request to ~/content/test.json and download its contents, but the path is not found.
I've tried using Url.Content to map a relative path to the absolute path, but it doesn't work.
var url = Url.Content("~/content/test.json"); // spits out "/content/test.json"
I've DI'd IWebHostEnvironment into the controller and tried to access the ContentRootFileProvider and the ContentRootPath and WebRootPath, but those paths aren't right either. They are pointing to my currently running service's wwwroot's parent and wwwroot, respectively.
I've tried creating my own file provider:
var filesProvider = new ManifestEmbeddedFileProvider(GetType().Assembly, "resources");
var content = filesProvider.GetDirectoryContents("content");
var fileInfo = filesProvider.GetFileInfo(Path.Combine("content", "test.json"));
This successfully finds the file and claims it exists, but the fileInfo's PhysicalPath is always null.
I just want to do something like this:
string SomeMagicMapFunction(string s) => ????
var webClient = new WebClient();
var json = webClient.DownloadString(SomeMagicMapFunction("~/content/test.json"));
Where am I going wrong? Any pointers are appreciated.

Can I serve static content with spring-boot-starter-tomcat but without spring-boot-starter-web?

I'm working on a web service using spring-boot-starter-jersey and spring-boot-starter-tomcat (v. 1.5.2) and as such, I'd rather not add spring-boot-starter-web and further complicate my configuration. I want to stick the Swagger UI static files in a folder and serve them from there.
What I'm wondering is, can I serve static files using just spring-boot-starter-tomcat? I've found Spring documentation saying that I can server static content from a variety of sources on the classpath, but the examples I've found seem to require Spring MVC. I've tried disabling Jersey and putting static files in src/main/resources/static to test just Tomcat, but when I go to localhost/index.html, I get a 404 not found error.
As you might be able to tell from my path, I'm using Maven.
Since you can serve static files with just Tomcat, it seems like I should be able to serve static files with spring-boot-starter-tomcat. If this is the case, where do I put those files?
To put this another way, say I have started with the Spring-provided
spring-boot-sample-jersey project. I have a requirement that the Jersey web service answer calls to the root address (/). How would I add some static content (HTML, CSS, JS) to be served from subdirectory called /swagger?
So the default servlet (which serves static content) is by default registered. But it will use only search specific paths as the document root. I had to go digging through source code to finally find it. If you look in the AbstractEmbeddedServletContainerFactory, you'll see
private static final String[] COMMON_DOC_ROOTS = {
"src/main/webapp", "public", "static" };
If we don't explicitly set the document root, the above three are the paths that will be searched. In order, the first directory found that exists, will be used as the document root. I've verified that all of these work.
If you want to set a different directory, you can use a customizer bean
#Bean
public EmbeddedServletContainerCustomizer tomcatCustomizer() {
return new EmbeddedServletContainerCustomizer() {
#Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.setDocumentRoot(new File("src/main/resources/static"));
}
};
}
The one thing I haven't figured out is if we can serve files as classpath resources, instead of file system resources. If you look at the source code I linked to, it has some code that looks for the existence of a META-INF/resources. I thought that might work, but unfortunately it didn't for me. Maybe some guys of the Spring Boot team can enlighten us.

Creating a new file without using a ServletContext

Assume I want to write to a new file created within the space of my webapp.
One way would be use getServletContext().getRealPath("/") and use that String to create a new file on the server. However, often I come across advice like not using getServletContext().getRealPath("/").
Can someone please let me know of another way to write a new file within my webapp?
Many thanks.
Have some configuration property containing the absolute path of a directory outside of the webapp and web server path, read this path from the configuration property, and write to this directory.
To serve files from this directory, write a servlet that takes the name or ID of this file as parameter, reads the file from the directory, and sends its content to the response.
This will
work even if the app is deployed as a war file and never unzipped to the file system
allow you to redeploy the next version of the app or server without deleting all the uploaded/created files
allow you to add whatever control you want on the uploaded/created files, instead of making them available to everyone
In short, treat these files as data, stored in a database which happens to be the file system instead of a SQL database.

Get path to servlet container deploy/webapps folder

From within the service method of a servlet, I can get the path to the web application's root folder with getServletContext.getRealPath(""), e.g. /tomcat/webapps/MyWebApplication, but is there any way I can get the path to /tomcat/webapps/ or optionally a specific other web application like /tomcat/webapps/MyOtherWebApplication (without resorting to hacks like substracting the context path)?
(Using only TomCat as an example, should work across all servlet containers.)
ServletContext has a getContext(String) method (javadoc) that return the ServletContext corresponding to another webapp, which you could then call getRealPath() on. However, the appserver's security model might forbid this, so use with caution.
Path to Tomcat dir (tomcat/bin):
File inputFile = new File("file.xml"); // tomcat_dir/bin/file.xml
Path to other Tomcat directories, "webapps" for example:
File inputFile = new File("../webapps/file.xml"); // tomcat_dir/webapps/file.xml
Nice way to get rid of the absolute paths :)

Flash XML config file problems with asp.net MVC

I'm creating an asp.net MVC app, first time I've done this. I have a flash component I need to use in a view. I have included the SWF files etc in the Contents folder and referenced it from my view, the flash file loads when you get to the view, great.
The problem occurs because the flash file references and XML file for its configuration data, and I'm getting an error accessing that XML file. I'm guessing this is because flash is looking for a relative path and is using the URL for the page, which is obviously an MVC url and so does not refer to an actual location on disk, so the XML file is not there.
I guess the obvious answer is the alter the flash file to look in the contents folder for the XML file, but that means re-compiling the flash, and I know very little about flash so I'd like to avoid doing that. So is there any way to get the XML file to show up in the same URL as the view, so at the moment, the page with the flash component on is located at htttp://localhost/upload/ so I guess the XML file needs to be accessible from http://localhost/upload/flash-settings.xml?
If there's any other better way to do this, without editing the flash file, im open to that too,
Add this Action to the FlashUpload Controller:
public class FlashUploadController : Controller
{
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult FlashSettings()
{
var fileName = Server.MapPath("~/Contents/flash-settings.xml");
return new FilePathResult(fileName, "text/xml");
}
}
And this route to the RouteTable:
routes.MapRoute("FlashSettings", "upload/flash-settings.xml",
new { Controller = "FlashUpload", Action = "FlashSettings" });
You'll need to either set the routing mechanism to allow for direct files access to the /upload/ folder, or create a Controller Action which will return an XML stream (dynamic or the one read from the physical XML file), and point your SWF to that Route. I'd go with the second option, as it is much flexible.

Resources