Рекомендуемый способ сохранения загруженных файлов в приложении сервлета


я прочитала здесь что не следует сохранять файл на сервере в любом случае, поскольку он не является портативным, транзакционным и требует внешних параметров. Однако, учитывая, что мне нужно решение tmp для tomcat (7) и что у меня есть (относительный) контроль над серверной машиной, я хочу знать :

  • что является лучшим местом для сохранения файла ? Я должен сохранить его в /WEB-INF/uploads (отсоветовали здесь) или где-нибудь под $CATALINA_BASE (см. здесь) или ... ? Учебник JavaEE 6 получает путь от пользователя (: wtf:). NB: файл ни в коем случае не должен быть загружен.

  • должен ли я настроить параметр конфигурации как подробный здесь ? Я был бы признателен за некоторый код (я бы предпочел дать ему относительный путь-так что это, по крайней мере, Tomcat portable) - Part.write() выглядит многообещающе - но, видимо, нужен абсолютный путь

  • мне было бы интересно в изложении недостатков этого подхода vs база данных / репозиторий JCR one

к сожалению FileServlet by @BalusC концентрируется на загрузке файлов, в то время как его ответ при загрузке файлов пропускает часть о том, где сохранить файл.

решение легко конвертируется для использования реализации DB или JCR (например,заяц) будет предпочтительнее.

2 107

2 ответа:

хранить его в любом месте в доступном месте за исключением папки проекта IDE aka папки развертывания сервера, по причинам, указанным в ответе на загруженное изображение доступно только после обновления страницы:

  1. изменения в папке проекта IDE не сразу отражаются в рабочей папке сервера. В IDE есть своего рода фоновое задание, которое заботится о том, чтобы рабочая папка сервера получала синхронизируется с последними обновлениями (это в терминах IDE называется "публикация"). Это основная причина проблемы, которую вы видите.

  2. в реальном мире кода есть обстоятельства, при которых хранение загруженных файлов в папке развертывания веб-приложения не будет работать вообще. Некоторые серверы (либо по умолчанию, либо по конфигурации) не разворачивают развернутый файл WAR в локальную дисковую файловую систему, а вместо этого полностью в памяти. Вы не можете создавать новые файлы в памяти без в основном редактирование развертывания War-файла и перевода его.

  3. даже когда сервер разворачивает развернутый файл WAR в локальную дисковую файловую систему, все вновь созданные файлы будут потеряны при повторном развертывании или даже простой перезагрузке, просто потому, что эти новые файлы не являются частью исходного файла WAR.

это действительно не имеет значения для меня или кого-либо еще, где именно на локальном диске файловой системы он будет сохранен, пока вы do не использовать getRealPath() метод. Использование этого метода находится в любой случае настораживает.

путь к месту хранения может быть определен различными способами. Вы должны сделать все это с помощью сами. Возможно, именно здесь ваша путаница вызвана тем, что вы каким-то образом ожидали, что сервер делает все это автоматически. Обратите внимание, что @MultipartConfig(location) тут не указать конечный пункт загрузки, но временное хранение кейс размер файла превышает пороговое значение памяти.

таким образом, путь к конечному месту хранения можно определить одним из следующих способов:

  • Hardcoded:

    File uploads = new File("/path/to/uploads");
    
  • переменная окружения через SET UPLOAD_LOCATION=/path/to/uploads:

    File uploads = new File(System.getenv("UPLOAD_LOCATION"));
    
  • VM аргумент при запуске сервера через -Dupload.location="/path/to/uploads":

    File uploads = new File(System.getProperty("upload.location"));
    
  • *.properties запись в файл как upload.location=/path/to/uploads:

    File uploads = new File(properties.getProperty("upload.location"));
    
  • web.xml<context-param> С именем upload.location и значение /path/to/uploads:

    File uploads = new File(getServletContext().getInitParameter("upload.location"));
    
  • если таковые имеются, используйте серверное расположение, например, в JBoss AS/WildFly:

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

в любом случае, вы можете легко ссылаться и сохранять файл следующим образом:

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

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

или, если вы хотите автоматически создать уникальное имя файла, чтобы предотвратить перезапись существующих пользователей файлы с совпадающим именем:

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

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

как получить part в JSP/сервлет отвечает в как загрузить файлы на сервер с помощью JSP / Servlet? и получении part в JSF отвечает как загрузить файл с помощью JSF 2.2 ? Где находится сохраненный файл?

Примечание: do не использовать Part#write() как он интерпретирует путь относительно места временного хранения, определенного в @MultipartConfig(location).

Читайте также:

я публикую свой окончательный способ сделать это на основе принятого ответа:

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

где :

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

и /WEB-INF / app.свойства :

upload.location=C:/_/

HTH и если вы найдете ошибку, дайте мне знать