Загрузка файла JSF 2.0

Я просматриваю несколько блогов, пытаясь найти способ загрузки файлов с использованием JSF 2.0. Но все решения меня смущают. Я хотел бы знать, что именно мне нужно, чтобы иметь возможность успешно загрузить файл (MP3, PDF, видео... любой тип текста) и сохранить его в базе данных как @Lob. Это то, что я сделал до сих пор:

  • Я создал объект, который имеет атрибут типа byte[], и он также помечен аннотацией @Lob.

  • Я создал EJB-компонент, который представит сущность с методом, у которого в качестве параметра есть byte[], и вставит его в базу данных с помощью класса EntityManager (метод persist).

  • Я создал страницу JSF с тегом ввода типа "файл" и кнопкой отправки

  • Я подготовил управляемый компонент для обмена информацией о файле со страницей JSF.

Теперь я застрял, и у меня много сомнений:

  • Что я должен сделать, чтобы передать файл из JSF в управляемый компонент, а затем преобразовать его в байт [](чтобы можно было передать его в EJB)?

  • Как мне может помочь сервлет?

  • Нужен ли сервлет для этого?

  • Также я обнаружил, что в каком-то блоге упоминается что-то о сервлетах 3.0, но я не знаю, использует ли это моя рабочая среда, как, если я использую сервлеты 3.0 (я использую JEE6)?

Я никогда не загружал файлы раньше, а также я не очень знаком с сервлетами. Я в замешательстве, кто-то может дать мне несколько советов, пожалуйста?

8 ответов

Решение

Прежде всего, этот (старый) вопрос и ответ предполагает JSF 2.0/2.1. Начиная с JSF 2.2 есть родной <h:inputFile> компонент без необходимости использования сторонних библиотек компонентов. Смотрите также Как загрузить файл с использованием JSF 2.2 ? Где находится сохраненный файл?


Самый простой способ - использовать Томагавк для JSF 2.0. Он предлагает<t:inputFileUpload> составная часть.

Вот пошаговое руководство:

  • Создайте пустой динамический веб-проект для Servlet 3.0 и JSF 2.0. web.xml должен соответствовать спецификации Servlet 3.0 и уже содержать сервлет JSF:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app 
        xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
        id="YourProjectName" version="3.0">
    
        <display-name>Your Project Name</display-name>
    
        <servlet>
            <servlet-name>Faces Servlet</servlet-name>
            <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>Faces Servlet</servlet-name>
            <url-pattern>*.xhtml</url-pattern>
        </servlet-mapping>
    
    </web-app>
    

    faces-config.xml должен соответствовать спецификации JSF 2.0:

    <?xml version="1.0" encoding="UTF-8"?>
    <faces-config
        xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
        version="2.0">
    
    </faces-config>
    

  • Загрузите Томагавк 1.1.10 для JSF 2.0. Извлеките zip-файл, перейдите к /lib папку и скопировать все *.jar файлы в ваш /WEB-INF/lib,

    Это 18 файлов, из которых batik*.jar а также xml*.jar не нужны для использования в одиночку t:inputFileUpload составная часть. Вы могли бы оставить их подальше.


  • Настройте фильтр расширений Томагавк в web.xml, Это тот, кто отвечает за обработку multipart/form-data запросы, которые необходимы для возможности отправки файлов по HTTP.

    <filter>
        <filter-name>MyFacesExtensionsFilter</filter-name>
        <filter-class>org.apache.myfaces.webapp.filter.ExtensionsFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>MyFacesExtensionsFilter</filter-name>
        <servlet-name>Faces Servlet</servlet-name>
    </filter-mapping>
    

    Обратите внимание, что <servlet-name> должен соответствовать точно <servlet-name> из FacesServlet как вы определили в web.xml,


  • Создать простой Facelet, upload.xhtml:

    <!DOCTYPE html>
    <html lang="en"
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:f="http://java.sun.com/jsf/core"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:t="http://myfaces.apache.org/tomahawk"
        xmlns:ui="http://java.sun.com/jsf/facelets">
        <h:head>
            <title>Tomahawk file upload demo</title>
        </h:head>
        <h:body>
            <h:form enctype="multipart/form-data">
                <t:inputFileUpload value="#{bean.uploadedFile}" />
                <h:commandButton value="submit" action="#{bean.submit}" />
                <h:messages />
            </h:form>
        </h:body> 
    </html>
    

    Обратите внимание enctype="multipart/form-data" атрибут на <h:form>это очень важно для возможности отправки файлов с HTTP.


  • Создать простой управляемый компонент, com.example.Bean:

    package com.example;
    
    import java.io.IOException;
    
    import javax.faces.application.FacesMessage;
    import javax.faces.bean.ManagedBean;
    import javax.faces.bean.RequestScoped;
    import javax.faces.context.FacesContext;
    
    import org.apache.commons.io.FilenameUtils;
    import org.apache.myfaces.custom.fileupload.UploadedFile;
    
    @ManagedBean
    @RequestScoped
    public class Bean {
    
        private UploadedFile uploadedFile;
    
        public void submit() throws IOException {
            String fileName = FilenameUtils.getName(uploadedFile.getName());
            String contentType = uploadedFile.getContentType();
            byte[] bytes = uploadedFile.getBytes();
    
            // Now you can save bytes in DB (and also content type?)
    
            FacesContext.getCurrentInstance().addMessage(null, 
                new FacesMessage(String.format("File '%s' of type '%s' successfully uploaded!", fileName, contentType)));
        }
    
        public UploadedFile getUploadedFile() {
            return uploadedFile;
        }
    
        public void setUploadedFile(UploadedFile uploadedFile) {
            this.uploadedFile = uploadedFile;
        }
    
    }
    

