Записать файл на диск с помощью JSF 2.2 inputFile

Я пытаюсь загрузить файл изображения с помощью тега h: inputFile и записать его на диск.

Мой код JSF:

<h:form id="fileUploadForm" enctype='multipart/form-data' prependId="false">
   <h:inputFile value="#{solicitacaoManagedBean.imagemCarregada}" />
   <br />
   <h:commandButton styleClass="btn btn-primary " value="Enviar" action="#{solicitacaoManagedBean.enviarImagem}" />
</h:form>

Мой управляемый компонент:

@Named(value = "solicitacaoManagedBean")
@SessionScoped
@MultipartConfig(location = "/home/rogerio/tmp/")
public class SolicitacaoManagedBean implements Serializable {

   private Part imagemCarregada;

(...)

   public void enviarImagem() throws IOException {
      try {
         imagemCarregada.write("teste.jpg");
      } catch (IOException ioe) {
         System.out.println("Erro ao escrever: " + ioe.getLocalizedMessage());
      }
   }
}

Предположительно метод write загружает элемент на диск, и исключение IOException также не генерируется/не перехватывается.


person rogerio_gentil    schedule 28.08.2013    source источник
comment
Так что-то не работает?   -  person Scary Wombat    schedule 28.08.2013
comment
да. Файл не записывается на диск.   -  person rogerio_gentil    schedule 28.08.2013


Ответы (1)


Предполагается, что аннотация @javax.servlet.annotation.MultipartConfig должна быть размещена в классе, реализующем HttpServlet, а не в классе поддерживающего компонента. По сути, эта аннотация должна быть помещена в класс FacesServlet, что уже сделано, начиная с JSF 2.2.

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

System.out.println(new File(".").getAbsolutePath());

Там вы увидите загруженный файл.

Более того, даже если аннотация @MultipartConfig работала, атрибут location на самом деле не представляет собой постоянное место сохранения загрузки файла. Вместо этого он представляет собой временное место хранения на диске на тот случай, если размер загружаемого файла превышает доступный/настроенный объем памяти. Вы никогда не должны постоянно хранить загруженные файлы в месте, указанном @MultipartConfig(location). Вы всегда должны получать содержимое файла через Part#getInputStream() и записывать его в нужное постоянное место, указанное новым File или Path, представляющим абсолютный путь.

Избавьтесь от всей этой аннотации @MultipartConfig. Он не делает ничего полезного в классе поддерживающего компонента. Просто получите содержимое файла с помощью Part#getInputStream() и скопируйте его по нужному абсолютному пути:

try (InputStream input = imagemCarregada.getInputStream()) {
    Files.copy(input, new File("/home/rogerio/tmp/teste.jpg").toPath());
}

Смотрите также


Не связанный с конкретной проблемой, использование bean-компонента с областью действия сеанса для этой цели не является идеальным. Скорее используйте представление или запрос с ограниченной областью действия. См. также Как правильно выбрать область действия bean-компонента? И, используя prependId="false" не рекомендуется для других целей, кроме форм входа, привязанных к инфраструктуре входа, которая не поддерживает идентификатор JSF, добавленный в начале, в именах параметров запроса. См. также UIForm с prependId=false breaks ‹f:ajax render›.

person BalusC    schedule 30.08.2013
comment
Вы всегда должны записывать его в нужное постоянное место с помощью Part#write() ›› вы имеете в виду Path#write() ? - person Mr_and_Mrs_D; 06.09.2013
comment
@Mr_and_Mrs_D: Нет, Part — это javax.servlet.http.Part . См. также мой обновленный ответ на ваш текущий вопрос. - person BalusC; 06.09.2013
comment
Я предполагаю так: fileName — имя файла, в который будет записываться поток. Файл создается относительно местоположения, указанного в MultipartConfig, из документы меня смутили - person Mr_and_Mrs_D; 06.09.2013
comment
Спасибо @BalusC. Теперь я понял, в какую директорию метод write() помещает файл, но даже указав абсолютный путь, он не работает. Выдается исключение: java.io.FileNotFoundException: /srv/glassfish-4.0/glassfish/domains/domain1/generated/jsp/identidadeWeb-war/home/rogerio/teste.jpg. Я попробую по-другому. - person rogerio_gentil; 05.10.2013
comment
Похоже на баг ГФ. В этом случае вместо этого транслируйте Part#getInputStream() на FileOutputStream самостоятельно. - person BalusC; 05.10.2013
comment
@rogerio_gentil: Glassfish не поддерживает абсолютные пути к файлам в Part.write(), по-видимому: см. здесь - person Mr_and_Mrs_D; 02.11.2013
comment
Спасибо @Mr_and_Mrs_D! - person rogerio_gentil; 13.02.2014