Загрузка файла 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:
Вы должны добавить 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)