Это должно быть так. Откройте его по http://localhost:8080/projectname/upload.xhtml.

Что касается ваших конкретных вопросов:

Что я должен сделать, чтобы передать файл из JSF в управляемый компонент, а затем преобразовать его в байт [](чтобы можно было передать его в EJB)?

Это ответ выше.

Как мне может помочь сервлет?

Он способен обрабатывать и контролировать HTTP-запросы / ответы. В среде JSF FacesServlet уже делает всю работу.

Нужен ли мне сервлет для этого?

В среде JSF FacesServlet является обязательным. Но это уже предусмотрено API, вам не нужно писать его самостоятельно. Однако, чтобы иметь возможность загружать файлы из базы данных, определенно полезен другой сервлет. Вы можете найти базовый пример здесь: Сервлет для обслуживания статического контента.

Также я обнаружил, что в каком-то блоге упоминается что-то о сервлетах 3.0, но я не знаю, использует ли это моя рабочая среда, как, если я использую сервлеты 3.0(я использую JEE6)?

Если вы используете контейнер Servlet 3.0, такой как Glassfish 3, JBoss AS 6, Tomcat 7 и т. Д., И web.xml объявлен как Servlet 3.0, то вы определенно используете Servlet 3.0. Сервлет 3.0 является частью Java EE 6.

Для полноты картины я просто хочу привести полностью функциональный автономный пример того, как это делается с помощью JSF 2.2, либо с запросами не-Ajax и Ajax. Имейте в виду, что JSF 2.2 использует разные пространства имен, и вам нужно работать с контейнером Servlet 3.0 (как Tomcat 7.0.x, JBoss AS 6.x и 7.x и GlassFish 3.x).

fileUpload.xhtml

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head />
<h:body>
    <h:form enctype="multipart/form-data">
        <h:inputFile value="#{uploadBean.file}" />
        <h:commandButton value="Post Upload" action="#{uploadBean.upload}" />
    </h:form>
    <h:form enctype="multipart/form-data">
        <h:inputFile value="#{uploadBean.file}" />
        <h:commandButton value="Ajax Upload">
            <f:ajax listener="#{uploadBean.upload}" execute="@form"
                render="countOutput" />
        </h:commandButton>
    <!-- Counts the uploaded items -->
    <h:outputText id="countOutput"
        value="Files uploaded #{uploadBean.filesUploaded}" />
    </h:form>
</h:body>
</html>

UploadBean.java:

@ManagedBean
@ViewScoped
public class UploadBean {

    private int filesUploaded = 0;

    //javax.servlet.http.Part (Servlet 3.0 API)
    private Part file;
    private String fileContent;

