Загрузка файла не работает с AJAX в PrimeFaces 4.0/JSF 2.2.x - javax.servlet.ServletException: тип содержимого запроса не является мультиформатным/форм-данным
Важно: Проблема, которая обсуждалась в этом потоке, была исправлена от PrimeFaces 5.1 final (релиз сообщества) выпущен в понедельник, октябрь 6, 2014 (всего несколько минут назад). Я попытался выполнить JSF 2.2.8-02 (или api, impl).
Как таковой, если вы использовали эту версию (или выше, не нужно упоминать), вам даже не нужно было бы читать этот вопрос больше.
У меня есть веб-приложение, работающее на
- GlassFish 4.0
- Mojarra 2.2.4
- PrimeFaces 4.0 final
Все, кроме загрузки файлов с помощью AJAX, хорошо работает. Следующий файл xhtml отправляет многостраничное содержимое через запрос AJAX, инициируемый кнопкой команды PrimeFaces.
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:p="http://primefaces.org/ui"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
<title>Test</title>
</h:head>
<h:body>
<h:form prependId="true" enctype="multipart/form-data">
<p:fileUpload id="txtCatImage"
value="#{testManagedBean.uploadedFile}"
mode="advanced"
dragDropSupport="true"
fileLimit="1"
sizeLimit="100000"
multiple="false"
allowTypes="/(\.|\/)(gif|jpe?g|png)$/"
fileUploadListener="#{testManagedBean.fileUploadListener}"/>
<p:message for="txtCatImage" showSummary="false"/>
<p:commandButton id="btnSubmit"
actionListener="#{testManagedBean.insert}"
ajax="true" icon="ui-icon-check" value="Save"/>
</h:form>
</h:body>
</html>
Управляемый тестом bean:
@ManagedBean
@ViewScoped
public final class TestManagedBean implements Serializable {
private static final long serialVersionUID = 1L;
private UploadedFile uploadedFile;
public TestManagedBean(){}
public UploadedFile getUploadedFile() {
return uploadedFile;
}
public void setUploadedFile(UploadedFile uploadedFile) {
this.uploadedFile = uploadedFile;
}
public void fileUploadListener(FileUploadEvent event){
uploadedFile=event.getFile();
}
public void insert(){
if(uploadedFile!=null){
System.out.println(uploadedFile.getFileName());
}
else{
System.out.println("The file object is null.");
}
}
}
Когда файл загружается из браузера файлов, он показывает имя файла в своем слушателе - fileUploadListener()
.
После загрузки файла, когда нажата данная кнопка (ajax="true"
), она вызывает следующее исключение.
WARNING: javax.servlet.ServletException: The request content-type is not a multipart/form-data
javax.faces.FacesException: javax.servlet.ServletException: The request content-type is not a multipart/form-data
at org.primefaces.component.fileupload.NativeFileUploadDecoder.decode(NativeFileUploadDecoder.java:44)
at org.primefaces.component.fileupload.FileUploadRenderer.decode(FileUploadRenderer.java:44)
at javax.faces.component.UIComponentBase.decode(UIComponentBase.java:831)
at javax.faces.component.UIInput.decode(UIInput.java:771)
at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:1225)
at javax.faces.component.UIInput.processDecodes(UIInput.java:676)
at javax.faces.component.UIForm.processDecodes(UIForm.java:225)
at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:1220)
at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:1220)
at javax.faces.component.UIViewRoot.processDecodes(UIViewRoot.java:929)
at com.sun.faces.lifecycle.ApplyRequestValuesPhase.execute(ApplyRequestValuesPhase.java:78)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:646)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:344)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:70)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
at filter.NoCacheFilter.doFilter(NoCacheFilter.java:28)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:316)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:357)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:260)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:188)
at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:191)
at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:168)
at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:189)
at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114)
at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838)
at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544)
at java.lang.Thread.run(Thread.java:722)
Caused by: javax.servlet.ServletException: The request content-type is not a multipart/form-data
at org.apache.catalina.fileupload.Multipart.getPart(Multipart.java:187)
at org.apache.catalina.connector.Request.getPart(Request.java:4535)
at org.apache.catalina.connector.RequestFacade.getPart(RequestFacade.java:1095)
at org.primefaces.component.fileupload.NativeFileUploadDecoder.decodeAdvanced(NativeFileUploadDecoder.java:60)
at org.primefaces.component.fileupload.NativeFileUploadDecoder.decode(NativeFileUploadDecoder.java:37)
... 48 more
SEVERE: javax.servlet.ServletException: The request content-type is not a multipart/form-data
at org.apache.catalina.fileupload.Multipart.getPart(Multipart.java:187)
at org.apache.catalina.connector.Request.getPart(Request.java:4535)
at org.apache.catalina.connector.RequestFacade.getPart(RequestFacade.java:1095)
at org.primefaces.component.fileupload.NativeFileUploadDecoder.decodeAdvanced(NativeFileUploadDecoder.java:60)
at org.primefaces.component.fileupload.NativeFileUploadDecoder.decode(NativeFileUploadDecoder.java:37)
at org.primefaces.component.fileupload.FileUploadRenderer.decode(FileUploadRenderer.java:44)
at javax.faces.component.UIComponentBase.decode(UIComponentBase.java:831)
at javax.faces.component.UIInput.decode(UIInput.java:771)
at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:1225)
at javax.faces.component.UIInput.processDecodes(UIInput.java:676)
at javax.faces.component.UIForm.processDecodes(UIForm.java:225)
at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:1220)
at javax.faces.component.UIComponentBase.processDecodes(UIComponentBase.java:1220)
at javax.faces.component.UIViewRoot.processDecodes(UIViewRoot.java:929)
at com.sun.faces.lifecycle.ApplyRequestValuesPhase.execute(ApplyRequestValuesPhase.java:78)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:646)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:344)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:70)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
at filter.NoCacheFilter.doFilter(NoCacheFilter.java:28)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:256)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:316)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734)
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673)
at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174)
at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:357)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:260)
at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:188)
at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:191)
at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:168)
at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:189)
at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:288)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:206)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:136)
at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:114)
at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:838)
at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:113)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:115)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:55)
at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:135)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:564)
at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:544)
at java.lang.Thread.run(Thread.java:722)
Он может работать только тогда, когда для атрибута ajax кнопки команды установлено значение false - ajax="false"
.
Я понизил версию Mojarra до 2.1.9 в Tomcat 7.0.35. Он работал с этой версией Mojarra вместе с PrimeFaces 4.0 final (и PrimeFaces 4.0 RC1) - файлы, загруженные с помощью запроса AJAX.
Я также попробовал следующие версии Mojarra
- 2.2.0
- 2.2.1
- 2.2.2
- 2.2.3
- 2.2.4
в GlassFish 4.0, но никому из них не удалось загрузить файлы с запросом AJAX, что крайне необходимо, потому что редактирование строк с использованием <p:rowEditor/>
(наряду с изображениями в каждой строке, например) в PrimeFaces DataTable всегда основано на AJAX.
Я хочу держать GlassFish 4.0 в любом случае. Я также попытался понизить Mojarra 2.1.9 в GlassFish 4.0, но не смог создать пакеты, заканчивающиеся на исключение. GlassFish 4.0, похоже, не работает с Mojarra ниже 2.2.x.
Итак, что несет ответственность за причинение этого исключения - PrimeFaces или JSF? Просто смущен. Есть ли способ обхода файлов с запросами AJAX в данной среде?
EDIT:
Отображение фильтра в 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>
<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>*.jsf</url-pattern>
</servlet-mapping>
Проблема остается неподвижной вместе с версией Мохарры 2.2.5 (или api, impl) выпущен от 08 января 2014 года.
Еще раз попробовал версию Mojarra 2.2.6 (или api, impl) выпущен 04 марта 2014 года. Проблема остается нетронутой.
Все еще не работает над PrimeFaces 5.0 окончательный выпущен мая 05, 2014.
Ответы
Ответ 1
У меня была такая же проблема. Похоже, что он больше связан с компонентом <p:commandButton>
, чем <p:fileUpload>
, поскольку он работает с <h:commandButton>
(даже с ajax).
Вы можете попробовать:
<h:commandButton id="btnSubmit" actionListener="#{testManagedBean.insert}" value="Save">
<f:ajax execute="@all" render="@form"/>
</h:commandButton>
Я не могу сказать вам, почему и как это работает, но это устранило проблему для меня.
Недостатком, конечно же, является то, что вы должны сами делать стиль, по крайней мере до тех пор, пока
ребята Primefaces исправляют эту проблему.
ИЗМЕНИТЬ
После копания в источниках и выполнения некоторой отладки, если выяснилось, что на самом деле было сделано два запроса (я пробовал в <p:wizard/>
). Первый - это multipart/form-data
, который фактически загружает файл. Он запускает файл fileUploadEvent в Bean. Я нажимаю следующую кнопку wizards другую форму с enctype application/www-urlencoded
. Это вызывает исключение. Заключение заключается в том, что в отличие от того, что я написал в комментарии, подавляющее исключение, является допустимым решением. Это может быть даже сделано таким образом, что не включает в себя изменение Primefaces.jar, что удобно, если ребята исправляют проблему в будущей версии.
Итак, вот что нужно сделать:
- Создайте новый класс
com.yourpackage.fileupload.FileUploadRenderer
-
Скопируйте и вставьте следующий код в свой новый класс:
package com.yourpackage.fileupload.fileupload;
import java.io.IOException;
import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.servlet.http.HttpServletRequest;
import org.primefaces.component.fileupload.CommonsFileUploadDecoder;
import org.primefaces.component.fileupload.FileUpload;
import org.primefaces.component.fileupload.NativeFileUploadDecoder;
import org.primefaces.config.ConfigContainer;
import org.primefaces.context.RequestContext;
import org.primefaces.expression.SearchExpressionFacade;
import org.primefaces.renderkit.CoreRenderer;
import org.primefaces.util.HTML;
import org.primefaces.util.WidgetBuilder;
public class FileUploadRenderer extends CoreRenderer {
@Override
public void decode(FacesContext context, UIComponent component) {
FileUpload fileUpload = (FileUpload) component;
if (!fileUpload.isDisabled()) {
ConfigContainer cc = RequestContext.getCurrentInstance().getApplicationContext().getConfig();
String uploader = cc.getUploader();
boolean isAtLeastJSF22 = cc.isAtLeastJSF22();
if (uploader.equals("auto")) {
if (isAtLeastJSF22) {
if (isMultiPartRequest(context)) {
NativeFileUploadDecoder.decode(context, fileUpload);
}
} else {
CommonsFileUploadDecoder.decode(context, fileUpload);
}
} else if (uploader.equals("native")) {
if (!isAtLeastJSF22) {
throw new FacesException("native uploader requires at least a JSF 2.2 runtime");
}
NativeFileUploadDecoder.decode(context, fileUpload);
} else if (uploader.equals("commons")) {
CommonsFileUploadDecoder.decode(context, fileUpload);
}
}
}
@Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
FileUpload fileUpload = (FileUpload) component;
encodeMarkup(context, fileUpload);
if (fileUpload.getMode().equals("advanced")) {
encodeScript(context, fileUpload);
}
}
protected void encodeScript(FacesContext context, FileUpload fileUpload) throws IOException {
String clientId = fileUpload.getClientId(context);
String update = fileUpload.getUpdate();
String process = fileUpload.getProcess();
WidgetBuilder wb = getWidgetBuilder(context);
wb.initWithDomReady("FileUpload", fileUpload.resolveWidgetVar(), clientId, "fileupload");
wb.attr("auto", fileUpload.isAuto(), false)
.attr("dnd", fileUpload.isDragDropSupport(), true)
.attr("update", SearchExpressionFacade.resolveComponentsForClient(context, fileUpload, update), null)
.attr("process", SearchExpressionFacade.resolveComponentsForClient(context, fileUpload, process), null)
.attr("maxFileSize", fileUpload.getSizeLimit(), Long.MAX_VALUE)
.attr("fileLimit", fileUpload.getFileLimit(), Integer.MAX_VALUE)
.attr("invalidFileMessage", fileUpload.getInvalidFileMessage(), null)
.attr("invalidSizeMessage", fileUpload.getInvalidSizeMessage(), null)
.attr("fileLimitMessage", fileUpload.getFileLimitMessage(), null)
.attr("messageTemplate", fileUpload.getMessageTemplate(), null)
.attr("previewWidth", fileUpload.getPreviewWidth(), 80)
.attr("disabled", fileUpload.isDisabled(), false)
.callback("onstart", "function()", fileUpload.getOnstart())
.callback("onerror", "function()", fileUpload.getOnerror())
.callback("oncomplete", "function()", fileUpload.getOncomplete());
if (fileUpload.getAllowTypes() != null) {
wb.append(",allowTypes:").append(fileUpload.getAllowTypes());
}
wb.finish();
}
protected void encodeMarkup(FacesContext context, FileUpload fileUpload) throws IOException {
if (fileUpload.getMode().equals("simple")) {
encodeSimpleMarkup(context, fileUpload);
} else {
encodeAdvancedMarkup(context, fileUpload);
}
}
protected void encodeAdvancedMarkup(FacesContext context, FileUpload fileUpload) throws IOException {
ResponseWriter writer = context.getResponseWriter();
String clientId = fileUpload.getClientId(context);
String style = fileUpload.getStyle();
String styleClass = fileUpload.getStyleClass();
styleClass = styleClass == null ? FileUpload.CONTAINER_CLASS : FileUpload.CONTAINER_CLASS + " " + styleClass;
boolean disabled = fileUpload.isDisabled();
writer.startElement("div", fileUpload);
writer.writeAttribute("id", clientId, "id");
writer.writeAttribute("class", styleClass, styleClass);
if (style != null) {
writer.writeAttribute("style", style, "style");
}
//buttonbar
writer.startElement("div", fileUpload);
writer.writeAttribute("class", FileUpload.BUTTON_BAR_CLASS, null);
//choose button
encodeChooseButton(context, fileUpload, disabled);
if (!fileUpload.isAuto()) {
encodeButton(context, fileUpload.getUploadLabel(), FileUpload.UPLOAD_BUTTON_CLASS, "ui-icon-arrowreturnthick-1-n");
encodeButton(context, fileUpload.getCancelLabel(), FileUpload.CANCEL_BUTTON_CLASS, "ui-icon-cancel");
}
writer.endElement("div");
//content
writer.startElement("div", null);
writer.writeAttribute("class", FileUpload.CONTENT_CLASS, null);
writer.startElement("table", null);
writer.writeAttribute("class", FileUpload.FILES_CLASS, null);
writer.startElement("tbody", null);
writer.endElement("tbody");
writer.endElement("table");
writer.endElement("div");
writer.endElement("div");
}
protected void encodeSimpleMarkup(FacesContext context, FileUpload fileUpload) throws IOException {
encodeInputField(context, fileUpload, fileUpload.getClientId(context));
}
protected void encodeChooseButton(FacesContext context, FileUpload fileUpload, boolean disabled) throws IOException {
ResponseWriter writer = context.getResponseWriter();
String clientId = fileUpload.getClientId(context);
String cssClass = HTML.BUTTON_TEXT_ICON_LEFT_BUTTON_CLASS + " " + FileUpload.CHOOSE_BUTTON_CLASS;
if (disabled) {
cssClass += " ui-state-disabled";
}
writer.startElement("span", null);
writer.writeAttribute("class", cssClass, null);
//button icon
writer.startElement("span", null);
writer.writeAttribute("class", HTML.BUTTON_LEFT_ICON_CLASS + " ui-icon-plusthick", null);
writer.endElement("span");
//text
writer.startElement("span", null);
writer.writeAttribute("class", HTML.BUTTON_TEXT_CLASS, null);
writer.writeText(fileUpload.getLabel(), "value");
writer.endElement("span");
if (!disabled) {
encodeInputField(context, fileUpload, clientId + "_input");
}
writer.endElement("span");
}
protected void encodeInputField(FacesContext context, FileUpload fileUpload, String clientId) throws IOException {
ResponseWriter writer = context.getResponseWriter();
writer.startElement("input", null);
writer.writeAttribute("type", "file", null);
writer.writeAttribute("id", clientId, null);
writer.writeAttribute("name", clientId, null);
if (fileUpload.isMultiple()) {
writer.writeAttribute("multiple", "multiple", null);
}
if (fileUpload.getStyle() != null) {
writer.writeAttribute("style", fileUpload.getStyle(), "style");
}
if (fileUpload.getStyleClass() != null) {
writer.writeAttribute("class", fileUpload.getStyleClass(), "styleClass");
}
if (fileUpload.isDisabled()) {
writer.writeAttribute("disabled", "disabled", "disabled");
}
writer.endElement("input");
}
protected void encodeButton(FacesContext context, String label, String styleClass, String icon) throws IOException {
ResponseWriter writer = context.getResponseWriter();
String cssClass = HTML.BUTTON_TEXT_ICON_LEFT_BUTTON_CLASS + " ui-state-disabled " + styleClass;
writer.startElement("button", null);
writer.writeAttribute("type", "button", null);
writer.writeAttribute("class", cssClass, null);
writer.writeAttribute("disabled", "disabled", null);
//button icon
String iconClass = HTML.BUTTON_LEFT_ICON_CLASS;
writer.startElement("span", null);
writer.writeAttribute("class", iconClass + " " + icon, null);
writer.endElement("span");
//text
writer.startElement("span", null);
writer.writeAttribute("class", HTML.BUTTON_TEXT_CLASS, null);
writer.writeText(label, "value");
writer.endElement("span");
writer.endElement("button");
}
private boolean isMultiPartRequest(FacesContext context) {
if (context == null) {
return false;
}
return ((HttpServletRequest) context.getExternalContext().getRequest()).getContentType().startsWith("multipart");
}
}
-
Добавьте следующие строки внизу faces-config.xml
:
<render-kit>
<renderer>
<component-family>org.primefaces.component</component-family>
<renderer-type>org.primefaces.component.FileUploadRenderer</renderer-type>
<renderer-class>com.yourpackage.fileupload.FileUploadRenderer</renderer-class>
</renderer>
</render-kit>
-
Вы готовы к работе!
Что мы сделали? Мы создали собственный FileUploadRenderer, который проверяет, действительно ли contentType multipart/form-data
используется метод isMultiPartRequest()
. Только если это возвращает true, остальная часть кода выполняется. В любом другом случае ничего не произойдет, что означает, что исключение не будет выбрано. Если Primefaces исправляет эту проблему, вам просто нужно удалить строки из faces-config.xml
, чтобы использовать их класс.
Сообщите мне, если это сработает для вас!
ИЗМЕНИТЬ
Этот код проверяет, не имеет ли данный запрос тип multipart/form-data. Если это не прекращение выполнения. Первоначальный код Primefaces будет продолжен. Как я уже упоминал выше, если вы загружаете файл внутри компонента Primefaces, на самом деле выполняются два запроса:
- Ajax-FileUpload с помощью
<p:fileUpload/>
(enctype: multipart/form-data
)
- Действие Ajax в
<p:editRow/>
или <p:wizard/>
(enctype: application/www-form-urlencoded
)
Первый обрабатывается рендерером, а второй вызывает исключение в исходном коде, поскольку рендеринг пытается обрабатывать то, на что он не способен. С изменениями, внесенными только в код, обрабатываются только формами multipart/form-data
, но исключений не происходит. ИМО явно является ошибкой в источниках Primefaces. Различия в коде - это всего лишь метод private boolean isMultiPartRequest(FacesContext context)
и его одно вхождение в коде. Рад, что я могу вам помочь!
Ответ 2
Как Кай по праву указал в свой ответ на текущий вопрос, проблема вызвана NativeFileUploadDecoder
как используется FileUploadRenderer
, не проверяя, является ли запрос является запросом multipart/form-data
или нет. Это вызовет проблемы, когда компонент присутствует в форме, на которую отправляется "обычный" запрос ajax. CommonsFileUploadDecoder
проверяет это правильно и почему он корректно работает в JSF 2.1, у которого еще нет собственного загрузчика файлов.
Его решение обхода этого с помощью специального рендеринга находится в правильном направлении, однако подход довольно неуклюжий. Там в этом конкретном случае абсолютно нет необходимости копировать весь класс, состоящий более чем из 200 строк, чтобы добавить еще несколько строк. Вместо этого просто расширьте именно этот класс и переопределите именно метод с проверкой if перед делегированием супер следующим образом:
package com.example;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import org.primefaces.component.fileupload.FileUploadRenderer;
public class MyFileUploadRenderer extends FileUploadRenderer {
@Override
public void decode(FacesContext context, UIComponent component) {
if (context.getExternalContext().getRequestContentType().toLowerCase().startsWith("multipart/")) {
super.decode(context, component);
}
}
}
Что он (сохраните эту запись <renderer-kit>
в faces-config.xml
, хотя). Нет смысла продолжать декодирование, если запрос не является запросом multipart
. В любом случае части файлов не будут доступны (и также нет смысла возвращаться к API javax.servlet.*
, когда те же функции легко доступны через ExternalContext
).
Ответ 3
Хотя это уже давно и уже ответили, я хотел поделиться чем-то, на всякий случай, если вы его пропустили:
Теперь у PrimeFaces 4+ есть параметр контекста, который вы можете использовать (в web.xml), чтобы вручную выбрать, какой загрузчик следует использовать (native-servlet3 или commons). Вы можете использовать это, чтобы заставить commons-uploader следующим образом:
<context-param>
<param-name>primefaces.UPLOADER</param-name>
<param-value>commons</param-value>
</context-param>
(Конечно, вам все еще нужен FileUploadFilter, как описано выше и в руководстве).
Дополнительную информацию см. В руководстве пользователя PrimeFaces.
Ответ 4
@BalusC - Ваше предложение по расширению существующего FileUploadRenderer
очень чистое. Спасибо!
В зависимости от версии JSF вы можете использовать случайный iFrame. Это ошибка, отмеченная здесь: JAVASERVERFACES-2843
В моей первой попытке исправить это (без обновления до 2.2.1) я просто спрятал iFrame с помощью CSS.
#JSFFrameId {
visibility:hidden;
}
Это сработало, но почему-то дополнительные сообщения AJAX не срабатывали. Затем я вызвал небольшой script, чтобы удалить iFrame и устранил проблему.
<h:commandButton id="btnSubmit" action="#{fileUploadController.upload}" value="Save" >
<f:ajax execute="@all" render="frmMain" onevent="removeIFrame()" />
</h:commandButton>
JavaScript:
function removeIFrame()
{
document.getElementById("JSFFrameId").removeNode();
}
Ответ 5
У меня была такая же проблема,
В моем случае я использовал файл загрузки файлов primefaces в таблице данных, попытался изменить существующее изображение, используя onRowEdit, в результате чего была упомянута выше упомянутая ошибка.
Затем я изменил размерность jars на 5.1. Теперь он работает отлично.