Uploading files with PrimeFaces 4.0 , and jsf 2.2

2019-07-28 17:16发布

I'm using: -primefaces 4.0 -jsf mojarra 2.2 -google app engine (servlet api 2.5) and this solution (Getting primefaces p:fileUpload to work under google appengine) doesn't help me because my version of primefaces is higher. There is exception when I'm using my form below with p:commandButton:

java.lang.NoSuchMethodError: javax.servlet.http.HttpServletRequest.getPart(Ljava/lang/String;)Ljavax/servlet/http/Part;
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)
....

and this is because google don't support servlet api 3.0. I realy can't find a solution for now. Running primefaces 3.5 is not a option because the project is with JSF 2.2 and 2.2 is not compatible with primefaces 3.5.

One usable comment from this topic: How to use PrimeFaces p:fileUpload? Listener method is never invoked or UploadedFile is null

Update: since PrimeFaces 4.x, when used in combination with JSF 2.2 and Servlet 3.0, the filter is not necessary anymore. The Servlet 3.0 / JSF 2.2 native API will be used instead of Apache Commons FileUpload. Other rules however still apply and from the possible causes you can scratch #1 and #2.

My form:

<h:form enctype="multipart/form-data">
<p:fileUpload id="filePhoto" fileUploadListener="#{atlasCasesMB.handleFileUpload}" mode="advanced" dragDropSupport="false"  
    update=":messages" sizeLimit="614400" fileLimit="3" allowTypes="/(\.|\/)(gif|jpe?g|png)$/" />
</h:form>

In this form fileUploadListener is not invoked.

I've tried to use the solution from this topic: Getting primefaces p:fileUpload to work under google appengine modify the DiskFileItem), but obviously this cannot help because JSF 2.2 uses native API instead of Apache Commons FileUpload.

    <filter>
    <filter-name>PrimeFaces FileUpload Filter</filter-name>
    <filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
    <init-param>
        <param-name>thresholdSize</param-name>
        <param-value>2147483647</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>PrimeFaces FileUpload Filter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>

Any suggestions? (Downgrading primefaces and jsf is not an option because the project is in final stage)

The solution ,that I tried, is to force primefaces to use apache common file upload (commons-fileupload-1.3.jar) using this:

<context-param>
  <param-name>primefaces.UPLOADER</param-name>
  <param-value>commons</param-value>
</context-param>

Then I used the filter:

<filter>
    <filter-name>PrimeFaces FileUpload Filter</filter-name>
    <filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
    <init-param>
        <param-name>thresholdSize</param-name>
        <param-value>2147483647</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>PrimeFaces FileUpload Filter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>

important here is to set thresholdSize so big that write method in some of the apache common classes(I forgot which) is not invoked. And finally add the filter FileUploadFilter from primefaces 4.0 source files: http://www.primefaces.org/downloads.html

All sources that I used to get to this point:

http://davebarber.blog.com/2010/10/15/jsf-2-0-on-google-app-engine/

PrimeFaces 4.0 FileUpload works with Mojarra 2.2 but not MyFaces 2.2

How to use PrimeFaces p:fileUpload? Listener method is never invoked or UploadedFile is null

Getting primefaces p:fileUpload to work under google appengine

This fires :

java.lang.verifyerror inconsistent stackmap frames at branch target

1条回答
萌系小妹纸
2楼-- · 2019-07-28 18:16

To prevent primefaces to use its native file upload, add the following parameter.

<context-param>
  <param-name>primefaces.UPLOADER</param-name>
  <param-value>commons</param-value>
</context-param>

Then I used the filter:

<filter>
    <filter-name>PrimeFaces FileUpload Filter</filter-name>
    <filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
    <init-param>
        <param-name>thresholdSize</param-name>
        <param-value>2147483647</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>PrimeFaces FileUpload Filter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>

important here is to set thresholdSize so big that write method in some of the apache common classes(I forgot which) is not invoked. And finally add the filter FileUploadFilter from primefaces 4.0 modified:

package org.primefaces.webapp.filter;

import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.gmr.web.multipart.GFileItemFactory;
import org.primefaces.webapp.MultipartRequest;

public class FileUploadFilter implements Filter {

    private final static Logger logger = Logger.getLogger(FileUploadFilter.class.getName());

    private final static String THRESHOLD_SIZE_PARAM = "thresholdSize";

    private final static String UPLOAD_DIRECTORY_PARAM = "uploadDirectory";

    private String thresholdSize;

    private String uploadDir;