    /**
     * Just prints out file content
     */
    public void upload() {
        try {
            fileContent = new Scanner(file.getInputStream())
                    .useDelimiter("\\A").next();
            System.out.println(fileContent + " uploaded");
            filesUploaded++;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public int getFilesUploaded() {
        return filesUploaded;
    }

    public Part getFile() {
        return file;
    }

    public void setFile(Part file) {
        this.file = file;
    }
}

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

Я бы порекомендовал использовать такую ​​библиотеку, как Томагавк<t:inputFileUpload> или PrimeFaces<p:fileUpload>,

У BalusC также есть хороший пост в блоге о загрузке файлов с помощью JSF 2.0 и Servlet 3.0.

Сообщение в блоге BalusC: загрузка файлов с помощью JSF 2.0 и Servlet 3.0 - это то, что спасло меня, потому что у меня были проблемы с запуском тега RichFaces 4 fileUpload с Spring WebFlow.

Стоит изменить код BalusC, чтобы использовать Spring MultipartResolver - тебе не нужен его MultipartMap из другого поста в блоге.

Я достиг этого, изменив decode метод в FileRenderer как это:

    UploadedFile ret = null;

    Object req = context.getExternalContext().getRequest();
    if (req instanceof MultipartHttpServletRequest) {
      MultipartFile file = ((MultipartHttpServletRequest)req).getFile(clientId);

      File temp = null;
      try {
        temp = File.createTempFile("_UPLOAD_", null);
        file.transferTo(temp);

        String name = new File(file.getOriginalFilename()).getName();
        ret = new UploadedFile(temp, name);

      } catch (IOException e) {
        throw new RuntimeException("Could not create temp file.", e);
      }
    } else {
      throw new IllegalStateException("Request is not multipart. Use spring's multipart resolver.");
    }
    // If no file is specified, set empty String to trigger validators.
    ((UIInput) component).setSubmittedValue( ret == null ? EMPTY_STRING : ret);

UploadedFile это простой сериализуемый POJO, используемый для возврата результатов в бэк.

В JSF 2.2 вы можете легко загрузить файл, используя тег, без использования commons-io или фильтра. Этот тег поддерживает как обычный, так и AJAX процесс.

Нормальный:

    <h:inputFile id="file"  value="#{fileUploadBean.uploadedFile}"/> 
    <h:commandButton id="button" action="#{fileUploadBean.sumbit()}" value="Upload"/>

Ajax:

    <h:inputFile id="file" value="#{fileUploadBean.uploadedFile}"/> 
    <h:commandButton id="button" value="submit">
      <f:ajax execute="@all" render="@all" onevent="statusUpdate"/>
    </h:commandButton>

Создайте свой управляемый компонент следующим образом:

  @Named
  @RequestScoped
  public class FileUploadBean {

   private Part uploadedFile;

  }

Самый простой способ - это использовать тег inputFileUpload, который вы можете найти в MyFaces:

http://myfaces.apache.org/

Вы должны добавить commons-fileupload-1.2.1.jar в нашем проекте Build Path

1. Настройте файл web.xml:

Web.xml

    <filter>
        <filter-name>PrimeFaces FileUpload Filter</filter-name>
        <filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>PrimeFaces FileUpload Filter</filter-name>
        <servlet-name>Faces Servlet</servlet-name>
    </filter-mapping>
    <mime-mapping>        
        <extension>png</extension>
        <mime-type>image/png</mime-type>
    </mime-mapping>

2. Создать ManagedBean

   @ManagedBean
   @SessionScoped
public class FileUploadBean implements Serializable{
public FileUpload (){
}
  private StreamedContent file;
public void loadFile(FileUploadEvent event) throws IOException, InterruptedException {

        InputStream input = new ByteArrayInputStream(event.getFile().getContents());
        file= new DefaultStreamedContent(input, "image/jpg");
    }
}

3.jsf файл (xhtml)

   <h:form enctype="multipart/form-data"> 
         <p:fileUpload fileUploadListener="#{fileUploadBean.file}" sizeLimit="100000" allowTypes="/(\.|\/)(gif|jpe?g|png|bmp)$/"/>
        </h:form>

IceFaces2.0 имеет один, http://wiki.icefaces.org/display/ICE/FileEntry Еще не пытался его реализовать, но в загрузке есть примеры приложений, и он работает под Tomcat 6 (сервлет 2.5, поэтому не JEE6)

Другие вопросы по тегам