IT/development

[spring] spring excel download 모듈화 ver 2

알 수 없는 사용자 2024. 1. 14.

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

 

[spring] spring excel download (feat. 공통으로 분리)

목차 아래 포스팅에서 이어진 내용입니다. [spring] spring excel download (feat. 체크박스) 목차 화면에서 사용자가 체크한 row의 데이터들만 서버로 보내서 엑셀 다운로드 창을 브라우저에게 띄우게 하...

yaga.tistory.com


모듈화 ver 1에서는 화면이 늘어나고 구분자가 늘어남에 따라 ExcelUtil의 static method가 길어진다는 단점이 있어서 불편했다.

그래서 더 고민 끝에 구분자에 따른 시트명, 파일명, 헤더정보를 별도의 파일로 빼기로 했다.

이렇게 되면 파일에 내용만 추가하면 되고 소스는 건드릴 필요가 없게된다.


pages.json(시트명, 파일명, 헤더 정보가 있는 파일) resources 하위에 생성

{
  "comments": {
    "description": "이 파일은 엑셀 다운로드에 사용되는 엑셀 정보를 포함합니다.",
    "fileType": "json"
  },
  "singer": {
    "sheetName": "가수시트",
    "fileName": "가수",
    "headers": ["아이디", "이름", "직업"]
  },
  "currency": {
    "sheetName": "통화시트",
    "fileName": "통화",
    "headers": ["나라", "통화"]
  },
  "actor": {
    "sheetName": "배우시트",
    "fileName": "배우",
    "headers": ["성명", "연기력"]
  }
  //필요 시 추가..
}

 

PageInfo

package study.dev.thboard3.board.file.web;

import lombok.Data;

@Data
//pages.json의 필드를 담을 객체
public class PageInfo {

    private String sheetName;   //시트명
    private String fileName;    //엑셀파일명
    private String headers[];   //헤더 목록
}

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;

@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, pageGubun);
    }
}

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.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import study.dev.thboard3.board.file.web.PageInfo;

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 {

    @Value("classpath:pages.json")
    private Resource pagesJsonResources;

    /**
     * 엑셀 다운로드 처리
     * @param paramData
     * @param response
     * @param pageGubun
     * @throws IOException
     */
    public void download(String paramData, HttpServletResponse response, String pageGubun) throws IOException {

        ObjectMapper objectMapper = new ObjectMapper();
        //json파일에서 페이지 정보 읽어서 map으로 반환
        Map<String, PageInfo> pageMap = objectMapper.readValue(pagesJsonResources.getInputStream(), new TypeReference<Map<String, PageInfo>>() {});
        //구분자에 해당되는 json파일의 내용이 담긴 객체
        PageInfo pageInfo = pageMap.get(pageGubun);
        // map타입의 list로 반환
        List<Map<String, String>> dataList = convertJsonToList(paramData);

        if (pageInfo != null) {
            // 엑셀 생성/다운로드 처리
            excelParsingProcess(dataList, response, pageInfo.getSheetName(), pageInfo.getFileName(), pageInfo.getHeaders());
        }
    }

    /**
     * 엑셀 파싱, 다운로드 처리
     * @param dataList
     * @param response
     * @param sheetName
     * @param fileName
     * @param headers
     * @throws IOException
     */
    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>>>() {});
    }


}

ver 1의 ExcelUtil 클래스는 삭제해도 된다.(pages.json로 대체)

테스트


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

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