1. 程式人生 > >怎樣獲取form-data方式POST的資料

怎樣獲取form-data方式POST的資料

轉自:http://ju.outofmemory.cn/entry/201812

用x-www-form-urlencoded方式提交表單就可以正常繫結資料,但是用form-data方式提交就繫結不了:

@Controller@RequestMapping("/tag")publicclassTagController{@AutowiredprivateNanTianMenFacade nanTianMenFacade;@RequestMapping(value ="/uploadTags")@ResponseBodypublicTagUploadResult uploadTags(TagParamsparams
){String tagIds =params.getTagIds();String uuid =params.getUuid();TagUploadResult result =null;try{ result = nanTianMenFacade.uploadTags(tagIds, uuid);}catch(Exception e){ result =newTagUploadResult(); result.setS(0);}return result;}}

對於我來說,一直都是用x-www-form-urlencoded提交表單資料,除非是要上傳檔案,才會使用form-data方式。也一直以為Spring對不同的提交方式應該是透明的。不過確實用form-data提交普通表單,確實是拿不到提交的資料。DEBUG發現, request

.getParameterMap()返回的就是空的!

然後發現 org.apache.commons.io.IOUtils.toString(request.getInputStream());其實是有返回提交的資料的:

------WebKitFormBoundaryd7FGw9vQyyFIAYd7Content-Disposition: form-data; name="uuid"56------WebKitFormBoundaryd7FGw9vQyyFIAYd7Content-Disposition: form-data; name="tagIds"------WebKitFormBoundaryd7FGw9vQyyFIAYd7
Content-Disposition: form-data; name="aaa" bbb ------WebKitFormBoundaryd7FGw9vQyyFIAYd7--

也就是資料其實是有正常提交到後臺的。那麼就是這種方式提交的資料,並沒有放在pararmeterMap中了。而是要自己去解析這個inputstream的內容,再放回parameterMap中,這樣Spring才能夠繫結?這個不就是 multipartResolver 做的事情嗎?試著配置了一下,發現果然可以了:

<beanid="multipartResolver"class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><propertyname="maxUploadSize"value="10000000"></property></bean>

然後深入Spring MVC的程式碼,其實是做了一個判斷,如果是Multipart,那麼就會進行解析,然後將解析結果放回parameterMap中:

