Learn to upload multiple multipart binary files (e.g. jpeg image) with a Spring REST API accepting an array of MultipartFile request.
1. Maven dependency
Apart from spring webmvc, we will need
commons-fileupload
and commons-io
in classpath.dependency> < groupId >org.springframework</ groupId > < artifactId >spring-webmvc</ artifactId > < version >5.1.6.RELEASE</ version > </ dependency > < dependency > < groupId >commons-fileupload</ groupId > < artifactId >commons-fileupload</ artifactId > < version >1.4</ version > </ dependency > < dependency > < groupId >commons-io</ groupId > < artifactId >commons-io</ artifactId > < version >2.6</ version > </ dependency > |
2. Configure CommonsMultipartResolver
It is Servlet-based
MultipartResolver
implementation for commons-fileupload
. It provides “maxUploadSize“, “maxInMemorySize” and “defaultEncoding” settings as bean properties.
The purpose of this class is to save the temporary files to the servlet container’s temporary directory.
< beans > ... < bean id = "multipartResolver" class = "org.springframework.web.multipart.commons.CommonsMultipartResolver" > < property name = "maxUploadSize" value = "1000000" /> </ bean > ... </ beans > |
Equivalent Java annotation configuration is :
@Bean (name = "multipartResolver" ) public CommonsMultipartResolver multipartResolver() { CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(); multipartResolver.setMaxUploadSize( 20848820 ); return multipartResolver; } |
3. Create multiple upload rest api
Create given REST API which will responsible for handling multiple uploads posted to server. It given example, I have created the API at path
/employee-management/employees/1/photo/multiple
.
I am assuming at employee with id
'1'
exist in database. Feel free to change the resource path and implementation.package com.howtodoinjava.demo.controller; import static org.springframework.web.servlet .support.ServletUriComponentsBuilder.fromCurrentRequest; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URI; import java.util.concurrent.Callable; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.PropertySource; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.util.FileCopyUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import com.howtodoinjava.demo.exception.RecordNotFoundException; import com.howtodoinjava.demo.model.Employee; import com.howtodoinjava.demo.repository.EmployeeRepository; @RestController @RequestMapping (value = "/employee-management/employees/{id}/photo" ) @PropertySource ( "classpath:application.properties" ) public class EmployeeImageController { @Autowired private EmployeeRepository repository; private File uploadDirRoot; @Autowired EmployeeImageController( @Value ( "${image.upload.dir}" ) String uploadDir, EmployeeRepository repository) { this .uploadDirRoot = new File(uploadDir); this .repository = repository; } @PostMapping (value = "/multiple" , consumes = { "multipart/form-data" }) Callable<ResponseEntity<?>> writeMultiple( @PathVariable Long id, @RequestParam ( "files" ) MultipartFile[] files) throws Exception { return () -> this .repository.findById(id).map(employee -> { Arrays.asList(files).stream().forEach(file -> { File fileForEmployee; try { fileForEmployee = uploadPath(employee, file); } catch (IOException e) { throw new RuntimeException(e); } try (InputStream in = file.getInputStream(); OutputStream out = new FileOutputStream(fileForEmployee)) { FileCopyUtils.copy(in, out); } catch (IOException ex) { throw new RuntimeException(ex); } }); return ResponseEntity.ok().build(); }).orElseThrow(() -> new RecordNotFoundException( "Employee id is not present in database" )); } private File uploadPath(Employee e, MultipartFile file) throws IOException { File uploadPath = Paths.get( this .uploadDirRoot.getPath(), e.getId().toString()).toFile(); if (uploadPath.exists() == false ) { uploadPath.mkdirs(); } return new File(uploadPath.getAbsolutePath(), file.getOriginalFilename()); } } |
Above REST controller creates a upload folder (with name as employee id) if not already present in filesystem. Still we need to define following property.
image.upload.dir=c:/temp/images |
Also, the controller returns the Callable which means the method returns immediately while the IO operations may run. Once the upload process is finished, API returns the response. To enable async support, configure async-supported in
DispatcherServlet
.< web-app > < display-name >Employee Management REST APIs</ display-name > < servlet > < servlet-name >rest</ servlet-name > < servlet-class >org.springframework.web.servlet.DispatcherServlet</ servlet-class > < load-on-startup >1</ load-on-startup > < async-supported >true</ async-supported > </ servlet > < servlet-mapping > < servlet-name >rest</ servlet-name > < url-pattern >/api/rest/*</ url-pattern > </ servlet-mapping > </ web-app > |
4. Multiple multipart uploads request demo
For demo purpose, I have created a JSP page with only multiple fields of type file. We will browse few images from computer, and upload them to server.
< html > < head > < title >Spring REST File Upload</ title > </ head > < body > < form method = "POST" action = "/SpringRestExample/api/rest/employee-management/employees/1/photo/multiple" enctype = "multipart/form-data" > < table > < tr > < td >Select first file to upload</ td > < td >< input type = "file" name = "files" /></ td > </ tr > < tr > < td >Select second file to upload</ td > < td >< input type = "file" name = "files" /></ td > </ tr > < tr > < td >Select third file to upload</ td > < td >< input type = "file" name = "files" /></ td > </ tr > < tr > < td >< input type = "submit" value = "Submit" /></ td > </ tr > </ table > </ form > </ body > </ html > |
Now start the server and open the upload page in URL
http://localhost:8080/SpringRestExample/multipleFileUpload.jsp
. Browser the images and click on Submit button. The image files will be uploaded to server in configured upload directory.
To download the file, enter the URL
/employee-management/employees/1/photo
in browser and image will be displayed. An download API is already part of attached source.
Drop me your questions related to creating Spring MVC REST API to handle multiple uploads of files such as images.
No comments:
Post a Comment