Simplest way to serve static data from outside the application server in a Java web application

杀马特。学长 韩版系。学妹 提交于 2019-11-25 21:49:55

问题


I have a Java web application running on Tomcat. I want to load static images that will be shown both on the Web UI and in PDF files generated by the application. Also new images will be added and saved by uploading via the Web UI.

It\'s not a problem to do this by having the static data stored within the the web container but storing and loading them from outside the web container is giving me headache.

I\'d prefer not to use a separate web server like Apache for serving the static data at this point. I also don\'t like the idea of storing the images in binary in a database.

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?

Some suggest writing a filter or a servlet for handling the image serving but those suggestions have been very vague and high-level without pointers to more detailed information on how to accomplish this.


回答1:


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 (i.e. you use exclusively forward slashes as in /path/to/files), then it will work on Windows as well without the need to fiddle around with ugly File.separator string-concatenations. 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/to/files would actually point to C:\path\to\files.

If the files 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 inside <Host> tag:

<Context docBase="/path/to/files" path="/files" />

This way they'll be accessible through http://example.com/files/.... GlassFish/Payara configuration example can be found here and WildFly configuration example can be found here.

If you want to have control over reading/writing files yourself, then you need to create a Servlet for this which basically just gets an InputStream of the file in flavor of for example FileInputStream and writes it to the OutputStream of the HttpServletResponse.

On the response, you should set the Content-Type header so that the client knows which application to associate with the provided file. And, you should set the Content-Length header so that the client can calculate the download progress, otherwise it will be unknown. And, you should set the Content-Disposition header to attachment if you want a Save As dialog, otherwise the client will attempt to display it inline. Finally just write the file content to the response output stream.

Here's a basic example of such a servlet:

@WebServlet("/files/*")
public class FileServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException
    {
        String filename = URLDecoder.decode(request.getPathInfo().substring(1), "UTF-8");
        File file = new File("/path/to/files", filename);
        response.setHeader("Content-Type", getServletContext().getMimeType(filename));
        response.setHeader("Content-Length", String.valueOf(file.length()));
        response.setHeader("Content-Disposition", "inline; filename=\"" + file.getName() + "\"");
        Files.copy(file.toPath(), response.getOutputStream());
    }

}

