Méthode recommandée pour enregistrer les fichiers téléchargés dans une application de servlet

J’ai lu ici que l’on ne devrait de toute façon pas enregistrer le fichier sur le serveur car il n’est pas portable, transactionnel et nécessite des parameters externes. Cependant, étant donné que j’ai besoin d’une solution tmp pour tomcat (7) et que j’ai un contrôle (relatif) sur la machine serveur, je veux savoir:

Malheureusement, le FileServlet de @BalusC se concentre sur le téléchargement de fichiers, tandis que sa réponse sur le téléchargement de fichiers ignore la partie où enregistrer le fichier.

Une solution facilement convertible pour utiliser une implémentation DB ou JCR (comme jackrabbit ) serait préférable.

Stockez-le n’importe où dans un emplacement accessible, à l’ exception du dossier de projet de l’EDI, à savoir le dossier de déploiement du serveur, pour les raisons mentionnées dans la réponse à l’ image téléchargée uniquement disponible après l’actualisation de la page :

  1. Les modifications apscopes au dossier de projet de l’EDI ne sont pas immédiatement reflétées dans le dossier de travail du serveur. Il y a une sorte de tâche en arrière-plan dans l’EDI qui veille à ce que le dossier de travail du serveur soit synchronisé avec les dernières mises à jour (ceci est dans les termes de l’EDI appelé “publication”). C’est la cause principale du problème que vous rencontrez.

  2. Dans le code du monde réel, il existe des circonstances dans lesquelles le stockage des fichiers téléchargés dans le dossier de déploiement de l’application Web ne fonctionnera pas du tout. Certains serveurs (par défaut ou par configuration) ne développent pas le fichier WAR déployé dans le système de fichiers du disque local, mais au contraire dans la mémoire. Vous ne pouvez pas créer de nouveaux fichiers dans la mémoire sans modifier le fichier WAR déployé et le redéployer.

  3. Même lorsque le serveur développe le fichier WAR déployé dans le système de fichiers du disque local, tous les fichiers nouvellement créés seront perdus lors d’un redéploiement ou même d’un simple redémarrage, simplement parce que ces nouveaux fichiers ne font pas partie du fichier WAR d’origine.

Cela n’a vraiment aucune importance pour moi ou pour qui que ce soit sur le système de fichiers du disque local, il sera sauvegardé, à condition de ne jamais utiliser la méthode getRealPath() . L’utilisation de cette méthode est en tout cas alarmante.

Le chemin d’access à l’emplacement de stockage peut à son tour être défini de plusieurs manières. Vous devez tout faire vous-même . Peut-être est-ce là que votre confusion est due au fait que vous vous attendiez à ce que le serveur fasse tout cela automatiquement. Notez que @MultipartConfig(location) ne spécifie pas la destination finale du téléchargement, mais que l’emplacement de stockage temporaire pour la taille du fichier de cas dépasse le seuil de stockage de la mémoire.

Ainsi, le chemin d’access à l’emplacement de stockage final peut être défini de l’une des manières suivantes:

  • Hardcoded:

     File uploads = new File("/path/to/uploads"); 
  • Variable d’environnement via SET UPLOAD_LOCATION=/path/to/uploads :

     File uploads = new File(System.getenv("UPLOAD_LOCATION")); 
  • Argument de la VM lors du démarrage du serveur via -Dupload.location="/path/to/uploads" :

     File uploads = new File(System.getProperty("upload.location")); 
  • Entrée du fichier *.properties upload.location=/path/to/uploads comme upload.location=/path/to/uploads :

     File uploads = new File(properties.getProperty("upload.location")); 
  • web.xml avec le nom upload.location et la valeur /path/to/uploads :

     File uploads = new File(getServletContext().getInitParameter("upload.location")); 
  • Le cas échéant, utilisez l’emplacement fourni par le serveur, par exemple dans JBoss AS / WildFly :

     File uploads = new File(System.getProperty("jboss.server.data.dir"), "uploads"); 

