주요글: 도커 시작하기
반응형

스프링 부트 2.0에서 엑셀 다운로드 기능을 구현하는 방법을 정리했다.


pom.xml 설정


https://start.spring.io/ 사이트에서 스프링 부트 2.0.x 버전을 선택해서 프로젝트를 생성한다. Dependencies로는 Web과 Thymeleaf를 선택한다. 생성한 프로젝트 pom.xml 파일에 엑셀 생성을 위해 poi 의존을 추가한다.


<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"

         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 

              http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>


    <groupId>madvirus</groupId>

    <artifactId>excel-download</artifactId>

    <version>0.0.1-SNAPSHOT</version>

    <packaging>jar</packaging>


    <name>excel-download</name>

    <description>Demo project for Spring Boot</description>


    <parent>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-parent</artifactId>

        <version>2.0.1.RELEASE</version>

        <relativePath/> <!-- lookup parent from repository -->

    </parent>


    <properties>

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

        <java.version>1.8</java.version>

    </properties>


    <dependencies>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-web</artifactId>

        </dependency>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-thymeleaf</artifactId>

        </dependency>


        <dependency>

            <groupId>org.apache.poi</groupId>

            <artifactId>poi</artifactId>

            <version>3.17</version>

        </dependency>


        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-devtools</artifactId>

            <scope>runtime</scope>

        </dependency>

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-test</artifactId>

            <scope>test</scope>

        </dependency>

    </dependencies>


    <build>

        <plugins>

            <plugin>

                <groupId>org.springframework.boot</groupId>

                <artifactId>spring-boot-maven-plugin</artifactId>

            </plugin>

        </plugins>

    </build>



</project>


엑셀 다운로드 위한 application.properties 파일 설정


확장자나 파라미터를 이용해서 엑셀 다운로드를 처리할 수 있도록 application.propertie 파일에 다음 설정을 추가한다.


spring.mvc.contentnegotiation.favor-parameter=true

spring.mvc.contentnegotiation.favor-path-extension=true

spring.mvc.contentnegotiation.media-types.xls=application/vnd.ms-excel


스프링 부트는 기본적으로 ContentNegotiationViewResolver를 사용하는데 각 프로퍼티는 다음을 설정한다.

  • favor-parameter: 이 값이 true면 ContentNegotiationViewResolver가 format 파라미터로 지정한 미디어 타입을 사용하도록 설정
  • favor-path-extension: 이 값이 true면 ContentNegotiationViewResolver가 확장자로 지정한 미디어 타입을 사용하도록 설정
  • media-types.타입: 타입에 해당하는 컨텐츠 타입을 지정

예를 들어 위 설정을 사용하면 다음 요청을 엑셀 타입(application/vnd.ms-excel) 요청으로 인지하고, 엑셀 미디어 타입에 해당하는 응답을 처리할 수 있는 뷰를 사용해서 응답을 생성한다.

  • stat.xls (확장자가 xls)
  • stat?format=xls (format 파라미터가 xls)

예제 컨트롤러


다음 코드는 일반 뷰와 엑셀 다운로드를 처리하는 컨트롤러 코드이다.


@Controller

public class StatController {

    private void populateModel(Model model) {

        List<StatRow> rows = Arrays.asList(

                new StatRow("고객1", 1000, 1500),

                new StatRow("고객2", 2000, 2500),

                new StatRow("고객3", 3000, 3500)

        );

        model.addAttribute("rows", rows);

    }


    @GetMapping("/stat")

    public String get(Model model) {

        populateModel(model);

        return "stat";

    }


    @GetMapping("/stat.xls")

    public String getExcelByExt(Model model) {

        populateModel(model);

        return "statXls";

    }


    @GetMapping(path = "/stat", params = "format=xls")

    public String getExcelByParam(Model model) {

        populateModel(model);

        return "statXls";

    }

}


