h:commandButton is not firing action if the h:form has enctype=“multipart/form-data”

生来就可爱ヽ(ⅴ<●) 提交于 2019-12-01 08:20:49

问题


JSF: 1.2

Server: Weblogic

I am trying to implement multiple file upload. As I need to give support for IE7 so I cannot use HTML5 input file. So I have planned to add a button, on clicking it will add a input file in the page.

Primarily I have started my work with ADF Faces. But that didn't worked. That was behaving in unexpected way.

I have also tried Tomahawk's file upload component, but the problem was with this component that after adding a new file upload from the backend the previously created file upload fields were get empty; not the UploadedFile instance. But this will not meet my requirement. As I need to show all the path in the file uploaders until the final Submit form button has been clicked.

Then I took help of apache commons fileupload.

I have tried this with pure JSP and apaches fileupload and that worked well.

But I want to implement it with JSF with apaches fileupload, and when I tried to do this it started causing issues.

The jspx page is given below:

<?xml version='1.0' encoding='utf-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns:h="http://java.sun.com/jsf/html">
  <jsp:output omit-xml-declaration="true" doctype-root-element="HTML"
              doctype-system="http://www.w3.org/TR/html4/loose.dtd"
              doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN"/>
  <jsp:directive.page contentType="text/html;charset=utf-8"/>
  <f:view>
    <html>
      <head>
        <meta http-equiv="Content-Type"
              content="text/html; charset=utf-8"/>
        <title>home</title>
      </head>
      <body>
        <h:form enctype="multipart/form-data">
            <input type="file" name="file"/>
            <h:commandButton value="Upload" action="#{uploadBean.upload}" />
        </h:form>
      </body>
    </html>
  </f:view>
</jsp:root>

I have created a filter as I cannot get the proper multipart request from the action event.

The web.xml is:

