Saltar al contenido

Forma recomendada de guardar archivos cargados en una aplicación de servlet

Solución:

Guárdelo en cualquier lugar en un lugar accesible excepto de la carpeta del proyecto del IDE, también conocida como la carpeta de implementación del servidor, por los motivos mencionados en la respuesta a la imagen cargada solo está disponible después de actualizar la página:

  1. Los cambios en la carpeta del proyecto del IDE no se reflejan inmediatamente en la carpeta de trabajo del servidor. Hay una especie de trabajo en segundo plano en el IDE que se encarga de que la carpeta de trabajo del servidor se sincronice con las últimas actualizaciones (esto en términos del IDE se llama “publicación”). Ésta es la causa principal del problema que está viendo.

  2. En el código del mundo real, hay circunstancias en las que almacenar archivos cargados en la carpeta de implementación de la aplicación web no funcionará en absoluto. Algunos servidores (ya sea por defecto o por configuración) no expanden el archivo WAR implementado en el sistema de archivos del disco local, sino completamente en la memoria. No puede crear nuevos archivos en la memoria sin básicamente editar el archivo WAR implementado y volver a implementarlo.

  3. Incluso cuando el servidor expande el archivo WAR implementado en el sistema de archivos del disco local, todos los archivos recién creados se perderán en una nueva implementación o incluso en un simple reinicio, simplemente porque esos nuevos archivos no son parte del archivo WAR original.

Realmente no me importa a mí ni a nadie más dónde se guardará exactamente en el sistema de archivos del disco local, siempre y cuando usted lo haga no alguna vez uso getRealPath() método. Usar ese método está en alguna caso alarmante.

A su vez, la ruta al lugar de almacenamiento puede definirse de muchas formas. Tienes que hacerlo todo por tú mismo. Quizás aquí es donde se produce su confusión porque de alguna manera esperaba que el servidor lo hiciera todo automágicamente. Tenga en cuenta que @MultipartConfig(location) lo hace no especifique el destino de carga final, pero la ubicación de almacenamiento temporal para el tamaño del archivo del caso excede el umbral de almacenamiento de memoria.

Por lo tanto, la ruta a la ubicación de almacenamiento final se puede definir de cualquiera de las siguientes maneras:

  • Codificado:

      File uploads = new File("/path/to/uploads");
    
  • Variable de entorno a través de SET UPLOAD_LOCATION=/path/to/uploads:

      File uploads = new File(System.getenv("UPLOAD_LOCATION"));
    
  • Argumento de VM durante el inicio del servidor a través de -Dupload.location="/path/to/uploads":

      File uploads = new File(System.getProperty("upload.location"));
    
  • *.properties entrada de archivo como upload.location=/path/to/uploads:

      File uploads = new File(properties.getProperty("upload.location"));
    
  • web.xml <context-param> con nombre upload.location y valor /path/to/uploads:

      File uploads = new File(getServletContext().getInitParameter("upload.location"));
    
  • Si existe, use la ubicación proporcionada por el servidor, por ejemplo, en JBoss AS / WildFly:

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

De cualquier manera, puede hacer referencia y guardar fácilmente el archivo de la siguiente manera:

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

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

O, cuando desee generar automáticamente un nombre de archivo único para evitar que los usuarios sobrescriban archivos existentes con el mismo nombre coincidentemente:

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

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

Como obtener part en JSP / Servlet se responde en ¿Cómo cargar archivos al servidor usando JSP / Servlet? y como obtener part en JSF se responde en Cómo cargar un archivo usando JSF 2.2 ? ¿Dónde está el archivo guardado?

Nota: haz no usar Part#write() ya que interpreta la ruta relativa a la ubicación de almacenamiento temporal definida en @MultipartConfig(location).

Ver también:

  • Cómo guardar el archivo cargado en JSF (dirigido a JSF, pero el principio es prácticamente el mismo)
  • La forma más sencilla de servir datos estáticos desde fuera del servidor de aplicaciones en una aplicación web Java (en caso de que desee devolverlos)
  • Cómo guardar el archivo generado temporalmente en una aplicación web basada en servlet

Publico mi forma final de hacerlo según la respuesta aceptada:

@SuppressWarnings("serial")
@WebServlet("https://foroayuda.es/")
@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("https://foroayuda.es/") + 1)
                        .substring(filename.lastIndexOf('\') + 1); // MSIE fix.
            }
        }
        return null;
    }
}

dónde :

@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);
    }
}

y /WEB-INF/app.properties:

upload.location=C:/_/

HTH y si encuentra un error, avíseme

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *