IT/development

[spring] spring excel download 모듈화 ver 1

알 수 없는 사용자 2024. 1. 14. 12:01
반응형

목차

    아래 포스팅에서 이어진 내용입니다.

     

    [spring] spring excel download (feat. 체크박스)

    목차 화면에서 사용자가 체크한 row의 데이터들만 서버로 보내서 엑셀 다운로드 창을 브라우저에게 띄우게 하고 엑셀 다운로드 하는 로직 springBoot 2.7.7, jdk 11 version view 엑셀 다운로드 예제 목록

    yaga.tistory.com


    프로젝트 팀원들이 내가 만든 엑셀 모듈을 그냥 화면에서 호출만 하고 나머지는 신경쓰게 하고 싶지 않았다.

    호출하는 쪽에서는 모듈이 어떻게 작동하는지 모르게 만드는 것, 나는 알맞은 조건으로 호출만 하면 되는 것

    그래서 고민 끝에 일단 무식하게 아래와 같이 구현했다.(보완 사항이 많은 소스임)

    화면에서는 공통 엑셀 컨트롤러의 url 호출 시 매개변수(json데이터, 구분자)만 인코딩해서 넘기면 된다.

    html

    <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>엑셀 다운로드 예제1</title>
        <script src="https://code.jquery.com/jquery-latest.min.js"></script>
    </head>
    <body>
    
    <div class="contents">
          <h2>엑셀 다운로드 예제1</h2>
    
          <div class="tbl scroll-x">
                <table>
                  <caption>목록</caption>
                  <colgroup>
                    <col width="60px">
                    <col width="60px">
                    <col width="100px">
                    <col width="150px">
                  </colgroup>
                  <thead>
                  <tr>
                    <th scope="row">체크박스</th>
                    <th scope="row">순번</th>
                    <th scope="row">사원명</th>
                    <th scope="row">직업</th>
                  </tr>
                  </thead>
                  <tbody class="center">
                    <tr>
                      <td><input type="checkbox" class="checkbox"></td>
                      <td>kkh</td>
                      <td>김경호</td>
                      <td>가수</td>
                    </tr>
                    <tr>
                      <td><input type="checkbox" class="checkbox"></td>
                      <td>ljb</td>
                      <td>박완규</td>
                      <td>가수</td>
                    </tr>
                    <tr>
                      <td><input type="checkbox" class="checkbox"></td>
                      <td>jkh</td>
                      <td>정경화</td>
                      <td>가수</td>
                    </tr>
                  </tbody>
                </table>
    
                <button id="btn">엑셀 다운로드</button>
              </div>
      </div>
    
        <script>
            function downloadExcel(pageGubun) {
    			//데이터 담을 배열
                var selectedData = [];
    			//class명이 checkbox인 친구들 루프 돌며 td 엘리먼트에서 텍스트를 가져온다.
                $('.checkbox:checked').each(function() {
                    var rowData = $(this).closest('tr');
                    var fields = rowData.find('td');
    				//td에 표시된 데이터들을 JSON형식으로 세팅
                    var dataObject = {
                        id: fields.eq(1).text(),
                        name: fields.eq(2).text(),
                        job: fields.eq(3).text(),
                    };
    				//배열에 JSON 데이터 저장
                    selectedData.push(dataObject);
                });
    			//엑셀다운로드 url + 데이터 인코딩한 값을 쿼리스트링으로 붙인 값으로 주소 변경
                var downloadUrl = 'exceldownload?selectedData=' + encodeURIComponent(JSON.stringify(selectedData)) + "&pageGubun=" + encodeURIComponent(pageGubun);
                window.location.href = downloadUrl;
            }
    
            $("#btn").on("click", function () {
            	//구분자 추가
                downloadExcel("singer");
            });
        </script>
    
    
    </body>
    </html>

    Controller

    package study.dev.thboard3.board.file.web;
    
    import lombok.RequiredArgsConstructor;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.servlet.ModelAndView;
    import study.dev.thboard3.board.file.service.ExcelService;
    
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    import static study.dev.thboard3.cmm.util.ExcelUtil.*;
    
    @Controller
    @Slf4j
    @RequiredArgsConstructor
    public class ExcelController {
    
        private final ExcelService excelService;
    
        /**
         * 엑셀 다운로드 처리
         * @param paramData
         * @param pageGubun
         * @param response
         */
        @GetMapping("/exceldownload")
        public void downloadExcel(@RequestParam(name = "selectedData") String paramData,
                                  @RequestParam(name = "pageGubun") String pageGubun,
                                  HttpServletResponse response) throws IOException {
            //엑셀 다운로드 호출
            excelService.download(paramData, response, getSheetName(pageGubun), getExcelFileName(pageGubun), getHeaders(pageGubun));
        }
    }

    ExcelUtil

    여기서는 static method에서 구분자에 따라 미리 정의된 값만 반환하는 단순한 코드이고 이를 컨트롤러에서 사용해서 헤더, 시트명, 엑셀파일명을 세팅한다.

    package study.dev.thboard3.cmm.util;
    
    
    public class ExcelUtil {
    
        /**
         * 구분자에 해당되는 헤더를 배열로 반환한다.
         * @param pageGubun
         * @return
         */
        public static String[] getHeaders(String pageGubun) {
            switch (pageGubun) {
                case "singer":
                    return new String[]{"아이디", "이름", "직업"};
                case "currency":
                    return new String[]{"나라", "통화"};
                default:
                    // 기본 헤더 또는 예외 처리
                    return new String[]{"Default Header 1", "Default Header 2"};
            }
        }
    
        /**
         * 구분자에 해당되는 시트명을 구한다.
         * @param pageGubun
         * @return
         */
        public static String getSheetName(String pageGubun) {
            switch (pageGubun) {
                case "singer":
                    return new String("가수시트");
                case "currency":
                    return new String("통화시트");
                default:
                    // 기본 헤더 또는 예외 처리
                    return new String("기본");
            }
        }
    
        /**
         * 구분자에 해당되는 엑셀파일명을 구한다.
         * @param pageGubun
         * @return
         */
        public static String getExcelFileName(String pageGubun) {
                switch (pageGubun) {
                    case "singer":
                        return new String("가수");
                    case "currency":
                        return new String("통화");
                    default:
                        // 기본 헤더 또는 예외 처리
                        return new String("기본");
                }
            }
    }

    Service

    package study.dev.thboard3.board.file.service;
    
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.core.type.TypeReference;
    import com.fasterxml.jackson.databind.ObjectMapper;
    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 javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.net.URLEncoder;
    import java.util.List;
    import java.util.Map;
    
    @Service("excelService")
    public class ExcelService {
    
        /**
         * 엑셀 다운로드 처리
         * @param paramData
         * @param response
         * @param sheetName
         * @param fileName
         * @param headers
         */
        public void download(String paramData,
                             HttpServletResponse response,
                             String sheetName,
                             String fileName,
                             String[] headers) throws IOException {
            // map타입의 list로 반환
            List<Map<String, String>> dataList = convertJsonToList(paramData);
            // 엑셀 생성/다운로드 처리
            excelParsingProcess(dataList, response, sheetName, fileName, headers);
        }
    
        /**
         * 엑셀 파싱, 다운로드 처리
         * @param dataList
         * @param response
         * @param sheetName
         * @param fileName
         * @param headers
         */
        private void excelParsingProcess(List<Map<String, String>> dataList,
                                         HttpServletResponse response,
                                         String sheetName,
                                         String fileName,
                                         String[] headers) throws IOException {
    
            Workbook wb = new XSSFWorkbook();
            //시트 생성
            Sheet sheet = wb.createSheet(sheetName);
    
            // header row  세팅
            Row headerRow = sheet.createRow(0);
    
            int cellNum = 0;
            for (String header : headers) {
                //헤더값 세팅
                headerRow.createCell(cellNum++).setCellValue(header);
            }
            // body row 세팅
            int rowNum = 1;
            for (Map<String, String> data : dataList) {
               Row row = sheet.createRow(rowNum++);
    
               cellNum = 0;
               //데이터 세팅
               for (String key : data.keySet()) {
                   row.createCell(cellNum++).setCellValue(data.get(key));
               }
            }
    
            String extension = ".xlsx";
    
            // HTTP 응답 설정
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName + extension, "UTF-8"));
    
            wb.write(response.getOutputStream());
            wb.close();
        }
    
        /**
         * json 형식 데이터를 map타입의 list로 반환한다.
         * @param jsonData
         * @return
         * @throws JsonProcessingException
         */
        private List<Map<String, String>> convertJsonToList(String jsonData) throws JsonProcessingException {
    
            ObjectMapper objectMapper = new ObjectMapper();
            return objectMapper.readValue(jsonData, new TypeReference<List<Map<String, String>>>() {});
        }
    
    
    }

    테스트

    이렇게 무식하지만 나름 모듈화를 해봤다.

    물론 구분자에 따른 값이 늘어날 수록 static method가 지저분 해진다는 단점은 있고 그밖의 단점도 많다.

    아래에서 한번 더 리팩토링을 해봤다.

     

    [spring] spring excel download 모듈화 ver 2

    아래 포스팅에서 이어진 내용입니다. [spring] spring excel download (feat. 공통으로 분리) 목차 아래 포스팅에서 이어진 내용입니다. [spring] spring excel download (feat. 체크박스) 목차 화면에서 사용자가 체

    yaga.tistory.com


    개인 스터디 기록을 메모하는 공간이라 틀린점이 있을 수 있습니다.

    틀린 점 있을 경우 댓글 부탁드립니다.

    반응형