본문 바로가기
  • A space that records me :)
Language/JAVA

[JAVA] Excel Download - 읽기, 수정, 다운로드 (Servlet, POI)

by yjkim_97 2020. 11. 13.

2020.11.13

서버에 업로드되어 있는 파일을 읽은 후 데이터를 추가(수정)하고 다운로드하는 기능 구현

- 업로드되어 있는 파일 (양식)

- DB에 저장된 데이터를 엑셀에 추가

 

사용

- HttpServletRequest, HttpServletResponse

- FileInputStream

- XSSFWorkbook

- ServletOutputStream

 


1. Controller

API를 호출하면 엑셀다운로드 기능을 제공하는 Service를 호출한다.

@GetMapping(value = "/v1/cpnType/{cpnTypeId}/promotion/iss/{issDstrSeq}/target/excel/down")
public void excelDownloadIssTarget(HttpServletRequest request, HttpServletResponse response,
		@PathVariable(value = "cpnTypeId") Long cpnTypeId, @PathVariable(value = "issDstrSeq") Long issDstrSeq) {
	PromCpnIssTgtr promCpnIssTgtr = new PromCpnIssTgtr();
	promCpnIssTgtr.setCpnTypeId(cpnTypeId);
	promCpnIssTgtr.setIssDstrSeq(issDstrSeq);
		
	promotionCpnIssTgtrService.excelTypeTargetExcelDownload(request, response, promCpnIssTgtr);
}

 

2. HttpServletResponse header설정

서블릿을 이용하여 엑셀 다운로드기능 구현

엑셀 파일을 출력하기 위해 서블릿의 헤더를 설정해주는 메소드 구현.

 

궁금증)

1. 서블릿의 헤더에서 각각 키의 역할이 궁금하다.

public class ExcelUtils {
	public static final Logger logger = LoggerFactory.getLogger(ExcelUtils.class);
	public static void setServletHeader(HttpServletResponse response, String fileName)
	{
		String headerKey = "Content-Disposition";
		String headerValue = "attachment; filename=".concat(fileName);
		
		response.setContentType("application/octet-stream");
		response.setHeader(headerKey, headerValue);
	}
}

 

3. 엑셀파일 읽기, 수정, 다운로드 - FileInputStream, POI(XSSF), ServletOutputStream

엑셀파일 읽기 - FileInputStream

FileInputStream vs FileOutputStream

https://hyeonstorage.tistory.com/236

 

[JAVA] ByteStream : FileInputStream / FileOutputStream

ByteStream : FileInputStream / FileOutputStream 직접 키보드를 통하여 입력하는 데이터는 대개 임시 자료인 경우가 많다. 중요한 자료는 대부분 데이터베이스에 저장되어 있거나 파일 시스템에 저장된다. F

hyeonstorage.tistory.com

FileInputStream

  • InputStream 클래스를 상속받은 후손 클래스이다.
  • 하드 디스크상에 존재하는 파일을 바이트 단위로 입력을 받는 클래스이다.
  • 이 클래스는 출발지점과 도착지점을 연결하는 통로(?)로, 즉 스트림을 생성하는 클래스이다.
생성자 설명
new FileInputStream(String); filepath로 지정한 파일에 대한 입력 스트림을 생성한다.
FileNotFoundException 발생
new FileInputStream(File); fileObj로 지정한 파일에 대한 입력 스트림을 생성한다. 
FileNotFoundException 발생
new FileInputStream(FileDescriptor); fdObj 로 기존의 접속을 나타내는 파일 시스템의 입력 스트림을 생성한다.
SecurityException 발생

FileOutputStream

  • OutputStream 클래스의 후손 클래스
  • 바이트 단위로 파일에 출력을 하는 클래스이다.

 

엑셀파일 수정 - POI (XSSF)

HSSFWorkbook vs XSSFWorkbook vs SXSSFWorkbook

http://poi.apache.org/components/spreadsheet/

 

POI-HSSF and POI-XSSF/SXSSF - Java API To Access Microsoft Excel Format Files

POI-HSSF and POI-XSSF/SXSSF - Java API To Access Microsoft Excel Format Files Overview Overview HSSF is the POI Project's pure Jav

poi.apache.org

HSSFWorkbook 

 

  • 엑셀 97~2003버전을 위한 Workbook
  • .xls 파일형식만을 다룬다.

XSSFWorkbook 

  • 2007이상의 버전을 위한 Workbook
  • .xlsx 파일형식을 다룬다.
  • XSSF는 문서의 모든 행에 대한 액세스를 제공하여 SXSSF보다 메모리사용량이 높다.

SXSSFWorkbook

  • XSSF의 성능을 개선한 버전으로, 대용량 스프레드 시트를 위한 Workbook이다.
  • XSSF와 다르게 슬라이딩 윈도우 내에 있는 행에 대한 액세스를 제한하여 XSSF보다 메모리 사용량을 줄였다.
  • 한 시점에 제한된 수의 행만 액세스 할수 있다.
  • Sheet.clone()이 지원되지 않는다.

엑셀파일 다운로드 - ServletOutputStream

docs.oracle.com/javaee/7/api/javax/servlet/ServletOutputStream.html

 

ServletOutputStream (Java(TM) EE 7 Specification APIs)

Provides an output stream for sending binary data to the client. A ServletOutputStream object is normally retrieved via the ServletResponse.getOutputStream() method. This is an abstract class that the servlet container implements. Subclasses of this class

docs.oracle.com

궁금증)

1. ServletOutputStream과 FileOutputStream의 차이

2. HttpServletResponse에 헤더를 설정해줬는데 이거랑 관려이 있나? 두개가 전혀 다른 역할을 하는 것인가? 그럼 각각 정확히 어떤 기능을 제공해 주는것이고 왜 있는것인가?

3. 아래 코들르 보면 ServletOutputStream을 생성하고 XSSFWorkbook에 write를 했다. 두개의 연관성은? 이렇게해서 다운로드가 되는건가? 어떻게 되는건가?

public void excelTypeTargetExcelDownload(HttpServletRequest request, HttpServletResponse response, PromCpnIssTgtr obj) {
	if(ObjectUtils.isEmpty(obj.getIssDstrSeq()) || ObjectUtils.isEmpty(obj.getCpnTypeId())) {
		return;
	}
		
	// DB에 저장된 데이터
	List<PromCpnIssTgtr> list =  this.listPromCpnIssTgtrWithName(obj);

	// 엑셀 다운로드
	FileInputStream fin = null;
	try {

		// 엑셀 양식 파일 읽어오기
        // 문자열 형태의 파일경로명으로 읽을 파일 지정
		fin = new FileInputStream(request.getSession().getServletContext().getRealPath(CpnConstants.ISS_TARGET_EXCEL_FORMAT_PATH));
		XSSFWorkbook wb = new XSSFWorkbook(fin);

		// 엑셀 양식 파일 수정 (=DB에 저장된 발행/배포대상자 정보를 엑셀에 입력)
		XSSFSheet sheet = wb.getSheetAt(0);
		XSSFRow row = null;
		XSSFCell cell = null;

		int rowIdx = 0; 
		for(PromCpnIssTgtr pcit : list) {
			row = sheet.createRow(++rowIdx); // start index 1 row, already input index 0 row.
			// account no.
			cell = row.createCell(0);
			cell.setCellValue(pcit.getMbsAccNo());
			// account name
			cell = row.createCell(1);
			cell.setCellValue(pcit.getAccNm());
			// phone
			cell = row.createCell(2);
			cell.setCellValue(pcit.getPhoneNo());
			// email.
			cell = row.createCell(3);
			cell.setCellValue(pcit.getEmailAdr());
		}
			
            // 엑셀 파일 출력
		ServletOutputStream outputStream = response.getOutputStream();
		wb.write(outputStream);
		wb.close();
		outputStream.close();
        
          // 엑셀파일 다운로드를 위한 서블릿 헤더 설정
          ExcelUtils.setServletHeader(response, this.getExcelFileName(obj) + ".xlsx");
			
	} catch(Exception e) {
		throw new CpnRuntimeException();
	} finally {
		try {
			if (fin != null) {
				fin.close();
			}
			
		} catch (Exception ex) {
			LOGGER.error(ex.toString(), ex);
		} finally {
			fin = null;
		}
	}
}