get() 메서드는 일반 뷰를 사용해서 응답을 생성한다. getExcelByExt() 메서드는 확장자가 xls인 요청 경로를 처리하므로 "statXls"에 대응하는 뷰 중에서 엑셀 타입을 응답으로 생성할 수 있는 뷰를 선택한다. 비슷하게 getExcelByParam() 역시 format 파라미터가 xls인 요청을 처리하므로 엑셀 타입을 생성할 수 있는 뷰를 선택한다.


엑셀 생성을 위한 뷰 클래스


엑셀 다운로드를 위한 뷰 클래스는 다음과 같이 구현한다. 빈 객체 이름으로 "statxls"를 사용했는데 이 이름은 앞서 컨트롤러에서 리턴한 뷰 이름과 같다.


package exceldownload;


import org.apache.poi.ss.usermodel.*;

import org.springframework.stereotype.Component;

import org.springframework.web.servlet.view.document.AbstractXlsView;


import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.util.List;

import java.util.Map;


@Component("statXls")

public class StatXlsView extends AbstractXlsView {

    @Override

    protected void buildExcelDocument(

            Map<String, Object> model, Workbook workbook,

            HttpServletRequest request, HttpServletResponse response) throws Exception {

        response.setHeader("Content-Disposition", "attachment; filename=\"stat.xls\"");


        List<StatRow> stats = (List<StatRow>) model.get("rows");


        CellStyle numberCellStyle = workbook.createCellStyle();

        DataFormat numberDataFormat = workbook.createDataFormat();

        numberCellStyle.setDataFormat(numberDataFormat.getFormat("#,##0"));


        Sheet sheet = workbook.createSheet("mobilestat");

        for (int i = 0 ; i < stats.size() ; i++) {

            StatRow stat = stats.get(i);

            Row row = sheet.createRow(i);


            Cell cell0 = row.createCell(0);

            cell0.setCellValue(stat.getName());


            Cell cell1 = row.createCell(1);

            cell1.setCellType(CellType.NUMERIC);

            cell1.setCellValue(stat.getValue1());

            cell1.setCellStyle(numberCellStyle);


            Cell cell2 = row.createCell(2);

            cell2.setCellType(CellType.NUMERIC);

            cell2.setCellValue(stat.getValue2());

            cell2.setCellStyle(numberCellStyle);

        }

    }

}



타임리프 뷰 구현


타임리프트를 이용한 뷰 구현 파일인 stat.html은 다음과 같아 간단하게 구현했다. 엑셀 다운로드를 위한 링크를 추가했다.


<!DOCTYPE HTML>

<html xmlns:th="http://www.thymeleaf.org">

<head>

    <meta charset="utf-8" />

    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

    <title>통계</title>

</head>

<body>


<a href="stat.xls">엑셀다운, 확장자(stat.xls)</a> |

<a href="stat?format=xls">엑셀다운, 파라미터(stat?format=xls)</a>

<table border="1">

    <thead>

    <tr>

        <th>이름</th>

        <th>값1</th>

        <th>값2</th>

    </tr>

    </thead>

    <tbody>

    <tr th:each="row : ${rows}">

        <td th:text="${row.name}"></td>

        <td th:text="${#numbers.formatInteger(row.value1, 1, 'COMMA')}"></td>

        <td th:text="${#numbers.formatInteger(row.value2, 1, 'COMMA')}"></td>

    </tr>

    </tbody>

</table>


</body>

</html>


예제 실행


완전한 예제 프로젝트는 https://github.com/madvirus/excel-download 리포지토리에서 구할 수 있다. 명령 프롬프트에서 "mvnw spring-boot:run" 명령어를 부트 어플리케이션을 실행한 뒤에 http://localhost:8080/stat 주소에 연결해보자. 다음 결과를 볼 수 있다.



엑셀 다운로드 링크를 클릭해보자. 두 링크 중 아무거나 클릭하면 엑셀 파일을 다운로드 한다.



실제 다운로드한 파일을 열어보자. 아래와 같이 엑셀 파일이 올바르게 생성된 것을 확인할 수 있다.



+ Recent posts