J'ai une application Web Java s'exécutant 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 ayant les données statiques stockées dans le conteneur Web, mais les stocker et les charger de l'extérieur du conteneur Web me donne mal à la tête.
Je préférerais ne pas utiliser un serveur Web distinct comme Apache pour servir les données statiques à ce stade. Je n'aime pas non plus l'idée de stocker les images au format binaire dans une base de données.
J'ai déjà vu des suggestions, comme par exemple que le répertoire d'images soit un lien symbolique pointant vers un répertoire situé en dehors du conteneur Web, mais cette approche fonctionnera-t-elle à la fois dans les environnements Windows et * nix?
Certains suggèrent d'écrire un filtre ou une servlet pour gérer la diffusion d'images, mais ces suggestions ont été très vagues et de haut niveau, sans indications sur des informations plus détaillées sur la manière de procéder.
J'ai déjà vu quelques suggestions, comme par exemple que le répertoire des images soit un lien symbolique pointant vers un répertoire situé en dehors du conteneur Web, mais cette approche fonctionnera-t-elle à la fois dans les environnements Windows et * nix?
Si vous respectez les règles de chemin d'accès 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 qu'il soit nécessaire de bricoler avec les horribles concaténations de chaînes File.separator
. Toutefois, il ne sera analysé que sur le même disque de travail à partir duquel cette commande a été appelée. Ainsi, si Tomcat est par exemple installé sur C:
, le /path/to/files
pointerait en fait sur C:\path\to\files
.
Si les fichiers sont tous situés en dehors de l'application Web et que vous souhaitez que DefaultServlet
de Tomcat les gère, il vous suffit dans Tomcat 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/...
. Vous trouverez un exemple de configuration GlassFish/Payara ici et un exemple de configuration WildFly ici .
Si vous voulez contrôler vous-même la lecture/l'écriture de fichiers, vous devez créer un Servlet
qui obtiendra essentiellement un InputStream
du fichier sous la forme, par exemple, de FileInputStream
et l'écrivera dans le OutputStream
du 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
pour 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 souhaitez une boîte de dialogue Enregistrer sous, sinon le client essaiera de l'afficher en ligne. Enfin, écrivez simplement le contenu du fichier dans le flux de sortie de la 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
de par exemple /files/*
, vous pouvez l'appeler par http://example.com/files/image.png
. De cette façon, vous pouvez avoir plus de contrôle sur les demandes que le DefaultServlet
, par exemple en fournissant une image par défaut (c'est-à-dire if (!file.exists()) file = new File("/path/to/files", "404.gif")
ou à peu près). Également, utiliser request.getPathInfo()
est préférable à request.getParameter()
car il est plus convivial pour le référencement, sinon IE ne sélectionnera pas le nom de fichier correct lors de Save As.
Vous pouvez réutiliser la même logique pour servir des fichiers à partir d'une base de données. Remplacez simplement new FileInputStream()
par ResultSet#getInputStream()
.
J'espère que cela t'aides.
Vous pouvez le faire en plaçant vos images sur un chemin fixe (par exemple:/var/images ou c:\images), ajouter un paramètre dans les paramètres de votre application (représenté dans mon exemple par Settings.class) et les charger. comme ça, dans une 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érents types de contenu - "image/jpeg", basé par exemple sur l'extension du fichier. Aussi, vous devriez fournir un peu de cache.
De plus, vous pouvez utiliser cette servlet pour redimensionner la qualité de vos images, en fournissant des paramètres de largeur et de hauteur sous forme d'arguments, et en utilisant image.getScaledInstance(w, h, Image.SCALE_SMOOTH
), en tenant compte des performances, bien sûr.
Condition préalable: accès aux ressources statiques (images/vidéos, etc.) de l'extérieur du répertoire WEBROOT ou du disque local
Étape 1 :
Créez un dossier sous les applications Web du serveur Tomcat., Disons que le nom du dossier est myproj
Étape 2 :
Sous myproj, créez un dossier WEB-INF. Créez-y un simple web.xml.
code sous web.xml
<web-app>
</web-app>
Structure du répertoire pour les deux étapes ci-dessus
c:\programfile\apachesoftwarefoundation\Tomcat\...\webapps
|
|---myproj
| |
| |---WEB-INF
| |
|---web.xml
Étape 3:
Créez maintenant un fichier XML avec le nom myproj.xml à 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) Créez maintenant 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 que myfoto.jpg soit 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 fichier web.xml dans le dossier WEB-INF.
Code dans web.xml
<web-app>
</web-app>
Étape 5:
Créez maintenant un document .html avec le nom index.html et placez-le sous e:\myproj
CODE sous index.html Bienvenue sur Myproj
La structure du 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:
Maintenant démarrez le serveur Apache Tomcat
Étape 7:
ouvrez le navigateur et tapez l'URL comme suit
http://localhost:8080/myproj
puis u affichez le contenu fourni dans index.html
Étape 8:
Accéder aux images sur votre disque dur local (en dehors de Webroot)
http://localhost:8080/myproj/images/myfoto.jpg
C'est l'histoire de mon lieu de travail:
- Nous essayons de télécharger plusieurs images et les fichiers de documents utilisent Struts 1 et Tomcat 7.x.
- Nous essayons d'écrire les fichiers téléchargés dans le système de fichiers, le nom du fichier et le chemin complet des enregistrements de la base de données.
- Nous essayons de séparer les dossiers de fichiers en dehors du répertoire d'application web. (*)
La solution ci-dessous est assez simple, efficace pour le besoin (*):
Dans le fichier META-INF/context.xml
, le fichier contient le contenu suivant: (Exemple, mon application est exécutée à http://localhost:8080/ABC
, mon application/projet nommé ABC
) . 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 les images sous: D:\images\foo.jpg
.__ et visionnons le lien ou en utilisant le tag 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 le fichier WEB-INF\context.xml
)
Ajouter au fichier server.xml:
<Context docBase="c:/dirtoshare" path="/dir" />
Activer le paramètre de liste de fichiers dir dans web.xml:
<init-param>
<param-name>listings</param-name>
<param-value>true</param-value>
</init-param>
Si vous décidez d'envoyer à FileServlet
, vous aurez également besoin de allowLinking="true"
dans context.xml
afin de permettre à FileServlet
de parcourir les liens symboliques.
Voir http://Tomcat.Apache.org/Tomcat-6.0-doc/config/context.html
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);
}
};
}
en utilisant javax.ws.rs.core.Response
et com.google.common.io.ByteStreams
Lisez le flux d'entrée d'un fichier et écrivez-le dans ServletOutputStream
pour l'envoi de 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));
}
}
Renvoie directement l'URL dans l'attribut src
.
<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 quelqu'un n'est pas capable de résoudre son problème avec une réponse acceptée, alors notez les considérations suivantes:
localhost:<port>
avec l'attribut <img> src
.context docBase
dans son fichier server.xml
local.