package org.springframework.web.servlet;publicclassDispatcherServletextendsFrameworkServlet{protectedvoid doDispatch(HttpServletRequest request,HttpServletResponse response)throwsException{HttpServletRequest processedRequest = request;HandlerExecutionChain mappedHandler =null;boolean multipartRequestParsed =false;WebAsyncManager asyncManager =WebAsyncUtils.getAsyncManager(request);try{ModelAndView mv =null;Exception dispatchException =null;try{
                processedRequest = checkMultipart(request);
                multipartRequestParsed = processedRequest != request;// Determine handler for the current request.
                mappedHandler = getHandler(processedRequest,false);if(mappedHandler ==null|| mappedHandler.getHandler()==null){
                    noHandlerFound(processedRequest, response);return;}// Determine handler adapter for the current request.HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());// Process last-modified header, if supported by the handler.String method = request.getMethod();boolean isGet ="GET".equals(method);if(isGet ||"HEAD".equals(method)){long lastModified = ha.getLastModified(request, mappedHandler.getHandler());if(logger.isDebugEnabled()){
                        logger.debug("Last-Modified value for ["+ getRequestUri(request)+"] is: "+ lastModified);}if(newServletWebRequest(request, response).checkNotModified(lastModified)&& isGet){return;}}if(!mappedHandler.applyPreHandle(processedRequest, response)){return;}try{// Actually invoke the handler.
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());}finally{if(asyncManager.isConcurrentHandlingStarted()){return;}}
                applyDefaultViewName(request, mv);
                mappedHandler.applyPostHandle(processedRequest, response, mv);}catch(Exception ex){
                dispatchException = ex;}
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}catch(Exception ex){
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);}catch(Error err){
            triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);}finally{if(asyncManager.isConcurrentHandlingStarted()){// Instead of postHandle and afterCompletion
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);return;}// Clean up any resources used by a multipart request.if(multipartRequestParsed){
                cleanupMultipart(processedRequest);}}}/**
     * Convert the request into a multipart request, and make multipart resolver available.
     * <p>If no multipart resolver is set, simply use the existing request.
     * @param request current HTTP request
     * @return the processed request (multipart wrapper if necessary)
     * @see MultipartResolver#resolveMultipart
     */protectedHttpServletRequest checkMultipart(HttpServletRequest request)throwsMultipartException{if(this.multipartResolver !=null&&this.multipartResolver.isMultipart(request)){if(request instanceofMultipartHttpServletRequest){
                logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, "+"this typically results from an additional MultipartFilter in web.xml");}else{returnthis.multipartResolver.resolveMultipart(request);}}// If not returned before: return original request.return request;}}package org.springframework.web.multipart.commons;publicclassCommonsMultipartResolverextendsCommonsFileUploadSupportimplementsMultipartResolver,ServletContextAware{publicMultipartHttpServletRequest resolveMultipart(finalHttpServletRequest request)throwsMultipartException{Assert.notNull(request,"Request must not be null");if(this.resolveLazily){returnnewDefaultMultipartHttpServletRequest(request){@Overrideprotectedvoid initializeMultipart(){MultipartParsingResult parsingResult = parseRequest(request);
                    setMultipartFiles(parsingResult.getMultipartFiles());
                    setMultipartParameters(parsingResult.getMultipartParameters());
                    setMultipartParameterContentTypes(parsingResult.getMultipartParameterContentTypes());}};}else{MultipartParsingResult parsingResult = parseRequest(request);returnnewDefaultMultipartHttpServletRequest(request, parsingResult.getMultipartFiles(),
                    parsingResult.getMultipartParameters(), parsingResult.getMultipartParameterContentTypes());}}/**
     * Parse the given servlet request, resolving its multipart elements.
     * @param request the request to parse
     * @return the parsing result
     * @throws MultipartException if multipart resolution failed.
     */@SuppressWarnings("unchecked")protectedMultipartParsingResult parseRequest(HttpServletRequest request)throwsMultipartException{String encoding = determineEncoding(request);FileUpload fileUpload = prepareFileUpload(encoding);try{List<FileItem> fileItems =((ServletFileUpload) fileUpload).parseRequest(request);return parseFileItems(fileItems, encoding);}catch(FileUploadBase.SizeLimitExceededException ex){thrownewMaxUploadSizeExceededException(fileUpload.getSizeMax(), ex);}catch(FileUploadException ex){thrownewMultipartException("Could not parse multipart servlet request", ex);}}}package org.apache.commons.fileupload;publicabstractclassFileUploadBase{/**
     * Processes an <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
     * compliant <code>multipart/form-data</code> stream.
     *
     * @param request The servlet request to be parsed.
     *
     * @return A list of <code>FileItem</code> instances parsed from the
     *         request, in the order that they were transmitted.
     *
     * @throws FileUploadException if there are problems reading/parsing
     *                             the request or storing files.
     */@OverridepublicList<FileItem> parseRequest(HttpServletRequest request)throwsFileUploadException{return parseRequest(newServletRequestContext(request));}/**
     * Processes an <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
     * compliant <code>multipart/form-data</code> stream.
     *
     * @param ctx The context for the request to be parsed.
     *
     * @return A list of <code>FileItem</code> instances parsed from the
     *         request, in the order that they were transmitted.
     *
     * @throws FileUploadException if there are problems reading/parsing
     *                             the request or storing files.
     */publicList<FileItem> parseRequest(RequestContext ctx)throwsFileUploadException{List<FileItem> items =newArrayList<FileItem>();boolean successful =false;try{FileItemIterator iter = getItemIterator(ctx);FileItemFactory fac = getFileItemFactory();if(fac ==null){thrownewNullPointerException("No FileItemFactory has been set.");}while(iter.hasNext()){finalFileItemStream item = iter.next();// Don't use getName() here to prevent an InvalidFileNameException.finalString fileName =((FileItemIteratorImpl.FileItemStreamImpl) item).name;FileItem fileItem = fac.createItem(item.getFieldName(), item.getContentType(),
                                                   item.isFormField(), fileName);
                items.add(fileItem);try{Streams.copy(item.openStream(), fileItem.getOutputStream(),true);}catch(FileUploadIOException e){throw(FileUploadException) e.getCause();}catch(IOException e){thrownewIOFileUploadException(format("Processing of %s request failed. %s",
                                                           MULTIPART_FORM_DATA, e.getMessage()), e);}finalFileItemHeaders fih = item.getHeaders();
                fileItem.setHeaders(fih);}
            successful =true;return items;}catch(FileUploadIOException e){throw(FileUploadException) e.getCause();}catch(IOException e){thrownewFileUploadException(e.getMessage(), e);}finally{if(!successful){for(FileItem fileItem : items){try{
                        fileItem.delete();}catch(Throwable e){// ignore it}}}}}}
POST 獲取 Data 資料 form