Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- BufferedReader
- html
- select
- Linux
- 자바
- 개발자
- order by
- 정보처리기사
- 자바스크립트
- DML
- 프로그래머스 SQL
- 예외처리
- 형변환
- MySQL
- 웹개발
- 클래스
- 프로그래밍
- 리눅스
- 알고리즘
- StringBuilder
- sql문
- JavaScript
- 입출력
- github
- String클래스
- where
- mybatis
- 스프링
- 프로그래머스 sql 고득점 kit
- 메서드
- scanner
- 백엔드
- 데이터 조회
- SQL
- select문
- 프론트엔드
- 백준
- 정보처리기사필기요약
- Java
- Git
Archives
- Today
- Total
ToBe끝판왕
[ Poi 라이브러리 ] JAVA로 Excel 다운로드 기능 구현 (2) 본문
반응형
Apache POI 라이브러리 + 달력 형식의 Excel 파일 다운로드
▶ 기본적인 환경설정
• InteliJ + SpringFramework + Maven 프로젝트
• JDK 버전 : 1.8
• SpringFramework 버전 : 5.2.3 release
• Apache POI 버전 : 4.1.2
• Servlet Api 버전 : 3.1.0
▶ 예제 기획
• view 페이지에서 년도, 월을 서택하고 해당 월에 맞는 달력을 보여줌
• 프로젝트 내 있는 Excel 파일에서 셀 스타일 복사하여 달력에 적용
• 셀스타일 + 달력 적용하여 새로운 Excel 파일 생성
• 해당 Excel 파일 다운로드 ( 경로 지정 )
• View 페이지 ( Excel2.jsp )
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>엑셀다운로드 과제 페이지</title>
</head>
<script type="text/javascript">
</script>
<body>
<form name="calendar" action="/calendar.do" method="get" style="text-align:center;">
<div style="text-align:center;">
<select id="year" name="year">
<option value="2024">2024</option>
</select>
</div>
<div style="text-align:center;">
<select id="month" name="month">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
</select>
</div>
<div style="text-align:center;">
<button type="submit">달력 엑셀다운</button>
</div>
</form>
</body>
</html>
• Controller( CalController.java )
@Controller
public class CalController {
@RequestMapping(value = "/calendar.do", method = RequestMethod.GET)
public void downloadCalendar( HttpServletRequest request, HttpServletResponse response) throws IOException {
// 엑셀파일 경로 변수 선언 및 초기화
String localFile = "excel/localExcel.xlsx";
String newFile = "C:/excel/copyExcel.xlsx";
// 디렉토리 생성 관련 변수 선언 및 초기화
String path = "C:/excel";
File Folder = new File(path);
// 해당 디렉토리가 없을경우 디렉토리를 생성합니다.
if (!Folder.exists()) {
try{
Folder.mkdir(); //폴더 생성합니다.
System.out.println("폴더가 생성되었습니다.");
}
catch(Exception e){
e.getStackTrace();
}
}else {
System.out.println("이미 폴더가 생성되어 있습니다.");
}
try {
// FileInputStream 객체 생성 ( src/main/resources/excel 에 있는 Excel 파일 읽기 )
// Poi 라이브러리 사용 > Excel 파일을 Workbook 객체로 로드 + XSSF( .xlsx )생성 > localWorkbook 변수 선언
Resource resource = new ClassPathResource(localFile);
InputStream inputStream = resource.getInputStream();
XSSFWorkbook localWorkBook = new XSSFWorkbook(inputStream);
// java.lang.IllegalArgumentException: Sheet index (0) is out of range (no sheets) 발생
// Sheet 가 있는지 체크 필요
int sheetCount = localWorkBook.getNumberOfSheets();
if(sheetCount < 1)
{
System.out.println("기존 엑셀파일에 시트가 없습니다.");
return;
}
// 셀 스타일 행, 열 관련 전역변수 저장
// 복사할 셀 스타일의 셀 행과 열 변수 선언 및 초기화
int endRow = 0;
int endColumn = 0;
// localWorkBook 객체의 첫번째 시트를 가져옴
XSSFSheet worksheet = localWorkBook.getSheetAt(0);
// worksheet의 실제 행 갯수를 가져옴
endRow = worksheet.getPhysicalNumberOfRows();
// endRow 까지 반복하며 각 행의 Cell 갯수 체크
for(int i = 0; i < endRow; i++) {
// i번쨰 행의 실제 Cell 갯수를 가져옴
int maxCells = worksheet.getRow(i).getPhysicalNumberOfCells();
// 각 행의 Cell 중 가장 큰값 저장
if(maxCells > endColumn) endColumn = maxCells;
}
// 달력 form 생성
// 로컬 Excel 파일의 Cell 스타일을 복사할 새 Excel 파일 Workbook 객체 생성
XSSFWorkbook newWorkBook = new XSSFWorkbook();
// 달력 불러오기 관련 변수 선언 및 초기화
int year = Integer.parseInt(request.getParameter("year"));
int month = Integer.parseInt(request.getParameter("month"));
// 달력 Form 생성 메서드
makeCalendar(localWorkBook, newWorkBook, year, month, endRow, endColumn);
// 새로운 Excel 파일 저장
FileOutputStream fos = new FileOutputStream(newFile);
newWorkBook.write(fos);
fos.close();
// 새로운 Excel 파일 다운로드 매서드
downloadFile(response, newFile);
// Excel 파일에 대한 모든 변경사항 저장 > workBook.close() 메서드 사용 필수
// workBook.close()를 안쓴 경우, > Excel 파일 다운로드 시, 손상된 엑셀파일 다운로드 오류 발생 가능
// Excel 파일을 닫고 + 메모리 확보의 역할
localWorkBook.close();
newWorkBook.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
• downloadCalendar 내 달력 form 생성 메서드 + 셀 스타일 복사 메서드
private static void makeCalendar(XSSFWorkbook localWorkBook, XSSFWorkbook newWorkBook, int year, int month, int endRow, int endColumn) {
// 시트 가져오기
XSSFSheet calendarSheet = localWorkBook.getSheetAt(0);
// 시트 유무 파악
// newWorkBook 객체에 있는 시트 갯수 저장
int sheetCount = newWorkBook.getNumberOfSheets();
XSSFSheet newSheet = null;
if(sheetCount == 0 ) {
newSheet = newWorkBook.createSheet(calendarSheet.getSheetName());
} else {
newSheet = newWorkBook.getSheetAt(0);
}
// 년도, 월 값 세팅 > index 0행에 세팅
XSSFRow calendarRow = newSheet.createRow(0);
calendarRow.createCell(1).setCellValue(year + "년");
calendarRow.createCell(2).setCellValue(month + "월");
// 요일 Header 세팅
// Header 요일 배열 선언 및 초기화
String[] daysOfWeek = {"일", "월", "화", "수", "목", "금", "토"};
// 헤더값 설정할 행 생성 > index 1행에 헤더값들이 세팅되어야 함
XSSFRow headerRow = newSheet.createRow(1);
// 헤더값들은 간격을 두고 cell에 세팅되어야 한다.
for (int i = 0; i < daysOfWeek.length; i++) {
int cellIndex = (i * 3) + 2;
headerRow.createCell(cellIndex).setCellValue(daysOfWeek[i]);
}
// 달력 일수 Excel 파일 세팅
// Calendar 클래스는 추상클래스이므로 직접 객체 생성 불가능
// 월은 0부터 시작하기 때문에 1을 빼야 한다.
Calendar cal = Calendar.getInstance();
cal.set(year, month-1, 1);
// 해당 월의 시작 요일 계산 > 현재 Calendar 객체가 가리키는 날짜의 요일 반환
// get() 메서드에서는 일요일은 1을 반환, 일반적으로 요일은 0(일요일) ~ 6(토요일)이기 때문에 -1을 한다.
int startDay = cal.get(Calendar.DAY_OF_WEEK) -1;
// 해당 월의 마지막 날짜 계산
// getActualMaximum()메서드는 특정달의 마지막 날짜를 가져올때 사용
int lastDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
//
int totalDay = startDay + lastDay;
int currDay = 1;
for(int i = 0; i < totalDay; i++) {
if(i < startDay) {
copyCellStyles(localWorkBook, newWorkBook, endRow, endColumn, i, 0);
} else {
copyCellStyles(localWorkBook, newWorkBook, endRow, endColumn, i, currDay);
currDay++;
}
}
}
// 기존 Excel 파일 Cell 스타일 복사 메서드
private static void copyCellStyles(XSSFWorkbook styleWorkbook, XSSFWorkbook calWorkbook, int styleEndRow, int styleEndColumn, int dataIdx, int data) {
// 기존 엑셀파일 i번째 Sheet 가져오기
XSSFSheet styleSheet = styleWorkbook.getSheetAt(0);
// 새로운 엑셀파일 i번째 Sheet 생성
// 시트 유무 파악
int sheetCount = calWorkbook.getNumberOfSheets();
XSSFSheet newSheet = null;
if(sheetCount == 0) {
newSheet = calWorkbook.createSheet(styleSheet.getSheetName());
} else {
newSheet = calWorkbook.getSheetAt(0);
}
//데이터삽입 시작 위치 ( 달력의 시작 Row Index )
int startIdx = 2;
//데이터를 삽입할 행 위치
int startRowShare = dataIdx / 7;
//데이터를 삽입할 시작 행위치 계산
int startRow = startIdx + (startRowShare * styleEndRow);
//데이터를 삽입할 끝 행 위치 계산
int endRow = startRow + styleEndRow;
//데이터를 삽입할 시작 열위치 계산
int startColumn = (dataIdx % 7) * styleEndColumn;
//데이터를 삽입할 끝 열위치 계산
int endColumn = startColumn + styleEndColumn;
int i = 0;
for (int j = startRow; j < endRow; j++) {
// 기존 엑셀파일 Sheet의 i번째 행 가져오기
XSSFRow originalRow = styleSheet.getRow(i);
// 새로운 엑셀파일 Sheet에 j번쨰 행 생성 / 행이 없는 경우 행 생성
XSSFRow newRow = newSheet.getRow(j);
if(newRow == null) newRow = newSheet.createRow(j);
for (int k = startColumn; k < endColumn; k++) {
// 기존 행의 k번째 셀 가져오기
XSSFCell originalCell = originalRow.getCell(k%3);
// 새로운 행에 k번째 셀 생성
XSSFCell newCell = newRow.getCell(k);
if(newCell == null) newCell = newRow.createCell(k);
// 날짜 값 셋팅 > 첫번째 행의 마지막 열에 데이터를 삽입하는 경우
if(j == startRow && k == endColumn -1 && data > 0) {
newCell.setCellValue(data);
}
if(originalCell != null) {
// 새로운 셀에 새로운 스타일 생성
XSSFCellStyle newCellStyle = calWorkbook.createCellStyle();
// 새로운 스타일에 기존 셀의 스타일 복사
newCellStyle.cloneStyleFrom(originalCell.getCellStyle());
// 새로운 셀에 복사한 스타일 적용
newCell.setCellStyle(newCellStyle);
}
}
i++;
}
}
• downloadCalendar 내 Excel 다운로드 메서드
// 생성된 Excel 파일 다운로드 메서드
private static void downloadFile(HttpServletResponse response, String filePath) {
try {
// 다운로드할 Excel 파일을 filepath를 통해서 읽어온다.
File file = new File(filePath);
// FileInputStream 객체 생성
FileInputStream inputStream = new FileInputStream(file);
// 컨텐츠 타입 및 파일명 지정
// HTTP 응답 content-Type 의 헤더를 Excel파일의 MME 타입 "" 로 설정
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment;filename=copyExel.xlsx");
// Content-length 헤더를 설정하여 클라이언트에게 전송되는 데이터 크기를 설정
response.setContentLength((int) file.length());
// 클라이언트에게 전송할 데이터를 출력할 OutputStream 객체 생성
OutputStream outputStream = response.getOutputStream();
// 데이터 읽을 버퍼 설정 ( 배열의 크기 1024 )
byte[] buffer = new byte[1024];
int bytesRead;
// inputStream에서 데이터를 읽고 buffer에 저장( 데이터가 남아있지 않을때 까지 ) / 읽은 byte수를 byteRead에 저장
while ((bytesRead = inputStream.read(buffer)) != -1) {
// buffer 배열의 0번 Index부터 byteRead의 길이만큼 데이터를 ouputStream(출력스트림)으로 전송
outputStream.write(buffer, 0, bytesRead);
}
// inputStream 객체 닫기
inputStream.close();
// outputStream에 남아있는 데이터를 강제로 내보냄( 데이터가 제대로 저장되는걸 도움 )
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
• 결과물
- C:/excel1 디렉터리가 생성되고 그 안에 copyExcel.xlsx 파일이 다운로드 되게 된다.
- View 페이지에서 select 태그 값으로 2024년 1월을 선택한 경우
반응형
'■ 공부 기록 > 기능 구현' 카테고리의 다른 글
[ Poi 라이브러리 ] JAVA로 Excel 다운로드 기능 구현 (1) (0) | 2024.04.07 |
---|
Comments