Learn to upload multipart binary file (e.g. jpeg image) with a Spring REST API accepting MultipartFile request. Also learn to download file using another REST API using FileSystemResource.
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>    ...    <beanid="multipartResolver"class="org.springframework.web.multipart.commons.CommonsMultipartResolver">        <propertyname="maxUploadSize"value="100000"/>    </bean>    ...</beans> | 
3. Create multipart handler apis
Create two REST APIs which will responsible for handling upload and download requests and responses. It given example, I have created APIs at path 
/employee-management/employees/1/photo.
I am assuming at employee with id 
'1' exist in database. Feel free to change the resource path and implementation.| packagecom.howtodoinjava.demo.controller;importstaticorg.springframework.web.servlet        .support.ServletUriComponentsBuilder.fromCurrentRequest;importjava.io.File;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.InputStream;importjava.io.OutputStream;importjava.net.URI;importjava.util.concurrent.Callable;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.context.annotation.PropertySource;importorg.springframework.core.io.FileSystemResource;importorg.springframework.core.io.Resource;importorg.springframework.http.MediaType;importorg.springframework.http.ResponseEntity;importorg.springframework.util.FileCopyUtils;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.PathVariable;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RequestMethod;importorg.springframework.web.bind.annotation.RequestParam;importorg.springframework.web.bind.annotation.RestController;importorg.springframework.web.multipart.MultipartFile;importcom.howtodoinjava.demo.exception.RecordNotFoundException;importcom.howtodoinjava.demo.model.Employee;importcom.howtodoinjava.demo.repository.EmployeeRepository;@RestController@RequestMapping(value = "/employee-management/employees/{id}/photo")@PropertySource("classpath:application.properties")publicclassEmployeeImageController {    @Autowired    privateEmployeeRepository repository;    privateFile uploadDirRoot;    @Autowired    EmployeeImageController(@Value("${image.upload.dir}") String uploadDir,                                         EmployeeRepository repository) {        this.uploadDirRoot = newFile(uploadDir);        this.repository = repository;    }    @GetMapping    ResponseEntity<Resource> read(@PathVariableLong id)     {        returnthis.repository.findById(id)        .map(employee ->         {            File file = fileFor(employee);            Resource fileSystemResource = newFileSystemResource(file);            returnResponseEntity.ok()                    .contentType(MediaType.IMAGE_JPEG)                    .body(fileSystemResource);        })        .orElseThrow(() -> newRecordNotFoundException("Image for available"));    }    @RequestMapping(method = { RequestMethod.POST, RequestMethod.PUT },                                 consumes = { "multipart/form-data"})    Callable<ResponseEntity<?>> write(@PathVariableLong id,             @RequestParam("file") MultipartFile file) throwsException     {        return() -> this.repository.findById(id)        .map(employee ->         {            File fileForEmployee = fileFor(employee);            try(InputStream in = file.getInputStream();                         OutputStream out = newFileOutputStream(fileForEmployee))             {                FileCopyUtils.copy(in, out);            }             catch(IOException ex)             {                thrownewRuntimeException(ex);            }            URI location = fromCurrentRequest().buildAndExpand(id).toUri();            returnResponseEntity.created(location).build();        })        .orElseThrow(() -> newRecordNotFoundException("Employee id is not present in database"));    }    privateFile fileFor(Employee e) {        returnnewFile(this.uploadDirRoot, Long.toString(e.getId()));    }} | 
Above REST controller relies on existence of upload folder configured in properties file i.e. 
image.upload.dir.| 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. Multipart upload request demo
For demo purpose, I have created a JSP page with only single field of type file. We will browse a image from computer, and upload it to server.
| <html><head>    <title>Spring REST File Upload</title></head><body>    <formmethod="POST"        action="/SpringRestExample/api/rest/employee-management/employees/1/photo"        enctype="multipart/form-data">        <table>            <tr>                <td>Select a file to upload</td>                <td><inputtype="file"name="file"/></td>            </tr>            <tr>                <td><inputtype="submit"value="Submit"/></td>            </tr>        </table>    </form></body></html> | 
Now start the server and open the upload page in URL 
http://localhost:8080/SpringRestExample/singleFileUpload.jsp. Browser the file and click on Submit button. The image file 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. 
No comments:
Post a Comment