When mapped on an url-pattern of for example /files/*, then you can call it by http://example.com/files/image.png. 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/files", "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 reuse the same logic for serving files from database. Simply replace new FileInputStream() by ResultSet#getInputStream().

Hope this helps.

See also:

  • Recommended way to save uploaded files in a servlet application
  • Abstract template for a static resource servlet (supporting HTTP cache)
  • How to retrieve and display images from a database in a JSP page?
  • How to stream audio/video files such as MP3, MP4, AVI, etc using a Servlet



回答2:


You can do it by putting your images on a fixed path (for example: /var/images, or c:\images), add a setting in your application settings (represented in my example by the Settings.class), and load them like that, in a HttpServlet of yours:

String filename = Settings.getValue("images.path") + request.getParameter("imageName")
FileInputStream fis = new FileInputStream(filename);

int b = 0;
while ((b = fis.read()) != -1) {
        response.getOutputStream().write(b);
}

Or if you want to manipulate the image:

String filename = Settings.getValue("images.path") + request.getParameter("imageName")
File imageFile = new File(filename);
BufferedImage image = ImageIO.read(imageFile);
ImageIO.write(image, "image/png", response.getOutputStream());

then the html code would be <img src="imageServlet?imageName=myimage.png" />

Of course you should think of serving different content types - "image/jpeg", for example based on the file extension. Also you should provide some caching.

In addition you could use this servlet for quality rescaling of your images, by providing width and height parameters as arguments, and using image.getScaledInstance(w, h, Image.SCALE_SMOOTH), considering performance, of course.




回答3:


Requirement : Accessing the static Resources (images/videos., etc.,) from outside of WEBROOT directory or from local disk

Step 1 :
Create a folder under webapps of tomcat server., let us say the folder name is myproj

Step 2 :
Under myproj create a WEB-INF folder under this create a simple web.xml

code under web.xml

<web-app>
</web-app>

Directory Structure for the above two steps

c:\programfile\apachesoftwarefoundation\tomcat\...\webapps
                                                            |
                                                            |---myproj
                                                            |   |
                                                            |   |---WEB-INF
                                                                |   |
                                                                    |---web.xml

Step 3:
Now create a xml file with name myproj.xml under the following location

c:\programfile\apachesoftwarefoundation\tomcat\conf\catalina\localhost

CODE in myproj.xml:

<Context path="/myproj/images" docBase="e:/myproj/" crossContext="false" debug="0" reloadable="true" privileged="true" /> 

Step 4:
4 A) Now create a folder with name myproj in E drive of your hard disk and create a new

folder with name images and place some images in images folder (e:myproj\images\)

Let us suppose myfoto.jpg is placed under e:\myproj\images\myfoto.jpg

4 B) Now create a folder with name WEB-INF in e:\myproj\WEB-INF and create a web.xml in WEB-INF folder

Code in web.xml

<web-app>
</web-app>

Step 5:
Now create a .html document with name index.html and place under e:\myproj

CODE under index.html Welcome to Myproj

The Directory Structure for the above Step 4 and Step 5 is as follows

E:\myproj
    |--index.html
    |
    |--images
    |     |----myfoto.jpg
    |
    |--WEB-INF
    |     |--web.xml

Step 6:
Now start the apache tomcat server

Step 7:
open the browser and type the url as follows

http://localhost:8080/myproj    

then u display the content which is provided in index.html

Step 8:
To Access the Images under your local hard disk (outside of webroot)

http://localhost:8080/myproj/images/myfoto.jpg



回答4:


This is story from my workplace:
- We try to upload multiply images and document files use Struts 1 and Tomcat 7.x.
- We try to write uploaded files to file system, filename and full path to database records.
- We try to separate file folders outside web app directory. (*)

The below solution is pretty simple, effective for requirement (*):

In file META-INF/context.xml file with the following content: (Example, my application run at http://localhost:8080/ABC, my application / project named ABC). (this is also full content of file context.xml)

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/ABC" aliases="/images=D:\images,/docs=D:\docs"/>

(works with Tomcat version 7 or later)

Result: We have been created 2 alias. For example, we save images at: D:\images\foo.jpg and view from link or using image tag:

<img src="http://localhost:8080/ABC/images/foo.jsp" alt="Foo" height="142" width="142">

or

<img src="/images/foo.jsp" alt="Foo" height="142" width="142">

(I use Netbeans 7.x, Netbeans seem auto create file WEB-INF\context.xml)




回答5:


Add to server.xml :

 <Context docBase="c:/dirtoshare" path="/dir" />

Enable dir file listing parameter in web.xml :

    <init-param>
        <param-name>listings</param-name>
        <param-value>true</param-value>
    </init-param>



回答6:


If you decide to dispatch to FileServlet then you will also need allowLinking="true" in context.xml in order to allow FileServlet to traverse the symlinks.

See http://tomcat.apache.org/tomcat-6.0-doc/config/context.html




回答7:


if anyone not able to resolve his problem with accepted answer, then note these below considerations:

  1. no need to mention localhost:<port> with <img> src attribute.
  2. make sure you are running this project outside eclipse, because eclipse creates context docBase entry on its own inside its local server.xml file.



回答8:


Read the InputStream of a file and write it to ServletOutputStream for sending binary data to the client.

  • Local file You can read a file directly using FileInputStream('path/image.png').
  • Mongo DataBase file's you can get InputStream using GridFS.
@WebServlet("/files/URLStream")
public class URLStream extends HttpServlet {
    private static final long serialVersionUID = 1L;

    public URLStream() {
        super();
    }

    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        File source = new File("D:\\SVN_Commit.PNG");
        long start = System.nanoTime();

        InputStream image = new FileInputStream(source);

        /*String fileID = request.getParameter("id");
        System.out.println("Requested File ID : "+fileID);
        // Mongo DB GridFS - https://stackoverflow.com/a/33544285/5081877
        image = outputImageFile.getInputStream();*/

        if( image != null ) {
            BufferedInputStream bin = null;
            BufferedOutputStream bout = null;
            ServletOutputStream sos = response.getOutputStream();
            try {
                bin = new BufferedInputStream( image );
                bout = new BufferedOutputStream( sos );
                int ch =0; ;
                while((ch=bin.read())!=-1) {
                    bout.write(ch);
                }
            } finally {
                bin.close();
                image.close();
                bout.close();
                sos.close();
            }

        } else {
            PrintWriter writer = response.getWriter();
            writer.append("Something went wrong with your request.");
            System.out.println("Image not available.");
        }
        System.out.println("Time taken by Stream Copy = "+(System.nanoTime()-start));
    }
}

Result the URL directly to the src attibute.

<img src='http://172.0.0.1:8080/ServletApp/files/URLStream?id=5a575be200c117cc2500003b' alt="mongodb File"/>
<img src='http://172.0.0.1:8080/ServletApp/files/URLStream' alt="local file"/>

<video controls="controls" src="http://172.0.0.1:8080/ServletApp/files/URLStream"></video>



回答9:


If you want to work with JAX-RS (e.g. RESTEasy) try this:

@Path("/pic")
public Response get(@QueryParam("url") final String url) {
    String picUrl = URLDecoder.decode(url, "UTF-8");

    return Response.ok(sendPicAsStream(picUrl))
            .header(HttpHeaders.CONTENT_TYPE, "image/jpg")
            .build();
}

private StreamingOutput sendPicAsStream(String picUrl) {
    return output -> {
        try (InputStream is = (new URL(picUrl)).openStream()) {
            ByteStreams.copy(is, output);
        }
    };
}

using javax.ws.rs.core.Response and com.google.common.io.ByteStreams




回答10:


I did it even simpler. Problem: A CSS file had url links to img folder. Gets 404.

I looked at url, http://tomcatfolder:port/img/blablah.png, which does not exist. But, that is really pointing to the ROOT app in Tomcat.

So I just copied the img folder from my webapp into that ROOT app. Works!

Not recommended for production, of course, but this is for an internal tool dev app.



来源:https://stackoverflow.com/questions/1812244/simplest-way-to-serve-static-data-from-outside-the-application-server-in-a-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!