    public void init(FilterConfig filterConfig) throws ServletException {
        thresholdSize = filterConfig.getInitParameter(THRESHOLD_SIZE_PARAM);
        uploadDir = filterConfig.getInitParameter(UPLOAD_DIRECTORY_PARAM);

        logger.warning("init:uploadDir=" + uploadDir + "; thresholdSize=" + thresholdSize);
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        boolean isMultipart = ServletFileUpload.isMultipartContent(httpServletRequest);

        if (isMultipart) {
                logger.warning("Parsing file upload request");

            // start change
            FileItemFactory diskFileItemFactory = new GFileItemFactory();
            /*
             * if(thresholdSize != null) { diskFileItemFactory.setSizeThreshold(Integer.valueOf(thresholdSize)); } if(uploadDir != null) { diskFileItemFactory.setRepository(new File(uploadDir)); }
             */
            // end change

            ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
            MultipartRequest multipartRequest = new MultipartRequest(httpServletRequest, servletFileUpload);

            if (logger.isLoggable(Level.FINE))
                logger.fine("File upload request parsed succesfully, continuing with filter chain with a wrapped multipart request");

            filterChain.doFilter(multipartRequest, response);
        } else {
            filterChain.doFilter(request, response);
        }
    }

    public void destroy() {
        if (logger.isLoggable(Level.FINE))
            logger.fine("Destroying FileUploadFilter");
    }

}

Form:

<h:form >
<p:fileUpload id="filePhoto" fileUploadListener="#{atlasCasesMB.handleFileUpload}" mode="advanced" dragDropSupport="false"
                    update=":messages" sizeLimit="614400" fileLimit="3" allowTypes="/(\.|\/)(gif|jpe?g|png)$/" />
                <br />
<p:commandButton value="#{bundle['save']}" actionListener="#{atlasCasesMB.saveCase}"  process="@form" />
</h:form>

File upload handler:

public void handleFileUpload(FileUploadEvent event) {
        log.warning("handleFileUpload(FileUploadEvent event)");
        UploadedFile uploadedFile = event.getFile();
        photosArr.add(uploadedFile.getContents());
        //photos.add(new File(uploadedFile.getFileName()));
        FacesMessage msg = new FacesMessage("Succesful", event.getFile().getFileName() + " is uploaded.");  
        FacesContext.getCurrentInstance().addMessage(null, msg);
    }

List of byte array photos:

private List<byte[]> photosArr;

libraries:

  • commons-fileupload-1.3.jar
  • commons-io-2.4.jar
  • gmultipart-0.2.jar
  • portlet-2.0.jar
  • primefaces-4.0.jar

DiskFileItem: comment UID and inside of write method

and ViewScoped Bean

========================================

there is second way to do this: using multipart request to jersey:

<p:dialog id="upladPhotoDialog" widgetVar="upladPhotoDlg" header="#{bundle['uploading.photos']}" >
    <form action="rest/case" method="post" enctype="multipart/form-data">
        <p>#{bundle['upload.photo.select.images.to.upload']}</p>
    <br />
    <input id="photo1" type="file" name="photo1" />
    <br />
    <input id="photo2" type="file" name="photo2" />
    <br />
    <input id="photo3" type="file" name="photo3" />
    <br />
    <input id="caseId" type="text" name="caseId" style="display:none" value="#{atlasCasesMB.savedCaseId}" />
    <br />
    <input id="btn-post" class="active btn" type="submit" value="Send" />
</form>

@POST
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public void insertPhotoForCase (
            @FormDataParam("photo1") InputStream photoIS1,
            @FormDataParam("photo2") InputStream photoIS2,
            @FormDataParam("photo3") InputStream photoIS3,
            @FormDataParam("caseId") String caseId , @Context HttpServletRequest httpRequest , @Context HttpServletResponse httpResponse) {
        try {
            DataService<Case> das = new CaseDataService();
            Case caze = das.find(Integer.parseInt(caseId));
            byte[] photoBytes = IOUtils.toByteArray(photoIS1);
            if(photoBytes.length != 0 ){
                sendPhotoToBlob (createPhoto(caze).getId() ,photoBytes);
            }
            photoBytes = IOUtils.toByteArray(photoIS2);
            if(photoBytes.length != 0 ){
                sendPhotoToBlob (createPhoto(caze).getId() ,photoBytes);
            }
            photoBytes = IOUtils.toByteArray(photoIS3);
            if(photoBytes.length != 0 ){
                sendPhotoToBlob (createPhoto(caze).getId() ,photoBytes);
            }
            //currentResponse.sendRedirect("/atlascases.xhtml");
            _context.getRequestDispatcher("/atlascases.xhtml").forward(httpRequest, httpResponse);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

file:jersey-multipart-config.properties in src folder with text inside:

bufferThreshold = -1

in web.xml

    <servlet>
    <servlet-name>Jersey REST Service</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>com.sun.jersey.config.property.packages</param-name>
        <param-value>com.smartinteractive.medimaging.service</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>Jersey REST Service</servlet-name>
    <url-pattern>/rest/*</url-pattern>
</servlet-mapping>
查看更多
登录 后发表回答