How to process multipart requests in Java Server Faces

This post describes how multipart/form-data requests can be processed within a Java Server Faces managed bean in order to implement file uploads.

First, intercept the servlet request and wrap it in custom HttpServletRequestWrapper before passing it to FacesServlet for further processing. This is achieved via a web filter, as follows.

@WebFilter(urlPatterns = "/*")
public class MultipartRequestFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest httpServletRequest;
        if (request instanceof ServletRequest) {
            httpServletRequest = (HttpServletRequest) request;
        } else if (request instanceof ServletRequestWrapper) {
            httpServletRequest = (HttpServletRequest) ((ServletRequestWrapper)request).getRequest();
        } else {
	    throw new UnsupportedOperationException("Not implemented");
	}
        if (isMultipartRequest(httpServletRequest)) {
            request = new MultipartServletRequestWrapper(httpServletRequest);
        }
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
    }

    private boolean isMultipartRequest(HttpServletRequest request) {
        return "POST".equalsIgnoreCase(request.getMethod()) &&
                request.getContentType() != null &&
                request.getContentType().toLowerCase().startsWith("multipart/");
    }
}

This code extract shows the request being checked, transformed into a MultipartServletRequestWrapper, and passed down the filter chain.

Next, implement MultipartServletRequestWrapper, as follows.

public class MultipartServletRequestWrapper extends HttpServletRequestWrapper {
    private Hashtable<String , Part> managedParts = new Hashtable<>();

    public MultipartServletRequestWrapper(HttpServletRequest request) throws IOException, ServletException {
		super(request);
		readParts(request);
    }

    @Override
    public String getParameter(String name) {
        String[] parameterValues = getParameterValues(name);
        return parameterValues.length > 0 ? parameterValues[0] : null;
    }

    @Override
    public Enumeration<String> getParameterNames() {
        return managedParts.keys();
    }

    @Override
    public String[] getParameterValues(String name) {
        Part p = managedParts.get(name);
        if (null == p) return new String[0];
        byte[] b = new byte[(int) p.getSize()];
        try {
            p.getInputStream().read(b);
            return new String[]{new String(b)};
        } catch (IOException ex) {
            return new String[0];
        }
    }

    @Override
    public Map<String , String[]> getParameterMap() {
        HashMap<String , String[]> map = new HashMap<>();
        Enumeration<String> keys = managedParts.keys();
        while (keys.hasMoreElements()) {
            String key = keys.nextElement();
            map.put(key, getParameterValues(key));
        }
        return map;
    }

    private void readParts(HttpServletRequest request) throws IOException, ServletException {
        for (Part part : request.getParts()) {
            managedParts.put(part.getName(), part);
        }
    }
}

Overriding the getParameter* methods is the crucial part of this class; without these, JSF is unable to restore views and by extension process the submission.

Finally, in your bean, obtain the part that contains the file upload and process it as desired.

@ManagedBean(name="fileUploadBean")
@RequestScoped
public class FileUploadBean {

    public String upload() throws FileNotFoundException, IOException, ServletException {
        ServletRequest servletRequest = (ServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
        if (servletRequest instanceof MultipartServletRequestWrapper) {
            Part part = ((MultipartServletRequestWrapper) servletRequest).getPart("fileUpload");
            String header = part.getHeader("Content-disposition");
            String filename = header.substring(header.indexOf("filename=") + "filename=".length());
            if ((null != filename) && (0 < filename.length())) {
                FileOutputStream fos = new FileOutputStream("C:\\Temp\\test.png");
                byte[] b = new byte[(int) part.getSize()];
                part.getInputStream().read(b);
                fos.write(b);
                fos.close();
            }
        }
        return null;
    }
}

This bean here reads the content of the part and writes it to file.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>