La façon la plus simple de servir des données statiques provenant de l'extérieur du serveur d'application dans une application Web Java

j'ai une application Web Java qui tourne sur Tomcat. Je veux charger des images statiques qui seront affichées à la fois sur L'interface utilisateur Web et dans les fichiers PDF générés par l'application. De plus, de nouvelles images seront ajoutées et sauvegardées en les téléchargeant via L'interface utilisateur Web.

ce n'est pas un problème de le faire en ayant les données statiques stockées dans le conteneur web, mais le stockage et le chargement de l'extérieur du conteneur web me donne mal à la tête.

je préfère ne pas utiliser un serveur web séparé comme Apache pour servir les données statiques à ce point. Je n'aime pas l'idée de stocker les images en binaire dans une base de données.

j'ai vu quelques suggestions comme avoir le répertoire d'image étant un lien symbolique pointant vers un répertoire en dehors du conteneur web, mais cette approche fonctionnera-t-elle à la fois sur les environnements Windows et *nix?

certains suggèrent d'écrire un filtre ou un servlet pour manipuler le service d'image mais ceux les suggestions ont été très vagues et de haut niveau, sans indiquer de renseignements plus détaillés sur la façon d'y parvenir.

122
demandé sur BalusC 2009-11-28 13:58:38

10 réponses

j'ai vu quelques suggestions comme avoir le répertoire d'image étant un lien symbolique pointant vers un répertoire en dehors du conteneur web, mais cette approche fonctionnera-t-elle à la fois sur les environnements Windows et *nix?

si vous respectez les règles de chemin du système de fichiers *nix (c'est-à-dire que vous utilisez exclusivement des slashs forward comme dans /path/to/files ), alors cela fonctionnera sur Windows aussi bien sans avoir besoin de tripoter avec ugly File.separator chaîne-concaténations. Toutefois, il serait seulement être analysé sur le même disque que d'où cette commande est invoquée. Ainsi, si Tomcat est par exemple installé sur C: , alors le /path/to/files indiquerait en fait C:\path\to\files .

si les fichiers sont tous situés en dehors de la webapp, et que vous voulez avoir le DefaultServlet de Tomcat pour les gérer, alors tout ce que vous avez essentiellement à faire dans Tomcat est d'ajouter l'élément de contexte suivant à /conf/server.xml à l'intérieur de <Host> tag:

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

de cette façon, ils seront accessibles par http://example.com/files/... . L'exemple de configuration GlassFish/Payara peut être trouvé ici et L'exemple de configuration WildFly peut être trouvé ici .

si vous voulez avoir le contrôle sur la lecture / écriture des fichiers vous-même, alors vous devez créer un Servlet pour ce qui essentiellement obtient juste un InputStream du fichier dans saveur de par exemple FileInputStream et l'écrit à la OutputStream de la HttpServletResponse .

sur la réponse, vous devez définir l'en-tête Content-Type pour que le client sache quelle application associer au fichier fourni. Et, vous devez définir l'en-tête Content-Length de sorte que le client puisse calculer la progression du téléchargement, sinon il sera inconnu. Et, vous devez définir l'en-tête Content-Disposition à attachment si vous voulez un Enregistrer sous Dialogue , sinon le client tentera de l'afficher en ligne. Enfin, il suffit d'écrire le contenu du fichier pour la réponse flux de sortie.

voici un exemple de base d'un tel 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());
    }

}