De toute façon, vous pouvez facilement référencer et enregistrer le fichier comme suit:

 File file = new File(uploads, "somefilename.ext"); try (InputStream input = part.getInputStream()) { Files.copy(input, file.toPath()); } 

Ou, lorsque vous souhaitez générer automatiquement un nom de fichier unique pour empêcher les utilisateurs de remplacer les fichiers existants par un nom identique:

 File file = File.createTempFile("somefilename-", ".ext", uploads); try (InputStream input = part.getInputStream()) { Files.copy(input, file.toPath(), StandardCopyOption.REPLACE_EXISTING); } 

Comment obtenir une part dans JSP / Servlet répond à Comment charger des fichiers sur un serveur à l’aide de JSP / Servlet? et comment obtenir une part dans JSF répond à Comment charger un fichier avec JSF 2.2 ? Où est le fichier enregistré?

Remarque: n’utilisez pas Part#write() car il interprète le chemin d’access par rapport à l’emplacement de stockage temporaire défini dans @MultipartConfig(location) .

Voir également:

  • Comment enregistrer le fichier téléchargé dans JSF (ciblé par JSF, mais le principe est à peu près le même)
  • Un moyen simple de diffuser des données statiques depuis l’extérieur du serveur d’applications dans une application Web Java (au cas où vous souhaiteriez le renvoyer)
  • Comment enregistrer le fichier généré temporairement dans une application Web basée sur un servlet

Je poste ma dernière méthode en fonction de la réponse acceptée:

 @SuppressWarnings("serial") @WebServlet("/") @MultipartConfig public final class DataCollectionServlet extends Controller { private static final Ssortingng UPLOAD_LOCATION_PROPERTY_KEY="upload.location"; private Ssortingng uploadsDirName; @Override public void init() throws ServletException { super.init(); uploadsDirName = property(UPLOAD_LOCATION_PROPERTY_KEY); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // ... } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Collection parts = req.getParts(); for (Part part : parts) { File save = new File(uploadsDirName, getFilename(part) + "_" + System.currentTimeMillis()); final Ssortingng absolutePath = save.getAbsolutePath(); log.debug(absolutePath); part.write(absolutePath); sc.getRequestDispatcher(DATA_COLLECTION_JSP).forward(req, resp); } } // helpers private static Ssortingng getFilename(Part part) { // courtesy of BalusC : http://stackoverflow.com/a/2424824/281545 for (Ssortingng cd : part.getHeader("content-disposition").split(";")) { if (cd.sortingm().startsWith("filename")) { Ssortingng filename = cd.subssortingng(cd.indexOf('=') + 1).sortingm() .replace("\"", ""); return filename.subssortingng(filename.lastIndexOf('/') + 1) .subssortingng(filename.lastIndexOf('\\') + 1); // MSIE fix. } } return null; } } 

où :

 @SuppressWarnings("serial") class Controller extends HttpServlet { static final Ssortingng DATA_COLLECTION_JSP="/WEB-INF/jsp/data_collection.jsp"; static ServletContext sc; Logger log; // private // "/WEB-INF/app.properties" also works... private static final Ssortingng PROPERTIES_PATH = "WEB-INF/app.properties"; private Properties properties; @Override public void init() throws ServletException { super.init(); // synchronize ! if (sc == null) sc = getServletContext(); log = LoggerFactory.getLogger(this.getClass()); try { loadProperties(); } catch (IOException e) { throw new RuntimeException("Can't load properties file", e); } } private void loadProperties() throws IOException { try(InputStream is= sc.getResourceAsStream(PROPERTIES_PATH)) { if (is == null) throw new RuntimeException("Can't locate properties file"); properties = new Properties(); properties.load(is); } } Ssortingng property(final Ssortingng key) { return properties.getProperty(key); } } 

et /WEB-INF/app.properties:

 upload.location=C:/_/ 

HTH et si vous trouvez un bug faites le moi savoir