Spring MVC – Phần 11: Download file với Spring MVC, tạo API download file
Ở phần JSP Servlet mình đã giới thiệu cơ chế download file trong JSP Servlet. Trong Spring MVC chúng ta cũng có thể download file như thế, ngoài ra Spring MVC còn hỗ trợ việc download file với API để kèm theo status và các thông tin khác khi download file.
(Xem lại: Download file với JSP-Servlet)
Download file với Spring MVC, tạo API download file
Thư viện sử dụng:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>stackjava.com</groupId> <artifactId>SpringMVCDownloadFile</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.0</version> <scope>provided</scope> </dependency> </dependencies> </project>
Ở đây mình sử dụng thêm thư viện commons-io phục vụ cho viện đọc, ghi file (xem lại: Đọc ghi file với Apache Common IO)
File Controller:
package stackjava.com.springmvc.downloadfile.controller; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.FileUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.InputStreamResource; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.util.FileCopyUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller public class BaseController { @Autowired private ServletContext context; @RequestMapping("/") public String index() { return "index"; } @RequestMapping(value = "/download1", method = RequestMethod.GET) public void download1(HttpServletResponse response) throws IOException { try { File file = new File(context.getRealPath("/file/demo.txt")); byte[] data = FileUtils.readFileToByteArray(file); // Thiết lập thông tin trả về response.setContentType("application/octet-stream"); response.setHeader("Content-disposition", "attachment; filename=" + file.getName()); response.setContentLength(data.length); InputStream inputStream = new BufferedInputStream(new ByteArrayInputStream(data)); FileCopyUtils.copy(inputStream, response.getOutputStream()); } catch (Exception ex) { ex.printStackTrace(); } } @RequestMapping(value = "/download2", method = RequestMethod.GET) public ResponseEntity<InputStreamResource> download2(HttpServletRequest request) throws IOException { HttpHeaders responseHeader = new HttpHeaders(); try { File file = new File(context.getRealPath("/file/demo.txt")); byte[] data = FileUtils.readFileToByteArray(file); // Set mimeType trả về responseHeader.setContentType(MediaType.APPLICATION_OCTET_STREAM); // Thiết lập thông tin trả về responseHeader.set("Content-disposition", "attachment; filename=" + file.getName()); responseHeader.setContentLength(data.length); InputStream inputStream = new BufferedInputStream(new ByteArrayInputStream(data)); InputStreamResource inputStreamResource = new InputStreamResource(inputStream); return new ResponseEntity<InputStreamResource>(inputStreamResource, responseHeader, HttpStatus.OK); } catch (Exception ex) { return new ResponseEntity<InputStreamResource>(null, responseHeader, HttpStatus.INTERNAL_SERVER_ERROR); } } }
Ở đây mình có 2 url thực hiện download file là /download1 và /download2
Cả 2 url trên đều thực hiện đọc file demo.txt từ folder webapp/file và trả về cho client
Cách 1: /download1: thực hiện giống như download file thông thường với JSP – Servlet: đọc file cần download và ghi file đó ra outputstream của response
Cách 2: /download2: trả về đối tượng ResponseEntity với dữ liệu bên trong. Cách này thường dùng để cung cấp các API vì ngoài dữ liệu trả về nó còn có thêm HTTPStatus.
Lưu ý, với cách thứ 2, khi trả về ResponseEntity thì phải khai báo thẻ <mvc:annotation-driven /> trong file spring config nếu không sẽ bị lỗi 406.
File Spring Config:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <context:component-scan base-package="stackjava.com.springmvc.downloadfile.controller" /> <mvc:annotation-driven /> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix"> <value>/WEB-INF/views/jsp/</value> </property> <property name="suffix"> <value>.jsp</value> </property> </bean> </beans>
File webapp/file/demo.txt
stackjava.com
File view:
<html> <body> <a href="download1">/download1</a> <br/> <a href="download2">/download2</a> <br/> </body> </html>
Demo:
Okay, Done!
Dowload code ví dụ trên tại đây