<?xml version = '1.0' encoding = 'windows-1252'?>
<web-app 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_2_5.xsd"
         version="2.5" xmlns="http://java.sun.com/xml/ns/javaee">
  <context-param>
    <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
    <param-value>server</param-value>
  </context-param>
  <filter>
    <filter-name>UploadFilter</filter-name>
    <filter-class>com.edfx.massupload.filter.UploadFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>UploadFilter</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>/faces/*</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>/home.jspx</welcome-file>
  </welcome-file-list>
</web-app>

The UploadFilter:

import java.io.IOException;

import java.util.ArrayList;
import java.util.List;

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.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;


public class UploadFilter implements Filter {
    private FilterConfig _filterConfig = null;

    public void init(FilterConfig filterConfig) throws ServletException {
        _filterConfig = filterConfig;
    }

    public void destroy() {
        _filterConfig = null;
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("Filter");
        if (!(request instanceof HttpServletRequest)) {
            chain.doFilter(request, response);
            return;
        }

        HttpServletRequest httpRequest = (HttpServletRequest)request;

        boolean isMultipartContent = ServletFileUpload.isMultipartContent(httpRequest);

        if (!isMultipartContent) {
            chain.doFilter(request, response);
            return;
        }

        long maxFileSize = (1024 * 1024 * 1024);
        DiskFileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload upload = new ServletFileUpload(factory);
        upload.setHeaderEncoding("UTF-8");
        upload.setSizeMax(maxFileSize);
        upload.setFileSizeMax(maxFileSize);

        try {
            List<FileItem> items = upload.parseRequest(httpRequest);
            System.out.println(items.size());
            List<FileItem> files = new ArrayList<FileItem>();            
            for (FileItem item : items) {
                if (!item.isFormField()) {
                    files.add(item);
                }
            }

            httpRequest.setAttribute("files", files);
        } catch (FileUploadException ex) {
            ex.printStackTrace();
        }        

        chain.doFilter(request, response);
    }
}

And lastly the managed bean:

import javax.faces.context.FacesContext;

import javax.servlet.http.HttpServletRequest;

public class UploadBean {
    public UploadBean() {
        super();
    }

    public String upload() {
        System.out.println("====JYM");
        HttpServletRequest httpRequest = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
        System.out.println(httpRequest.getAttribute("files"));
        return "";
    }
}

My aim is to add the input file field dynamically by JavaScript or jQuery, which works well in JSP, I want to get that in JSF.

If I remove the enctype="multipart/form-data" from the h:form then the action method is executing, otherwise not.

Any suggestion would be very helpful to me.


回答1:


Here,

for (FileItem item : items) {
    if (!item.isFormField()) {
        files.add(item);
    }
}

you're ignoring all form fields, such as the button itself. When continuing such a request, JSF will have no clue that a button was been invoked and thus not queue any action at all.

You need to add an else to collect all form fields in a Map<String, String[]> and wrap the request with a HttpServletRequestWrapper which delegates to that map on all getParameterXxx() calls and finally continue the filter chain with the wrapped request. This way JSF will find out that the button was invoked and then queue to the proper action.




回答2:


As @BalusC instructed:

import java.io.IOException;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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 javax.servlet.http.HttpServletRequestWrapper;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;


public class UploadFilter implements Filter {
    private FilterConfig filterConfig = null;

    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }

    public void destroy() {
        this.filterConfig = null;
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        if (!(request instanceof HttpServletRequest)) {
            chain.doFilter(request, response);
            return;
        }

        HttpServletRequest httpRequest = (HttpServletRequest)request;

        boolean isMultipartContent = ServletFileUpload.isMultipartContent(httpRequest);

        if (!isMultipartContent) {
            chain.doFilter(request, response);
            return;
        }        

        try {
            DiskFileItemFactory factory = new DiskFileItemFactory();
            ServletFileUpload upload = new ServletFileUpload(factory);
            upload.setHeaderEncoding("UTF-8");
            upload.setSizeMax(-1);

            List<FileItem> items = upload.parseRequest(httpRequest);
            final Map<String, String[]> parameterMap = new HashMap<String, String[]>();

            for (FileItem item : items) {
                if (item.isFormField()) {
                    processFormField(item, parameterMap);
                } else {
                    processFileField(item, httpRequest);
                }
            }

            chain.doFilter(new HttpServletRequestWrapper(httpRequest) {

                    public Map<String, String[]> getParameterMap() {
                        return parameterMap;
                    }

                    public String[] getParameterValues(String name) {
                        return (String[])parameterMap.get(name);
                    }

                    public String getParameter(String name) {
                        String[] params = getParameterValues(name);
                        if (params == null) {
                            return null;
                        }
                        return params[0];
                    }

                    public Enumeration<String> getParameterNames() {
                        return Collections.enumeration(parameterMap.keySet());
                    }
                }, response);
        } catch (Exception ex) {
            ServletException servletException = new ServletException();
            servletException.initCause(ex);
            throw servletException;
        }
    }

    private void processFormField(FileItem formField, Map<String, String[]> parameterMap) {
        String name = formField.getFieldName();
        String value = formField.getString();
        String[] values = parameterMap.get(name);

        if (values == null) {
            parameterMap.put(name, new String[] { value });
        } else {
            int length = values.length;
            String[] newValues = new String[length + 1];
            System.arraycopy(values, 0, newValues, 0, length);
            newValues[length] = value;
            parameterMap.put(name, newValues);
        }
    }

    private void processFileField(FileItem fileField, HttpServletRequest request) {
        if (request.getAttribute(fileField.getFieldName()) == null) {
            List<FileItem> fileFields = new ArrayList<FileItem>(0);
            fileFields.add(fileField);
            request.setAttribute(fileField.getFieldName(), fileFields);
        } else {
            List<FileItem> fileFields = (List<FileItem>)request.getAttribute(fileField.getFieldName());
            fileFields.add(fileField);
        }
    }
}

Since I will have multiple input file component; so I have used List to store all the file fields in the method processFileField and then have set it to the request.



来源:https://stackoverflow.com/questions/14242293/hcommandbutton-is-not-firing-action-if-the-hform-has-enctype-multipart-form-d

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!