Moyen le plus simple de servir des données statiques depuis l'extérieur du serveur d'applications dans une application Web Java


J'ai une application Web Java en cours d'exécution sur Tomcat. Je souhaite 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 nouvelles images seront également ajoutées et enregistrées en les téléchargeant via l'interface utilisateur Web.

Ce n'est pas un problème de le faire en stockant les données statiques dans le conteneur Web, mais les stocker et les charger depuis l'extérieur du conteneur Web me donne mal à la tête.

Je préférerais ne pas utiliser un serveur Web séparé comme Apache pour servir les données statiques à ce stade. 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 le fait que le répertoire image soit 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 gérer le service d'image, mais ces suggestions ont été très vagues et de haut niveau sans pointeurs vers plus des informations détaillées sur la façon d'accomplir ceci.

Author: BalusC, 2009-11-28

10 answers

J'ai vu quelques suggestions comme le fait que le répertoire image soit 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 barres obliques comme dans /path/to/files), cela fonctionnera également sous Windows sans avoir besoin de jouer avec des File.separator chaînes-concaténations laides. Il ne serait cependant scanné que sur le même disque de travail à partir duquel cette commande a été appelée. Donc, si Tomcat est par exemple installé sur C: alors le /path/to/files pointerait en fait vers 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, tout ce que vous devez faire dans Tomcat est d'ajouter l'élément de contexte suivant à /conf/server.xml dans la balise <Host>:

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

De cette façon, ils seront accessibles via http://example.com/files/.... Exemple de configuration GlassFish/Payara peut être trouvé iciet l'exemple de configuration WildFly peut être trouvé ici.

Si vous voulez avoir le contrôle de la lecture/écriture de fichiers vous-même, vous devez créer un Servlet pour cela qui obtient simplement un InputStream du fichier dans la saveur de par exemple FileInputStream et l'écrit dans le OutputStream du HttpServletResponse.

Sur la réponse, vous devez définir l'en-tête Content-Type afin que le client sache quelle application associer au fichier fourni. Et, vous devez définir le Content-Length en-tête afin 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 sur attachment si vous voulez une boîte de dialogue Enregistrer sous, sinon le client tentera de l'afficher en ligne. Enfin, il suffit d'écrire le contenu du fichier dans le flux de sortie de réponse.

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 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 fait, comme fournir une image par défaut (c'est-à-dire if (!file.exists()) file = new File("/path/to/files", "404.gif") ou plus). L'utilisation du request.getPathInfo() est également préférée ci-dessus request.getParameter()car il est plus convivial pour le référencement et sinon IE ne choisira pas le nom de fichier correct pendant Enregistrer sous.

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

J'espère que cela aide.

Voir aussi:

 147
Author: BalusC, 2017-05-23 12:34:34

Vous pouvez le faire en plaçant vos images sur un chemin fixe (par exemple: / var / images, ou c:\images), ajoutez un paramètre dans les paramètres de votre application (représenté dans mon exemple par les paramètres.classe), et les charger comme ça, 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());

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

Bien sûr, vous devriez penser à servir différents types de contenu - "image/jpeg", par exemple en fonction de l'extension de fichier. Aussi, vous devez fournir une certaine mise en cache.

De plus, vous pouvez utiliser ce servlet pour la redimensionnement 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 tenant compte des performances, bien sûr.

 9
Author: Bozho, 2009-11-28 11:58:22

Exigence: Accéder aux ressources statiques (images / vidéos., etc.,) depuis l'extérieur du répertoire WEBROOT ou depuis le disque local

Étape 1:
Créez un dossier sous webapps du serveur tomcat., disons que le nom du dossier est myproj

Étape 2:
Sous myproj créer un dossier WEB-INF sous ce créer un simple web.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 dans myproj.xml:

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

Étape 4:
4 A) Maintenant, créez un dossier avec le nom myproj dans le lecteur E de votre disque dur et créez un nouveau

Dossier avec le nom images et placez quelques images dans le dossier images (e:myproj\images\)

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

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

Le Code dans le web.xml

<web-app>
</web-app>

Étape 5:
Maintenant, créez un .document html avec index de nom.html et placer sous e:\myproj

CODE sous index.HTML Bienvenue sur Myproj

La structure de répertoire pour les étapes 4 et 5 ci-dessus est la suivante

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

Étape 6:
Démarrez maintenant le serveur apache tomcat

Étape 7:
ouvrez le navigateur et tapez l'url que suit

http://localhost:8080/myproj    

Ensuite, u affiche le contenu fourni dans index.code html

Étape 8:
Pour accéder aux images sous votre disque dur local (en dehors de webroot)

http://localhost:8080/myproj/images/myfoto.jpg
 6
Author: sbabamca, 2013-03-16 05:27:01

Ajouter au serveur.xml:

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

Activer le paramètre de liste de fichiers dir dans le web.xml:

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

Ceci est une histoire de mon lieu de travail:
- Nous essayons de télécharger multiplier les images et les fichiers de documents utilisent Struts 1 et Tomcat 7.x.
- Nous essayons d'écrire des fichiers téléchargés dans le système de fichiers, le nom de fichier et le chemin complet vers les enregistrements de base de données.
- Nous essayons de séparer les dossiers de fichiers en dehors de répertoire web app . (*)

La solution ci-dessous est assez simple, efficace pour les besoins ( * ):

Dans le fichier META-INF/context.xml fichier avec le contenu suivant: (Exemple, mon application exécuter à http://localhost:8080/ABC, mon application / projet nommé ABC). (ceci est également le contenu complet du 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 la balise 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 semble créer automatiquement un fichier WEB-INF\context.xml)

 5
Author: Do Nhu Vy, 2015-06-05 22:35:25

Si vous décidez d'envoi de FileServlet, alors vous aurez également besoin d' allowLinking="true" dans context.xml afin de permettre FileServlet pour parcourir les liens symboliques.

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

 2
Author: cherouvim, 2012-07-18 10:46:20

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

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

Lire le flux d'entrée d'un fichier et l'écrire dans ServletOutputStream pour envoyer des données binaires au client.

@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
Author: Yash, 2018-01-12 11:13:45

Si vous voulez travailler avec JAX-RS (par exemple 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);
        }
    };
}

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

 0
Author: 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é URL, http://tomcatfolder:port/img/blablah.png , qui n'existe pas. Mais, cela pointe vraiment vers l'application RACINE dans Tomcat.

Je viens donc de copier le dossier img de mon application Web dans cette application RACINE. Œuvres!

Non recommandé pour la production, bien sûr, mais c'est pour une application de développement d'outil interne.

 -1
Author: Josef.B, 2016-08-31 14:57:02