본문 바로가기
실습/리눅스 서버 + 스프링 부트

[JAVA] POI 라이브러리를 사용한 엑셀 파일 만들기

by 이민우 2024. 3. 31.
728x90
반응형

POI 라이브러리를 사용해 사용자에게 업로드된 엑셀 파일을 읽는 포스팅은 직전 포스팅에서 복기했다.

 

그렇다면 기존 데이터를 엑셀 파일로 만들어서 다운로드하게 해주는 기능은 어떻게 해야하는 방법도 포스팅 해놓으면 훗날 도움이 될 것 같아 작성한다.

 

마찬가지로 POI 라이브러리를 사용하며, 프로젝트는 이전 프로젝트를 그대로 사용한다.

https://123okk2.tistory.com/506

 

[JAVA] POI 라이브러리를 사용한 엑셀 파싱

직전 프로젝트 두 번째 복기를 해볼까 한다. 우선 간단하게 설명하자면, 나는 사용자에게 파일을 받아 이를 HTTPFS를 통해 HDFS에 저장하고, 내용을 파싱해서 DB에 저장한느 프로그램을 개발했다.

123okk2.tistory.com

 

프로젝트 설정

코드 작성에 앞서 디펜던시를 추가해야 한다.

아래 과정은 굳이 하지 않아도 상관없다. 그럼에도 불구하고 하는 이유는 다음 포스팅에서 사용할 예정이기 때문이다.

 

디펜던시는 UI를 보여주기 위해 Thymeleaf만 추가한다.

 

참고로 중간에 추가했으므로 resource에 templates 폴더를 추가하고, application.properties에 prefix와 suffix를 추가한다.

spring.thymeleaf.prefix=classpath:templates/
spring.thymeleaf.suffix=.html
spring.thymeleaf.encoding=UTF-8

 

코드 작성

사실 딱히 설명할 게 없다. 그냥 Sheet 만들기 > Row 만들기 > Cell 만들기가 전부이다.

 

그러니 오늘도 설명은 생략하고 간단한 DownloadService와 DownloadRestController를 작성한다.

 

DownloadService.java

package com.mwlee.test.service;

import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;

import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class DownloadService {
	
	// 엑셀 파일로 만들 데이터
	// 실구현에서는 DB에서 쿼리 결과로 가져온 것.
	private List<Map<String, Object>> result = new ArrayList<>();
	
	
	/**
	 * 원래는 DB에서 데이터를 빼와야하지만,
	 * 굳이 그럴 필요 없으므로 가라 데이터 생성
	 */
	@PostConstruct
	private void setDate() {
		// result 세팅
		// 컬럼들
		String[] columns = new String[] {
				"col_1",
				"col_2",
				"col_3"
		};
		
		Map<String, Object> firstRow = new HashMap<>();
		firstRow.put(columns[0], 1);
		firstRow.put(columns[1], "a");
		firstRow.put(columns[2], "20240101");
		result.add(firstRow);
		
		// 1번 데이터 빼기
		Map<String, Object> secondRow = new HashMap<>();
		secondRow.put(columns[0], 2);
		secondRow.put(columns[2], "20240102");
		result.add(secondRow);
		
		// 3번 데이터 빼기
		Map<String, Object> thirdRow = new HashMap<>();
		thirdRow.put(columns[0], 3);
		thirdRow.put(columns[1], "b");
		result.add(thirdRow);
	}
	
	/**
	 * 엑셀 파일을 만들어 전송
	 * @return
	 */
	public byte[] generateExcel() {

		try {
			// 필요 stream 및 writer 선언
        	Workbook workbook = new XSSFWorkbook();
        	Sheet sheet = workbook.createSheet("Sheet1");
        	
        	// 맨 위에 각 컬럼명 작성
        	List<String> keys = new ArrayList<>(result.get(0).keySet());
        	Row headerRow = sheet.createRow(0);
        	for(int i=0; i<keys.size(); i++) {
        		Cell cell = headerRow.createCell(i);
        		cell.setCellValue(keys.get(i));
        	}
        	
        	// 둘째 줄부터 데이터 삽입
        	int rowNum = 1; // 0은 컬럼들이므로 1부터 시작
        	for(Map<String, Object> data : result) {
        		// row 생성
        		Row row = sheet.createRow(rowNum++);
        		// 각 cell 생성
        		for(int i=0; i<keys.size(); i++) {
        			Cell cell = row.createCell(i);
        			if(data.get(keys.get(i)) != null) {
        				// 없는 데이터면 패스하고, type에 따라 분기
        				if(data.get(keys.get(i)) instanceof Integer) {
        					cell.setCellValue((Integer) data.get(keys.get(i)));
        				}
        				else if(data.get(keys.get(i)) instanceof Double) {
        					cell.setCellValue((Double) data.get(keys.get(i)));
        				}
        				else if(data.get(keys.get(i)) instanceof String) {
        					cell.setCellValue((String) data.get(keys.get(i)));
        				}
        			}
        		}
        	}

        	// byte[]를 return하기위해 변형 및 workbook close
        	ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        	workbook.write(outputStream);
        	workbook.close();
        	
        	// byte[] return
        	return outputStream.toByteArray();
		}
		catch(Exception e) {
			return new byte[] {};
		}
	}
}

 

 

DownloadRestController.java

package com.mwlee.test.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DownloadRestController {
	@Autowired DownloadService service;
	
	@GetMapping("/download/excel")
	public ResponseEntity<Resource> downloadExcel() {
		
		byte[] excelData = service.generateExcel();
		
		if(excelData == null || excelData.length == 0) {
			return ResponseEntity.internalServerError().build();
		}
		
		Resource resource = new ByteArrayResource(excelData);
		
		return ResponseEntity.ok()
				.contentType(
						MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
				)
				.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"test-download-excel.xlsx\"")
				.body(resource);
	}
}

 

 

테스트

이제 설정한대로 http://localhost:8080/download/excel에 진입해보자.

그러면 파일이 다운로드 될 것이다.

 

그리고 파일을 열어보면 아래와 같이 파일이 잘 다운로드 되었음을 확인할 수 있다.

 

 

728x90
반응형