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

j'ai lu ici que l'on ne devrait pas enregistrer le fichier dans le serveur de toute façon comme il n'est pas portable, les opérations et la nécessite de paramètres 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:

  • Quel est le meilleur endroit pour enregistrer le fichier ? Si je le mets dans /WEB-INF/uploads (conseillé contre ici ) ou quelque part sous $CATALINA_BASE (voir ici ) ou ... ? Le tutoriel JavaEE 6 reçoit le chemin de l'utilisateur (: wtf:). NB: le fichier ne doit en aucun cas être téléchargeable.

  • dois-je configurer un paramètre de configuration comme détaillé ici ? J'apprécierais un peu de code (je préférerais lui donner un chemin relatif - donc il est au moins Tomcat portable) - Part.write() looks prometteur - mais apparemment a besoin d'un chemin absolu

  • je serais intéressé par une exposition des inconvénients de cette approche vs une base de données / dépôt JCR one

malheureusement, le FileServlet de @BalusC se concentre sur le téléchargement de fichiers, tandis que son réponse sur le téléchargement de fichiers saute la partie sur Où sauvegarder le fichier.

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

107
demandé sur Community 2013-09-06 22:49:20

2 réponses

stocker n'importe où dans un endroit accessible excepté du dossier de projet de L'IDE alias le dossier de déploiement du serveur, pour les raisons mentionnées dans la réponse à image téléchargée seulement disponible après rafraîchissement de la page :

  1. les changements dans le dossier de projet de L'IDE ne se reflètent pas immédiatement dans le dossier de travail du serveur. Il y a une sorte de travail de fond dans L'IDE ce qui prend soin que le dossier de travail du serveur soit synchronisé avec les dernières mises à jour (Ceci est en termes D'IDE appelé "publication"). C'est la principale cause du problème que vous avez vu.

  2. dans le code du monde réel il y a des circonstances où stocker des fichiers téléchargés dans le dossier deploy de la webapp ne fonctionnera pas du tout. Certains serveurs (par défaut ou par configuration) n'étendent pas le fichier WAR déployé dans le système de fichiers Disque local, mais entièrement dans mémoire. Vous ne pouvez pas créer de nouveaux fichiers en mémoire sans essentiellement éditer le fichier WAR déployé et le redéployer.

  3. même si le serveur étend le fichier WAR déployé dans le système de fichiers Disque local, tous les fichiers nouvellement créés seront perdus sur un redéploiement ou même un simple redémarrage, simplement parce que ces nouveaux fichiers ne font pas partie du fichier WAR original.

il vraiment n'a pas d'importance pour moi ou n'importe qui d'autre où exactement sur le système de fichiers de disque local il sera sauvé, aussi longtemps que vous do pas jamais utiliser getRealPath() méthode . En utilisant cette méthode est dans tout cas alarmant.

Le chemin vers l'emplacement de stockage peut à son tour être défini de plusieurs façons. Vous devez tout faire par vous-même . Peut-être que c'est là que votre confusion est due, car vous vous attendiez d'une façon ou d'une autre à ce que le serveur fasse tout cela automatiquement. S'il vous plaît noter que @MultipartConfig(location) ne pas spécifier la destination finale de téléchargement, mais l'emplacement de stockage temporaire pour la taille du dossier de cas dépasse le seuil de stockage en mémoire.

ainsi, le chemin vers le lieu de stockage final peut être défini de l'une des façons suivantes:

  • codé en dur:

    File uploads = new File("/path/to/uploads");
    
  • variable d'Environnement par l'intermédiaire de SET UPLOAD_LOCATION=/path/to/uploads :

    File uploads = new File(System.getenv("UPLOAD_LOCATION"));
    
  • argument VM pendant le démarrage du serveur via -Dupload.location="/path/to/uploads" :

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

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

    File uploads = new File(getServletContext().getInitParameter("upload.location"));
    
  • le cas échéant, utiliser l'emplacement fourni par le serveur, p.ex. dans JBoss AS / WildFly :

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

de toute façon, vous pouvez facilement consulter 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 voulez autogénérer un nom de fichier unique pour empêcher les utilisateurs d'écraser des fichiers existants avec coïncidence le même nom:

File file = File.createTempFile("somefilename-", ".ext", uploads);

try (InputStream input = part.getInputStream()) {
    Files.copy(input, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
}

Comment obtenir des part en JSP/Servlet est répondu dans Comment télécharger des fichiers vers le serveur à l'aide de JSP/Servlet? et comment l'obtenir part dans le JSF est répondu dans Comment télécharger des fichiers en utilisant JSF 2.2 ? Où est le fichier sauvegardé?

Remarque: ne pas utiliser Part#write() qu'il interprète le chemin d'accès par rapport à l'emplacement de stockage temporaire défini dans @MultipartConfig(location) .

voir aussi:

138
répondu BalusC 2017-05-23 12:02:50

je poste ma dernière façon de le faire basée sur la réponse acceptée:

@SuppressWarnings("serial")
@WebServlet("/")
@MultipartConfig
public final class DataCollectionServlet extends Controller {

    private static final String UPLOAD_LOCATION_PROPERTY_KEY="upload.location";
    private String 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<Part> parts = req.getParts();
        for (Part part : parts) {
            File save = new File(uploadsDirName, getFilename(part) + "_"
                + System.currentTimeMillis());
            final String absolutePath = save.getAbsolutePath();
            log.debug(absolutePath);
            part.write(absolutePath);
            sc.getRequestDispatcher(DATA_COLLECTION_JSP).forward(req, resp);
        }
    }

    // helpers
    private static String getFilename(Part part) {
        // courtesy of BalusC : http://stackoverflow.com/a/2424824/281545
        for (String cd : part.getHeader("content-disposition").split(";")) {
            if (cd.trim().startsWith("filename")) {
                String filename = cd.substring(cd.indexOf('=') + 1).trim()
                        .replace("\"", "");
                return filename.substring(filename.lastIndexOf('/') + 1)
                        .substring(filename.lastIndexOf('\') + 1); // MSIE fix.
            }
        }
        return null;
    }
}

où:

@SuppressWarnings("serial")
class Controller extends HttpServlet {

    static final String DATA_COLLECTION_JSP="/WEB-INF/jsp/data_collection.jsp";
    static ServletContext sc;
    Logger log;
    // private
    // "/WEB-INF/app.properties" also works...
    private static final String 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);
        }
    }

    String property(final String key) {
        return properties.getProperty(key);
    }
}

et the /WEB-INF/app.propriétés:

upload.location=C:/_/

HTH et si vous trouvez un bug laissez-moi savoir

6
répondu Mr_and_Mrs_D 2016-03-17 12:36:07