Hướng dẫn xuất file Excel từ hệ thống Spring Boot và Vue.js

Việc xuất dữ liệu ra định dạng Excel là một yêu cầu phổ biến trong các ứng dụng quản lý doanh nghiệp. Quy trình này thường bao gồm hai giai đoạn: Backend xử lý dữ liệu và tạo luồng nhị phân (binary stream), trong khi Frontend tiếp nhận luồng đó để chuyển đổi thành file tải về trên trình duyệt.

1. Xử lý phía Backend với Spring Boot và Apache POI

Trong ví dụ này, chúng ta sử dụng thư viện Apache POI để khởi tạo workbook và ghi dữ liệu vào các ô. Mã nguồn dưới đây minh họa cách lấy dữ liệu từ dịch vụ và ghi trực tiếp vào HttpServletResponse.


@RestController
@RequestMapping("/api/reports")
public class ExportController {

    @Autowired
    private BusinessService businessService;

    @PostMapping("/excel/enterprise")
    public void generateEnterpriseExcel(@RequestBody SearchCriteria criteria, HttpServletResponse response) {
        try {
            // Lấy danh sách dữ liệu từ cơ sở dữ liệu
            List<Enterprise> dataList = businessService.searchByCriteria(criteria);

            // Khởi tạo Workbook (XSSF dùng cho định dạng .xlsx)
            XSSFWorkbook workbook = new XSSFWorkbook();
            XSSFSheet sheet = workbook.createSheet("Thông Tin Doanh Nghiệp");

            // Tạo tiêu đề cột (Header)
            String[] headers = {"ID", "Tên Công Ty", "Mã Số Thuế", "Địa Chỉ", "Người Đại Diện", "Trạng Thái"};
            XSSFRow headerRow = sheet.createRow(0);
            for (int i = 0; i < headers.length; i++) {
                XSSFCell cell = headerRow.createCell(i);
                cell.setCellValue(headers[i]);
            }

            // Đổ dữ liệu vào các dòng tiếp theo
            int rowIdx = 1;
            for (Enterprise ent : dataList) {
                XSSFRow row = sheet.createRow(rowIdx++);
                row.createCell(0).setCellValue(ent.getId());
                row.createCell(1).setCellValue(ent.getCompanyName());
                row.createCell(2).setCellValue(ent.getTaxCode());
                row.createCell(3).setCellValue(ent.getAddress());
                row.createCell(4).setCellValue(ent.getRepresentative());
                row.createCell(5).setCellValue(ent.getIsActive() ? "Đang hoạt động" : "Ngừng hoạt động");
            }

            // Tự động điều chỉnh độ rộng cột
            for (int i = 0; i < headers.length; i++) {
                sheet.autoSizeColumn(i);
            }

            // Thiết lập thông tin phản hồi (Response Header)
            String filename = "danh_sach_doanh_nghiep.xlsx";
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(filename, "UTF-8"));

            // Ghi workbook vào luồng đầu ra
            OutputStream outputStream = response.getOutputStream();
            workbook.write(outputStream);
            outputStream.flush();
            workbook.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2. Xử lý phía Frontend với Vue.js và Axios

Khi gọi API xuất file, điều quan trọng nhất là phải thiết lập thuộc tính responseType: 'blob' trong Axios. Nếu không, dữ liệu trả về sẽ bị hiểu sai định dạng và file Excel tải xuống sẽ bị lỗi nội dung.

Cấu hình API gọi bằng Axios


import axios from 'axios';

export const requestExportExcel = (searchParams) => {
  return axios({
    url: '/api/reports/excel/enterprise',
    method: 'post',
    data: searchParams,
    responseType: 'blob' // Bắt buộc để xử lý dữ liệu nhị phân
  });
};

Xử lý tải file trong Component Vue

Tại phương thức xử lý sự kiện click, chúng ta sẽ nhận phản hồi từ server, tạo một URL tạm thời cho đối tượng Blob và kích hoạt lệnh tải xuống thông qua một thẻ <a> ảo.


methods: {
  async handleDownload() {
    try {
      const response = await requestExportExcel(this.filterQuery);
      
      if (!response.data) {
        this.$message.error("Không có dữ liệu để xuất");
        return;
      }

      // Tạo đối tượng Blob từ dữ liệu trả về
      const blob = new Blob([response.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
      const downloadUrl = window.URL.createObjectURL(blob);
      
      // Tạo link ẩn để thực hiện tải file
      const link = document.createElement('a');
      link.href = downloadUrl;
      link.download = `Report_${new Date().getTime()}.xlsx`;
      document.body.appendChild(link);
      link.click();

      // Giải phóng bộ nhớ
      document.body.removeChild(link);
      window.URL.revokeObjectURL(downloadUrl);

    } catch (error) {
      console.error("Lỗi khi xuất file:", error);
    }
  }
}

Lưu ý kỹ thuật

  • Định dạng file: Sử dụng SXSSFWorkbook nếu dữ liệu cực lớn để tránh lỗi tràn bộ nhớ (OutOfMemoryError) trên server.
  • Bảo mật: Đảm bảo endpoint xuất file vẫn được bảo vệ bởi Token (JWT) tương tự như các API lấy dữ liệu thông thường.
  • Trải nghiệm người dùng: Nên thêm hiệu ứng loading trong khi chờ server xử lý file, vì quá trình tạo file Excel có thể mất vài giây với hàng nghìn dòng dữ liệu.

Thẻ: SpringBoot Vue.js apache-poi excel-export Axios

Đăng vào ngày 25 tháng 7 lúc 04:57