Java tutorial
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package filter; /** * * @author TrungHTH */ 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.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; 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; @WebFilter(filterName = "MultipartRequestFilter") public class MultipartRequestFilter implements Filter { // Init --------------------------------------------------------------------------------------- private long maxFileSize; // Actions ------------------------------------------------------------------------------------ /** * Configure the 'maxFileSize' parameter. * @throws ServletException If 'maxFileSize' parameter value is not numeric. * @see javax.servlet.Filter#init(javax.servlet.FilterConfig) */ public void init(FilterConfig filterConfig) throws ServletException { // Configure maxFileSize. String maxFileSize = filterConfig.getInitParameter("maxFileSize"); if (maxFileSize != null) { if (!maxFileSize.matches("^\\d+$")) { throw new ServletException("MultipartFilter 'maxFileSize' is not numeric."); } this.maxFileSize = Long.parseLong(maxFileSize); } } /** * Check the type request and if it is a HttpServletRequest, then parse the request. * @throws ServletException If parsing of the given HttpServletRequest fails. * @see javax.servlet.Filter#doFilter( * javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException { System.out.println("filter: request map = " + request.getParameterMap()); // Check type request. if (request instanceof HttpServletRequest) { // Cast back to HttpServletRequest. HttpServletRequest httpRequest = (HttpServletRequest) request; // Parse HttpServletRequest. HttpServletRequest parsedRequest = parseRequest(httpRequest); // Continue with filter chain. chain.doFilter(parsedRequest, response); } else { // Not a HttpServletRequest. chain.doFilter(request, response); } } /** * @see javax.servlet.Filter#destroy() */ public void destroy() { // I am a boring method. } // Helpers ------------------------------------------------------------------------------------ /** * Parse the given HttpServletRequest. If the request is a multipart request, then all multipart * request items will be processed, else the request will be returned unchanged. During the * processing of all multipart request items, the name and value of each regular form field will * be added to the parameterMap of the HttpServletRequest. The name and File object of each form * file field will be added as attribute of the given HttpServletRequest. If a * FileUploadException has occurred when the file size has exceeded the maximum file size, then * the FileUploadException will be added as attribute value instead of the FileItem object. * @param request The HttpServletRequest to be checked and parsed as multipart request. * @return The parsed HttpServletRequest. * @throws ServletException If parsing of the given HttpServletRequest fails. */ @SuppressWarnings("unchecked") // ServletFileUpload#parseRequest() does not return generic type. private HttpServletRequest parseRequest(HttpServletRequest request) throws ServletException { // Check if the request is actually a multipart/form-data request. if (!ServletFileUpload.isMultipartContent(request)) { // If not, then return the request unchanged. return request; } // Prepare the multipart request items. // I'd rather call the "FileItem" class "MultipartItem" instead or so. What a stupid name ;) List<FileItem> multipartItems = null; try { // Parse the multipart request items. multipartItems = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request); // Note: we could use ServletFileUpload#setFileSizeMax() here, but that would throw a // FileUploadException immediately without processing the other fields. So we're // checking the file size only if the items are already parsed. See processFileField(). } catch (FileUploadException e) { throw new ServletException("Cannot parse multipart request: " + e.getMessage()); } // Prepare the request parameter map. Map<String, String[]> parameterMap = new HashMap<String, String[]>(); // Loop through multipart request items. for (FileItem multipartItem : multipartItems) { if (multipartItem.isFormField()) { // Process regular form field (input type="text|radio|checkbox|etc", select, etc). processFormField(multipartItem, parameterMap); } else { // Process form file field (input type="file"). processFileField(multipartItem, request); } } // Wrap the request with the parameter map which we just created and return it. return wrapRequest(request, parameterMap); } /** * Process multipart request item as regular form field. The name and value of each regular * form field will be added to the given parameterMap. * @param formField The form field to be processed. * @param parameterMap The parameterMap to be used for the HttpServletRequest. */ 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) { // Not in parameter map yet, so add as new value. parameterMap.put(name, new String[] { value }); } else { // Multiple field values, so add new value to existing array. int length = values.length; String[] newValues = new String[length + 1]; System.arraycopy(values, 0, newValues, 0, length); newValues[length] = value; parameterMap.put(name, newValues); } } /** * Process multipart request item as file field. The name and FileItem object of each file field * will be added as attribute of the given HttpServletRequest. If a FileUploadException has * occurred when the file size has exceeded the maximum file size, then the FileUploadException * will be added as attribute value instead of the FileItem object. * @param fileField The file field to be processed. * @param request The involved HttpServletRequest. */ private void processFileField(FileItem fileField, HttpServletRequest request) { if (fileField.getName().length() <= 0) { // No file uploaded. addAttributeValue(request, fileField.getFieldName(), null); } else if (maxFileSize > 0 && fileField.getSize() > maxFileSize) { // File size exceeds maximum file size. addAttributeValue(request, fileField.getFieldName(), new FileUploadException("File size exceeds maximum file size of " + maxFileSize + " bytes.")); // Immediately delete temporary file to free up memory and/or disk space. fileField.delete(); } else { // File uploaded with good size. addAttributeValue(request, fileField.getFieldName(), fileField); } } private static void addAttributeValue(HttpServletRequest request, String name, final Object value) { System.out.println("Add attribute value: name=" + name + ", value = " + value); if (value == null) { return; } final Object attrValue = request.getAttribute(name); System.out.println("oldValue = " + attrValue); if (attrValue == null) { request.setAttribute(name, value); } else if (attrValue instanceof List) { ((List) attrValue).add(value); } else { request.setAttribute(name, new ArrayList() { { add(attrValue); add(value); } }); } } // Utility (may be refactored to public utility class) ---------------------------------------- /** * Wrap the given HttpServletRequest with the given parameterMap. * @param request The HttpServletRequest of which the given parameterMap have to be wrapped in. * @param parameterMap The parameterMap to be wrapped in the given HttpServletRequest. * @return The HttpServletRequest with the parameterMap wrapped in. */ private static HttpServletRequest wrapRequest(HttpServletRequest request, final Map<String, String[]> parameterMap) { return new HttpServletRequestWrapper(request) { public Map<String, String[]> getParameterMap() { return parameterMap; } public String[] getParameterValues(String name) { return parameterMap.get(name); } public String getParameter(String name) { String[] params = getParameterValues(name); return params != null && params.length > 0 ? params[0] : null; } public Enumeration<String> getParameterNames() { return Collections.enumeration(parameterMap.keySet()); } }; } }