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.
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:
- Méthode recommandée pour sauvegarder les fichiers téléchargés dans une application servlet
- Abstrait modèle pour une ressource statique servlet (soutien de cache HTTP)
- comment récupérer et afficher des images à partir d'une base de données dans une page JSP?
- comment diffuser des fichiers audio / vidéo tels que MP3, MP4, AVI, etc en utilisant un Servlet
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.
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
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>
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
)
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
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:
- pas besoin de mentionner
localhost:<port>
avec l'attribut<img> src
. - assurez-vous que vous exécutez ce projet en dehors d'eclipse, car eclipse crée
context docBase
entrée seule dans son fichier localserver.xml
.
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>
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
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.