I've seen some suggestions like having the image directory being a symbolic link pointing to a directory outside the web container, but will this approach work both on Windows and *nix environments?
If you adhere the *nix filesystem path rules (e.g. /path/to/images
), it will work on Windows as well. It would however only be scanned on the same working disk as from where this command is been invoked. So if Tomcat is for example installed on C:
then the path would actually point to C:/path/to/images
.
If the images are all located outside the webapp and you want to have Tomcat's DefaultServlet
to handle them, then all you basically need to do in Tomcat is to add the following Context element to /conf/server.xml
:
<Context docBase="/path/to/images" path="/images" />
This way they'll be accessible through http://example.com/images/...
.
If you want to have control over reading/writing images yourself, then you need to create a Servlet
for this which basically just gets an InputStream
of the image in flavor of for example FileInputStream
and writes it to the OutputStream
of the HttpServletResponse
. Importantingly, you need to set the Content-Type
response header as well and preferably also the Content-Length
and Content-Disposition
.
Here's a basic example of such a servlet:
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
String filename = URLDecoder.decode(request.getPathInfo(), "UTF-8");
File file = new File("/path/to/images", filename);
response.setContentType(getServletContext().getMimeType(file.getName()));
response.setContentLength(file.length());
response.setHeader("Content-Disposition", "inline; filename=\"" + file.getName() + "\"");
BufferedInputStream input = null;
BufferedOutputStream output = null;
try {
input = new BufferedInputStream(new FileInputStream(file));
output = new BufferedOutputStream(response.getOutputStream());
byte[] buffer = new byte[8192];
int length;
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
} finally {
if (output != null) try { output.close(); } catch (IOException ignore) {}
if (input != null) try { input.close(); } catch (IOException ignore) {}
}
}
Map it on an url-pattern
of for example /images/*
and then you can call it by http://example.com/images/filename.jpg
. This way you can have more control over the requests than the DefaultServlet
does, such as providing a default image (i.e. if (!file.exists()) file = new File("/path/to/images", "404.gif")
or so). Also using the request.getPathInfo()
is preferred above request.getParameter()
because it is more SEO friendly and otherwise IE won't pick the correct filename during Save As.
You can find here a complete example of a FileServlet
supporting pretty much all of the efficientness which HTTP provides (caching, resume, gzip).
Hope this helps.