개발자's Life

[JAVA] POI 라이브러리를 이용한 Excel Down 기능 구현 본문

Back-end/Java

[JAVA] POI 라이브러리를 이용한 Excel Down 기능 구현

Rowen Jobs 2023. 3. 25. 21:36
728x90
반응형

회사에서 엑셀 업로드 및 다운로드 기능을 구현하며 개발을 이어 나가고 있습니다. 

 

오늘은 엑셀 다운로드의 기본 구성에 대해 쉽게 설명 드릴 예정입니다 

 

개발 환경

- Java 17

- 인텔리제이

- Gradle 

 

1. Gradle 의존성 추가

// POI 라이브러리 추가.(xls)
implementation 'org.apache.poi:poi-ooxml:4.1.2'

 

 

2. 화면구성(필요할 경우만 참고)

<!doctype html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-aFq/bzH65dt+w6FI2ooMVUpc+21e0SRygnTpmBvdBgSdnuTN7QbdgL+OapgHtvPp" crossorigin="anonymous">
    <title>Excel 예제</title>
</head>
<body>
    <form action="/excelDown" method="POST">
        <div>
            <label>엑셀 파일명</label>
            <input type="text" name="fileName">
        </div>
        <div>
            <label>엑셀 열 갯수</label>
            <input type="number" name="colNum">
        </div>
        <div>
            <label>엑셀 행 갯수</label>
            <input type="number" name="rowNum">
        </div>
        <button class="btn btn-primary rounded-pill px-3" type="submit">엑셀 다운</button>
    </form>
</body>
</html>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha2/dist/js/bootstrap.bundle.min.js" integrity="sha384-qKXV1j0HvMUeCBQ+QVp7JcfGl760yU08IQ+GpUo5hlbpg51QRiuqHAJz8+BrxE/N" crossorigin="anonymous"></script>

 

POST 타입으로 Mapping 시도. 

 

3. Controller 단에서 Mapping 

package excel.excelproject.controller;

import excel.excelproject.model.FormModel;
import excel.excelproject.service.MainServiceImpl;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.Map;

@Controller
public class MainController {

    @Autowired
    MainServiceImpl mainService;

    @GetMapping("/")
    public String mainPage(){
        return "index.html";
    }

    @PostMapping("/excelDown")
    public @ResponseBody Map<Object, Object> excelDown(HttpServletRequest request, HttpServletResponse response, FormModel formModel){
        HashMap<Object, Object> map = new HashMap<>();
        String result = mainService.excelDown(request, response, formModel);
        map.put("result", result);
        return  map;
    };
}

필요에 따라 Map 타입 활용하시면 될 거 같습니다.

 

4. Sevice 단에서 Excel 기능 구현

package excel.excelproject.service;

import excel.excelproject.model.FormModel;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
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.springframework.stereotype.Service;

import java.io.IOException;
import java.net.URLEncoder;

@Service
public class MainServiceImpl implements MainService{


    @Override
    public String excelDown(HttpServletRequest request, HttpServletResponse response, FormModel formModel) {
        try {
            Workbook workbook = new HSSFWorkbook();
            Sheet sheet = workbook.createSheet();

            // 파일명 설정
            String tempName = formModel.getFileName() + ".xls";
            int rowNum = formModel.getRowNum();
            int colNum = formModel.getColNum();

            String name = "출력될파명이름";
            
            // 한글이 포함
            if(tempName.matches(".*[ㄱ-ㅎㅏ-ㅣ가-힣]+.*")) {
                // 브라우저 별 한글 인코딩 https://byul91oh.tistory.com/487 참고
                String header = request.getHeader("User-Agent");
                if (header.contains("Edge")){
                    name = URLEncoder.encode(tempName, "UTF-8").replaceAll("\\+", "%20");
                    response.setHeader("Content-Disposition", "attachment;filename=\"" + name + "\".xlsx;");
                } else if (header.contains("MSIE") || header.contains("Trident")) { // IE 11버전부터 Trident로 변경되었기때문에 추가해준다.
                    name = URLEncoder.encode(tempName, "UTF-8").replaceAll("\\+", "%20");
                    response.setHeader("Content-Disposition", "attachment;filename=" + name + ".xlsx;");
                } else if (header.contains("Chrome")) {
                    name = new String(tempName.getBytes("UTF-8"), "ISO-8859-1");
                    response.setHeader("Content-Disposition", "attachment; filename=\"" + name + "\".xlsx");
                } else if (header.contains("Opera")) {
                    name = new String(tempName.getBytes("UTF-8"), "ISO-8859-1");
                    response.setHeader("Content-Disposition", "attachment; filename=\"" + name + "\".xlsx");
                } else if (header.contains("Firefox")) {
                    name = new String(tempName.getBytes("UTF-8"), "ISO-8859-1");
                    response.setHeader("Content-Disposition", "attachment; filename=" + name + ".xlsx");
                }
            } else {// 한글 미 포함
                name = tempName;
            }

            // 입력 Row 만큼 반복문 실행
            for (int rowCnt = 0; rowCnt < rowNum; rowCnt++){
                Row row = sheet.createRow(rowCnt);
                // 입력 Column 만큼 반복문 실행
                for(int colCnt = 0; colCnt < colNum; colCnt++){
                    row.createCell(colCnt).setCellValue("cell Number : " + colCnt);
                }
            }
		
        
        	// 엑셀 셋팅
            response.setContentType("ms-vnd/excel");
            // name 이 엑셀 파일명
            response.setHeader("Content-Disposition", "attachment;filename=" + name);

            workbook.write(response.getOutputStream());
            workbook.close();

        } catch (IOException e) {
            throw new RuntimeException(e);
        }


        return null;
    }
}

저는 Param 으로 파일명, Row 갯수, Column 갯수 를 받아 출력하였습니다. 

파일명이 한글이 포함되면 인코딩 에러가 발생하여 

https://byul91oh.tistory.com/487 

 

[JAVA]브라우저별 한글 파일명 인코딩 _ excel파일

서버에서 프론트로 파일을 전송할 때 한글로 파일명을 보내면 깨지는 경우가 다반사입니다. 따라서 아래 로직과 같이 User-Agent header 값을 가져와서 브라우저 별로 인코딩을 해 줘야 한글이 깨지

byul91oh.tistory.com

코드 활용하여 한글일 경우에도 정상적으로 다운로드 가능하게 구현하였습니다. 

 

주석으로 자세히 달아서 참고 부탁드리고 틀린 부분 있으시면 댓글 부탁드립니다! 

 

코드는 

https://github.com/RowenKim/downExcel

 

GitHub - RowenKim/downExcel: SpringBoot, Poi library, Html, JAVA

SpringBoot, Poi library, Html, JAVA. Contribute to RowenKim/downExcel development by creating an account on GitHub.

github.com

참고해주세요!

728x90
Comments