Lorsque mappé sur un url-pattern de par exemple /files/* , alors vous pouvez l'appeler par http://example.com/files/image.png . De cette façon, vous pouvez avoir plus de contrôle sur les requêtes que le DefaultServlet ne le fait, comme fournir une image par défaut (i.e. if (!file.exists()) file = new File("/path/to/files", "404.gif") ou plus). Aussi en utilisant le request.getPathInfo() est préférable au-dessus de request.getParameter() parce qu'il est plus SEO amical et autrement IE ne choisira pas le bon nom de fichier pendant enregistrer comme .

vous pouvez réutiliser la même logique pour servir des fichiers à partir de la base de données. Il suffit de remplacer new FileInputStream() par ResultSet#getInputStream() .

Espérons que cette aide.

voir aussi:

147
répondu BalusC 2017-05-23 12:34:34

Vous pouvez le faire en mettant vos images sur un chemin fixe (par exemple: /var/images, ou c:\images), ajouter un paramètre dans vos paramètres de l'application (représenté dans mon exemple par les Paramètres.classe), et les charger comme cela, dans un HttpServlet de la vôtre:

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);
}

Ou si vous voulez manipuler l'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());

alors le code html serait <img src="imageServlet?imageName=myimage.png" />

bien sûr, vous devriez penser à servir différent types de contenu - "image / jpeg", par exemple basé sur l'extension du fichier. Aussi, vous devriez fournir une certaine mise en cache.

en outre, vous pouvez utiliser ce servlet pour le réajustement de qualité de vos images, en fournissant des paramètres de largeur et de hauteur comme arguments, et en utilisant image.getScaledInstance(w, h, Image.SCALE_SMOOTH ), en considérant la performance, bien sûr.

9
répondu Bozho 2009-11-28 11:58:22

exigence: accéder aux ressources statiques (images/vidéos., etc.,) à partir de l'extérieur du répertoire WEBROOT ou à partir du disque local

Étape 1:

Créer un dossier sous webapps de tomcat server., disons que le nom du dossier est myproj

Étape 2:

sous myproj créer un dossier WEB-INF sous ceci Créer un web simple.xml

code sous Web.xml

<web-app>
</web-app>

structure de répertoire pour les deux étapes ci-dessus

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

Étape 3:

Maintenant, créez un fichier xml avec le nom myproj.xml sous l'emplacement suivant

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" /> 

Étape 4:

4 A) créer maintenant un dossier avec le nom myproj dans le disque E de votre disque dur et créer un nouveau

dossier avec des images de nom et placer quelques images dans le dossier d'images (e:myproj\images\)

supposons myfoto.jpg est placé sous e:\myproj\images\myfoto.jpg

4 B) maintenant créer un dossier avec le nom WEB-INF dans e:\myproj\WEB-INF et créer un web.xml in WEB-INF folder

Code dans web.xml

<web-app>
</web-app>

Étape 5:

maintenant créer un .document html avec nom index.html et place sous e:\myproj

CODE sous index.HTML Bienvenue à Myproj

la Structure du répertoire pour L'Étape 4 et L'Étape 5 ci-dessus est la suivante

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

Étape 6:

maintenant démarrer le serveur Apache tomcat

Étape 7:

ouvrez le navigateur et tapez l'url comme suit

http://localhost:8080/myproj    

puis u afficher le contenu qui est fourni dans l'index.html

Étape 8:

pour accéder aux Images sous votre disque dur local (à l'extérieur de webroot)

http://localhost:8080/myproj/images/myfoto.jpg
6
répondu sbabamca 2013-03-16 05:27:01

ajouter au serveur.xml:

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

active le paramètre de listage de fichier dir dans web.xml:

    <init-param>
        <param-name>listings</param-name>
        <param-value>true</param-value>
    </init-param>
5
répondu blue-sky 2015-05-12 10:27:58

C'est l'histoire de mon travail:

- Nous essayons de télécharger des images multiples et des fichiers de documents à L'aide de Struts 1 et Tomcat 7.x.

- Nous essayons d'écrire des fichiers téléchargés vers le système de fichiers, le nom de fichier et le chemin complet vers les enregistrements de base de données.

- Nous essayons de dossiers de fichiers séparés à l'extérieur Web app directory . ( * )

la solution CI-DESSOUS est assez simple, en vigueur pour l'exigence ( * ):

Dans le fichier META-INF/context.xml fichier avec le contenu suivant: (Exemple: mon application tourne à http://localhost:8080/ABC , mon application / projet s'appelle ABC ). (c'est aussi plein de contenu de fichier context.xml )

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

(fonctionne avec Tomcat version 7 ou ultérieure)

résultat: nous avons été créés 2 alias. Par exemple, nous enregistrons des images à: D:\images\foo.jpg et voir à partir du lien ou en utilisant l'étiquette d'image:

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

ou

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

(J'utilise Netbeans 7.x, Netbeans semblent auto de créer le fichier WEB-INF\context.xml )

5
répondu Do Nhu Vy 2015-06-05 22:35:25

si vous décidez d'Envoyer à FileServlet alors vous aurez également besoin de allowLinking="true" dans context.xml afin de permettre à FileServlet de traverser les liens symboliques.

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

2
répondu cherouvim 2012-07-18 10:46:20

si quelqu'un n'est pas en mesure de résoudre son problème avec la réponse acceptée, alors notez ces considérations ci-dessous:

  1. pas besoin de mentionner localhost:<port> avec l'attribut <img> src .
  2. assurez-vous que vous exécutez ce projet en dehors d'eclipse, car eclipse crée context docBase entrée seule dans son fichier local server.xml .
0
répondu JPG 2017-10-26 08:37:03

lire le flux D'entrée d'un fichier et l'écrire à ServletOutputStream pour l'envoi de données binaires au client.

  • fichier Local vous pouvez lire un fichier directement en utilisant FileInputStream('chemin/image.png') .
  • Mongo DataBase files 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));
    }
}

résultat L'URL directement à la 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>
0
répondu Yash 2018-01-12 11:13:45

si vous voulez travailler avec JAX-RS (par ex. RESTEasy) essayez ceci:

@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);
        }
    };
}

utilisant javax.ws.rs.core.Response et com.google.common.io.ByteStreams

0
répondu electrobabe 2018-04-03 01:04:21

je l'ai fait encore plus simple. Problème: un fichier CSS avait des liens url vers le dossier img. Obtient 404.

j'ai regardé l'url, http://tomcatfolder:port/img/blablah.png , qui n'existe pas. Mais, c'est vraiment pointer vers L'application racine dans Tomcat.

donc j'ai juste copié le dossier img de mon webapp dans cette application racine. Œuvres!

Pas recommandés pour la production, bien sûr, mais c'est un outil interne dev app.

-1
répondu Josef.B 2016-08-31 14:57:02