STACKJAVA

Spring MVC – Phần 11: Download file với Spring MVC, tạo API download file

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