if you look at the source code of spring, you will find that spring parses Content-Type to MediaType, during parameter processing and then handles it by a specific RequestBodyAdviceAdapter registered in the spring framework, and different Content-Type corresponds to different RequestBodyAdviceAdapter. This implementation class implements the parsing of uploaded files.
when spring mvc uploads files, you need to configure the org.springframework.web.multipart.commons.CommonsMultipartResolver file upload parser in the spring mvc configuration file.
1: when a request comes, the doDispatch (HttpServletRequest, HttpServletResponse) method in the DispatcherServlet class is called.
doDispatch method body
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
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()) {
String requestUri = urlPathHelper.getRequestUri(request);
logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
}
if (new ServletWebRequest(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);
}
}
}
2: call the checkMultipart (request) method in the body of the doDispatch method to determine whether it is a request for file upload, and determine whether it is based on Content-type. If it is a request for file upload, the checkMultipart (request) method will call the method in CommonsMultipartResolver to parse the file (actually calling the long-distance file upload plug-in of apache commons-fileupload). After the parsing is completed, the file has already been uploaded to the local disk of the server. Please see the following code snippet.
protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
if (request instanceof MultipartHttpServletRequest) {
logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " +
"this typically results from an additional MultipartFilter in web.xml");
}
else {
return this.multipartResolver.resolveMultipart(request);
}
}
// If not returned before: return original request.
return request;
}
the resolveMultipart method of the CommonsMultipartResolver class is called in the body of the checkMultipart method to parse the file, which returns a MultipartHttpServletRequest object that contains the file object local to the server that has been uploaded.
3: get the method of the specific processor (mv = ha.handle (processedRequest, response, mappedHandler.getHandler ()) line of code).
if the file is uploaded, processedRequest is the object returned by the checkMultipart method above.
the handle method of the org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter class that is actually called, which gets the annotations on the actual called method parameters, and then gets the corresponding values from processedRequest according to some configuration of the annotations.
for example, the testUpload () method above you. In the handle () method of AnnotationMethodHandlerAdapter, you will get the annotation @ RequestParam as the method parameter of testUpload (), then parse the annotation, get the value of desc from the processedRequest request, get the file named file, and finally call the testUploaad () method. You can take a look at the org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments (Method, Object, NativeWebRequest, ExtendedModelMap) method body for details on how to analyze it.