엑셀 다운로드
기본 원칙
- Controller 반환 타입:
ResponseEntity<byte[]> Content-Disposition헤더로 파일명 지정XSSFWorkbook,ByteArrayOutputStream사용ExcelUtil유틸리티 메서드를 활용한다
의존성
// build.gradle
implementation 'org.apache.poi:poi-ooxml:5.2.5'
컨트롤러 엑셀 다운로드 처리
@RestController
@RequiredArgsConstructor
@Slf4j
@RequestMapping("/api/user")
public class UserController {
private final UserExcelService userExcelService;
/**
* 사용자 목록 엑셀 다운로드
*/
@PostMapping("/excel")
public ResponseEntity<byte[]> downloadExcel(@RequestBody UserVo vo) {
byte[] excel = userExcelService.createUserExcel(vo);
String filename = "사용자목록_" + DateUtil.getCurrentDateTime("yyyyMMdd") + ".xlsx";
String encodedFilename = URLEncoder.encode(filename, StandardCharsets.UTF_8)
.replace("+", "%20");
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename*=UTF-8''" + encodedFilename)
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(excel);
}
}
Service에서 ExcelUtil 사용
@Service
@RequiredArgsConstructor
@Slf4j
public class UserExcelService {
private final UserMapper userMapper;
@Transactional(readOnly = true)
public byte[] createUserExcel(UserVo vo) {
List<UserVo> list = userMapper.getList(vo);
try (XSSFWorkbook workbook = new XSSFWorkbook()) {
Sheet sheet = workbook.createSheet("사용자 목록");
// 열 너비 설정
ExcelUtil.setWidthCell(sheet, 0, 3000); // 사용자번호
ExcelUtil.setWidthCell(sheet, 1, 5000); // 사용자명
ExcelUtil.setWidthCell(sheet, 2, 8000); // 이메일
ExcelUtil.setWidthCell(sheet, 3, 6000); // 등록일시
// 헤더 행 생성 (0번째 행)
Row headerRow = sheet.createRow(0);
ExcelUtil.setHeightRow(headerRow, 400);
Cell h0 = headerRow.createCell(0);
Cell h1 = headerRow.createCell(1);
Cell h2 = headerRow.createCell(2);
Cell h3 = headerRow.createCell(3);
ExcelUtil.setStringValue(h0, "사용자번호");
ExcelUtil.setStringValue(h1, "사용자명");
ExcelUtil.setStringValue(h2, "이메일");
ExcelUtil.setStringValue(h3, "등록일시");
// 헤더 스타일
ExcelUtil.setStyleFont(h0, true, 11);
ExcelUtil.setStyleFont(h1, true, 11);
ExcelUtil.setStyleFont(h2, true, 11);
ExcelUtil.setStyleFont(h3, true, 11);
ExcelUtil.setStyleRowCellColor(h0, IndexedColors.GREY_25_PERCENT);
ExcelUtil.setStyleRowCellColor(h1, IndexedColors.GREY_25_PERCENT);
ExcelUtil.setStyleRowCellColor(h2, IndexedColors.GREY_25_PERCENT);
ExcelUtil.setStyleRowCellColor(h3, IndexedColors.GREY_25_PERCENT);
ExcelUtil.setStyleAlignment(h0, HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
// 데이터 행 생성
int rowIdx = 1;
for (UserVo user : list) {
Row row = sheet.createRow(rowIdx++);
ExcelUtil.setNumberValue(row.createCell(0), user.getUserSn());
ExcelUtil.setStringValue(row.createCell(1), user.getUserNm());
ExcelUtil.setStringValue(row.createCell(2), user.getUserEmail());
ExcelUtil.setDateValue(row.createCell(3), user.getRegDt(), "yyyy-MM-dd HH:mm:ss");
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
workbook.write(out);
return out.toByteArray();
} catch (IOException e) {
log.error("엑셀 생성 실패", e);
throw new RuntimeException("엑셀 파일 생성 중 오류가 발생했습니다.");
}
}
}
ExcelUtil 주요 메서드
| 메서드 | 설명 |
|---|---|
setWidthCell(sheet, col, width) | 열 너비 설정 |
setHeightRow(row, height) | 행 높이 설정 |
setStringValue(cell, value) | 문자열 값 설정 |
setDateValue(cell, value, format) | 날짜 값 설정 |
setNumberValue(cell, value) | 숫자 값 설정 |
setCurrencyValue(cell, value) | 통화 값 설정 (천 단위 구분) |
setStyleFont(cell, bold, size) | 폰트 스타일 설정 |
setStyleAlignment(cell, hAlign, vAlign) | 정렬 설정 |
setStyleRowCellColor(cell, color) | 배경색 설정 |
mergeRowCell(sheet, row, colStart, colEnd) | 셀 병합 |
setImage(sheet, imgPath, row, col) | 이미지 삽입 |
파일명 인코딩
한글 파일명은 RFC 5987 방식으로 인코딩한다.
// 한글 파일명 인코딩
String filename = "사용자목록_20260516.xlsx";
String encodedFilename = URLEncoder.encode(filename, StandardCharsets.UTF_8)
.replace("+", "%20");
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename*=UTF-8''" + encodedFilename)
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(excel);
보안 주의사항
- 엑셀 데이터에 개인정보 포함 시 권한 검증 필수
- 대용량 데이터 엑셀 생성은 비동기 처리 고려 (OOM 방지)
체크리스트
- [ ] Controller 반환 타입:
ResponseEntity<byte[]> - [ ]
Content-Disposition헤더에attachment지정 - [ ] 한글 파일명 UTF-8 인코딩 (
filename*=UTF-8'') - [ ]
ExcelUtil메서드 활용 - [ ]
XSSFWorkbook,ByteArrayOutputStream사용 - [ ] 다운로드 권한 검증
- [ ] 엑셀 파일에 개인정보 포함 여부 확인