docs
Support for handling multipart file uploads in forms and API endpoints with automatic binding to method parameters, including MultipartFile interface and related components.
Represents an uploaded file in a multipart request.
/**
* A representation of an uploaded file received in a multipart request.
*
* The file contents are either stored in memory or temporarily on disk.
* In either case, the user is responsible for copying file contents to a
* session-level or persistent store as and if desired. The temporary storage
* will be cleared at the end of request processing.
*/
public interface MultipartFile {
/**
* Return the name of the parameter in the multipart form.
*
* @return the name of the parameter
*/
String getName();
/**
* Return the original filename in the client's filesystem.
* This may contain path information depending on the browser used,
* but it typically will not with any other than Opera.
*
* @return the original filename, or the empty String if no file was chosen
*/
String getOriginalFilename();
/**
* Return the content type of the file.
*
* @return the content type, or null if not defined
*/
String getContentType();
/**
* Return whether the uploaded file is empty, that is, either no file has
* been chosen in the multipart form or the chosen file has no content.
*
* @return whether the uploaded file is empty
*/
boolean isEmpty();
/**
* Return the size of the file in bytes.
*
* @return the size of the file, or 0 if empty
*/
long getSize();
/**
* Return the contents of the file as an array of bytes.
*
* @return the contents of the file as bytes, or an empty byte array if empty
* @throws IOException in case of access errors
*/
byte[] getBytes() throws IOException;
/**
* Return an InputStream to read the contents of the file from.
*
* @return the contents of the file as stream, or an empty stream if empty
* @throws IOException in case of access errors
*/
InputStream getInputStream() throws IOException;
/**
* Transfer the received file to the given destination file.
*
* @param dest the destination file
* @throws IOException in case of reading or writing errors
* @throws IllegalStateException if the file has already been moved
*/
void transferTo(File dest) throws IOException, IllegalStateException;
/**
* Transfer the received file to the given destination file.
*
* @param dest the destination file
* @throws IOException in case of reading or writing errors
* @throws IllegalStateException if the file has already been moved
*/
default void transferTo(Path dest) throws IOException, IllegalStateException {
transferTo(dest.toFile());
}
}Usage Example:
@RestController
@RequestMapping("/api/upload")
public class FileUploadController {
@PostMapping("/single")
public ResponseEntity<FileInfo> uploadFile(@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) {
return ResponseEntity.badRequest().build();
}
try {
String filename = file.getOriginalFilename();
long size = file.getSize();
String contentType = file.getContentType();
// Save file
Path path = Paths.get(uploadDir, filename);
file.transferTo(path);
FileInfo info = new FileInfo(filename, size, contentType);
return ResponseEntity.ok(info);
} catch (IOException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
@PostMapping("/multiple")
public ResponseEntity<List<FileInfo>> uploadMultipleFiles(
@RequestParam("files") List<MultipartFile> files) {
List<FileInfo> uploadedFiles = new ArrayList<>();
for (MultipartFile file : files) {
if (!file.isEmpty()) {
try {
Path path = Paths.get(uploadDir, file.getOriginalFilename());
file.transferTo(path);
uploadedFiles.add(new FileInfo(
file.getOriginalFilename(),
file.getSize(),
file.getContentType()
));
} catch (IOException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
}
return ResponseEntity.ok(uploadedFiles);
}
@PostMapping("/with-data")
public ResponseEntity<Document> uploadWithMetadata(
@RequestParam("file") MultipartFile file,
@RequestParam("title") String title,
@RequestParam("description") String description) {
try {
byte[] content = file.getBytes();
Document doc = documentService.save(title, description, content, file.getContentType());
return ResponseEntity.status(HttpStatus.CREATED).body(doc);
} catch (IOException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
}Strategy interface for multipart file upload resolution.
/**
* A strategy interface for multipart file upload resolution in accordance
* with RFC 1867. Implementations are typically usable both within an
* application context and standalone.
*/
public interface MultipartResolver {
/**
* Determine if the given request contains multipart content.
*
* @param request the servlet request to be evaluated
* @return whether the request contains multipart content
*/
boolean isMultipart(HttpServletRequest request);
/**
* Parse the given HTTP request into multipart files and parameters,
* and wrap the request inside a MultipartHttpServletRequest object
* that provides access to file descriptors and makes contained
* parameters accessible via the standard ServletRequest methods.
*
* @param request the servlet request to wrap
* @return the wrapped servlet request
* @throws MultipartException if the servlet request is not multipart
*/
MultipartHttpServletRequest resolveMultipart(HttpServletRequest request)
throws MultipartException;
/**
* Cleanup any resources used for the multipart handling,
* like a storage for the uploaded files.
*
* @param request the request to cleanup resources for
*/
void cleanupMultipart(MultipartHttpServletRequest request);
}Annotation for binding a part in a multipart request to a method parameter.
/**
* Annotation that can be used to associate the part of a "multipart/form-data" request
* with a method argument.
*
* Supported method argument types include MultipartFile in conjunction with Spring's
* MultipartResolver abstraction, javax.servlet.http.Part in conjunction with Servlet 3.0
* multipart requests, or otherwise for any other method argument, the content of the part
* is passed through an HttpMessageConverter considering the 'Content-Type' header of the
* request part.
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestPart {
@AliasFor("name")
String value() default "";
@AliasFor("value")
String name() default "";
boolean required() default true;
}Usage Example:
@RestController
@RequestMapping("/api/documents")
public class DocumentController {
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Document> createDocument(
@RequestPart("file") MultipartFile file,
@RequestPart("metadata") DocumentMetadata metadata) {
try {
Document doc = documentService.create(file, metadata);
return ResponseEntity.status(HttpStatus.CREATED).body(doc);
} catch (IOException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
@PostMapping("/gallery")
public ResponseEntity<Gallery> createGallery(
@RequestPart("images") List<MultipartFile> images,
@RequestPart("info") GalleryInfo info) {
Gallery gallery = galleryService.create(images, info);
return ResponseEntity.status(HttpStatus.CREATED).body(gallery);
}
@PostMapping("/profile")
public ResponseEntity<Profile> updateProfile(
@RequestPart("profile") ProfileData profileData,
@RequestPart(value = "avatar", required = false) MultipartFile avatar) {
Profile profile = profileService.update(profileData, avatar);
return ResponseEntity.ok(profile);
}
}Interface for multipart requests with access to file parts.
public interface MultipartHttpServletRequest extends HttpServletRequest {
Iterator<String> getFileNames();
MultipartFile getFile(String name);
List<MultipartFile> getFiles(String name);
Map<String, MultipartFile> getFileMap();
MultiValueMap<String, MultipartFile> getMultiFileMap();
}Exception thrown when multipart resolution fails.
public class MultipartException extends RuntimeException {
public MultipartException(String msg) {}
public MultipartException(String msg, Throwable cause) {}
}@Configuration
public class MultipartConfig {
@Bean
public MultipartResolver multipartResolver() {
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setMaxUploadSize(10485760); // 10MB
resolver.setMaxUploadSizePerFile(5242880); // 5MB
resolver.setMaxInMemorySize(1048576); // 1MB
return resolver;
}
}